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