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