Bug 1890689 accumulate input in LargerReceiverBlockSizeThanDesiredBuffering GTest...
[gecko.git] / gfx / gl / AutoMappable.h
blobf93b2ccb5738c661f7bc6e94375ce1fd6b701247
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #ifndef MOZILLA_AUTO_MAPPABLE_H
6 #define MOZILLA_AUTO_MAPPABLE_H
8 // Here be dragons.
10 #include <functional>
12 namespace mozilla::gfx {
14 template <class T>
15 size_t Hash(const T&);
17 template <class T>
18 struct StaticStdHasher {
19 static auto HashImpl(const T& v) { return std::hash<T>()(v); }
22 template <class T>
23 struct StaticHasher {
24 static auto HashImpl(const T& v) { return v.hash(); }
26 template <class T>
27 struct StaticHasher<std::optional<T>> {
28 static size_t HashImpl(const std::optional<T>& v) {
29 if (!v) return 0;
30 return Hash(*v);
33 template <>
34 struct StaticHasher<int> : public StaticStdHasher<int> {};
35 template <>
36 struct StaticHasher<bool> : public StaticStdHasher<bool> {};
37 template <>
38 struct StaticHasher<float> : public StaticStdHasher<float> {};
40 template <class T>
41 size_t Hash(const T& v) {
42 return StaticHasher<T>::HashImpl(v);
45 //-
46 // From Boost:
47 // https://www.boost.org/doc/libs/1_37_0/doc/html/hash/reference.html#boost.hash_combine
49 inline size_t HashCombine(size_t seed, const size_t hash) {
50 seed ^= hash + 0x9e3779b9 + (seed << 6) + (seed >> 2);
51 return seed;
54 // -
55 // See
56 // https://codereview.stackexchange.com/questions/136770/hashing-a-tuple-in-c17
58 template <class... Args, size_t... Ids>
59 size_t HashTupleN(const std::tuple<Args...>& tup,
60 const std::index_sequence<Ids...>&) {
61 size_t seed = 0;
62 for (const auto& hash : {Hash(std::get<Ids>(tup))...}) {
63 seed = HashCombine(seed, hash);
65 return seed;
68 template <class... Args>
69 size_t HashTuple(const std::tuple<Args...>& tup) {
70 return HashTupleN(tup, std::make_index_sequence<sizeof...(Args)>());
73 // -
75 template <class T>
76 auto MembersEq(const T& a, const T& b) {
77 const auto atup = a.Members();
78 const auto btup = b.Members();
79 return atup == btup;
82 template <class T>
83 auto MembersLt(const T& a, const T& b) {
84 const auto atup = a.Members();
85 const auto btup = b.Members();
86 return atup == btup;
89 template <class T>
90 auto MembersHash(const T& a) {
91 const auto atup = a.Members();
92 return HashTuple(atup);
95 template <class T>
96 struct MembersHasher final {
97 auto operator()(const T& v) const { return v.hash(); }
100 /** E.g.:
101 struct Foo {
102 int i;
103 bool b;
105 auto Members() const { return std::tie(i, b); }
106 INLINE_AUTO_MAPPABLE(Foo)
108 std::unordered_set<T, T::Hasher> easy;
110 #define INLINE_DERIVE_MEMBERS_EQ(T) \
111 friend bool operator==(const T& a, const T& b) { \
112 return mozilla::gfx::MembersEq(a, b); \
114 friend bool operator!=(const T& a, const T& b) { return !operator==(a, b); }
115 #define INLINE_AUTO_MAPPABLE(T) \
116 friend bool operator<(const T& a, const T& b) { \
117 return mozilla::gfx::MembersLt(a, b); \
119 INLINE_DERIVE_MEMBERS_EQ(T) \
120 size_t hash() const { \
121 return mozilla::gfx::MembersHash(*reinterpret_cast<const T*>(this)); \
123 using Hasher = mozilla::gfx::MembersHasher<T>;
125 // -
127 /** E.g.:
129 struct Foo : public AutoMappable<Foo> {
130 int i;
131 bool b;
133 auto Members() const { return std::tie(i, b); }
135 std::unordered_set<T, T::Hasher> easy;
137 `easy.insert({{}, 2, true});`
138 The initial {} is needed for aggregate initialization of AutoMappable<Foo>.
139 Use INLINE_AUTO_MAPPABLE if this is too annoying.
141 template <class T>
142 struct AutoMappable {
143 INLINE_AUTO_MAPPABLE(T)
146 } // namespace mozilla::gfx
148 #endif // MOZILLA_AUTO_MAPPABLE_H