1#pragma once
2
3#include <c10/macros/Macros.h>
4#include <cstddef>
5#include <functional>
6#include <utility>
7
8namespace 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 */
26template <class ConcreteType, class UnderlyingType>
27class 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