1e5ec94a1SRuslan Arutyunyan //===----------------------------------------------------------------------===//
2e5ec94a1SRuslan Arutyunyan //
3e5ec94a1SRuslan Arutyunyan // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5ec94a1SRuslan Arutyunyan // See https://llvm.org/LICENSE.txt for license information.
5e5ec94a1SRuslan Arutyunyan // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5ec94a1SRuslan Arutyunyan //
7e5ec94a1SRuslan Arutyunyan //===----------------------------------------------------------------------===//
8e5ec94a1SRuslan Arutyunyan
9e5ec94a1SRuslan Arutyunyan #ifndef TEST_TRANSPARENT_UNORDERED_H
10e5ec94a1SRuslan Arutyunyan #define TEST_TRANSPARENT_UNORDERED_H
11e5ec94a1SRuslan Arutyunyan
12e5ec94a1SRuslan Arutyunyan #include "test_macros.h"
13e5ec94a1SRuslan Arutyunyan #include "is_transparent.h"
14e5ec94a1SRuslan Arutyunyan
15e5ec94a1SRuslan Arutyunyan #include <cassert>
16e5ec94a1SRuslan Arutyunyan
17e5ec94a1SRuslan Arutyunyan #if TEST_STD_VER > 17
18e5ec94a1SRuslan Arutyunyan
19*d5db71d1SArthur O'Dwyer template <typename T>
20*d5db71d1SArthur O'Dwyer struct StoredType;
21*d5db71d1SArthur O'Dwyer
22*d5db71d1SArthur O'Dwyer template <typename T>
23*d5db71d1SArthur O'Dwyer struct SearchedType;
24*d5db71d1SArthur O'Dwyer
25*d5db71d1SArthur O'Dwyer struct hash_impl {
26*d5db71d1SArthur O'Dwyer template <typename T>
operatorhash_impl27*d5db71d1SArthur O'Dwyer constexpr std::size_t operator()(SearchedType<T> const& t) const {
28*d5db71d1SArthur O'Dwyer return static_cast<std::size_t>(t.get_value());
29*d5db71d1SArthur O'Dwyer }
30*d5db71d1SArthur O'Dwyer
31*d5db71d1SArthur O'Dwyer template <typename T>
operatorhash_impl32*d5db71d1SArthur O'Dwyer constexpr std::size_t operator()(StoredType<T> const& t) const {
33*d5db71d1SArthur O'Dwyer return static_cast<std::size_t>(t.get_value());
34*d5db71d1SArthur O'Dwyer }
35*d5db71d1SArthur O'Dwyer };
36*d5db71d1SArthur O'Dwyer
37*d5db71d1SArthur O'Dwyer struct non_transparent_hash : hash_impl {};
38*d5db71d1SArthur O'Dwyer
39*d5db71d1SArthur O'Dwyer struct transparent_hash : hash_impl {
40*d5db71d1SArthur O'Dwyer using is_transparent = void;
41*d5db71d1SArthur O'Dwyer };
42*d5db71d1SArthur O'Dwyer
43*d5db71d1SArthur O'Dwyer struct transparent_hash_final final : transparent_hash {};
44*d5db71d1SArthur O'Dwyer
45*d5db71d1SArthur O'Dwyer struct transparent_equal_final final : std::equal_to<> {};
46*d5db71d1SArthur O'Dwyer
47*d5db71d1SArthur O'Dwyer template <typename T>
48*d5db71d1SArthur O'Dwyer struct SearchedType {
SearchedTypeSearchedType49*d5db71d1SArthur O'Dwyer explicit SearchedType(T value, int *counter) : value_(value), conversions_(counter) { }
50*d5db71d1SArthur O'Dwyer
51*d5db71d1SArthur O'Dwyer // Whenever a conversion is performed, increment the counter to keep track
52*d5db71d1SArthur O'Dwyer // of conversions.
53*d5db71d1SArthur O'Dwyer operator StoredType<T>() const {
54*d5db71d1SArthur O'Dwyer ++*conversions_;
55*d5db71d1SArthur O'Dwyer return StoredType<T>{value_};
56*d5db71d1SArthur O'Dwyer }
57*d5db71d1SArthur O'Dwyer
get_valueSearchedType58*d5db71d1SArthur O'Dwyer int get_value() const {
59*d5db71d1SArthur O'Dwyer return value_;
60*d5db71d1SArthur O'Dwyer }
61*d5db71d1SArthur O'Dwyer
62*d5db71d1SArthur O'Dwyer private:
63*d5db71d1SArthur O'Dwyer T value_;
64*d5db71d1SArthur O'Dwyer int *conversions_;
65*d5db71d1SArthur O'Dwyer };
66*d5db71d1SArthur O'Dwyer
67*d5db71d1SArthur O'Dwyer template <typename T>
68*d5db71d1SArthur O'Dwyer struct StoredType {
69*d5db71d1SArthur O'Dwyer StoredType() = default;
StoredTypeStoredType70*d5db71d1SArthur O'Dwyer StoredType(T value) : value_(value) { }
71*d5db71d1SArthur O'Dwyer
72*d5db71d1SArthur O'Dwyer friend bool operator==(StoredType const& lhs, StoredType const& rhs) {
73*d5db71d1SArthur O'Dwyer return lhs.value_ == rhs.value_;
74*d5db71d1SArthur O'Dwyer }
75*d5db71d1SArthur O'Dwyer
76*d5db71d1SArthur O'Dwyer // If we're being passed a SearchedType<T> object, avoid the conversion
77*d5db71d1SArthur O'Dwyer // to T. This allows testing that the transparent operations are correctly
78*d5db71d1SArthur O'Dwyer // forwarding the SearchedType all the way to this comparison by checking
79*d5db71d1SArthur O'Dwyer // that we didn't have a conversion when we search for a SearchedType<T>
80*d5db71d1SArthur O'Dwyer // in a container full of StoredType<T>.
81*d5db71d1SArthur O'Dwyer friend bool operator==(StoredType const& lhs, SearchedType<T> const& rhs) {
82*d5db71d1SArthur O'Dwyer return lhs.value_ == rhs.get_value();
83*d5db71d1SArthur O'Dwyer }
84*d5db71d1SArthur O'Dwyer
get_valueStoredType85*d5db71d1SArthur O'Dwyer int get_value() const {
86*d5db71d1SArthur O'Dwyer return value_;
87*d5db71d1SArthur O'Dwyer }
88*d5db71d1SArthur O'Dwyer
89*d5db71d1SArthur O'Dwyer private:
90*d5db71d1SArthur O'Dwyer T value_;
91*d5db71d1SArthur O'Dwyer };
92*d5db71d1SArthur O'Dwyer
93*d5db71d1SArthur O'Dwyer template<template<class...> class UnorderedSet, class Hash, class Equal>
94e5ec94a1SRuslan Arutyunyan using unord_set_type = UnorderedSet<StoredType<int>, Hash, Equal>;
95e5ec94a1SRuslan Arutyunyan
96*d5db71d1SArthur O'Dwyer template<template<class...> class UnorderedMap, class Hash, class Equal>
97e5ec94a1SRuslan Arutyunyan using unord_map_type = UnorderedMap<StoredType<int>, int, Hash, Equal>;
98e5ec94a1SRuslan Arutyunyan
99*d5db71d1SArthur O'Dwyer template<class Container>
test_transparent_find(Container c)100*d5db71d1SArthur O'Dwyer void test_transparent_find(Container c) {
101e5ec94a1SRuslan Arutyunyan int conversions = 0;
102e5ec94a1SRuslan Arutyunyan assert(c.find(SearchedType<int>(1, &conversions)) != c.end());
103e5ec94a1SRuslan Arutyunyan assert(c.find(SearchedType<int>(2, &conversions)) != c.end());
104e5ec94a1SRuslan Arutyunyan assert(c.find(SearchedType<int>(3, &conversions)) == c.end());
105e5ec94a1SRuslan Arutyunyan assert(conversions == 0);
106e5ec94a1SRuslan Arutyunyan }
107e5ec94a1SRuslan Arutyunyan
108*d5db71d1SArthur O'Dwyer template<class Container>
test_non_transparent_find(Container c)109*d5db71d1SArthur O'Dwyer void test_non_transparent_find(Container c) {
110e5ec94a1SRuslan Arutyunyan int conversions = 0;
111e5ec94a1SRuslan Arutyunyan assert(c.find(SearchedType<int>(1, &conversions)) != c.end());
112*d5db71d1SArthur O'Dwyer assert(conversions == 1);
113e5ec94a1SRuslan Arutyunyan assert(c.find(SearchedType<int>(2, &conversions)) != c.end());
114*d5db71d1SArthur O'Dwyer assert(conversions == 2);
115e5ec94a1SRuslan Arutyunyan assert(c.find(SearchedType<int>(3, &conversions)) == c.end());
116*d5db71d1SArthur O'Dwyer assert(conversions == 3);
117e5ec94a1SRuslan Arutyunyan }
118e5ec94a1SRuslan Arutyunyan
119*d5db71d1SArthur O'Dwyer template<class Container>
test_transparent_count(Container c)120*d5db71d1SArthur O'Dwyer void test_transparent_count(Container c) {
121e5ec94a1SRuslan Arutyunyan int conversions = 0;
122e5ec94a1SRuslan Arutyunyan assert(c.count(SearchedType<int>(1, &conversions)) > 0);
123e5ec94a1SRuslan Arutyunyan assert(c.count(SearchedType<int>(2, &conversions)) > 0);
124e5ec94a1SRuslan Arutyunyan assert(c.count(SearchedType<int>(3, &conversions)) == 0);
125e5ec94a1SRuslan Arutyunyan assert(conversions == 0);
126e5ec94a1SRuslan Arutyunyan }
127e5ec94a1SRuslan Arutyunyan
128*d5db71d1SArthur O'Dwyer template<class Container>
test_non_transparent_count(Container c)129*d5db71d1SArthur O'Dwyer void test_non_transparent_count(Container c) {
130e5ec94a1SRuslan Arutyunyan int conversions = 0;
131e5ec94a1SRuslan Arutyunyan assert(c.count(SearchedType<int>(1, &conversions)) > 0);
132*d5db71d1SArthur O'Dwyer assert(conversions == 1);
133e5ec94a1SRuslan Arutyunyan assert(c.count(SearchedType<int>(2, &conversions)) > 0);
134*d5db71d1SArthur O'Dwyer assert(conversions == 2);
135e5ec94a1SRuslan Arutyunyan assert(c.count(SearchedType<int>(3, &conversions)) == 0);
136*d5db71d1SArthur O'Dwyer assert(conversions == 3);
137e5ec94a1SRuslan Arutyunyan }
138e5ec94a1SRuslan Arutyunyan
139*d5db71d1SArthur O'Dwyer template<class Container>
test_transparent_contains(Container c)140*d5db71d1SArthur O'Dwyer void test_transparent_contains(Container c) {
141e5ec94a1SRuslan Arutyunyan int conversions = 0;
142e5ec94a1SRuslan Arutyunyan assert(c.contains(SearchedType<int>(1, &conversions)));
143e5ec94a1SRuslan Arutyunyan assert(c.contains(SearchedType<int>(2, &conversions)));
144e5ec94a1SRuslan Arutyunyan assert(!c.contains(SearchedType<int>(3, &conversions)));
145e5ec94a1SRuslan Arutyunyan assert(conversions == 0);
146e5ec94a1SRuslan Arutyunyan }
147e5ec94a1SRuslan Arutyunyan
148*d5db71d1SArthur O'Dwyer template<class Container>
test_non_transparent_contains(Container c)149*d5db71d1SArthur O'Dwyer void test_non_transparent_contains(Container c) {
150e5ec94a1SRuslan Arutyunyan int conversions = 0;
151e5ec94a1SRuslan Arutyunyan assert(c.contains(SearchedType<int>(1, &conversions)));
152*d5db71d1SArthur O'Dwyer assert(conversions == 1);
153e5ec94a1SRuslan Arutyunyan assert(c.contains(SearchedType<int>(2, &conversions)));
154*d5db71d1SArthur O'Dwyer assert(conversions == 2);
155e5ec94a1SRuslan Arutyunyan assert(!c.contains(SearchedType<int>(3, &conversions)));
156*d5db71d1SArthur O'Dwyer assert(conversions == 3);
157e5ec94a1SRuslan Arutyunyan }
158e5ec94a1SRuslan Arutyunyan
159*d5db71d1SArthur O'Dwyer template<class Container>
test_transparent_equal_range(Container c)160*d5db71d1SArthur O'Dwyer void test_transparent_equal_range(Container c) {
161e5ec94a1SRuslan Arutyunyan int conversions = 0;
162e5ec94a1SRuslan Arutyunyan auto iters = c.equal_range(SearchedType<int>(1, &conversions));
163e5ec94a1SRuslan Arutyunyan assert(std::distance(iters.first, iters.second) > 0);
164e5ec94a1SRuslan Arutyunyan iters = c.equal_range(SearchedType<int>(2, &conversions));
165e5ec94a1SRuslan Arutyunyan assert(std::distance(iters.first, iters.second) > 0);
166e5ec94a1SRuslan Arutyunyan iters = c.equal_range(SearchedType<int>(3, &conversions));
167e5ec94a1SRuslan Arutyunyan assert(std::distance(iters.first, iters.second) == 0);
168e5ec94a1SRuslan Arutyunyan assert(conversions == 0);
169e5ec94a1SRuslan Arutyunyan }
170e5ec94a1SRuslan Arutyunyan
171*d5db71d1SArthur O'Dwyer template<class Container>
test_non_transparent_equal_range(Container c)172*d5db71d1SArthur O'Dwyer void test_non_transparent_equal_range(Container c) {
173e5ec94a1SRuslan Arutyunyan int conversions = 0;
174e5ec94a1SRuslan Arutyunyan auto iters = c.equal_range(SearchedType<int>(1, &conversions));
175e5ec94a1SRuslan Arutyunyan assert(std::distance(iters.first, iters.second) > 0);
176*d5db71d1SArthur O'Dwyer assert(conversions == 1);
177e5ec94a1SRuslan Arutyunyan iters = c.equal_range(SearchedType<int>(2, &conversions));
178e5ec94a1SRuslan Arutyunyan assert(std::distance(iters.first, iters.second) > 0);
179*d5db71d1SArthur O'Dwyer assert(conversions == 2);
180e5ec94a1SRuslan Arutyunyan iters = c.equal_range(SearchedType<int>(3, &conversions));
181e5ec94a1SRuslan Arutyunyan assert(std::distance(iters.first, iters.second) == 0);
182*d5db71d1SArthur O'Dwyer assert(conversions == 3);
183e5ec94a1SRuslan Arutyunyan }
184e5ec94a1SRuslan Arutyunyan
185e5ec94a1SRuslan Arutyunyan #endif // TEST_STD_VER > 17
186e5ec94a1SRuslan Arutyunyan
187e5ec94a1SRuslan Arutyunyan #endif // TEST_TRANSPARENT_UNORDERED_H
188