This commit is contained in:
Luca Passarella 2023-10-23 11:20:29 -04:00 committed by GitHub
commit 20261d52f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 174 additions and 14 deletions

View File

@ -132,6 +132,7 @@ class input_stream_adapter
};
#endif // JSON_NO_IO
// General-purpose iterator-based adapter. It might not be as fast as
// theoretically possible for some containers, but it is extremely versatile.
template<typename IteratorType>
@ -141,30 +142,46 @@ class iterator_input_adapter
using char_type = typename std::iterator_traits<IteratorType>::value_type;
iterator_input_adapter(IteratorType first, IteratorType last)
: current(std::move(first)), end(std::move(last))
: current(std::move(first)), end(std::move(last)), current_has_been_consumed(false)
{}
typename std::char_traits<char_type>::int_type get_character()
{
if (JSON_HEDLEY_LIKELY(current != end))
if (JSON_HEDLEY_LIKELY(current_has_been_consumed))
{
auto result = std::char_traits<char_type>::to_int_type(*current);
std::advance(current, 1);
return result;
}
return std::char_traits<char_type>::eof();
if (JSON_HEDLEY_LIKELY(current != end))
{
current_has_been_consumed = true;
return std::char_traits<char_type>::to_int_type(*current);
}
else
{
current_has_been_consumed = false;
return std::char_traits<char_type>::eof();
}
}
private:
IteratorType current;
IteratorType end;
mutable IteratorType current;
const IteratorType end;
mutable bool current_has_been_consumed;
template<typename BaseInputAdapter, size_t T>
friend struct wide_string_input_helper;
bool empty() const
{
if (JSON_HEDLEY_LIKELY(current_has_been_consumed))
{
std::advance(current, 1);
current_has_been_consumed = false;
}
return current == end;
}
};

View File

@ -6208,6 +6208,7 @@ class input_stream_adapter
};
#endif // JSON_NO_IO
// General-purpose iterator-based adapter. It might not be as fast as
// theoretically possible for some containers, but it is extremely versatile.
template<typename IteratorType>
@ -6217,30 +6218,46 @@ class iterator_input_adapter
using char_type = typename std::iterator_traits<IteratorType>::value_type;
iterator_input_adapter(IteratorType first, IteratorType last)
: current(std::move(first)), end(std::move(last))
: current(std::move(first)), end(std::move(last)), current_has_been_consumed(false)
{}
typename std::char_traits<char_type>::int_type get_character()
{
if (JSON_HEDLEY_LIKELY(current != end))
if (JSON_HEDLEY_LIKELY(current_has_been_consumed))
{
auto result = std::char_traits<char_type>::to_int_type(*current);
std::advance(current, 1);
return result;
}
return std::char_traits<char_type>::eof();
if (JSON_HEDLEY_LIKELY(current != end))
{
current_has_been_consumed = true;
return std::char_traits<char_type>::to_int_type(*current);
}
else
{
current_has_been_consumed = false;
return std::char_traits<char_type>::eof();
}
}
private:
IteratorType current;
IteratorType end;
mutable IteratorType current;
const IteratorType end;
mutable bool current_has_been_consumed;
template<typename BaseInputAdapter, size_t T>
friend struct wide_string_input_helper;
bool empty() const
{
if (JSON_HEDLEY_LIKELY(current_has_been_consumed))
{
std::advance(current, 1);
current_has_been_consumed = false;
}
return current == end;
}
};

View File

@ -0,0 +1,126 @@
#include "doctest_compatibility.h"
#define JSON_TESTS_PRIVATE
#include <nlohmann/json.hpp>
using nlohmann::json;
//This struct emulate an Input Stream, once a "char" is readed from it it is lost
struct EmulateStream
{
using difference_type = std::ptrdiff_t;
using value_type = char;
using pointer = const char*;
using reference = const char&;
using iterator_category = std::input_iterator_tag;
// Like a pop_left() -> consume one char from the underlying buffer
static char ConsumeChar(std::string* str)
{
const char c = str->front();
str->erase(0, 1);
return c;
}
EmulateStream()
:
target{nullptr}
{}
EmulateStream(std::string* target_)
:
target{target_},
c{ConsumeChar(target_)}
{}
EmulateStream& operator++()
{
c = ConsumeChar(target);
return *this;
}
bool operator!=(const EmulateStream& rhs) const
{
return rhs.target != target;
}
reference operator*() const
{
return c;
}
std::string* target;
char c;
};
EmulateStream CreateBegin(std::string& tgt)
{
return EmulateStream{&tgt};
}
EmulateStream CreateEnd(const std::string& tgt)
{
return {};
}
TEST_CASE("consume only needed")
{
nlohmann::detail::json_sax_acceptor<json> sax_parser;
const std::string json_A = R"({ "key_A" : "value_A" })";
const std::string json_B = R"({ "key_B" : "value_B" })";
std::string json_concat_AB = json_A + json_B;
CHECK(
json::sax_parse(
CreateBegin(json_concat_AB),
CreateEnd(json_concat_AB),
&sax_parser,
nlohmann::detail::input_format_t::json,
false
)
== true
);
CHECK(json_concat_AB == json_B);
CHECK(
json::sax_parse(
CreateBegin(json_concat_AB),
CreateEnd(json_concat_AB),
&sax_parser,
nlohmann::detail::input_format_t::json,
false
)
== true
);
CHECK(json_concat_AB == "");
CHECK(json_concat_AB.size() == 0);
CHECK(
json::sax_parse(
CreateBegin(json_concat_AB),
CreateEnd(json_concat_AB),
&sax_parser,
nlohmann::detail::input_format_t::json,
false
)
== false
);
}