xref: /aosp_15_r20/external/pytorch/c10/util/IdWrapper.h (revision da0073e96a02ea20f0ac840b70461e3646d07c45)
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