Skip to content

Commit

Permalink
Make json_pointer usable as map key (again) (#3685)
Browse files Browse the repository at this point in the history
* Make json_pointer usable as map key

* Add unit tests
  • Loading branch information
falbrechtskirchinger authored Aug 7, 2022
1 parent 231f310 commit 31265dc
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 4 deletions.
24 changes: 22 additions & 2 deletions include/nlohmann/detail/json_pointer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ class json_pointer
}

public:
#ifdef JSON_HAS_CPP_20
#if JSON_HAS_THREE_WAY_COMPARISON
/// @brief compares two JSON pointers for equality
/// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
template<typename RefStringTypeRhs>
Expand All @@ -862,6 +862,13 @@ class json_pointer
{
return *this == json_pointer(rhs);
}

/// @brief 3-way compares two JSON pointers
template<typename RefStringTypeRhs>
std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD*
{
return reference_tokens <=> rhs.reference_tokens; // *NOPAD*
}
#else
/// @brief compares two JSON pointers for equality
/// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
Expand Down Expand Up @@ -904,14 +911,20 @@ class json_pointer
// NOLINTNEXTLINE(readability-redundant-declaration)
friend bool operator!=(const StringType& lhs,
const json_pointer<RefStringTypeRhs>& rhs);

/// @brief compares two JSON pointer for less-than
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
// NOLINTNEXTLINE(readability-redundant-declaration)
friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
const json_pointer<RefStringTypeRhs>& rhs) noexcept;
#endif

private:
/// the reference tokens
std::vector<string_t> reference_tokens;
};

#ifndef JSON_HAS_CPP_20
#if !JSON_HAS_THREE_WAY_COMPARISON
// functions cannot be defined inside class due to ODR violations
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
Expand Down Expand Up @@ -958,6 +971,13 @@ inline bool operator!=(const StringType& lhs,
{
return !(lhs == rhs);
}

template<typename RefStringTypeLhs, typename RefStringTypeRhs>
inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
const json_pointer<RefStringTypeRhs>& rhs) noexcept
{
return lhs.reference_tokens < rhs.reference_tokens;
}
#endif

NLOHMANN_JSON_NAMESPACE_END
24 changes: 22 additions & 2 deletions single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14507,7 +14507,7 @@ class json_pointer
}

public:
#ifdef JSON_HAS_CPP_20
#if JSON_HAS_THREE_WAY_COMPARISON
/// @brief compares two JSON pointers for equality
/// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
template<typename RefStringTypeRhs>
Expand All @@ -14522,6 +14522,13 @@ class json_pointer
{
return *this == json_pointer(rhs);
}

/// @brief 3-way compares two JSON pointers
template<typename RefStringTypeRhs>
std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD*
{
return reference_tokens <=> rhs.reference_tokens; // *NOPAD*
}
#else
/// @brief compares two JSON pointers for equality
/// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
Expand Down Expand Up @@ -14564,14 +14571,20 @@ class json_pointer
// NOLINTNEXTLINE(readability-redundant-declaration)
friend bool operator!=(const StringType& lhs,
const json_pointer<RefStringTypeRhs>& rhs);

/// @brief compares two JSON pointer for less-than
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
// NOLINTNEXTLINE(readability-redundant-declaration)
friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
const json_pointer<RefStringTypeRhs>& rhs) noexcept;
#endif

private:
/// the reference tokens
std::vector<string_t> reference_tokens;
};

#ifndef JSON_HAS_CPP_20
#if !JSON_HAS_THREE_WAY_COMPARISON
// functions cannot be defined inside class due to ODR violations
template<typename RefStringTypeLhs, typename RefStringTypeRhs>
inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
Expand Down Expand Up @@ -14618,6 +14631,13 @@ inline bool operator!=(const StringType& lhs,
{
return !(lhs == rhs);
}

template<typename RefStringTypeLhs, typename RefStringTypeRhs>
inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
const json_pointer<RefStringTypeRhs>& rhs) noexcept
{
return lhs.reference_tokens < rhs.reference_tokens;
}
#endif

NLOHMANN_JSON_NAMESPACE_END
Expand Down
27 changes: 27 additions & 0 deletions tests/src/unit-json_pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ using nlohmann::json;
using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
#endif

#include <map>
#include <sstream>

TEST_CASE("JSON pointers")
Expand Down Expand Up @@ -697,6 +698,32 @@ TEST_CASE("JSON pointers")
}
}

SECTION("less-than comparison")
{
auto ptr1 = json::json_pointer("/foo/a");
auto ptr2 = json::json_pointer("/foo/b");

CHECK(ptr1 < ptr2);
CHECK_FALSE(ptr2 < ptr1);

// build with C++20
// JSON_HAS_CPP_20
#if JSON_HAS_THREE_WAY_COMPARISON
CHECK((ptr1 <=> ptr2) == std::strong_ordering::less); // *NOPAD*
CHECK(ptr2 > ptr1);
#endif
}

SECTION("usable as map key")
{
auto ptr = json::json_pointer("/foo");
std::map<json::json_pointer, int> m;

m[ptr] = 42;

CHECK(m.find(ptr) != m.end());
}

SECTION("backwards compatibility and mixing")
{
json j = R"(
Expand Down

0 comments on commit 31265dc

Please sign in to comment.