1c1757967SJacob Faibussowitsch static const char help[] = "Tests UnorderedMap.\n";
2c1757967SJacob Faibussowitsch
3c1757967SJacob Faibussowitsch #include <petsc/private/cpp/unordered_map.hpp>
4c1757967SJacob Faibussowitsch #include <petscviewer.h>
5c1757967SJacob Faibussowitsch
6c1757967SJacob Faibussowitsch #include <sstream> // std::ostringstream
7c1757967SJacob Faibussowitsch #include <string>
8c1757967SJacob Faibussowitsch #include <vector>
9c1757967SJacob Faibussowitsch #include <algorithm> // std::sort
10c1757967SJacob Faibussowitsch
11c1757967SJacob Faibussowitsch // ==========================================================================================
12c1757967SJacob Faibussowitsch // Setup
13c1757967SJacob Faibussowitsch // ==========================================================================================
14c1757967SJacob Faibussowitsch
15c1757967SJacob Faibussowitsch // see https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x
hash_combine(std::size_t &)16c1757967SJacob Faibussowitsch static inline void hash_combine(std::size_t &) noexcept { }
17c1757967SJacob Faibussowitsch
18c1757967SJacob Faibussowitsch template <typename T, typename... Rest>
hash_combine(std::size_t & seed,const T & v,Rest &&...rest)19c1757967SJacob Faibussowitsch static inline void hash_combine(std::size_t &seed, const T &v, Rest &&...rest) noexcept
20c1757967SJacob Faibussowitsch {
21c1757967SJacob Faibussowitsch std::hash<T> hasher;
22c1757967SJacob Faibussowitsch seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
23c1757967SJacob Faibussowitsch hash_combine(seed, std::forward<Rest>(rest)...);
24c1757967SJacob Faibussowitsch }
25c1757967SJacob Faibussowitsch
26c1757967SJacob Faibussowitsch #define MAKE_HASHABLE(type, ...) \
27c1757967SJacob Faibussowitsch namespace std \
28c1757967SJacob Faibussowitsch { \
29c1757967SJacob Faibussowitsch template <> \
30c1757967SJacob Faibussowitsch struct hash<type> { \
31c1757967SJacob Faibussowitsch std::size_t operator()(const type &t) const noexcept \
32c1757967SJacob Faibussowitsch { \
33c1757967SJacob Faibussowitsch std::size_t ret = 0; \
34c1757967SJacob Faibussowitsch hash_combine(ret, __VA_ARGS__); \
35c1757967SJacob Faibussowitsch return ret; \
36c1757967SJacob Faibussowitsch } \
37c1757967SJacob Faibussowitsch }; \
38c1757967SJacob Faibussowitsch }
39c1757967SJacob Faibussowitsch
40c1757967SJacob Faibussowitsch using pair_type = std::pair<int, double>;
41f5c5fea7SStefano Zampini MAKE_HASHABLE(pair_type, t.first, t.second)
42c1757967SJacob Faibussowitsch
43c1757967SJacob Faibussowitsch using namespace Petsc::util;
44c1757967SJacob Faibussowitsch
45c1757967SJacob Faibussowitsch struct Foo {
46c1757967SJacob Faibussowitsch int x{};
47c1757967SJacob Faibussowitsch double y{};
48c1757967SJacob Faibussowitsch
49c1757967SJacob Faibussowitsch constexpr Foo() noexcept = default;
FooFoo50c1757967SJacob Faibussowitsch constexpr Foo(int x, double y) noexcept : x(x), y(y) { }
51c1757967SJacob Faibussowitsch
operator ==Foo52c1757967SJacob Faibussowitsch bool operator==(const Foo &other) const noexcept { return x == other.x && y == other.y; }
operator !=Foo53c1757967SJacob Faibussowitsch bool operator!=(const Foo &other) const noexcept { return !(*this == other); }
operator <Foo54c1757967SJacob Faibussowitsch bool operator<(const Foo &other) const noexcept { return std::tie(x, y) < std::tie(other.x, other.y); }
55c1757967SJacob Faibussowitsch
to_stringFoo56c1757967SJacob Faibussowitsch PetscErrorCode to_string(std::string &buf) const noexcept
57c1757967SJacob Faibussowitsch {
58c1757967SJacob Faibussowitsch PetscFunctionBegin;
59c1757967SJacob Faibussowitsch PetscCallCXX(buf = std::to_string(x) + ", " + std::to_string(y));
603ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
61c1757967SJacob Faibussowitsch }
62c1757967SJacob Faibussowitsch
operator <<(std::ostream & oss,const Foo & f)63c1757967SJacob Faibussowitsch friend std::ostream &operator<<(std::ostream &oss, const Foo &f) noexcept
64c1757967SJacob Faibussowitsch {
65c1757967SJacob Faibussowitsch std::string ret;
66c1757967SJacob Faibussowitsch
67c1757967SJacob Faibussowitsch PetscFunctionBegin;
68c1757967SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, f.to_string(ret));
69c1757967SJacob Faibussowitsch oss << ret;
70c1757967SJacob Faibussowitsch PetscFunctionReturn(oss);
71c1757967SJacob Faibussowitsch }
72c1757967SJacob Faibussowitsch };
73c1757967SJacob Faibussowitsch
74f5c5fea7SStefano Zampini MAKE_HASHABLE(Foo, t.x, t.y)
75c1757967SJacob Faibussowitsch
76c1757967SJacob Faibussowitsch struct Bar {
77c1757967SJacob Faibussowitsch std::vector<int> x{};
78c1757967SJacob Faibussowitsch std::string y{};
79c1757967SJacob Faibussowitsch
80c1757967SJacob Faibussowitsch Bar() noexcept = default;
BarBar81c1757967SJacob Faibussowitsch Bar(std::vector<int> x, std::string y) noexcept : x(std::move(x)), y(std::move(y)) { }
82c1757967SJacob Faibussowitsch
operator ==Bar83c1757967SJacob Faibussowitsch bool operator==(const Bar &other) const noexcept { return x == other.x && y == other.y; }
operator <Bar84c1757967SJacob Faibussowitsch bool operator<(const Bar &other) const noexcept { return std::tie(x, y) < std::tie(other.x, other.y); }
85c1757967SJacob Faibussowitsch
to_stringBar86c1757967SJacob Faibussowitsch PetscErrorCode to_string(std::string &buf) const noexcept
87c1757967SJacob Faibussowitsch {
88c1757967SJacob Faibussowitsch PetscFunctionBegin;
89c1757967SJacob Faibussowitsch PetscCallCXX(buf = '<');
90c1757967SJacob Faibussowitsch for (std::size_t i = 0; i < x.size(); ++i) {
91c1757967SJacob Faibussowitsch PetscCallCXX(buf += std::to_string(x[i]));
92c1757967SJacob Faibussowitsch if (i + 1 != x.size()) PetscCallCXX(buf += ", ");
93c1757967SJacob Faibussowitsch }
94c1757967SJacob Faibussowitsch PetscCallCXX(buf += ">, <" + y + '>');
953ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
96c1757967SJacob Faibussowitsch }
97c1757967SJacob Faibussowitsch
operator <<(std::ostream & oss,const Bar & b)98c1757967SJacob Faibussowitsch friend std::ostream &operator<<(std::ostream &oss, const Bar &b) noexcept
99c1757967SJacob Faibussowitsch {
100c1757967SJacob Faibussowitsch std::string ret;
101c1757967SJacob Faibussowitsch
102c1757967SJacob Faibussowitsch PetscFunctionBegin;
103c1757967SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, b.to_string(ret));
104c1757967SJacob Faibussowitsch oss << ret;
105c1757967SJacob Faibussowitsch PetscFunctionReturn(oss);
106c1757967SJacob Faibussowitsch }
107c1757967SJacob Faibussowitsch };
108c1757967SJacob Faibussowitsch
109c1757967SJacob Faibussowitsch struct BadHash {
110c1757967SJacob Faibussowitsch template <typename T>
operator ()BadHash111c1757967SJacob Faibussowitsch constexpr std::size_t operator()(const T &) const noexcept
112c1757967SJacob Faibussowitsch {
113c1757967SJacob Faibussowitsch return 1;
114c1757967SJacob Faibussowitsch }
115c1757967SJacob Faibussowitsch };
116c1757967SJacob Faibussowitsch
117c1757967SJacob Faibussowitsch template <typename T>
118c1757967SJacob Faibussowitsch struct Printer {
119c1757967SJacob Faibussowitsch using signature = PetscErrorCode(const T &, std::string &);
120c1757967SJacob Faibussowitsch
121c1757967SJacob Faibussowitsch mutable std::string buffer;
122c1757967SJacob Faibussowitsch std::function<signature> printer;
123c1757967SJacob Faibussowitsch
124c1757967SJacob Faibussowitsch template <typename F>
PrinterPrinter125c1757967SJacob Faibussowitsch Printer(F &&printer) noexcept : printer(std::forward<F>(printer))
126c1757967SJacob Faibussowitsch {
127c1757967SJacob Faibussowitsch }
128c1757967SJacob Faibussowitsch
operator ()Printer129c1757967SJacob Faibussowitsch PETSC_NODISCARD const char *operator()(const T &value) const noexcept
130c1757967SJacob Faibussowitsch {
131c1757967SJacob Faibussowitsch PetscFunctionBegin;
132c1757967SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, this->printer(value, this->buffer));
133c1757967SJacob Faibussowitsch PetscFunctionReturn(this->buffer.c_str());
134c1757967SJacob Faibussowitsch }
135c1757967SJacob Faibussowitsch };
136c1757967SJacob Faibussowitsch
137c1757967SJacob Faibussowitsch #if defined(__GNUC__)
138c1757967SJacob Faibussowitsch // gcc 6.4 through 7.5 have a visibility bug:
139c1757967SJacob Faibussowitsch //
140c1757967SJacob Faibussowitsch // error: 'MapTester<T>::test_insert()::<lambda(MapTester<T>::value_type&)> [with T =
141c1757967SJacob Faibussowitsch // ...]::<lambda(...)>' declared with greater visibility than the type of its field
142c1757967SJacob Faibussowitsch // 'MapTester<T>::test_insert()::<lambda(MapTester<T>::value_type&)> [with T =
143c1757967SJacob Faibussowitsch // ...]::<lambda(const char*, const insert_return_type&)
144c1757967SJacob Faibussowitsch //
145c1757967SJacob Faibussowitsch // Error message implies that the visibility of the lambda in question is greater than the
146c1757967SJacob Faibussowitsch // visibility of the capture list value "this".
147c1757967SJacob Faibussowitsch //
148c1757967SJacob Faibussowitsch // Since lambdas are translated into the classes with the operator()(...) and (it seems like)
149c1757967SJacob Faibussowitsch // captured values are translated into the fields of this class it looks like for some reason
150c1757967SJacob Faibussowitsch // the visibility of that class is higher than the one of those fields.
151c1757967SJacob Faibussowitsch //
152c1757967SJacob Faibussowitsch // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947
153c1757967SJacob Faibussowitsch #if ((__GNUC__ == 6) && (__GNUC_MINOR__ >= 4)) || ((__GNUC__ == 7) && (__GNUC_MINOR__ <= 5))
154c1757967SJacob Faibussowitsch #define PETSC_GCC_LAMBDA_VISIBILITY_WORKAROUND 1
155c1757967SJacob Faibussowitsch #endif
156c1757967SJacob Faibussowitsch #endif
157c1757967SJacob Faibussowitsch
158c1757967SJacob Faibussowitsch #ifdef PETSC_GCC_LAMBDA_VISIBILITY_WORKAROUND
159c1757967SJacob Faibussowitsch #pragma GCC visibility push(hidden)
160c1757967SJacob Faibussowitsch #endif
161c1757967SJacob Faibussowitsch template <typename... T>
162c1757967SJacob Faibussowitsch class MapTester {
163c1757967SJacob Faibussowitsch public:
164c1757967SJacob Faibussowitsch using map_type = Petsc::UnorderedMap<T...>;
165c1757967SJacob Faibussowitsch using key_type = typename map_type::key_type;
166c1757967SJacob Faibussowitsch using value_type = typename map_type::value_type;
167c1757967SJacob Faibussowitsch using mapped_type = typename map_type::mapped_type;
168c1757967SJacob Faibussowitsch
169c1757967SJacob Faibussowitsch const PetscViewer vwr;
170c1757967SJacob Faibussowitsch const std::string map_name;
171c1757967SJacob Faibussowitsch Printer<key_type> key_printer;
172c1757967SJacob Faibussowitsch Printer<mapped_type> value_printer;
173c1757967SJacob Faibussowitsch std::function<value_type(void)> generator;
174c1757967SJacob Faibussowitsch
view_map(const map_type & map) const175089fb57cSJacob Faibussowitsch PetscErrorCode view_map(const map_type &map) const noexcept
176c1757967SJacob Faibussowitsch {
177c1757967SJacob Faibussowitsch std::ostringstream oss;
178c1757967SJacob Faibussowitsch
179c1757967SJacob Faibussowitsch PetscFunctionBegin;
180c1757967SJacob Faibussowitsch PetscCallCXX(oss << std::boolalpha);
181c1757967SJacob Faibussowitsch PetscCallCXX(oss << "map: '" << this->map_name << "'\n");
182c1757967SJacob Faibussowitsch PetscCallCXX(oss << " size: " << map.size() << '\n');
183c1757967SJacob Faibussowitsch PetscCallCXX(oss << " capacity: " << map.capacity() << '\n');
184c1757967SJacob Faibussowitsch PetscCallCXX(oss << " bucket count: " << map.bucket_count() << '\n');
185c1757967SJacob Faibussowitsch PetscCallCXX(oss << " empty: " << map.empty() << '\n');
186c1757967SJacob Faibussowitsch PetscCallCXX(oss << " flag bucket width: " << map_type::flag_bucket_width::value << '\n');
187c1757967SJacob Faibussowitsch PetscCallCXX(oss << " flag pairs per bucket: " << map_type::flag_pairs_per_bucket::value << '\n');
188c1757967SJacob Faibussowitsch PetscCallCXX(oss << " {\n");
189c1757967SJacob Faibussowitsch for (auto &&entry : map) PetscCallCXX(oss << " key: [" << this->key_printer(entry.first) << "] -> [" << this->value_printer(entry.second) << "]\n");
190c1757967SJacob Faibussowitsch PetscCallCXX(oss << " }\n");
191c1757967SJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(vwr, "%s", oss.str().c_str()));
1923ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
193c1757967SJacob Faibussowitsch }
194c1757967SJacob Faibussowitsch
195c1757967SJacob Faibussowitsch #define MapCheck(map__, cond__, comm__, ierr__, base_mess__, ...) \
196c1757967SJacob Faibussowitsch do { \
197c1757967SJacob Faibussowitsch if (PetscUnlikely(!(cond__))) { \
198c1757967SJacob Faibussowitsch PetscCall(this->view_map(map__)); \
199c1757967SJacob Faibussowitsch SETERRQ(comm__, ierr__, "%s: " base_mess__, this->map_name.c_str(), __VA_ARGS__); \
200c1757967SJacob Faibussowitsch } \
201c1757967SJacob Faibussowitsch } while (0)
202c1757967SJacob Faibussowitsch
check_size_capacity_coherent(map_type & map) const203089fb57cSJacob Faibussowitsch PetscErrorCode check_size_capacity_coherent(map_type &map) const noexcept
204c1757967SJacob Faibussowitsch {
205c1757967SJacob Faibussowitsch const auto msize = map.size();
206c1757967SJacob Faibussowitsch const auto mcap = map.capacity();
207c1757967SJacob Faibussowitsch
208c1757967SJacob Faibussowitsch PetscFunctionBegin;
209c1757967SJacob Faibussowitsch MapCheck(map, msize == map.size(), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map size appears to change each time it is called! first call: %zu, second call %zu", msize, map.size());
210c1757967SJacob Faibussowitsch MapCheck(map, mcap == map.capacity(), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map capacity appears to change each time it is called! first call: %zu, second call %zu", mcap, map.capacity());
211c1757967SJacob Faibussowitsch MapCheck(map, msize >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map size %zu unexpected!", msize);
212c1757967SJacob Faibussowitsch MapCheck(map, mcap >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map capacity %zu unexpected!", mcap);
213c1757967SJacob Faibussowitsch MapCheck(map, mcap >= msize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map capacity %zu < map size %zu!", mcap, msize);
2143ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
215c1757967SJacob Faibussowitsch }
216c1757967SJacob Faibussowitsch
check_size_capacity_coherent(map_type & map,std::size_t expected_size,std::size_t expected_min_capacity) const217089fb57cSJacob Faibussowitsch PetscErrorCode check_size_capacity_coherent(map_type &map, std::size_t expected_size, std::size_t expected_min_capacity) const noexcept
218c1757967SJacob Faibussowitsch {
219c1757967SJacob Faibussowitsch PetscFunctionBegin;
220c1757967SJacob Faibussowitsch PetscCall(check_size_capacity_coherent(map));
221c1757967SJacob Faibussowitsch MapCheck(map, map.size() == expected_size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map size %zu did not increase (from %zu) after insertion!", map.size(), expected_size);
222c1757967SJacob Faibussowitsch MapCheck(map, map.capacity() >= expected_min_capacity, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map capacity %zu did not increase (from %zu)!", map.capacity(), expected_min_capacity);
2233ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
224c1757967SJacob Faibussowitsch }
225c1757967SJacob Faibussowitsch
test_insert(map_type & map)226089fb57cSJacob Faibussowitsch PetscErrorCode test_insert(map_type &map) noexcept
227c1757967SJacob Faibussowitsch {
228c1757967SJacob Faibussowitsch auto key = key_type{};
229c1757967SJacob Faibussowitsch auto value = mapped_type{};
230c1757967SJacob Faibussowitsch auto size_before = map.size();
231c1757967SJacob Faibussowitsch auto capacity_before = map.capacity();
232c1757967SJacob Faibussowitsch
233c1757967SJacob Faibussowitsch const auto check_all_reinsert = [&](value_type &key_value) {
234c1757967SJacob Faibussowitsch using insert_return_type = std::pair<typename map_type::iterator, bool>;
235c1757967SJacob Faibussowitsch auto &key = key_value.first;
236c1757967SJacob Faibussowitsch auto &value = key_value.second;
237c1757967SJacob Faibussowitsch const auto key_const = key;
238c1757967SJacob Faibussowitsch const auto value_const = value;
239c1757967SJacob Faibussowitsch const auto pair = std::make_pair(key_const, value_const);
240c1757967SJacob Faibussowitsch const auto check_reinsert = [&](const char op[], const insert_return_type &ret) {
241c1757967SJacob Faibussowitsch PetscFunctionBegin;
242c1757967SJacob Faibussowitsch MapCheck(map, !ret.second, PETSC_COMM_SELF, PETSC_ERR_PLIB, "%s reinserted key '%s'", op, this->key_printer(key));
243c1757967SJacob Faibussowitsch MapCheck(map, ret.first->first == key, PETSC_COMM_SELF, PETSC_ERR_PLIB, "%s returned iterator key '%s' != expected '%s'", this->key_printer(ret.first->first), op, this->key_printer(key));
244c1757967SJacob Faibussowitsch MapCheck(map, ret.first->second == value, PETSC_COMM_SELF, PETSC_ERR_PLIB, "%s returned iterator value '%s' != expected '%s'", op, this->value_printer(ret.first->second), this->value_printer(value));
245c1757967SJacob Faibussowitsch MapCheck(map, map[key] == value, PETSC_COMM_SELF, PETSC_ERR_PLIB, "%s map[%s] '%s' != '%s'", op, this->key_printer(key), this->value_printer(map[key]), this->value_printer(value));
246c1757967SJacob Faibussowitsch MapCheck(map, map[key_const] == value_const, PETSC_COMM_SELF, PETSC_ERR_PLIB, "%s changed value '%s' != expected '%s'", op, this->value_printer(map[key_const]), this->value_printer(value_const));
2473ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
248c1757967SJacob Faibussowitsch };
249c1757967SJacob Faibussowitsch
250c1757967SJacob Faibussowitsch PetscFunctionBegin;
251c1757967SJacob Faibussowitsch #define CHECK_REINSERT(...) check_reinsert(PetscStringize(__VA_ARGS__), __VA_ARGS__)
252c1757967SJacob Faibussowitsch // check the following operations don't clobber values
253c1757967SJacob Faibussowitsch PetscCall(CHECK_REINSERT(map.emplace(key, value)));
254c1757967SJacob Faibussowitsch PetscCall(CHECK_REINSERT(map.emplace(std::piecewise_construct, std::make_tuple(key), std::make_tuple(value))));
255c1757967SJacob Faibussowitsch PetscCall(CHECK_REINSERT(map.insert(std::make_pair(key, value))));
256c1757967SJacob Faibussowitsch PetscCall(CHECK_REINSERT(map.insert(pair)));
257c1757967SJacob Faibussowitsch #undef CHECK_REINSERT
2583ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
259c1757967SJacob Faibussowitsch };
260c1757967SJacob Faibussowitsch
261c1757967SJacob Faibussowitsch PetscFunctionBegin;
262c1757967SJacob Faibussowitsch PetscCall(this->check_size_capacity_coherent(map));
263c1757967SJacob Faibussowitsch // put key in map
264c1757967SJacob Faibussowitsch PetscCallCXX(map[key] = value);
265c1757967SJacob Faibussowitsch // check we properly sized up
266c1757967SJacob Faibussowitsch PetscCall(this->check_size_capacity_coherent(map, size_before + 1, capacity_before));
267c1757967SJacob Faibussowitsch // and that the value matches
268c1757967SJacob Faibussowitsch MapCheck(map, map[key] == value, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map default key %s != map value %s", this->key_printer(key), this->value_printer(value));
269c1757967SJacob Faibussowitsch // and that the following operations don't clobber the value
270c1757967SJacob Faibussowitsch {
271c1757967SJacob Faibussowitsch value_type kv{key, value};
272c1757967SJacob Faibussowitsch
273c1757967SJacob Faibussowitsch PetscCall(check_all_reinsert(kv));
274c1757967SJacob Faibussowitsch }
275c1757967SJacob Faibussowitsch
276c1757967SJacob Faibussowitsch // test that clearing workings
277c1757967SJacob Faibussowitsch capacity_before = map.capacity();
278c1757967SJacob Faibussowitsch PetscCall(map.clear());
279c1757967SJacob Faibussowitsch // should have size = 0 (but capacity unchanged)
280c1757967SJacob Faibussowitsch PetscCall(this->check_size_capacity_coherent(map, 0, capacity_before));
281c1757967SJacob Faibussowitsch
282c1757967SJacob Faibussowitsch // test that all inserted values are found in the map
283c1757967SJacob Faibussowitsch const auto test_map_contains_expected_items = [&](std::function<PetscErrorCode(std::vector<value_type> &)> fill_map, std::size_t kv_size) {
284c1757967SJacob Faibussowitsch auto key_value_pairs = this->make_key_values(kv_size);
285c1757967SJacob Faibussowitsch std::vector<std::size_t> found_key_value(key_value_pairs.size());
286c1757967SJacob Faibussowitsch
287c1757967SJacob Faibussowitsch PetscFunctionBegin;
288c1757967SJacob Faibussowitsch PetscCall(map.clear());
289c1757967SJacob Faibussowitsch PetscCall(this->check_size_capacity_coherent(map, 0, 0));
290c1757967SJacob Faibussowitsch PetscCall(fill_map(key_value_pairs));
291c1757967SJacob Faibussowitsch // map size should exactly match the size of the vector, but we don't care about capacity
292c1757967SJacob Faibussowitsch PetscCall(this->check_size_capacity_coherent(map, key_value_pairs.size(), 0));
293c1757967SJacob Faibussowitsch
294c1757967SJacob Faibussowitsch // sort the vector so we can use std::binary_search on it
295c1757967SJacob Faibussowitsch PetscCallCXX(std::sort(key_value_pairs.begin(), key_value_pairs.end()));
296c1757967SJacob Faibussowitsch for (auto it = map.cbegin(); it != map.cend(); ++it) {
297c1757967SJacob Faibussowitsch const auto kv_begin = key_value_pairs.cbegin();
298c1757967SJacob Faibussowitsch const auto found = std::lower_bound(kv_begin, key_value_pairs.cend(), *it);
299c1757967SJacob Faibussowitsch const auto dist = std::distance(kv_begin, found);
300c1757967SJacob Faibussowitsch
301c1757967SJacob Faibussowitsch // check that the value returned exists in our expected range
302c1757967SJacob Faibussowitsch MapCheck(map, found != key_value_pairs.cend(), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map contained key-value pair (%s, %s) not present in input range!", this->key_printer(it->first), this->value_printer(it->second));
303c1757967SJacob Faibussowitsch MapCheck(map, dist >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Index of found key-value pair (%s -> %s) %td is < 0", this->key_printer(it->first), this->value_printer(it->second), static_cast<std::ptrdiff_t>(dist));
304c1757967SJacob Faibussowitsch // record that we found this particular entry
305c1757967SJacob Faibussowitsch PetscCallCXX(++found_key_value.at(static_cast<std::size_t>(dist)));
306c1757967SJacob Faibussowitsch }
307c1757967SJacob Faibussowitsch
308c1757967SJacob Faibussowitsch // there should only be 1 instance of each key-value in the map
309c1757967SJacob Faibussowitsch for (std::size_t i = 0; i < found_key_value.size(); ++i) {
310c1757967SJacob Faibussowitsch MapCheck(map, found_key_value[i] == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map failed to insert key %s (value %s), have find count %zu", this->key_printer(key_value_pairs[i].first), this->value_printer(key_value_pairs[i].second), found_key_value[i]);
311c1757967SJacob Faibussowitsch }
3123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
313c1757967SJacob Faibussowitsch };
314c1757967SJacob Faibussowitsch
315c1757967SJacob Faibussowitsch // clang-format off
316c1757967SJacob Faibussowitsch PetscCall(
317c1757967SJacob Faibussowitsch test_map_contains_expected_items(
318c1757967SJacob Faibussowitsch [&](std::vector<value_type> &key_value_pairs)
319c1757967SJacob Faibussowitsch {
320c1757967SJacob Faibussowitsch PetscFunctionBegin;
321c1757967SJacob Faibussowitsch for (auto &&key_value : key_value_pairs) {
322c1757967SJacob Faibussowitsch PetscCallCXX(map[key_value.first] = key_value.second);
323c1757967SJacob Faibussowitsch PetscCall(check_all_reinsert(key_value));
324c1757967SJacob Faibussowitsch }
3253ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
326c1757967SJacob Faibussowitsch },
327c1757967SJacob Faibussowitsch 108
328c1757967SJacob Faibussowitsch )
329c1757967SJacob Faibussowitsch );
330c1757967SJacob Faibussowitsch // clang-format on
331c1757967SJacob Faibussowitsch
332c1757967SJacob Faibussowitsch // test that inserting using std algorithms work
333c1757967SJacob Faibussowitsch {
334c1757967SJacob Faibussowitsch value_type saved_value;
335c1757967SJacob Faibussowitsch
336c1757967SJacob Faibussowitsch // clang-format off
337c1757967SJacob Faibussowitsch PetscCall(
338c1757967SJacob Faibussowitsch test_map_contains_expected_items(
339c1757967SJacob Faibussowitsch [&](std::vector<value_type> &key_value_pairs)
340c1757967SJacob Faibussowitsch {
341c1757967SJacob Faibussowitsch PetscFunctionBegin;
342c1757967SJacob Faibussowitsch // save this for later
343c1757967SJacob Faibussowitsch PetscCallCXX(saved_value = key_value_pairs.front());
344c1757967SJacob Faibussowitsch // test the algorithm insert works as expected
345c1757967SJacob Faibussowitsch PetscCallCXX(std::copy(key_value_pairs.cbegin(), key_value_pairs.cend(), std::inserter(map, map.begin())));
3463ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
347c1757967SJacob Faibussowitsch },
348c1757967SJacob Faibussowitsch 179
349c1757967SJacob Faibussowitsch )
350c1757967SJacob Faibussowitsch );
351c1757967SJacob Faibussowitsch // clang-format on
352c1757967SJacob Faibussowitsch auto it = map.find(saved_value.first);
353c1757967SJacob Faibussowitsch
354c1757967SJacob Faibussowitsch // can't use map[] since that might inadvertently insert it
355c1757967SJacob Faibussowitsch MapCheck(map, it != map.end(), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map failed no longer contains key-value pair (%s -> %s) after std::copy() and container went out of scope", this->key_printer(saved_value.first), this->value_printer(saved_value.second));
356c1757967SJacob Faibussowitsch MapCheck(map, it->first == saved_value.first, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map founnd iterator key (%s) does not match expected key (%s) after std::copy() insertion", this->key_printer(it->first), this->key_printer(saved_value.first));
357c1757967SJacob Faibussowitsch MapCheck(map, it->second == saved_value.second, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map founnd iterator value (%s) does not match expected value (%s) after std::copy() insertion", this->value_printer(it->second), this->value_printer(saved_value.second));
358c1757967SJacob Faibussowitsch }
3593ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
360c1757967SJacob Faibussowitsch }
361c1757967SJacob Faibussowitsch
test_insert()362089fb57cSJacob Faibussowitsch PetscErrorCode test_insert() noexcept
363c1757967SJacob Faibussowitsch {
364c1757967SJacob Faibussowitsch map_type map;
365c1757967SJacob Faibussowitsch
366c1757967SJacob Faibussowitsch PetscFunctionBegin;
367c1757967SJacob Faibussowitsch PetscCall(test_insert(map));
3683ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
369c1757967SJacob Faibussowitsch }
370c1757967SJacob Faibussowitsch
test_find(map_type & map)371089fb57cSJacob Faibussowitsch PetscErrorCode test_find(map_type &map) noexcept
372c1757967SJacob Faibussowitsch {
373c1757967SJacob Faibussowitsch PetscFunctionBegin;
374c1757967SJacob Faibussowitsch {
375c1757967SJacob Faibussowitsch const auto sample_values = this->make_key_values(145);
376c1757967SJacob Faibussowitsch
377c1757967SJacob Faibussowitsch map = map_type(sample_values.begin(), sample_values.end());
378c1757967SJacob Faibussowitsch for (auto &&kv : sample_values) {
379c1757967SJacob Faibussowitsch auto &&key = kv.first;
380c1757967SJacob Faibussowitsch auto &&value = kv.second;
381c1757967SJacob Faibussowitsch auto it = map.find(key);
382c1757967SJacob Faibussowitsch
383c1757967SJacob Faibussowitsch MapCheck(map, it != map.end(), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed to find %s in map", this->key_printer(key));
384c1757967SJacob Faibussowitsch MapCheck(map, it->first == key, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Find iterator key %s != expected %s", this->key_printer(it->first), this->key_printer(key));
385c1757967SJacob Faibussowitsch MapCheck(map, it->second == value, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Find iterator value %s != expected %s", this->value_printer(it->second), this->value_printer(value));
386c1757967SJacob Faibussowitsch MapCheck(map, map.contains(key), PETSC_COMM_SELF, PETSC_ERR_PLIB, "map.contains(key) reports false, even though map.find(key) successfully found it! key: %s", this->key_printer(key));
387c1757967SJacob Faibussowitsch MapCheck(map, map.count(key) == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "map.count(%s) %zu != 1", this->key_printer(key), map.count(key));
388c1757967SJacob Faibussowitsch
389c1757967SJacob Faibussowitsch {
390c1757967SJacob Faibussowitsch const auto range = map.equal_range(key);
391c1757967SJacob Faibussowitsch const auto &range_begin = range.first;
392c1757967SJacob Faibussowitsch const auto range_size = std::distance(range_begin, range.second);
393c1757967SJacob Faibussowitsch
394c1757967SJacob Faibussowitsch MapCheck(map, range_size == 1, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map equal_range() returned a range of size %zu != 1", range_size);
395c1757967SJacob Faibussowitsch MapCheck(map, range_begin->first == key, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Equal range iterator key %s != expected %s", this->key_printer(range_begin->first), this->key_printer(key));
396c1757967SJacob Faibussowitsch MapCheck(map, range_begin->second == value, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Equal range iterator value %s != expected %s", this->value_printer(range_begin->second), this->value_printer(value));
397c1757967SJacob Faibussowitsch }
398c1757967SJacob Faibussowitsch }
399c1757967SJacob Faibussowitsch }
4003ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
401c1757967SJacob Faibussowitsch }
402c1757967SJacob Faibussowitsch
test_find()403089fb57cSJacob Faibussowitsch PetscErrorCode test_find() noexcept
404c1757967SJacob Faibussowitsch {
405c1757967SJacob Faibussowitsch map_type map;
406c1757967SJacob Faibussowitsch
407c1757967SJacob Faibussowitsch PetscFunctionBegin;
408c1757967SJacob Faibussowitsch PetscCall(test_find(map));
4093ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
410c1757967SJacob Faibussowitsch }
411c1757967SJacob Faibussowitsch
test_erase(map_type & map)412089fb57cSJacob Faibussowitsch PetscErrorCode test_erase(map_type &map) noexcept
413c1757967SJacob Faibussowitsch {
414c1757967SJacob Faibussowitsch auto sample_values = this->make_key_values(57);
415c1757967SJacob Faibussowitsch const map_type backup(sample_values.cbegin(), sample_values.cend());
416c1757967SJacob Faibussowitsch const auto check_map_is_truly_empty = [&](map_type &map) {
417c1757967SJacob Faibussowitsch PetscFunctionBegin;
418c1757967SJacob Faibussowitsch MapCheck(map, map.size() == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Erasing map via iterator range didn't work, map has size %zu", map.size());
419c1757967SJacob Faibussowitsch MapCheck(map, map.empty(), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Erasing map via iterators didn't work, map is not empty, has size %zu", map.size());
420c1757967SJacob Faibussowitsch // this loop should never actually fire!
421c1757967SJacob Faibussowitsch for (auto it = map.begin(); it != map.end(); ++it) MapCheck(map, false, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Erasing via iterator range did not work, map.begin() != map.end()%s", "");
4223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
423c1757967SJacob Faibussowitsch };
424c1757967SJacob Faibussowitsch
425c1757967SJacob Faibussowitsch PetscFunctionBegin;
426c1757967SJacob Faibussowitsch PetscCallCXX(map = backup);
427c1757967SJacob Faibussowitsch // test single erase from iterator works
428c1757967SJacob Faibussowitsch {
429c1757967SJacob Faibussowitsch const auto it = map.begin();
430c1757967SJacob Faibussowitsch const auto begin_key = it->first;
431c1757967SJacob Faibussowitsch const auto begin_val = it->second;
432c1757967SJacob Faibussowitsch
433c1757967SJacob Faibussowitsch PetscCallCXX(map.erase(it));
434c1757967SJacob Faibussowitsch for (auto &&kv : map) MapCheck(map, kv.first != begin_key, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Erasing %s did not work, found again in map", this->key_printer(begin_key));
435c1757967SJacob Faibussowitsch // reinsert the value
436c1757967SJacob Faibussowitsch PetscCallCXX(map[begin_key] = begin_val);
437c1757967SJacob Faibussowitsch }
438c1757967SJacob Faibussowitsch
439c1757967SJacob Faibussowitsch // test erase from iterator
440c1757967SJacob Faibussowitsch for (auto it = map.begin(); it != map.end(); ++it) {
441c1757967SJacob Faibussowitsch const auto before = it;
442c1757967SJacob Faibussowitsch
443c1757967SJacob Faibussowitsch PetscCallCXX(map.erase(it));
444c1757967SJacob Faibussowitsch MapCheck(map, before == it, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Iterator changed during erase%s", "");
445c1757967SJacob Faibussowitsch MapCheck(map, map.occupied(before) == false, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Iterator (%s -> %s) occupied after erase", this->key_printer(before->first), this->value_printer(before->second));
446c1757967SJacob Faibussowitsch }
447c1757967SJacob Faibussowitsch
448c1757967SJacob Faibussowitsch // test erase from iterator range
449c1757967SJacob Faibussowitsch PetscCall(check_map_is_truly_empty(map));
450c1757967SJacob Faibussowitsch PetscCallCXX(map = backup);
451c1757967SJacob Faibussowitsch PetscCallCXX(map.erase(map.begin(), map.end()));
452c1757967SJacob Faibussowitsch PetscCall(check_map_is_truly_empty(map));
453c1757967SJacob Faibussowitsch
454c1757967SJacob Faibussowitsch // test erase by clear
455c1757967SJacob Faibussowitsch PetscCallCXX(map = backup);
456c1757967SJacob Faibussowitsch PetscCall(map.clear());
457c1757967SJacob Faibussowitsch PetscCall(check_map_is_truly_empty(map));
458c1757967SJacob Faibussowitsch
4590a3351ceSJacob Faibussowitsch {
4600a3351ceSJacob Faibussowitsch std::size_t cap_before;
4610a3351ceSJacob Faibussowitsch
4620a3351ceSJacob Faibussowitsch PetscCallCXX(map = backup);
4630a3351ceSJacob Faibussowitsch cap_before = map.capacity();
4640a3351ceSJacob Faibussowitsch PetscCall(map.clear());
4650a3351ceSJacob Faibussowitsch PetscCall(check_map_is_truly_empty(map));
4660a3351ceSJacob Faibussowitsch MapCheck(map, map.capacity() == cap_before, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map capacity decreased on clear(), capacity before %zu != current capacity %zu", cap_before, map.capacity());
4670a3351ceSJacob Faibussowitsch PetscCall(map.shrink_to_fit());
4680a3351ceSJacob Faibussowitsch MapCheck(map, map.capacity() == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map capacity should be 0 (have %zu) after clear() -> shrink_to_fit()!", map.capacity());
4690a3351ceSJacob Faibussowitsch PetscCall(check_map_is_truly_empty(map));
4700a3351ceSJacob Faibussowitsch }
4710a3351ceSJacob Faibussowitsch
472c1757967SJacob Faibussowitsch // test that clear works OK (used to be a bug when inserting after clear)
473c1757967SJacob Faibussowitsch PetscCallCXX(map.insert(generator()));
474c1757967SJacob Faibussowitsch PetscCallCXX(map.insert(generator()));
475c1757967SJacob Faibussowitsch PetscCallCXX(map.insert(generator()));
476c1757967SJacob Faibussowitsch PetscCallCXX(map.insert(generator()));
477c1757967SJacob Faibussowitsch PetscCallCXX(map.erase(map.begin(), map.end()));
478c1757967SJacob Faibussowitsch PetscCall(check_map_is_truly_empty(map));
479c1757967SJacob Faibussowitsch
480c1757967SJacob Faibussowitsch // test erase by member function swapping with empty map
481c1757967SJacob Faibussowitsch for (auto &&kv : sample_values) PetscCallCXX(map.emplace(kv.first, kv.second));
482c1757967SJacob Faibussowitsch {
483c1757967SJacob Faibussowitsch map_type alt;
484c1757967SJacob Faibussowitsch
485c1757967SJacob Faibussowitsch // has the effect of clearing the map
486c1757967SJacob Faibussowitsch PetscCallCXX(map.swap(alt));
487c1757967SJacob Faibussowitsch }
488c1757967SJacob Faibussowitsch PetscCall(check_map_is_truly_empty(map));
489c1757967SJacob Faibussowitsch
490c1757967SJacob Faibussowitsch // test erase by std::swap with empty map
491c1757967SJacob Faibussowitsch PetscCallCXX(map = backup);
492c1757967SJacob Faibussowitsch {
493c1757967SJacob Faibussowitsch using std::swap;
494c1757967SJacob Faibussowitsch map_type alt;
495c1757967SJacob Faibussowitsch
496c1757967SJacob Faibussowitsch // has the effect of clearing the map
497c1757967SJacob Faibussowitsch PetscCallCXX(swap(map, alt));
498c1757967SJacob Faibussowitsch }
499c1757967SJacob Faibussowitsch PetscCall(check_map_is_truly_empty(map));
500c1757967SJacob Faibussowitsch
501c1757967SJacob Faibussowitsch // test erase by key, use new values to change it up
502c1757967SJacob Faibussowitsch sample_values = this->make_key_values();
503c1757967SJacob Faibussowitsch std::copy(sample_values.cbegin(), sample_values.cend(), std::inserter(map, map.begin()));
504c1757967SJacob Faibussowitsch for (auto &&kv : sample_values) PetscCallCXX(map.erase(kv.first));
505c1757967SJacob Faibussowitsch PetscCall(check_map_is_truly_empty(map));
5063ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
507c1757967SJacob Faibussowitsch }
508c1757967SJacob Faibussowitsch
test_erase()509089fb57cSJacob Faibussowitsch PetscErrorCode test_erase() noexcept
510c1757967SJacob Faibussowitsch {
511c1757967SJacob Faibussowitsch map_type map;
512c1757967SJacob Faibussowitsch
513c1757967SJacob Faibussowitsch PetscFunctionBegin;
514c1757967SJacob Faibussowitsch PetscCall(test_erase(map));
5153ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
516c1757967SJacob Faibussowitsch }
517c1757967SJacob Faibussowitsch
518c1757967SJacob Faibussowitsch // stupid dummy function because auto-lambdas are C++14
519c1757967SJacob Faibussowitsch template <typename It>
test_iterators(map_type & map,It it,It it2)520089fb57cSJacob Faibussowitsch PetscErrorCode test_iterators(map_type &map, It it, It it2) noexcept
521c1757967SJacob Faibussowitsch {
522c1757967SJacob Faibussowitsch constexpr std::size_t max_iter = 10000;
523c1757967SJacob Faibussowitsch constexpr auto is_normal = std::is_same<It, typename map_type::iterator>::value;
524c1757967SJacob Faibussowitsch constexpr auto is_const = std::is_same<It, typename map_type::const_iterator>::value;
525c1757967SJacob Faibussowitsch static_assert(is_normal || is_const, "");
526c1757967SJacob Faibussowitsch constexpr const char *it_name = is_normal ? "Non-const" : "Const";
527c1757967SJacob Faibussowitsch
528c1757967SJacob Faibussowitsch PetscFunctionBegin;
529c1757967SJacob Faibussowitsch MapCheck(map, it == it2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "%s iterator does not equal itself?", it_name);
530c1757967SJacob Faibussowitsch PetscCallCXX(++it);
531c1757967SJacob Faibussowitsch PetscCallCXX(it2++);
532c1757967SJacob Faibussowitsch MapCheck(map, it == it2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "%s iterator does not equal itself after ++it, and it2++", it_name);
533c1757967SJacob Faibussowitsch PetscCallCXX(--it);
534c1757967SJacob Faibussowitsch PetscCallCXX(it2--);
535c1757967SJacob Faibussowitsch MapCheck(map, it == it2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "%s iterator does not equal itself after --it, and it2--", it_name);
536c1757967SJacob Faibussowitsch MapCheck(map, map.size() < max_iter, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Forward progress test only works properly if the map size (%zu) < %zu", map.size(), max_iter);
537c1757967SJacob Faibussowitsch // check that the prefix and postfix increment and decerement make forward progress
538c1757967SJacob Faibussowitsch {
539c1757967SJacob Faibussowitsch std::size_t i;
540c1757967SJacob Faibussowitsch
541c1757967SJacob Faibussowitsch // increment
542c1757967SJacob Faibussowitsch PetscCallCXX(it = map.begin());
543c1757967SJacob Faibussowitsch for (i = 0; i < max_iter; ++i) {
544c1757967SJacob Faibussowitsch if (it == map.end()) break;
545c1757967SJacob Faibussowitsch PetscCallCXX(++it);
546c1757967SJacob Faibussowitsch }
547c1757967SJacob Faibussowitsch MapCheck(map, i < max_iter, PETSC_COMM_SELF, PETSC_ERR_PLIB, "%s iterator did not appear to make forward progress using prefix increment! Reached maximum iteration count %zu for map of size %zu", it_name, max_iter, map.size());
548c1757967SJacob Faibussowitsch PetscCallCXX(it = map.begin());
549c1757967SJacob Faibussowitsch for (i = 0; i < max_iter; ++i) {
550c1757967SJacob Faibussowitsch if (it == map.end()) break;
551c1757967SJacob Faibussowitsch PetscCallCXX(it++);
552c1757967SJacob Faibussowitsch }
553c1757967SJacob Faibussowitsch MapCheck(map, i < max_iter, PETSC_COMM_SELF, PETSC_ERR_PLIB, "%s iterator did not appear to make forward progress using postfix increment! Reached maximum iteration count %zu for map of size %zu", it_name, max_iter, map.size());
554c1757967SJacob Faibussowitsch
555c1757967SJacob Faibussowitsch // decrement
556c1757967SJacob Faibussowitsch PetscCallCXX(it = std::prev(map.end()));
557c1757967SJacob Faibussowitsch for (i = 0; i < max_iter; ++i) {
558c1757967SJacob Faibussowitsch if (it == map.begin()) break;
559c1757967SJacob Faibussowitsch PetscCallCXX(--it);
560c1757967SJacob Faibussowitsch }
561c1757967SJacob Faibussowitsch MapCheck(map, i < max_iter, PETSC_COMM_SELF, PETSC_ERR_PLIB, "%s iterator did not appear to make forward progress using prefix decrement! Reached maximum iteration count %zu for map of size %zu", it_name, max_iter, map.size());
562c1757967SJacob Faibussowitsch PetscCallCXX(it = std::prev(map.end()));
563c1757967SJacob Faibussowitsch for (i = 0; i < max_iter; ++i) {
564c1757967SJacob Faibussowitsch if (it == map.begin()) break;
565c1757967SJacob Faibussowitsch PetscCallCXX(it--);
566c1757967SJacob Faibussowitsch }
567c1757967SJacob Faibussowitsch MapCheck(map, i < max_iter, PETSC_COMM_SELF, PETSC_ERR_PLIB, "%s iterator did not appear to make forward progress using postfix decrement! Reached maximum iteration count %zu for map of size %zu", it_name, max_iter, map.size());
568c1757967SJacob Faibussowitsch }
5693ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
570c1757967SJacob Faibussowitsch }
571c1757967SJacob Faibussowitsch
test_misc()572089fb57cSJacob Faibussowitsch PetscErrorCode test_misc() noexcept
573c1757967SJacob Faibussowitsch {
574c1757967SJacob Faibussowitsch const auto sample_values = this->make_key_values(97);
575c1757967SJacob Faibussowitsch map_type map(sample_values.begin(), sample_values.end());
576c1757967SJacob Faibussowitsch
577c1757967SJacob Faibussowitsch PetscFunctionBegin;
578c1757967SJacob Faibussowitsch PetscCall(this->test_iterators(map, map.begin(), map.begin()));
579c1757967SJacob Faibussowitsch PetscCall(this->test_iterators(map, map.cbegin(), map.cbegin()));
580c1757967SJacob Faibussowitsch {
581c1757967SJacob Faibussowitsch const auto backup = map;
582c1757967SJacob Faibussowitsch auto map_copy = map;
583c1757967SJacob Faibussowitsch const auto check_original_map_did_not_change = [&](const char op[]) {
584c1757967SJacob Faibussowitsch PetscFunctionBegin;
585c1757967SJacob Faibussowitsch // the original map should not have changed at all
586c1757967SJacob Faibussowitsch MapCheck(map, map == backup, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Map does not equal the original map after %s", op);
5873ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
588c1757967SJacob Faibussowitsch };
589c1757967SJacob Faibussowitsch
590c1757967SJacob Faibussowitsch MapCheck(map_copy, map == map_copy, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Copy of map does not equal the original map%s", "");
591c1757967SJacob Faibussowitsch PetscCall(check_original_map_did_not_change("move assign"));
592c1757967SJacob Faibussowitsch // test that the copied map works OK
593c1757967SJacob Faibussowitsch PetscCall(this->test_insert(map_copy));
594c1757967SJacob Faibussowitsch PetscCall(check_original_map_did_not_change("test_insert()"));
595c1757967SJacob Faibussowitsch PetscCall(this->test_find(map_copy));
596c1757967SJacob Faibussowitsch PetscCall(check_original_map_did_not_change("test_find()"));
597c1757967SJacob Faibussowitsch PetscCall(this->test_erase(map_copy));
598c1757967SJacob Faibussowitsch PetscCall(check_original_map_did_not_change("test_erase()"));
599c1757967SJacob Faibussowitsch PetscCallCXX(map_copy = map);
600c1757967SJacob Faibussowitsch
601c1757967SJacob Faibussowitsch auto moved_copy = std::move(map_copy);
602c1757967SJacob Faibussowitsch
603c1757967SJacob Faibussowitsch MapCheck(moved_copy, map == moved_copy, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Moved copy of map does not equal the original map%s", "");
604c1757967SJacob Faibussowitsch PetscCall(check_original_map_did_not_change("move assign"));
605c1757967SJacob Faibussowitsch PetscCall(this->test_insert(moved_copy));
606c1757967SJacob Faibussowitsch PetscCall(check_original_map_did_not_change("test_insert()"));
607c1757967SJacob Faibussowitsch PetscCall(this->test_find(moved_copy));
608c1757967SJacob Faibussowitsch PetscCall(check_original_map_did_not_change("test_find()"));
609c1757967SJacob Faibussowitsch PetscCall(this->test_erase(moved_copy));
610c1757967SJacob Faibussowitsch PetscCall(check_original_map_did_not_change("test_erase()"));
611c1757967SJacob Faibussowitsch }
6123ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
613c1757967SJacob Faibussowitsch }
614c1757967SJacob Faibussowitsch
test()615089fb57cSJacob Faibussowitsch PetscErrorCode test() noexcept
616c1757967SJacob Faibussowitsch {
617c1757967SJacob Faibussowitsch PetscFunctionBegin;
618c1757967SJacob Faibussowitsch PetscCall(this->test_insert());
619c1757967SJacob Faibussowitsch PetscCall(this->test_find());
620c1757967SJacob Faibussowitsch PetscCall(this->test_erase());
621c1757967SJacob Faibussowitsch PetscCall(this->test_misc());
6223ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
623c1757967SJacob Faibussowitsch }
624c1757967SJacob Faibussowitsch
625c1757967SJacob Faibussowitsch private:
make_key_values(std::size_t size=100) const626c1757967SJacob Faibussowitsch PETSC_NODISCARD std::vector<value_type> make_key_values(std::size_t size = 100) const noexcept
627c1757967SJacob Faibussowitsch {
628c1757967SJacob Faibussowitsch std::vector<value_type> v(size);
629c1757967SJacob Faibussowitsch
630c1757967SJacob Faibussowitsch std::generate(v.begin(), v.end(), this->generator);
631c1757967SJacob Faibussowitsch return v;
632c1757967SJacob Faibussowitsch }
633c1757967SJacob Faibussowitsch };
634c1757967SJacob Faibussowitsch #ifdef PETSC_GCC_LAMBDA_VISIBILITY_WORKAROUND
635c1757967SJacob Faibussowitsch #pragma GCC visibility pop
636c1757967SJacob Faibussowitsch #endif
637c1757967SJacob Faibussowitsch
638c1757967SJacob Faibussowitsch template <typename... T, typename... Args>
make_tester(PetscViewer vwr,const char name[],Args &&...args)639c1757967SJacob Faibussowitsch PETSC_NODISCARD static MapTester<T...> make_tester(PetscViewer vwr, const char name[], Args &&...args)
640c1757967SJacob Faibussowitsch {
641c1757967SJacob Faibussowitsch return {vwr, name, std::forward<Args>(args)...};
642c1757967SJacob Faibussowitsch }
643c1757967SJacob Faibussowitsch
main(int argc,char * argv[])644c1757967SJacob Faibussowitsch int main(int argc, char *argv[])
645c1757967SJacob Faibussowitsch {
646c1757967SJacob Faibussowitsch PetscViewer vwr;
647c1757967SJacob Faibussowitsch PetscRandom rand;
648c1757967SJacob Faibussowitsch
649c1757967SJacob Faibussowitsch PetscFunctionBeginUser;
650c1757967SJacob Faibussowitsch PetscCall(PetscInitialize(&argc, &argv, nullptr, help));
651c1757967SJacob Faibussowitsch PetscCall(PetscRandomCreate(PETSC_COMM_SELF, &rand));
652c1757967SJacob Faibussowitsch PetscCall(PetscRandomSetInterval(rand, INT_MIN, INT_MAX));
653c1757967SJacob Faibussowitsch PetscCall(PetscRandomSetFromOptions(rand));
654c1757967SJacob Faibussowitsch PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_WORLD, &vwr));
655c1757967SJacob Faibussowitsch
656c1757967SJacob Faibussowitsch {
657c1757967SJacob Faibussowitsch // printer functions
658c1757967SJacob Faibussowitsch const auto int_printer = [](int key, std::string &buf) {
659c1757967SJacob Faibussowitsch PetscFunctionBegin;
660c1757967SJacob Faibussowitsch PetscCallCXX(buf = std::to_string(key));
6613ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
662c1757967SJacob Faibussowitsch };
663c1757967SJacob Faibussowitsch const auto double_printer = [](double value, std::string &buf) {
664c1757967SJacob Faibussowitsch PetscFunctionBegin;
665c1757967SJacob Faibussowitsch PetscCallCXX(buf = std::to_string(value));
6663ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
667c1757967SJacob Faibussowitsch };
668c1757967SJacob Faibussowitsch const auto foo_printer = [](const Foo &key, std::string &buf) {
669c1757967SJacob Faibussowitsch PetscFunctionBegin;
670c1757967SJacob Faibussowitsch PetscCall(key.to_string(buf));
6713ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
672c1757967SJacob Faibussowitsch };
673c1757967SJacob Faibussowitsch const auto bar_printer = [](const Bar &value, std::string &buf) {
674c1757967SJacob Faibussowitsch PetscFunctionBegin;
675c1757967SJacob Faibussowitsch PetscCall(value.to_string(buf));
6763ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
677c1757967SJacob Faibussowitsch };
678c1757967SJacob Faibussowitsch const auto pair_printer = [](const std::pair<int, double> &value, std::string &buf) {
679c1757967SJacob Faibussowitsch PetscFunctionBegin;
680c1757967SJacob Faibussowitsch PetscCallCXX(buf = '<' + std::to_string(value.first) + ", " + std::to_string(value.second) + '>');
6813ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS);
682c1757967SJacob Faibussowitsch };
683c1757967SJacob Faibussowitsch
684c1757967SJacob Faibussowitsch // generator functions
685c1757967SJacob Faibussowitsch const auto make_int = [&] {
686c1757967SJacob Faibussowitsch PetscReal x = 0.;
687c1757967SJacob Faibussowitsch
688c1757967SJacob Faibussowitsch PetscFunctionBegin;
689c1757967SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, PetscRandomGetValueReal(rand, &x));
690c1757967SJacob Faibussowitsch PetscFunctionReturn(static_cast<int>(x));
691c1757967SJacob Faibussowitsch };
692c1757967SJacob Faibussowitsch const auto make_double = [&] {
693c1757967SJacob Faibussowitsch PetscReal x = 0.;
694c1757967SJacob Faibussowitsch
695c1757967SJacob Faibussowitsch PetscFunctionBegin;
696c1757967SJacob Faibussowitsch PetscCallAbort(PETSC_COMM_SELF, PetscRandomGetValueReal(rand, &x));
697c1757967SJacob Faibussowitsch PetscFunctionReturn(static_cast<double>(x));
698c1757967SJacob Faibussowitsch };
699c1757967SJacob Faibussowitsch const auto make_foo = [&] {
700c1757967SJacob Faibussowitsch PetscFunctionBegin;
701c1757967SJacob Faibussowitsch auto ret = Foo{make_int(), make_double()};
702c1757967SJacob Faibussowitsch PetscFunctionReturn(ret);
703c1757967SJacob Faibussowitsch };
704c1757967SJacob Faibussowitsch const auto make_bar = [&] {
705c1757967SJacob Faibussowitsch constexpr std::size_t max_size = 14, min_size = 1;
706c1757967SJacob Faibussowitsch const auto isize = std::abs(make_int());
707c1757967SJacob Faibussowitsch std::vector<int> x(std::max(static_cast<std::size_t>(isize) % max_size, min_size));
708c1757967SJacob Faibussowitsch
709c1757967SJacob Faibussowitsch PetscFunctionBegin;
710c1757967SJacob Faibussowitsch PetscCallCXXAbort(PETSC_COMM_SELF, std::generate(x.begin(), x.end(), make_int));
711c1757967SJacob Faibussowitsch auto ret = Bar{std::move(x), std::to_string(isize)};
712c1757967SJacob Faibussowitsch PetscFunctionReturn(ret);
713c1757967SJacob Faibussowitsch };
714c1757967SJacob Faibussowitsch
715c1757967SJacob Faibussowitsch const auto int_double_generator = [&] { return std::make_pair(make_int(), make_double()); };
716c1757967SJacob Faibussowitsch PetscCall(make_tester<int, double>(vwr, "int-double basic map", int_printer, double_printer, int_double_generator).test());
717c1757967SJacob Faibussowitsch PetscCall(make_tester<int, double, BadHash>(vwr, "int-double bad hash map", int_printer, double_printer, int_double_generator).test());
718c1757967SJacob Faibussowitsch
719c1757967SJacob Faibussowitsch const auto int_foo_generator = [&] { return std::make_pair(make_int(), make_foo()); };
720c1757967SJacob Faibussowitsch PetscCall(make_tester<int, Foo, BadHash>(vwr, "int-foo bad hash map", int_printer, foo_printer, int_foo_generator).test());
721c1757967SJacob Faibussowitsch
722c1757967SJacob Faibussowitsch const auto foo_bar_generator = [&] { return std::make_pair(make_foo(), make_bar()); };
723c1757967SJacob Faibussowitsch PetscCall(make_tester<Foo, Bar>(vwr, "foo-bar basic map", foo_printer, bar_printer, foo_bar_generator).test());
724c1757967SJacob Faibussowitsch PetscCall(make_tester<Foo, Bar, BadHash>(vwr, "foo-bar bad hash map", foo_printer, bar_printer, foo_bar_generator).test());
725c1757967SJacob Faibussowitsch
726c1757967SJacob Faibussowitsch // these test that the indirect_hasher and indirect_equals classes don't barf, since the
727c1757967SJacob Faibussowitsch // value_type of the map and hashers is both the same thing
728c1757967SJacob Faibussowitsch const auto pair_pair_generator = [&] {
729c1757967SJacob Faibussowitsch auto pair = std::make_pair(make_int(), make_double());
730c1757967SJacob Faibussowitsch return std::make_pair(pair, pair);
731c1757967SJacob Faibussowitsch };
732c1757967SJacob Faibussowitsch PetscCall(make_tester<std::pair<int, double>, std::pair<int, double>>(vwr, "pair<int, double>-pair<int, double> basic map", pair_printer, pair_printer, pair_pair_generator).test());
733c1757967SJacob Faibussowitsch PetscCall(make_tester<std::pair<int, double>, std::pair<int, double>, BadHash>(vwr, "pair<int, double>-pair<int, double> bad hash map", pair_printer, pair_printer, pair_pair_generator).test());
734c1757967SJacob Faibussowitsch }
735c1757967SJacob Faibussowitsch
736c1757967SJacob Faibussowitsch PetscCall(PetscRandomDestroy(&rand));
737c1757967SJacob Faibussowitsch PetscCall(PetscFinalize());
738c1757967SJacob Faibussowitsch return 0;
739c1757967SJacob Faibussowitsch }
740c1757967SJacob Faibussowitsch
741c1757967SJacob Faibussowitsch /*TEST
742c1757967SJacob Faibussowitsch
743c1757967SJacob Faibussowitsch test:
744758f5028SMatthew G. Knepley suffix: umap_0
745*3886731fSPierre Jolivet output_file: output/empty.out
746c1757967SJacob Faibussowitsch
747c1757967SJacob Faibussowitsch TEST*/
748