1//===- llvm/CAS/CASID.h -----------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_CAS_CASID_H
10#define LLVM_CAS_CASID_H
11
12#include "llvm/ADT/ArrayRef.h"
13#include "llvm/ADT/DenseMapInfo.h"
14#include "llvm/ADT/SmallString.h"
15#include "llvm/ADT/StringExtras.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/Support/Error.h"
18
19namespace llvm {
20
21class raw_ostream;
22
23namespace cas {
24
25class CASID;
26
27/// Context for CAS identifiers.
28class CASContext {
29 virtual void anchor();
30
31public:
32 virtual ~CASContext() = default;
33
34 /// Get an identifer for the schema used by this CAS context. Two CAS
35 /// instances should return \c true for this identifier if and only if their
36 /// CASIDs are safe to compare by hash. This is used by \a
37 /// CASID::equalsImpl().
38 virtual StringRef getHashSchemaIdentifier() const = 0;
39
40protected:
41 /// Print \p ID to \p OS.
42 virtual void printIDImpl(raw_ostream &OS, const CASID &ID) const = 0;
43
44 friend class CASID;
45};
46
47/// Unique identifier for a CAS object.
48///
49/// Locally, stores an internal CAS identifier that's specific to a single CAS
50/// instance. It's guaranteed not to change across the view of that CAS, but
51/// might change between runs.
52///
53/// It also has \a CASIDContext pointer to allow comparison of these
54/// identifiers. If two CASIDs are from the same CASIDContext, they can be
55/// compared directly. If they are, then \a
56/// CASIDContext::getHashSchemaIdentifier() is compared to see if they can be
57/// compared by hash, in which case the result of \a getHash() is compared.
58class CASID {
59public:
60 void dump() const;
61
62 friend raw_ostream &operator<<(raw_ostream &OS, const CASID &ID) {
63 ID.print(OS);
64 return OS;
65 }
66
67 /// Print CASID.
68 void print(raw_ostream &OS) const {
69 return getContext().printIDImpl(OS, ID: *this);
70 }
71
72 /// Return a printable string for CASID.
73 LLVM_ABI std::string toString() const;
74
75 ArrayRef<uint8_t> getHash() const {
76 return arrayRefFromStringRef<uint8_t>(Input: Hash);
77 }
78
79 friend bool operator==(const CASID &LHS, const CASID &RHS) {
80 if (LHS.Context == RHS.Context)
81 return LHS.Hash == RHS.Hash;
82
83 // EmptyKey or TombstoneKey.
84 if (!LHS.Context || !RHS.Context)
85 return false;
86
87 // CASIDs are equal when they have the same hash schema and same hash value.
88 return LHS.Context->getHashSchemaIdentifier() ==
89 RHS.Context->getHashSchemaIdentifier() &&
90 LHS.Hash == RHS.Hash;
91 }
92
93 friend bool operator!=(const CASID &LHS, const CASID &RHS) {
94 return !(LHS == RHS);
95 }
96
97 friend hash_code hash_value(const CASID &ID) {
98 return hash_combine_range(R: ID.getHash());
99 }
100
101 const CASContext &getContext() const {
102 assert(Context && "Tombstone or empty key for DenseMap?");
103 return *Context;
104 }
105
106 static CASID getDenseMapEmptyKey() {
107 return CASID(nullptr, DenseMapInfo<StringRef>::getEmptyKey());
108 }
109 static CASID getDenseMapTombstoneKey() {
110 return CASID(nullptr, DenseMapInfo<StringRef>::getTombstoneKey());
111 }
112
113 CASID() = delete;
114
115 /// Create CASID from CASContext and raw hash bytes.
116 static CASID create(const CASContext *Context, StringRef Hash) {
117 return CASID(Context, Hash);
118 }
119
120private:
121 CASID(const CASContext *Context, StringRef Hash)
122 : Context(Context), Hash(Hash) {}
123
124 const CASContext *Context;
125 SmallString<32> Hash;
126};
127
128} // namespace cas
129
130template <> struct DenseMapInfo<cas::CASID> {
131 static cas::CASID getEmptyKey() { return cas::CASID::getDenseMapEmptyKey(); }
132
133 static cas::CASID getTombstoneKey() {
134 return cas::CASID::getDenseMapTombstoneKey();
135 }
136
137 static unsigned getHashValue(cas::CASID ID) {
138 return (unsigned)hash_value(ID);
139 }
140
141 static bool isEqual(cas::CASID LHS, cas::CASID RHS) { return LHS == RHS; }
142};
143
144} // namespace llvm
145
146#endif // LLVM_CAS_CASID_H
147