1 #pragma once 2 3 #include <cstddef> 4 #include <functional> 5 #include <utility> 6 7 namespace c10 { 8 9 /** 10 * This template simplifies generation of simple classes that wrap an id 11 * in a typesafe way. Namely, you can use it to create a very lightweight 12 * type that only offers equality comparators and hashing. Example: 13 * 14 * struct MyIdType final : IdWrapper<MyIdType, uint32_t> { 15 * constexpr explicit MyIdType(uint32_t id): IdWrapper(id) {} 16 * }; 17 * 18 * Then in the global top level namespace: 19 * 20 * C10_DEFINE_HASH_FOR_IDWRAPPER(MyIdType); 21 * 22 * That's it - equality operators and hash functions are automatically defined 23 * for you, given the underlying type supports it. 24 */ 25 template <class ConcreteType, class UnderlyingType> 26 class IdWrapper { 27 public: 28 using underlying_type = UnderlyingType; 29 using concrete_type = ConcreteType; 30 31 protected: IdWrapper(underlying_type id)32 constexpr explicit IdWrapper(underlying_type id) noexcept( 33 noexcept(underlying_type(std::declval<underlying_type>()))) 34 : id_(id) {} 35 underlyingId()36 constexpr underlying_type underlyingId() const 37 noexcept(noexcept(underlying_type(std::declval<underlying_type>()))) { 38 return id_; 39 } 40 41 private: hash_value(const concrete_type & v)42 friend size_t hash_value(const concrete_type& v) { 43 return std::hash<underlying_type>()(v.id_); 44 } 45 46 // TODO Making operator== noexcept if underlying type is noexcept equality 47 // comparable doesn't work with GCC 4.8. 48 // Fix this once we don't need GCC 4.8 anymore. 49 friend constexpr bool operator==( 50 const concrete_type& lhs, 51 const concrete_type& rhs) noexcept { 52 return lhs.id_ == rhs.id_; 53 } 54 55 // TODO Making operator!= noexcept if operator== is noexcept doesn't work with 56 // GCC 4.8. 57 // Fix this once we don't need GCC 4.8 anymore. 58 friend constexpr bool operator!=( 59 const concrete_type& lhs, 60 const concrete_type& rhs) noexcept { 61 return !(lhs == rhs); 62 } 63 64 underlying_type id_; 65 }; 66 67 } // namespace c10 68 69 #define C10_DEFINE_HASH_FOR_IDWRAPPER(ClassName) \ 70 namespace std { \ 71 template <> \ 72 struct hash<ClassName> { \ 73 size_t operator()(ClassName x) const { \ 74 return hash_value(x); \ 75 } \ 76 }; \ 77 } 78