diff --git a/README.md b/README.md index 98ac1a52..9b1c6f07 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Other aspects were not so important to us: As of February 2015, the following updates were made to the library - *Changed:* In the generic class `basic_json`, all JSON value types (array, object, string, bool, integer number, and floating-point) are now **templated**. That is, you can choose whether you like a `std::list` for your arrays or an `std::unordered_map` for your objects. The specialization `json` sets some reasonable defaults. -- *Changed:* The library now consists of a single header, called `json.hpp`. Consequently, build systems such as Automake or CMake are not any longer required. +- *Changed:* The library now consists of a **single header**, called `json.hpp`. Consequently, build systems such as Automake or CMake are not any longer required. - *Changed:* The **deserialization** is now supported by a lexer generated with [re2c](http://re2c.org) from file [`src/json.hpp.re2c`](https://github.com/nlohmann/json/blob/master/src/json.hpp.re2c). As a result, we follow the JSON specification more strictly. Note neither the tool re2c nor its input are required to use the class. - *Added:* The library now satisfies the [**ReversibleContainer**](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) requirement. It hence provides four different iterators (`iterator`, `const_iterator`, `reverse_iterator`, and `const_reverse_iterator`), comparison functions, `swap()`, `size()`, `max_size()`, and `empty()` member functions. - *Added*: The class uses **user-defined allocators** which default to `std::allocator`, but can be templated via parameter `Allocator`. @@ -184,7 +184,7 @@ These operators work for any subclasses of `std::istream` or `std::ostream`. ### STL-like access -We designed the JSON class to behave just like an STL container: +We designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) requirement. ```cpp // create an array using push_back diff --git a/src/json.hpp b/src/json.hpp index c1ab8760..14517db8 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -712,12 +712,26 @@ class basic_json /// access specified element inline reference operator[](size_type pos) { - // at only works for arrays + // implicitly convert null to object + if (m_type == value_t::null) + { + m_type = value_t::array; + Allocator alloc; + m_value.array = alloc.allocate(1); + alloc.construct(m_value.array); + } + + // [] only works for arrays if (m_type != value_t::array) { throw std::runtime_error("cannot use [] with " + type_name()); } + for (size_t i = m_value.array->size(); i <= pos; ++i) + { + m_value.array->push_back(basic_json()); + } + return m_value.array->operator[](pos); } @@ -769,7 +783,7 @@ class basic_json alloc.construct(m_value.object); } - // at only works for objects + // [] only works for objects if (m_type != value_t::object) { throw std::runtime_error("cannot use [] with " + type_name()); diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 9d63ae25..cff9b0dc 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -712,12 +712,26 @@ class basic_json /// access specified element inline reference operator[](size_type pos) { - // at only works for arrays + // implicitly convert null to object + if (m_type == value_t::null) + { + m_type = value_t::array; + Allocator alloc; + m_value.array = alloc.allocate(1); + alloc.construct(m_value.array); + } + + // [] only works for arrays if (m_type != value_t::array) { throw std::runtime_error("cannot use [] with " + type_name()); } + for (size_t i = m_value.array->size(); i <= pos; ++i) + { + m_value.array->push_back(basic_json()); + } + return m_value.array->operator[](pos); } @@ -769,7 +783,7 @@ class basic_json alloc.construct(m_value.object); } - // at only works for objects + // [] only works for objects if (m_type != value_t::object) { throw std::runtime_error("cannot use [] with " + type_name()); diff --git a/test/unit.cpp b/test/unit.cpp index 25b4d979..19d0f7d5 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -2033,10 +2033,20 @@ TEST_CASE("element access") { SECTION("null") { - json j_nonarray(json::value_t::null); - const json j_nonarray_const(j_nonarray); - CHECK_THROWS_AS(j_nonarray[0], std::runtime_error); - CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error); + SECTION("standard tests") + { + json j_nonarray(json::value_t::null); + const json j_nonarray_const(j_nonarray); + CHECK_NOTHROW(j_nonarray[0]); + CHECK_THROWS_AS(j_nonarray_const[0], std::runtime_error); + } + + SECTION("implicit transformation to properly filled array") + { + json j_nonarray; + j_nonarray[3] = 42; + CHECK(j_nonarray == json({nullptr, nullptr, nullptr, 42})); + } } SECTION("boolean")