1//     __ _____ _____ _____
2//  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
3// |  |  |__   |  |  | | | |  version 3.11.2
4// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5//
6// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7// SPDX-License-Identifier: MIT
8
9// cmake/test.cmake selects the C++ standard versions with which to build a
10// unit test based on the presence of JSON_HAS_CPP_<VERSION> macros.
11// When using macros that are only defined for particular versions of the standard
12// (e.g., JSON_HAS_FILESYSTEM for C++17 and up), please mention the corresponding
13// version macro in a comment close by, like this:
14// JSON_HAS_CPP_<VERSION> (do not remove; see note at top of file)
15
16#include "doctest_compatibility.h"
17
18#include <nlohmann/json.hpp>
19using nlohmann::json;
20
21#if JSON_HAS_RANGES
22    #include <algorithm>
23    #include <ranges>
24#endif
25
26TEST_CASE("iterators 2")
27{
28    SECTION("iterator comparisons")
29    {
30        json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"};
31
32        for (json& j : j_values)
33        {
34            auto it1 = j.begin();
35            auto it2 = j.begin();
36            auto it3 = j.begin();
37            ++it2;
38            ++it3;
39            ++it3;
40            auto it1_c = j.cbegin();
41            auto it2_c = j.cbegin();
42            auto it3_c = j.cbegin();
43            ++it2_c;
44            ++it3_c;
45            ++it3_c;
46
47            // comparison: equal
48            {
49                CHECK(it1 == it1);
50                CHECK(!(it1 == it2));
51                CHECK(!(it1 == it3));
52                CHECK(!(it2 == it3));
53                CHECK(it1_c == it1_c);
54                CHECK(!(it1_c == it2_c));
55                CHECK(!(it1_c == it3_c));
56                CHECK(!(it2_c == it3_c));
57            }
58
59            // comparison: not equal
60            {
61                // check definition
62                CHECK( (it1 != it1) == !(it1 == it1) );
63                CHECK( (it1 != it2) == !(it1 == it2) );
64                CHECK( (it1 != it3) == !(it1 == it3) );
65                CHECK( (it2 != it3) == !(it2 == it3) );
66                CHECK( (it1_c != it1_c) == !(it1_c == it1_c) );
67                CHECK( (it1_c != it2_c) == !(it1_c == it2_c) );
68                CHECK( (it1_c != it3_c) == !(it1_c == it3_c) );
69                CHECK( (it2_c != it3_c) == !(it2_c == it3_c) );
70            }
71
72            // comparison: smaller
73            {
74                if (j.type() == json::value_t::object)
75                {
76#if JSON_DIAGNOSTICS
77                    CHECK_THROWS_WITH_AS(it1 < it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
78                    CHECK_THROWS_WITH_AS(it1 < it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
79                    CHECK_THROWS_WITH_AS(it2 < it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
80                    CHECK_THROWS_WITH_AS(it1 < it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
81                    CHECK_THROWS_WITH_AS(it1_c < it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
82                    CHECK_THROWS_WITH_AS(it1_c < it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
83                    CHECK_THROWS_WITH_AS(it2_c < it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
84                    CHECK_THROWS_WITH_AS(it1_c < it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
85#else
86                    CHECK_THROWS_WITH_AS(it1 < it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
87                    CHECK_THROWS_WITH_AS(it1 < it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
88                    CHECK_THROWS_WITH_AS(it2 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
89                    CHECK_THROWS_WITH_AS(it1 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
90                    CHECK_THROWS_WITH_AS(it1_c < it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
91                    CHECK_THROWS_WITH_AS(it1_c < it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
92                    CHECK_THROWS_WITH_AS(it2_c < it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
93                    CHECK_THROWS_WITH_AS(it1_c < it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
94#endif
95                }
96                else
97                {
98                    CHECK(!(it1 < it1));
99                    CHECK(it1 < it2);
100                    CHECK(it1 < it3);
101                    CHECK(it2 < it3);
102                    CHECK(!(it1_c < it1_c));
103                    CHECK(it1_c < it2_c);
104                    CHECK(it1_c < it3_c);
105                    CHECK(it2_c < it3_c);
106                }
107            }
108
109            // comparison: less than or equal
110            {
111                if (j.type() == json::value_t::object)
112                {
113#if JSON_DIAGNOSTICS
114                    CHECK_THROWS_WITH_AS(it1 <= it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
115                    CHECK_THROWS_WITH_AS(it1 <= it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
116                    CHECK_THROWS_WITH_AS(it2 <= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
117                    CHECK_THROWS_WITH_AS(it1 <= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
118                    CHECK_THROWS_WITH_AS(it1_c <= it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
119                    CHECK_THROWS_WITH_AS(it1_c <= it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
120                    CHECK_THROWS_WITH_AS(it2_c <= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
121                    CHECK_THROWS_WITH_AS(it1_c <= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
122#else
123                    CHECK_THROWS_WITH_AS(it1 <= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
124                    CHECK_THROWS_WITH_AS(it1 <= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
125                    CHECK_THROWS_WITH_AS(it2 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
126                    CHECK_THROWS_WITH_AS(it1 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
127                    CHECK_THROWS_WITH_AS(it1_c <= it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
128                    CHECK_THROWS_WITH_AS(it1_c <= it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
129                    CHECK_THROWS_WITH_AS(it2_c <= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
130                    CHECK_THROWS_WITH_AS(it1_c <= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
131#endif
132                }
133                else
134                {
135                    // check definition
136                    CHECK( (it1 <= it1) == !(it1 < it1) );
137                    CHECK( (it1 <= it2) == !(it2 < it1) );
138                    CHECK( (it1 <= it3) == !(it3 < it1) );
139                    CHECK( (it2 <= it3) == !(it3 < it2) );
140                    CHECK( (it1_c <= it1_c) == !(it1_c < it1_c) );
141                    CHECK( (it1_c <= it2_c) == !(it2_c < it1_c) );
142                    CHECK( (it1_c <= it3_c) == !(it3_c < it1_c) );
143                    CHECK( (it2_c <= it3_c) == !(it3_c < it2_c) );
144                }
145            }
146
147            // comparison: greater than
148            {
149                if (j.type() == json::value_t::object)
150                {
151#if JSON_DIAGNOSTICS
152                    CHECK_THROWS_WITH_AS(it1 > it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
153                    CHECK_THROWS_WITH_AS(it1 > it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
154                    CHECK_THROWS_WITH_AS(it2 > it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
155                    CHECK_THROWS_WITH_AS(it1 > it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
156                    CHECK_THROWS_WITH_AS(it1_c > it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
157                    CHECK_THROWS_WITH_AS(it1_c > it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
158                    CHECK_THROWS_WITH_AS(it2_c > it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
159                    CHECK_THROWS_WITH_AS(it1_c > it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
160#else
161                    CHECK_THROWS_WITH_AS(it1 > it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
162                    CHECK_THROWS_WITH_AS(it1 > it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
163                    CHECK_THROWS_WITH_AS(it2 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
164                    CHECK_THROWS_WITH_AS(it1 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
165                    CHECK_THROWS_WITH_AS(it1_c > it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
166                    CHECK_THROWS_WITH_AS(it1_c > it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
167                    CHECK_THROWS_WITH_AS(it2_c > it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
168                    CHECK_THROWS_WITH_AS(it1_c > it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
169#endif
170                }
171                else
172                {
173                    // check definition
174                    CHECK( (it1 > it1) == (it1 < it1) );
175                    CHECK( (it1 > it2) == (it2 < it1) );
176                    CHECK( (it1 > it3) == (it3 < it1) );
177                    CHECK( (it2 > it3) == (it3 < it2) );
178                    CHECK( (it1_c > it1_c) == (it1_c < it1_c) );
179                    CHECK( (it1_c > it2_c) == (it2_c < it1_c) );
180                    CHECK( (it1_c > it3_c) == (it3_c < it1_c) );
181                    CHECK( (it2_c > it3_c) == (it3_c < it2_c) );
182                }
183            }
184
185            // comparison: greater than or equal
186            {
187                if (j.type() == json::value_t::object)
188                {
189#if JSON_DIAGNOSTICS
190                    CHECK_THROWS_WITH_AS(it1 >= it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
191                    CHECK_THROWS_WITH_AS(it1 >= it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
192                    CHECK_THROWS_WITH_AS(it2 >= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
193                    CHECK_THROWS_WITH_AS(it1 >= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
194                    CHECK_THROWS_WITH_AS(it1_c >= it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
195                    CHECK_THROWS_WITH_AS(it1_c >= it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
196                    CHECK_THROWS_WITH_AS(it2_c >= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
197                    CHECK_THROWS_WITH_AS(it1_c >= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
198#else
199                    CHECK_THROWS_WITH_AS(it1 >= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
200                    CHECK_THROWS_WITH_AS(it1 >= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
201                    CHECK_THROWS_WITH_AS(it2 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
202                    CHECK_THROWS_WITH_AS(it1 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
203                    CHECK_THROWS_WITH_AS(it1_c >= it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
204                    CHECK_THROWS_WITH_AS(it1_c >= it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
205                    CHECK_THROWS_WITH_AS(it2_c >= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
206                    CHECK_THROWS_WITH_AS(it1_c >= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
207#endif
208                }
209                else
210                {
211                    // check definition
212                    CHECK( (it1 >= it1) == !(it1 < it1) );
213                    CHECK( (it1 >= it2) == !(it1 < it2) );
214                    CHECK( (it1 >= it3) == !(it1 < it3) );
215                    CHECK( (it2 >= it3) == !(it2 < it3) );
216                    CHECK( (it1_c >= it1_c) == !(it1_c < it1_c) );
217                    CHECK( (it1_c >= it2_c) == !(it1_c < it2_c) );
218                    CHECK( (it1_c >= it3_c) == !(it1_c < it3_c) );
219                    CHECK( (it2_c >= it3_c) == !(it2_c < it3_c) );
220                }
221            }
222        }
223
224        // check exceptions if different objects are compared
225        for (auto j : j_values)
226        {
227            for (auto k : j_values)
228            {
229                if (j != k)
230                {
231#if JSON_DIAGNOSTICS
232                    // the output differs in each loop, so we cannot fix a string for the expected exception
233#else
234                    CHECK_THROWS_WITH_AS(j.begin() == k.begin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
235                    CHECK_THROWS_WITH_AS(j.cbegin() == k.cbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
236                    CHECK_THROWS_WITH_AS(j.begin() < k.begin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
237                    CHECK_THROWS_WITH_AS(j.cbegin() < k.cbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
238#endif
239                }
240            }
241        }
242    }
243
244    SECTION("iterator arithmetic")
245    {
246        json j_object = {{"one", 1}, {"two", 2}, {"three", 3}};
247        json j_array = {1, 2, 3, 4, 5, 6};
248        json j_null = nullptr;
249        json j_value = 42;
250
251        SECTION("addition and subtraction")
252        {
253            SECTION("object")
254            {
255                {
256                    auto it = j_object.begin();
257                    CHECK_THROWS_WITH_AS(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
258                }
259                {
260                    auto it = j_object.cbegin();
261                    CHECK_THROWS_WITH_AS(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
262                }
263                {
264                    auto it = j_object.begin();
265                    CHECK_THROWS_WITH_AS(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
266                }
267                {
268                    auto it = j_object.cbegin();
269                    CHECK_THROWS_WITH_AS(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
270                }
271                {
272                    auto it = j_object.begin();
273                    CHECK_THROWS_WITH_AS(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
274                }
275                {
276                    auto it = j_object.cbegin();
277                    CHECK_THROWS_WITH_AS(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
278                }
279                {
280                    auto it = j_object.begin();
281                    CHECK_THROWS_WITH_AS(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
282                }
283                {
284                    auto it = j_object.cbegin();
285                    CHECK_THROWS_WITH_AS(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
286                }
287                {
288                    auto it = j_object.begin();
289                    CHECK_THROWS_WITH_AS(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
290                }
291                {
292                    auto it = j_object.cbegin();
293                    CHECK_THROWS_WITH_AS(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
294                }
295                {
296                    auto it = j_object.begin();
297                    CHECK_THROWS_WITH_AS(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
298                }
299                {
300                    auto it = j_object.cbegin();
301                    CHECK_THROWS_WITH_AS(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
302                }
303            }
304
305            SECTION("array")
306            {
307                {
308                    auto it = j_array.begin();
309                    it += 3;
310                    CHECK((j_array.begin() + 3) == it);
311                    CHECK((3 + j_array.begin()) == it);
312                    CHECK((it - 3) == j_array.begin());
313                    CHECK((it - j_array.begin()) == 3);
314                    CHECK(*it == json(4));
315                    it -= 2;
316                    CHECK(*it == json(2));
317                }
318                {
319                    auto it = j_array.cbegin();
320                    it += 3;
321                    CHECK((j_array.cbegin() + 3) == it);
322                    CHECK((3 + j_array.cbegin()) == it);
323                    CHECK((it - 3) == j_array.cbegin());
324                    CHECK((it - j_array.cbegin()) == 3);
325                    CHECK(*it == json(4));
326                    it -= 2;
327                    CHECK(*it == json(2));
328                }
329            }
330
331            SECTION("null")
332            {
333                {
334                    auto it = j_null.begin();
335                    it += 3;
336                    CHECK((j_null.begin() + 3) == it);
337                    CHECK((3 + j_null.begin()) == it);
338                    CHECK((it - 3) == j_null.begin());
339                    CHECK((it - j_null.begin()) == 3);
340                    CHECK(it != j_null.end());
341                    it -= 3;
342                    CHECK(it == j_null.end());
343                }
344                {
345                    auto it = j_null.cbegin();
346                    it += 3;
347                    CHECK((j_null.cbegin() + 3) == it);
348                    CHECK((3 + j_null.cbegin()) == it);
349                    CHECK((it - 3) == j_null.cbegin());
350                    CHECK((it - j_null.cbegin()) == 3);
351                    CHECK(it != j_null.cend());
352                    it -= 3;
353                    CHECK(it == j_null.cend());
354                }
355            }
356
357            SECTION("value")
358            {
359                {
360                    auto it = j_value.begin();
361                    it += 3;
362                    CHECK((j_value.begin() + 3) == it);
363                    CHECK((3 + j_value.begin()) == it);
364                    CHECK((it - 3) == j_value.begin());
365                    CHECK((it - j_value.begin()) == 3);
366                    CHECK(it != j_value.end());
367                    it -= 3;
368                    CHECK(*it == json(42));
369                }
370                {
371                    auto it = j_value.cbegin();
372                    it += 3;
373                    CHECK((j_value.cbegin() + 3) == it);
374                    CHECK((3 + j_value.cbegin()) == it);
375                    CHECK((it - 3) == j_value.cbegin());
376                    CHECK((it - j_value.cbegin()) == 3);
377                    CHECK(it != j_value.cend());
378                    it -= 3;
379                    CHECK(*it == json(42));
380                }
381            }
382        }
383
384        SECTION("subscript operator")
385        {
386            SECTION("object")
387            {
388                {
389                    auto it = j_object.begin();
390                    CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators", json::invalid_iterator&);
391                    CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators", json::invalid_iterator&);
392                }
393                {
394                    auto it = j_object.cbegin();
395                    CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators", json::invalid_iterator&);
396                    CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.208] cannot use operator[] for object iterators", json::invalid_iterator&);
397                }
398            }
399
400            SECTION("array")
401            {
402                {
403                    auto it = j_array.begin();
404                    CHECK(it[0] == json(1));
405                    CHECK(it[1] == json(2));
406                    CHECK(it[2] == json(3));
407                    CHECK(it[3] == json(4));
408                    CHECK(it[4] == json(5));
409                    CHECK(it[5] == json(6));
410                }
411                {
412                    auto it = j_array.cbegin();
413                    CHECK(it[0] == json(1));
414                    CHECK(it[1] == json(2));
415                    CHECK(it[2] == json(3));
416                    CHECK(it[3] == json(4));
417                    CHECK(it[4] == json(5));
418                    CHECK(it[5] == json(6));
419                }
420            }
421
422            SECTION("null")
423            {
424                {
425                    auto it = j_null.begin();
426                    CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
427                    CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
428                }
429                {
430                    auto it = j_null.cbegin();
431                    CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
432                    CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
433                }
434            }
435
436            SECTION("value")
437            {
438                {
439                    auto it = j_value.begin();
440                    CHECK(it[0] == json(42));
441                    CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
442                }
443                {
444                    auto it = j_value.cbegin();
445                    CHECK(it[0] == json(42));
446                    CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
447                }
448            }
449        }
450    }
451
452    SECTION("reverse iterator comparisons")
453    {
454        json j_values = {nullptr, true, 42, 42u, 23.23, {{"one", 1}, {"two", 2}}, {1, 2, 3, 4, 5}, "Hello, world"};
455
456        for (json& j : j_values)
457        {
458            auto it1 = j.rbegin();
459            auto it2 = j.rbegin();
460            auto it3 = j.rbegin();
461            ++it2;
462            ++it3;
463            ++it3;
464            auto it1_c = j.crbegin();
465            auto it2_c = j.crbegin();
466            auto it3_c = j.crbegin();
467            ++it2_c;
468            ++it3_c;
469            ++it3_c;
470
471            // comparison: equal
472            {
473                CHECK(it1 == it1);
474                CHECK(!(it1 == it2));
475                CHECK(!(it1 == it3));
476                CHECK(!(it2 == it3));
477                CHECK(it1_c == it1_c);
478                CHECK(!(it1_c == it2_c));
479                CHECK(!(it1_c == it3_c));
480                CHECK(!(it2_c == it3_c));
481            }
482
483            // comparison: not equal
484            {
485                // check definition
486                CHECK( (it1 != it1) == !(it1 == it1) );
487                CHECK( (it1 != it2) == !(it1 == it2) );
488                CHECK( (it1 != it3) == !(it1 == it3) );
489                CHECK( (it2 != it3) == !(it2 == it3) );
490                CHECK( (it1_c != it1_c) == !(it1_c == it1_c) );
491                CHECK( (it1_c != it2_c) == !(it1_c == it2_c) );
492                CHECK( (it1_c != it3_c) == !(it1_c == it3_c) );
493                CHECK( (it2_c != it3_c) == !(it2_c == it3_c) );
494            }
495
496            // comparison: smaller
497            {
498                if (j.type() == json::value_t::object)
499                {
500#if JSON_DIAGNOSTICS
501                    CHECK_THROWS_WITH_AS(it1 < it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
502                    CHECK_THROWS_WITH_AS(it1 < it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
503                    CHECK_THROWS_WITH_AS(it2 < it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
504                    CHECK_THROWS_WITH_AS(it1 < it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
505                    CHECK_THROWS_WITH_AS(it1_c < it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
506                    CHECK_THROWS_WITH_AS(it1_c < it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
507                    CHECK_THROWS_WITH_AS(it2_c < it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
508                    CHECK_THROWS_WITH_AS(it1_c < it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
509#else
510                    CHECK_THROWS_WITH_AS(it1 < it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
511                    CHECK_THROWS_WITH_AS(it1 < it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
512                    CHECK_THROWS_WITH_AS(it2 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
513                    CHECK_THROWS_WITH_AS(it1 < it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
514                    CHECK_THROWS_WITH_AS(it1_c < it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
515                    CHECK_THROWS_WITH_AS(it1_c < it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
516                    CHECK_THROWS_WITH_AS(it2_c < it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
517                    CHECK_THROWS_WITH_AS(it1_c < it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
518#endif
519                }
520                else
521                {
522                    CHECK(!(it1 < it1));
523                    CHECK(it1 < it2);
524                    CHECK(it1 < it3);
525                    CHECK(it2 < it3);
526                    CHECK(!(it1_c < it1_c));
527                    CHECK(it1_c < it2_c);
528                    CHECK(it1_c < it3_c);
529                    CHECK(it2_c < it3_c);
530                }
531            }
532
533            // comparison: less than or equal
534            {
535                if (j.type() == json::value_t::object)
536                {
537#if JSON_DIAGNOSTICS
538                    CHECK_THROWS_WITH_AS(it1 <= it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
539                    CHECK_THROWS_WITH_AS(it1 <= it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
540                    CHECK_THROWS_WITH_AS(it2 <= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
541                    CHECK_THROWS_WITH_AS(it1 <= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
542                    CHECK_THROWS_WITH_AS(it1_c <= it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
543                    CHECK_THROWS_WITH_AS(it1_c <= it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
544                    CHECK_THROWS_WITH_AS(it2_c <= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
545                    CHECK_THROWS_WITH_AS(it1_c <= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
546#else
547                    CHECK_THROWS_WITH_AS(it1 <= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
548                    CHECK_THROWS_WITH_AS(it1 <= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
549                    CHECK_THROWS_WITH_AS(it2 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
550                    CHECK_THROWS_WITH_AS(it1 <= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
551                    CHECK_THROWS_WITH_AS(it1_c <= it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
552                    CHECK_THROWS_WITH_AS(it1_c <= it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
553                    CHECK_THROWS_WITH_AS(it2_c <= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
554                    CHECK_THROWS_WITH_AS(it1_c <= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
555#endif
556                }
557                else
558                {
559                    // check definition
560                    CHECK( (it1 <= it1) == !(it1 < it1) );
561                    CHECK( (it1 <= it2) == !(it2 < it1) );
562                    CHECK( (it1 <= it3) == !(it3 < it1) );
563                    CHECK( (it2 <= it3) == !(it3 < it2) );
564                    CHECK( (it1_c <= it1_c) == !(it1_c < it1_c) );
565                    CHECK( (it1_c <= it2_c) == !(it2_c < it1_c) );
566                    CHECK( (it1_c <= it3_c) == !(it3_c < it1_c) );
567                    CHECK( (it2_c <= it3_c) == !(it3_c < it2_c) );
568                }
569            }
570
571            // comparison: greater than
572            {
573                if (j.type() == json::value_t::object)
574                {
575#if JSON_DIAGNOSTICS
576                    CHECK_THROWS_WITH_AS(it1 > it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
577                    CHECK_THROWS_WITH_AS(it1 > it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
578                    CHECK_THROWS_WITH_AS(it2 > it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
579                    CHECK_THROWS_WITH_AS(it1 > it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
580                    CHECK_THROWS_WITH_AS(it1_c > it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
581                    CHECK_THROWS_WITH_AS(it1_c > it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
582                    CHECK_THROWS_WITH_AS(it2_c > it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
583                    CHECK_THROWS_WITH_AS(it1_c > it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
584#else
585                    CHECK_THROWS_WITH_AS(it1 > it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
586                    CHECK_THROWS_WITH_AS(it1 > it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
587                    CHECK_THROWS_WITH_AS(it2 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
588                    CHECK_THROWS_WITH_AS(it1 > it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
589                    CHECK_THROWS_WITH_AS(it1_c > it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
590                    CHECK_THROWS_WITH_AS(it1_c > it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
591                    CHECK_THROWS_WITH_AS(it2_c > it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
592                    CHECK_THROWS_WITH_AS(it1_c > it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
593#endif
594                }
595                else
596                {
597                    // check definition
598                    CHECK( (it1 > it1) == (it1 < it1) );
599                    CHECK( (it1 > it2) == (it2 < it1) );
600                    CHECK( (it1 > it3) == (it3 < it1) );
601                    CHECK( (it2 > it3) == (it3 < it2) );
602                    CHECK( (it1_c > it1_c) == (it1_c < it1_c) );
603                    CHECK( (it1_c > it2_c) == (it2_c < it1_c) );
604                    CHECK( (it1_c > it3_c) == (it3_c < it1_c) );
605                    CHECK( (it2_c > it3_c) == (it3_c < it2_c) );
606                }
607            }
608
609            // comparison: greater than or equal
610            {
611                if (j.type() == json::value_t::object)
612                {
613#if JSON_DIAGNOSTICS
614                    CHECK_THROWS_WITH_AS(it1 >= it1, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
615                    CHECK_THROWS_WITH_AS(it1 >= it2, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
616                    CHECK_THROWS_WITH_AS(it2 >= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
617                    CHECK_THROWS_WITH_AS(it1 >= it3, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
618                    CHECK_THROWS_WITH_AS(it1_c >= it1_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
619                    CHECK_THROWS_WITH_AS(it1_c >= it2_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
620                    CHECK_THROWS_WITH_AS(it2_c >= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
621                    CHECK_THROWS_WITH_AS(it1_c >= it3_c, "[json.exception.invalid_iterator.213] (/5) cannot compare order of object iterators", json::invalid_iterator&);
622#else
623                    CHECK_THROWS_WITH_AS(it1 >= it1, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
624                    CHECK_THROWS_WITH_AS(it1 >= it2, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
625                    CHECK_THROWS_WITH_AS(it2 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
626                    CHECK_THROWS_WITH_AS(it1 >= it3, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
627                    CHECK_THROWS_WITH_AS(it1_c >= it1_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
628                    CHECK_THROWS_WITH_AS(it1_c >= it2_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
629                    CHECK_THROWS_WITH_AS(it2_c >= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
630                    CHECK_THROWS_WITH_AS(it1_c >= it3_c, "[json.exception.invalid_iterator.213] cannot compare order of object iterators", json::invalid_iterator&);
631#endif
632                }
633                else
634                {
635                    // check definition
636                    CHECK( (it1 >= it1) == !(it1 < it1) );
637                    CHECK( (it1 >= it2) == !(it1 < it2) );
638                    CHECK( (it1 >= it3) == !(it1 < it3) );
639                    CHECK( (it2 >= it3) == !(it2 < it3) );
640                    CHECK( (it1_c >= it1_c) == !(it1_c < it1_c) );
641                    CHECK( (it1_c >= it2_c) == !(it1_c < it2_c) );
642                    CHECK( (it1_c >= it3_c) == !(it1_c < it3_c) );
643                    CHECK( (it2_c >= it3_c) == !(it2_c < it3_c) );
644                }
645            }
646        }
647
648        // check exceptions if different objects are compared
649        for (auto j : j_values)
650        {
651            for (auto k : j_values)
652            {
653                if (j != k)
654                {
655#if JSON_DIAGNOSTICS
656                    // the output differs in each loop, so we cannot fix a string for the expected exception
657#else
658                    CHECK_THROWS_WITH_AS(j.rbegin() == k.rbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
659                    CHECK_THROWS_WITH_AS(j.crbegin() == k.crbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
660                    CHECK_THROWS_WITH_AS(j.rbegin() < k.rbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
661                    CHECK_THROWS_WITH_AS(j.crbegin() < k.crbegin(), "[json.exception.invalid_iterator.212] cannot compare iterators of different containers", json::invalid_iterator&);
662#endif
663                }
664            }
665        }
666    }
667
668    SECTION("reverse iterator arithmetic")
669    {
670        json j_object = {{"one", 1}, {"two", 2}, {"three", 3}};
671        json j_array = {1, 2, 3, 4, 5, 6};
672        json j_null = nullptr;
673        json j_value = 42;
674
675        SECTION("addition and subtraction")
676        {
677            SECTION("object")
678            {
679                {
680                    auto it = j_object.rbegin();
681                    CHECK_THROWS_WITH_AS(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
682                }
683                {
684                    auto it = j_object.crbegin();
685                    CHECK_THROWS_WITH_AS(it += 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
686                }
687                {
688                    auto it = j_object.rbegin();
689                    CHECK_THROWS_WITH_AS(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
690                }
691                {
692                    auto it = j_object.crbegin();
693                    CHECK_THROWS_WITH_AS(it + 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
694                }
695                {
696                    auto it = j_object.rbegin();
697                    CHECK_THROWS_WITH_AS(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
698                }
699                {
700                    auto it = j_object.crbegin();
701                    CHECK_THROWS_WITH_AS(1 + it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
702                }
703                {
704                    auto it = j_object.rbegin();
705                    CHECK_THROWS_WITH_AS(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
706                }
707                {
708                    auto it = j_object.crbegin();
709                    CHECK_THROWS_WITH_AS(it -= 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
710                }
711                {
712                    auto it = j_object.rbegin();
713                    CHECK_THROWS_WITH_AS(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
714                }
715                {
716                    auto it = j_object.crbegin();
717                    CHECK_THROWS_WITH_AS(it - 1, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
718                }
719                {
720                    auto it = j_object.rbegin();
721                    CHECK_THROWS_WITH_AS(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
722                }
723                {
724                    auto it = j_object.crbegin();
725                    CHECK_THROWS_WITH_AS(it - it, "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
726                }
727            }
728
729            SECTION("array")
730            {
731                {
732                    auto it = j_array.rbegin();
733                    it += 3;
734                    CHECK((j_array.rbegin() + 3) == it);
735                    CHECK(json::reverse_iterator(3 + j_array.rbegin()) == it);
736                    CHECK((it - 3) == j_array.rbegin());
737                    CHECK((it - j_array.rbegin()) == 3);
738                    CHECK(*it == json(3));
739                    it -= 2;
740                    CHECK(*it == json(5));
741                }
742                {
743                    auto it = j_array.crbegin();
744                    it += 3;
745                    CHECK((j_array.crbegin() + 3) == it);
746                    CHECK(json::const_reverse_iterator(3 + j_array.crbegin()) == it);
747                    CHECK((it - 3) == j_array.crbegin());
748                    CHECK((it - j_array.crbegin()) == 3);
749                    CHECK(*it == json(3));
750                    it -= 2;
751                    CHECK(*it == json(5));
752                }
753            }
754
755            SECTION("null")
756            {
757                {
758                    auto it = j_null.rbegin();
759                    it += 3;
760                    CHECK((j_null.rbegin() + 3) == it);
761                    CHECK(json::reverse_iterator(3 + j_null.rbegin()) == it);
762                    CHECK((it - 3) == j_null.rbegin());
763                    CHECK((it - j_null.rbegin()) == 3);
764                    CHECK(it != j_null.rend());
765                    it -= 3;
766                    CHECK(it == j_null.rend());
767                }
768                {
769                    auto it = j_null.crbegin();
770                    it += 3;
771                    CHECK((j_null.crbegin() + 3) == it);
772                    CHECK(json::const_reverse_iterator(3 + j_null.crbegin()) == it);
773                    CHECK((it - 3) == j_null.crbegin());
774                    CHECK((it - j_null.crbegin()) == 3);
775                    CHECK(it != j_null.crend());
776                    it -= 3;
777                    CHECK(it == j_null.crend());
778                }
779            }
780
781            SECTION("value")
782            {
783                {
784                    auto it = j_value.rbegin();
785                    it += 3;
786                    CHECK((j_value.rbegin() + 3) == it);
787                    CHECK(json::reverse_iterator(3 + j_value.rbegin()) == it);
788                    CHECK((it - 3) == j_value.rbegin());
789                    CHECK((it - j_value.rbegin()) == 3);
790                    CHECK(it != j_value.rend());
791                    it -= 3;
792                    CHECK(*it == json(42));
793                }
794                {
795                    auto it = j_value.crbegin();
796                    it += 3;
797                    CHECK((j_value.crbegin() + 3) == it);
798                    CHECK(json::const_reverse_iterator(3 + j_value.crbegin()) == it);
799                    CHECK((it - 3) == j_value.crbegin());
800                    CHECK((it - j_value.crbegin()) == 3);
801                    CHECK(it != j_value.crend());
802                    it -= 3;
803                    CHECK(*it == json(42));
804                }
805            }
806        }
807
808        SECTION("subscript operator")
809        {
810            SECTION("object")
811            {
812                {
813                    auto it = j_object.rbegin();
814                    CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
815                    CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
816                }
817                {
818                    auto it = j_object.crbegin();
819                    CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
820                    CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.209] cannot use offsets with object iterators", json::invalid_iterator&);
821                }
822            }
823
824            SECTION("array")
825            {
826                {
827                    auto it = j_array.rbegin();
828                    CHECK(it[0] == json(6));
829                    CHECK(it[1] == json(5));
830                    CHECK(it[2] == json(4));
831                    CHECK(it[3] == json(3));
832                    CHECK(it[4] == json(2));
833                    CHECK(it[5] == json(1));
834                }
835                {
836                    auto it = j_array.crbegin();
837                    CHECK(it[0] == json(6));
838                    CHECK(it[1] == json(5));
839                    CHECK(it[2] == json(4));
840                    CHECK(it[3] == json(3));
841                    CHECK(it[4] == json(2));
842                    CHECK(it[5] == json(1));
843                }
844            }
845
846            SECTION("null")
847            {
848                {
849                    auto it = j_null.rbegin();
850                    CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
851                    CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
852                }
853                {
854                    auto it = j_null.crbegin();
855                    CHECK_THROWS_WITH_AS(it[0], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
856                    CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
857                }
858            }
859
860            SECTION("value")
861            {
862                {
863                    auto it = j_value.rbegin();
864                    CHECK(it[0] == json(42));
865                    CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
866                }
867                {
868                    auto it = j_value.crbegin();
869                    CHECK(it[0] == json(42));
870                    CHECK_THROWS_WITH_AS(it[1], "[json.exception.invalid_iterator.214] cannot get value", json::invalid_iterator&);
871                }
872            }
873        }
874    }
875
876
877#if JSON_HAS_RANGES
878    // JSON_HAS_CPP_20 (do not remove; see note at top of file)
879    SECTION("ranges")
880    {
881        SECTION("concepts")
882        {
883            using nlohmann::detail::iteration_proxy_value;
884            CHECK(std::bidirectional_iterator<json::iterator>);
885            CHECK(std::input_iterator<iteration_proxy_value<json::iterator>>);
886
887            CHECK(std::is_same<json::iterator, std::ranges::iterator_t<json>>::value);
888            CHECK(std::ranges::bidirectional_range<json>);
889
890            using nlohmann::detail::iteration_proxy;
891            using items_type = decltype(std::declval<json&>().items());
892            CHECK(std::is_same<items_type, iteration_proxy<json::iterator>>::value);
893            CHECK(std::is_same<iteration_proxy_value<json::iterator>, std::ranges::iterator_t<items_type>>::value);
894            CHECK(std::ranges::input_range<items_type>);
895        }
896
897        // libstdc++ algorithms don't work with Clang 15 (04/2022)
898#if !DOCTEST_CLANG || (DOCTEST_CLANG && defined(__GLIBCXX__))
899        SECTION("algorithms")
900        {
901            SECTION("copy")
902            {
903                json j{"foo", "bar"};
904                auto j_copied = json::array();
905
906                std::ranges::copy(j, std::back_inserter(j_copied));
907
908                CHECK(j == j_copied);
909            }
910
911            SECTION("find_if")
912            {
913                json j{1, 3, 2, 4};
914                auto j_even = json::array();
915
916#if JSON_USE_IMPLICIT_CONVERSIONS
917                auto it = std::ranges::find_if(j, [](int v) noexcept
918                {
919                    return (v % 2) == 0;
920                });
921#else
922                auto it = std::ranges::find_if(j, [](const json & j) noexcept
923                {
924                    int v;
925                    j.get_to(v);
926                    return (v % 2) == 0;
927                });
928#endif
929
930                CHECK(*it == 2);
931            }
932        }
933#endif
934
935        // libstdc++ views don't work with Clang 15 (04/2022)
936        // libc++ hides limited ranges implementation behind guard macro
937#if !(DOCTEST_CLANG && (defined(__GLIBCXX__) || defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)))
938        SECTION("views")
939        {
940            SECTION("reverse")
941            {
942                json j{1, 2, 3, 4, 5};
943                json j_expected{5, 4, 3, 2, 1};
944
945                auto reversed = j | std::views::reverse;
946                CHECK(reversed == j_expected);
947            }
948
949            SECTION("transform")
950            {
951                json j
952                {
953                    { "a_key", "a_value"},
954                    { "b_key", "b_value"},
955                    { "c_key", "c_value"},
956                };
957                json j_expected{"a_key", "b_key", "c_key"};
958
959                auto transformed = j.items() | std::views::transform([](const auto & item)
960                {
961                    return item.key();
962                });
963                auto j_transformed = json::array();
964                std::ranges::copy(transformed, std::back_inserter(j_transformed));
965
966                CHECK(j_transformed == j_expected);
967            }
968        }
969#endif
970    }
971#endif
972}
973