jlebar created this revision. jlebar added a reviewer: rnk. jlebar added subscribers: tra, cfe-commits.
CanonicalDeclPtr<T> is just like a T*, except it calls T::getCanonicalDecl() on construction. This is useful as the key in a "set of canonical Decls" -- it's much less error-prone than calling getCanonicalDecl() every time you touch the set. https://reviews.llvm.org/D25703 Files: clang/include/clang/AST/Redeclarable.h Index: clang/include/clang/AST/Redeclarable.h =================================================================== --- clang/include/clang/AST/Redeclarable.h +++ clang/include/clang/AST/Redeclarable.h @@ -279,6 +279,68 @@ bool isFirstDecl() const { return getFirstDecl() == this; } }; -} +/// A wrapper class around a pointer that always points to its canonical +/// declaration. +/// +/// CanonicalDeclPtr<decl_type> behaves just like decl_type*, except we call +/// decl_type::getCanonicalDecl() on construction. +/// +/// This is useful for hashtables that you want to be keyed on a declaration's +/// canonical decl -- if you use CanonicalDeclPtr as the key, you don't need to +/// remember to call getCanonicalDecl() everywhere. +template <typename decl_type> class CanonicalDeclPtr { +public: + CanonicalDeclPtr() : Ptr(nullptr) {} + CanonicalDeclPtr(decl_type *Ptr) + : Ptr(Ptr ? Ptr->getCanonicalDecl() : nullptr) {} + CanonicalDeclPtr(const CanonicalDeclPtr &) = default; + CanonicalDeclPtr &operator=(const CanonicalDeclPtr &) = default; + + operator decl_type *() { return Ptr; } + operator const decl_type *() const { return Ptr; } + + decl_type *operator->() { return Ptr; } + const decl_type *operator->() const { return Ptr; } + + decl_type &operator*() { return *Ptr; } + const decl_type &operator*() const { return *Ptr; } + +private: + friend struct llvm::DenseMapInfo<CanonicalDeclPtr<decl_type>>; + + decl_type *Ptr; +}; +} // namespace clang + +namespace llvm { +template <typename decl_type> +struct DenseMapInfo<clang::CanonicalDeclPtr<decl_type>> { + using CanonicalDeclPtr = clang::CanonicalDeclPtr<decl_type>; + using BaseInfo = DenseMapInfo<decl_type *>; + + static CanonicalDeclPtr getEmptyKey() { + // Construct our CanonicalDeclPtr this way because the regular constructor + // would dereference P.Ptr, which is not allowed. + CanonicalDeclPtr P; + P.Ptr = BaseInfo::getEmptyKey(); + return P; + } + + static CanonicalDeclPtr getTombstoneKey() { + CanonicalDeclPtr P; + P.Ptr = BaseInfo::getTombstoneKey(); + return P; + } + + static unsigned getHashValue(const CanonicalDeclPtr &P) { + return BaseInfo::getHashValue(P); + } + + static bool isEqual(const CanonicalDeclPtr &LHS, + const CanonicalDeclPtr &RHS) { + return BaseInfo::isEqual(LHS, RHS); + } +}; +} // namespace llvm #endif
Index: clang/include/clang/AST/Redeclarable.h =================================================================== --- clang/include/clang/AST/Redeclarable.h +++ clang/include/clang/AST/Redeclarable.h @@ -279,6 +279,68 @@ bool isFirstDecl() const { return getFirstDecl() == this; } }; -} +/// A wrapper class around a pointer that always points to its canonical +/// declaration. +/// +/// CanonicalDeclPtr<decl_type> behaves just like decl_type*, except we call +/// decl_type::getCanonicalDecl() on construction. +/// +/// This is useful for hashtables that you want to be keyed on a declaration's +/// canonical decl -- if you use CanonicalDeclPtr as the key, you don't need to +/// remember to call getCanonicalDecl() everywhere. +template <typename decl_type> class CanonicalDeclPtr { +public: + CanonicalDeclPtr() : Ptr(nullptr) {} + CanonicalDeclPtr(decl_type *Ptr) + : Ptr(Ptr ? Ptr->getCanonicalDecl() : nullptr) {} + CanonicalDeclPtr(const CanonicalDeclPtr &) = default; + CanonicalDeclPtr &operator=(const CanonicalDeclPtr &) = default; + + operator decl_type *() { return Ptr; } + operator const decl_type *() const { return Ptr; } + + decl_type *operator->() { return Ptr; } + const decl_type *operator->() const { return Ptr; } + + decl_type &operator*() { return *Ptr; } + const decl_type &operator*() const { return *Ptr; } + +private: + friend struct llvm::DenseMapInfo<CanonicalDeclPtr<decl_type>>; + + decl_type *Ptr; +}; +} // namespace clang + +namespace llvm { +template <typename decl_type> +struct DenseMapInfo<clang::CanonicalDeclPtr<decl_type>> { + using CanonicalDeclPtr = clang::CanonicalDeclPtr<decl_type>; + using BaseInfo = DenseMapInfo<decl_type *>; + + static CanonicalDeclPtr getEmptyKey() { + // Construct our CanonicalDeclPtr this way because the regular constructor + // would dereference P.Ptr, which is not allowed. + CanonicalDeclPtr P; + P.Ptr = BaseInfo::getEmptyKey(); + return P; + } + + static CanonicalDeclPtr getTombstoneKey() { + CanonicalDeclPtr P; + P.Ptr = BaseInfo::getTombstoneKey(); + return P; + } + + static unsigned getHashValue(const CanonicalDeclPtr &P) { + return BaseInfo::getHashValue(P); + } + + static bool isEqual(const CanonicalDeclPtr &LHS, + const CanonicalDeclPtr &RHS) { + return BaseInfo::isEqual(LHS, RHS); + } +}; +} // namespace llvm #endif
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits