mirror of
https://github.com/XRPLF/rippled.git
synced 2026-07-28 01:20:32 +00:00
fix(json): add missing iterator traits to Value iterators
json::ValueConstIterator and ValueIterator declared difference_type, reference and pointer but not value_type or iterator_category. Under C++23, std::iterator_traits then classifies them as output iterators, so std::all_of over a Value's members (isValidJson2 in RPCCall.cpp) fails to instantiate on GCC 13/14 with: cannot convert 'output_iterator_tag' to 'std::input_iterator_tag' GCC 15 masks this via LWG-3798/P2609, but the perf CI image ships GCC 13, so the source needs the traits regardless. The iterators wrap a std::map iterator (++/-- only), so the category is bidirectional. Add value_type + iterator_category to both iterators, include <iterator>, and add a regression test asserting the traits and that std::all_of / std::count_if compile and run over Value members. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <xrpl/json/json_forwards.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -623,6 +624,12 @@ class ValueConstIterator : public ValueIteratorBase
|
||||
public:
|
||||
using size_t = unsigned int;
|
||||
using difference_type = int;
|
||||
// std::iterator_traits needs value_type and iterator_category to classify
|
||||
// this as a Cpp17InputIterator; without them it defaults to output-only,
|
||||
// which breaks standard algorithms (e.g. std::all_of). The iterator walks a
|
||||
// map both ways via ++/--, so it is bidirectional.
|
||||
using value_type = Value;
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using reference = Value const&;
|
||||
using pointer = Value const*;
|
||||
using SelfType = ValueConstIterator;
|
||||
@@ -687,6 +694,10 @@ class ValueIterator : public ValueIteratorBase
|
||||
public:
|
||||
using size_t = unsigned int;
|
||||
using difference_type = int;
|
||||
// See ValueConstIterator: value_type and iterator_category are required for
|
||||
// std::iterator_traits to treat this as a bidirectional iterator.
|
||||
using value_type = Value;
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using reference = Value&;
|
||||
using pointer = Value*;
|
||||
using SelfType = ValueIterator;
|
||||
|
||||
@@ -11,12 +11,14 @@
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <numbers>
|
||||
#include <optional>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
@@ -1331,6 +1333,44 @@ TEST(json_value, iterator)
|
||||
}
|
||||
}
|
||||
|
||||
TEST(json_value, iterator_traits)
|
||||
{
|
||||
// The iterators must expose value_type and iterator_category so that
|
||||
// std::iterator_traits classifies them as (at least) input iterators.
|
||||
// Without these, iterator_traits deduces output_iterator_tag and standard
|
||||
// algorithms such as std::all_of fail to instantiate.
|
||||
using CIt = json::ValueConstIterator;
|
||||
using It = json::ValueIterator;
|
||||
|
||||
static_assert(std::is_same_v<std::iterator_traits<CIt>::value_type, json::Value>);
|
||||
static_assert(std::is_same_v<std::iterator_traits<It>::value_type, json::Value>);
|
||||
static_assert(std::is_same_v<
|
||||
std::iterator_traits<CIt>::iterator_category,
|
||||
std::bidirectional_iterator_tag>);
|
||||
static_assert(std::is_same_v<
|
||||
std::iterator_traits<It>::iterator_category,
|
||||
std::bidirectional_iterator_tag>);
|
||||
|
||||
// A standard algorithm over the iterators must compile and run. This is the
|
||||
// exact usage (std::all_of over a Value's members) that regressed the build.
|
||||
json::Value obj{json::ValueType::Object};
|
||||
obj["a"] = 2;
|
||||
obj["b"] = 4;
|
||||
obj["c"] = 6;
|
||||
|
||||
json::Value const& cobj = obj;
|
||||
EXPECT_TRUE(std::all_of(cobj.begin(), cobj.end(), [](json::Value const& v) {
|
||||
return v.asInt() % 2 == 0;
|
||||
}));
|
||||
EXPECT_FALSE(
|
||||
std::all_of(cobj.begin(), cobj.end(), [](json::Value const& v) { return v.asInt() > 3; }));
|
||||
|
||||
// count_if exercises the input-iterator contract and returns an exact count.
|
||||
EXPECT_EQ(
|
||||
std::count_if(cobj.begin(), cobj.end(), [](json::Value const& v) { return v.asInt() > 3; }),
|
||||
2);
|
||||
}
|
||||
|
||||
TEST(json_value, nest_limits)
|
||||
{
|
||||
json::Reader r;
|
||||
|
||||
Reference in New Issue
Block a user