constructor for an integer range
This commit is contained in:
parent
b801adca76
commit
ade49f8b2a
3 changed files with 432 additions and 1 deletions
89
src/json.hpp
89
src/json.hpp
|
@ -587,6 +587,95 @@ class basic_json
|
||||||
alloc.construct(m_value.array, count, other);
|
alloc.construct(m_value.array, count, other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// construct a JSON container given an iterator range
|
||||||
|
template <class T, typename
|
||||||
|
std::enable_if<
|
||||||
|
std::is_same<T, basic_json::iterator>::value or
|
||||||
|
std::is_same<T, basic_json::const_iterator>::value
|
||||||
|
, int>::type
|
||||||
|
= 0>
|
||||||
|
inline basic_json(T first, T last)
|
||||||
|
{
|
||||||
|
// make sure iterator fits the current value
|
||||||
|
if (first.m_object != last.m_object or
|
||||||
|
first.m_object->m_type != last.m_object->m_type)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("iterators are not compatible");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_type = first.m_object->m_type;
|
||||||
|
|
||||||
|
switch (m_type)
|
||||||
|
{
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::string:
|
||||||
|
{
|
||||||
|
if (first.m_it.generic_iterator != 0 or last.m_it.generic_iterator != 1)
|
||||||
|
{
|
||||||
|
throw std::out_of_range("iterators out of range");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_type)
|
||||||
|
{
|
||||||
|
case value_t::number_integer:
|
||||||
|
{
|
||||||
|
m_value.number_integer = first.m_object->m_value.number_integer;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::number_float:
|
||||||
|
{
|
||||||
|
m_value.number_float = first.m_object->m_value.number_float;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::boolean:
|
||||||
|
{
|
||||||
|
m_value.boolean = first.m_object->m_value.boolean;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::string:
|
||||||
|
{
|
||||||
|
AllocatorType<string_t> alloc;
|
||||||
|
m_value.string = alloc.allocate(1);
|
||||||
|
alloc.construct(m_value.string, *first.m_object->m_value.string);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
AllocatorType<object_t> alloc;
|
||||||
|
m_value.object = alloc.allocate(1);
|
||||||
|
alloc.construct(m_value.object, first.m_it.object_iterator, last.m_it.object_iterator);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
AllocatorType<array_t> alloc;
|
||||||
|
m_value.array = alloc.allocate(1);
|
||||||
|
alloc.construct(m_value.array, first.m_it.array_iterator, last.m_it.array_iterator);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw std::runtime_error("cannot use construct with iterators from " + first.m_object->type_name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
// other constructors and destructor //
|
// other constructors and destructor //
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
|
|
|
@ -587,6 +587,97 @@ class basic_json
|
||||||
alloc.construct(m_value.array, count, other);
|
alloc.construct(m_value.array, count, other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// construct a JSON container given an iterator range
|
||||||
|
template <class T, typename
|
||||||
|
std::enable_if<
|
||||||
|
std::is_same<T, basic_json::iterator>::value or
|
||||||
|
std::is_same<T, basic_json::const_iterator>::value
|
||||||
|
, int>::type
|
||||||
|
= 0>
|
||||||
|
inline basic_json(T first, T last)
|
||||||
|
{
|
||||||
|
// make sure iterator fits the current value
|
||||||
|
if (first.m_object != last.m_object or
|
||||||
|
first.m_object->m_type != last.m_object->m_type)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("iterators are not compatible");
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the type
|
||||||
|
m_type = first.m_object->m_type;
|
||||||
|
|
||||||
|
// check if iterator range is complete for non-compound values
|
||||||
|
switch (m_type)
|
||||||
|
{
|
||||||
|
case value_t::number_integer:
|
||||||
|
case value_t::number_float:
|
||||||
|
case value_t::boolean:
|
||||||
|
case value_t::string:
|
||||||
|
{
|
||||||
|
if (first.m_it.generic_iterator != 0 or last.m_it.generic_iterator != 1)
|
||||||
|
{
|
||||||
|
throw std::out_of_range("iterators out of range");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_type)
|
||||||
|
{
|
||||||
|
case value_t::number_integer:
|
||||||
|
{
|
||||||
|
m_value.number_integer = first.m_object->m_value.number_integer;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::number_float:
|
||||||
|
{
|
||||||
|
m_value.number_float = first.m_object->m_value.number_float;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::boolean:
|
||||||
|
{
|
||||||
|
m_value.boolean = first.m_object->m_value.boolean;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::string:
|
||||||
|
{
|
||||||
|
AllocatorType<string_t> alloc;
|
||||||
|
m_value.string = alloc.allocate(1);
|
||||||
|
alloc.construct(m_value.string, *first.m_object->m_value.string);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::object:
|
||||||
|
{
|
||||||
|
AllocatorType<object_t> alloc;
|
||||||
|
m_value.object = alloc.allocate(1);
|
||||||
|
alloc.construct(m_value.object, first.m_it.object_iterator, last.m_it.object_iterator);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case value_t::array:
|
||||||
|
{
|
||||||
|
AllocatorType<array_t> alloc;
|
||||||
|
m_value.array = alloc.allocate(1);
|
||||||
|
alloc.construct(m_value.array, first.m_it.array_iterator, last.m_it.array_iterator);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw std::runtime_error("cannot use construct with iterators from " + first.m_object->type_name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
// other constructors and destructor //
|
// other constructors and destructor //
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
|
|
253
test/unit.cpp
253
test/unit.cpp
|
@ -913,6 +913,257 @@ TEST_CASE("constructors")
|
||||||
CHECK(x == v);
|
CHECK(x == v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("create a JSON container from an iterator range")
|
||||||
|
{
|
||||||
|
SECTION("object")
|
||||||
|
{
|
||||||
|
SECTION("json(begin(), end())")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}};
|
||||||
|
json j_new(jobject.begin(), jobject.end());
|
||||||
|
CHECK(j_new == jobject);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}};
|
||||||
|
json j_new(jobject.cbegin(), jobject.cend());
|
||||||
|
CHECK(j_new == jobject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("json(begin(), begin())")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}};
|
||||||
|
json j_new(jobject.begin(), jobject.begin());
|
||||||
|
CHECK(j_new == json::object());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}};
|
||||||
|
json j_new(jobject.cbegin(), jobject.cbegin());
|
||||||
|
CHECK(j_new == json::object());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("construct from subrange")
|
||||||
|
{
|
||||||
|
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}};
|
||||||
|
json j_new(jobject.find("b"), jobject.find("e"));
|
||||||
|
CHECK(j_new == json({{"b", 1}, {"c", 17}, {"d", false}}));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("incompatible iterators")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}};
|
||||||
|
json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17}};
|
||||||
|
CHECK_THROWS_AS(json(jobject.begin(), jobject2.end()), std::runtime_error);
|
||||||
|
CHECK_THROWS_AS(json(jobject2.begin(), jobject.end()), std::runtime_error);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}};
|
||||||
|
json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17}};
|
||||||
|
CHECK_THROWS_AS(json(jobject.cbegin(), jobject2.cend()), std::runtime_error);
|
||||||
|
CHECK_THROWS_AS(json(jobject2.cbegin(), jobject.cend()), std::runtime_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("array")
|
||||||
|
{
|
||||||
|
SECTION("json(begin(), end())")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json jarray = {1, 2, 3, 4, 5};
|
||||||
|
json j_new(jarray.begin(), jarray.end());
|
||||||
|
CHECK(j_new == jarray);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json jarray = {1, 2, 3, 4, 5};
|
||||||
|
json j_new(jarray.cbegin(), jarray.cend());
|
||||||
|
CHECK(j_new == jarray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("json(begin(), begin())")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json jarray = {1, 2, 3, 4, 5};
|
||||||
|
json j_new(jarray.begin(), jarray.begin());
|
||||||
|
CHECK(j_new == json::array());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json jarray = {1, 2, 3, 4, 5};
|
||||||
|
json j_new(jarray.cbegin(), jarray.cbegin());
|
||||||
|
CHECK(j_new == json::array());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("construct from subrange")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json jarray = {1, 2, 3, 4, 5};
|
||||||
|
json j_new(jarray.begin() + 1, jarray.begin() + 3);
|
||||||
|
CHECK(j_new == json({2, 3}));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json jarray = {1, 2, 3, 4, 5};
|
||||||
|
json j_new(jarray.cbegin() + 1, jarray.cbegin() + 3);
|
||||||
|
CHECK(j_new == json({2, 3}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("incompatible iterators")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json jarray = {1, 2, 3, 4};
|
||||||
|
json jarray2 = {2, 3, 4, 5};
|
||||||
|
CHECK_THROWS_AS(json(jarray.begin(), jarray2.end()), std::runtime_error);
|
||||||
|
CHECK_THROWS_AS(json(jarray2.begin(), jarray.end()), std::runtime_error);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json jarray = {1, 2, 3, 4};
|
||||||
|
json jarray2 = {2, 3, 4, 5};
|
||||||
|
CHECK_THROWS_AS(json(jarray.cbegin(), jarray2.cend()), std::runtime_error);
|
||||||
|
CHECK_THROWS_AS(json(jarray2.cbegin(), jarray.cend()), std::runtime_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("other values")
|
||||||
|
{
|
||||||
|
SECTION("construct with two valid iterators")
|
||||||
|
{
|
||||||
|
SECTION("null")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json j;
|
||||||
|
CHECK_THROWS_AS(json(j.begin(), j.end()), std::runtime_error);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json j;
|
||||||
|
CHECK_THROWS_AS(json(j.cbegin(), j.cend()), std::runtime_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("string")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json j = "foo";
|
||||||
|
json j_new(j.begin(), j.end());
|
||||||
|
CHECK(j == j_new);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json j = "bar";
|
||||||
|
json j_new(j.cbegin(), j.cend());
|
||||||
|
CHECK(j == j_new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("number (boolean)")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json j = false;
|
||||||
|
json j_new(j.begin(), j.end());
|
||||||
|
CHECK(j == j_new);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json j = true;
|
||||||
|
json j_new(j.cbegin(), j.cend());
|
||||||
|
CHECK(j == j_new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("number (integer)")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json j = 17;
|
||||||
|
json j_new(j.begin(), j.end());
|
||||||
|
CHECK(j == j_new);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json j = 17;
|
||||||
|
json j_new(j.cbegin(), j.cend());
|
||||||
|
CHECK(j == j_new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("number (floating point)")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json j = 23.42;
|
||||||
|
json j_new(j.begin(), j.end());
|
||||||
|
CHECK(j == j_new);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json j = 23.42;
|
||||||
|
json j_new(j.cbegin(), j.cend());
|
||||||
|
CHECK(j == j_new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("construct with two invalid iterators")
|
||||||
|
{
|
||||||
|
SECTION("string")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json j = "foo";
|
||||||
|
CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range);
|
||||||
|
CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json j = "bar";
|
||||||
|
CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range);
|
||||||
|
CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("number (boolean)")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json j = false;
|
||||||
|
CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range);
|
||||||
|
CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json j = true;
|
||||||
|
CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range);
|
||||||
|
CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("number (integer)")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json j = 17;
|
||||||
|
CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range);
|
||||||
|
CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json j = 17;
|
||||||
|
CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range);
|
||||||
|
CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("number (floating point)")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
json j = 23.42;
|
||||||
|
CHECK_THROWS_AS(json(j.end(), j.end()), std::out_of_range);
|
||||||
|
CHECK_THROWS_AS(json(j.begin(), j.begin()), std::out_of_range);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
json j = 23.42;
|
||||||
|
CHECK_THROWS_AS(json(j.cend(), j.cend()), std::out_of_range);
|
||||||
|
CHECK_THROWS_AS(json(j.cbegin(), j.cbegin()), std::out_of_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("other constructors and destructor")
|
TEST_CASE("other constructors and destructor")
|
||||||
|
@ -2807,7 +3058,7 @@ TEST_CASE("element access")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("different arrays")
|
SECTION("different objects")
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}};
|
json jobject = {{"a", "a"}, {"b", 1}, {"c", 17}, {"d", false}, {"e", true}};
|
||||||
|
|
Loading…
Reference in a new issue