json/include/nlohmann/detail/json_pointer.hpp

990 lines
33 KiB
C++
Raw Normal View History

#pragma once
2019-01-13 22:31:22 +08:00
#include <algorithm> // all_of
#include <cctype> // isdigit
#include <limits> // max
#include <numeric> // accumulate
#include <string> // string
2019-03-15 21:55:13 +08:00
#include <utility> // move
#include <vector> // vector
#include <nlohmann/detail/exceptions.hpp>
2019-03-17 19:01:49 +08:00
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/string_escape.hpp>
#include <nlohmann/detail/value_t.hpp>
namespace nlohmann
{
template<typename BasicJsonType>
class json_pointer
{
// allow basic_json to access private members
NLOHMANN_BASIC_JSON_TPL_DECLARATION
friend class basic_json;
public:
/*!
@brief create JSON pointer
Create a JSON pointer according to the syntax described in
[Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).
@param[in] s string representing the JSON pointer; if omitted, the empty
string is assumed which references the whole JSON value
@throw parse_error.107 if the given JSON pointer @a s is nonempty and does
not begin with a slash (`/`); see example below
@throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is
not followed by `0` (representing `~`) or `1` (representing `/`); see
example below
@liveexample{The example shows the construction several valid JSON pointers
as well as the exceptional behavior.,json_pointer}
@since version 2.0.0
*/
explicit json_pointer(const std::string& s = "")
: reference_tokens(split(s))
{}
/*!
@brief return a string representation of the JSON pointer
@invariant For each JSON pointer `ptr`, it holds:
@code {.cpp}
ptr == json_pointer(ptr.to_string());
@endcode
@return a string representation of the JSON pointer
2019-03-19 17:06:35 +08:00
@liveexample{The example shows the result of `to_string`.,json_pointer__to_string}
@since version 2.0.0
*/
std::string to_string() const
{
return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
std::string{},
[](const std::string & a, const std::string & b)
{
return a + "/" + detail::escape(b);
});
}
/// @copydoc to_string()
operator std::string() const
{
return to_string();
}
/*!
@brief append another JSON pointer at the end of this JSON pointer
2019-03-19 17:06:35 +08:00
@param[in] ptr JSON pointer to append
@return JSON pointer with @a ptr appended
@liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}
@complexity Linear in the length of @a ptr.
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
@sa see @ref operator/=(std::string) to append a reference token
@sa see @ref operator/=(std::size_t) to append an array index
@sa see @ref operator/(const json_pointer&, const json_pointer&) for a binary operator
2019-03-19 17:06:35 +08:00
@since version 3.6.0
*/
json_pointer& operator/=(const json_pointer& ptr)
{
2019-03-18 05:25:18 +08:00
reference_tokens.insert(reference_tokens.end(),
ptr.reference_tokens.begin(),
ptr.reference_tokens.end());
return *this;
}
2019-03-19 17:06:35 +08:00
/*!
@brief append an unescaped reference token at the end of this JSON pointer
@param[in] token reference token to append
@return JSON pointer with @a token appended without escaping @a token
@liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}
@complexity Amortized constant.
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
@sa see @ref operator/=(const json_pointer&) to append a JSON pointer
@sa see @ref operator/=(std::size_t) to append an array index
@sa see @ref operator/(const json_pointer&, std::size_t) for a binary operator
2019-03-19 17:06:35 +08:00
@since version 3.6.0
*/
json_pointer& operator/=(std::string token)
{
push_back(std::move(token));
return *this;
}
2019-03-19 17:06:35 +08:00
/*!
@brief append an array index at the end of this JSON pointer
@param[in] array_idx array index to append
@return JSON pointer with @a array_idx appended
2019-03-19 17:06:35 +08:00
@liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}
@complexity Amortized constant.
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
@sa see @ref operator/=(const json_pointer&) to append a JSON pointer
@sa see @ref operator/=(std::string) to append a reference token
@sa see @ref operator/(const json_pointer&, std::string) for a binary operator
2019-03-19 17:06:35 +08:00
@since version 3.6.0
*/
json_pointer& operator/=(std::size_t array_idx)
{
return *this /= std::to_string(array_idx);
}
/*!
@brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
2019-03-19 17:06:35 +08:00
@param[in] lhs JSON pointer
@param[in] rhs JSON pointer
@return a new JSON pointer with @a rhs appended to @a lhs
@liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}
@complexity Linear in the length of @a lhs and @a rhs.
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
@sa see @ref operator/=(const json_pointer&) to append a JSON pointer
2019-03-19 17:06:35 +08:00
@since version 3.6.0
*/
2019-03-19 17:06:35 +08:00
friend json_pointer operator/(const json_pointer& lhs,
const json_pointer& rhs)
{
2019-03-19 17:06:35 +08:00
return json_pointer(lhs) /= rhs;
}
/*!
@brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
2019-03-19 17:06:35 +08:00
@param[in] ptr JSON pointer
@param[in] token reference token
@return a new JSON pointer with unescaped @a token appended to @a ptr
@liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}
@complexity Linear in the length of @a ptr.
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
@sa see @ref operator/=(std::string) to append a reference token
2019-03-19 17:06:35 +08:00
@since version 3.6.0
*/
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
friend json_pointer operator/(const json_pointer& ptr, std::string token) // NOLINT(performance-unnecessary-value-param)
{
return json_pointer(ptr) /= std::move(token);
}
/*!
@brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
2019-03-19 17:06:35 +08:00
@param[in] ptr JSON pointer
@param[in] array_idx array index
@return a new JSON pointer with @a array_idx appended to @a ptr
2019-03-19 17:06:35 +08:00
@liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}
@complexity Linear in the length of @a ptr.
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
@sa see @ref operator/=(std::size_t) to append an array index
2019-03-19 17:06:35 +08:00
@since version 3.6.0
*/
friend json_pointer operator/(const json_pointer& ptr, std::size_t array_idx)
{
return json_pointer(ptr) /= array_idx;
}
/*!
2019-03-18 05:25:18 +08:00
@brief returns the parent of this JSON pointer
@return parent of this JSON pointer; in case this JSON pointer is the root,
the root itself is returned
2019-03-19 22:40:23 +08:00
@complexity Linear in the length of the JSON pointer.
2019-03-18 05:25:18 +08:00
@liveexample{The example shows the result of `parent_pointer` for different
JSON Pointers.,json_pointer__parent_pointer}
@since version 3.6.0
*/
json_pointer parent_pointer() const
{
if (empty())
{
return *this;
}
json_pointer res = *this;
res.pop_back();
return res;
}
/*!
2019-03-19 22:40:23 +08:00
@brief remove last reference token
@pre not `empty()`
@liveexample{The example shows the usage of `pop_back`.,json_pointer__pop_back}
@complexity Constant.
@throw out_of_range.405 if JSON pointer has no parent
2019-03-19 22:40:23 +08:00
@since version 3.6.0
*/
2019-03-19 22:40:23 +08:00
void pop_back()
{
2019-07-02 04:37:30 +08:00
if (JSON_HEDLEY_UNLIKELY(empty()))
{
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType()));
}
reference_tokens.pop_back();
2019-03-19 22:40:23 +08:00
}
/*!
@brief return last reference token
@pre not `empty()`
@return last reference token
@liveexample{The example shows the usage of `back`.,json_pointer__back}
@complexity Constant.
@throw out_of_range.405 if JSON pointer has no parent
@since version 3.6.0
*/
const std::string& back() const
2019-03-19 22:40:23 +08:00
{
2019-07-02 04:37:30 +08:00
if (JSON_HEDLEY_UNLIKELY(empty()))
2019-03-19 22:40:23 +08:00
{
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType()));
2019-03-19 22:40:23 +08:00
}
return reference_tokens.back();
}
/*!
@brief append an unescaped token at the end of the reference pointer
2019-03-18 05:25:18 +08:00
@param[in] token token to add
@complexity Amortized constant.
@liveexample{The example shows the result of `push_back` for different
JSON Pointers.,json_pointer__push_back}
2019-03-19 22:40:23 +08:00
@since version 3.6.0
*/
void push_back(const std::string& token)
{
reference_tokens.push_back(token);
}
/// @copydoc push_back(const std::string&)
void push_back(std::string&& token)
{
reference_tokens.push_back(std::move(token));
}
2019-03-18 05:25:18 +08:00
/*!
@brief return whether pointer points to the root document
@return true iff the JSON pointer points to the root document
@complexity Constant.
@exceptionsafety No-throw guarantee: this function never throws exceptions.
@liveexample{The example shows the result of `empty` for different JSON
Pointers.,json_pointer__empty}
@since version 3.6.0
*/
bool empty() const noexcept
{
return reference_tokens.empty();
}
private:
2019-03-18 05:25:18 +08:00
/*!
@param[in] s reference token to be converted into an array index
@return integer representation of @a s
@throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index begins not with a digit
2019-03-18 05:25:18 +08:00
@throw out_of_range.404 if string @a s could not be converted to an integer
@throw out_of_range.410 if an array index exceeds size_type
2019-03-18 05:25:18 +08:00
*/
static typename BasicJsonType::size_type array_index(const std::string& s)
2019-03-18 05:25:18 +08:00
{
using size_type = typename BasicJsonType::size_type;
// error condition (cf. RFC 6901, Sect. 4)
if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))
{
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::parse_error::create(106, 0, "array index '" + s + "' must not begin with '0'", BasicJsonType()));
}
2020-04-07 10:00:21 +08:00
// error condition (cf. RFC 6901, Sect. 4)
if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
{
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number", BasicJsonType()));
}
2019-03-18 05:25:18 +08:00
std::size_t processed_chars = 0;
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
unsigned long long res = 0; // NOLINT(runtime/int)
JSON_TRY
{
res = std::stoull(s, &processed_chars);
}
2020-03-25 15:56:45 +08:00
JSON_CATCH(std::out_of_range&)
{
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'", BasicJsonType()));
}
2019-03-18 05:25:18 +08:00
// check if the string was completely read
2019-07-02 04:37:30 +08:00
if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size()))
2019-03-18 05:25:18 +08:00
{
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'", BasicJsonType()));
2019-03-18 05:25:18 +08:00
}
// only triggered on special platforms (like 32bit), see also
// https://github.com/nlohmann/json/pull/2203
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)())) // NOLINT(runtime/int)
{
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::out_of_range::create(410, "array index " + s + " exceeds size_type", BasicJsonType())); // LCOV_EXCL_LINE
}
return static_cast<size_type>(res);
2019-03-18 05:25:18 +08:00
}
JSON_PRIVATE_UNLESS_TESTED:
json_pointer top() const
{
2019-07-02 04:37:30 +08:00
if (JSON_HEDLEY_UNLIKELY(empty()))
{
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType()));
}
json_pointer result = *this;
result.reference_tokens = {reference_tokens[0]};
return result;
}
private:
/*!
@brief create and return a reference to the pointed to value
@complexity Linear in the number of reference tokens.
@throw parse_error.109 if array index is not a number
@throw type_error.313 if value cannot be unflattened
*/
BasicJsonType& get_and_create(BasicJsonType& j) const
{
:rotating_light: add new CI and fix warnings (#2561) * :alembic: move CI targets to CMake * :recycle: add target for cpplint * :recycle: add target for self-contained binaries * :recycle: add targets for iwyu and infer * :loud_sound: add version output * :recycle: add target for oclint * :rotating_light: fix warnings * :recycle: rename targets * :recycle: use iwyu properly * :rotating_light: fix warnings * :recycle: use iwyu properly * :recycle: add target for benchmarks * :recycle: add target for CMake flags * :construction_worker: use GitHub Actions * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: try to install Clang 11 * :alembic: try to install GCC 11 * :alembic: add clang analyze target * :fire: remove Google Benchmark * :arrow_up: Google Benchmark 1.5.2 * :fire: use fetchcontent * :penguin: add target to download a Linux version of CMake * :hammer: fix dependency * :rotating_light: fix includes * :rotating_light: fix comment * :wrench: adjust flags for GCC 11.0.0 20210110 (experimental) * :whale: user Docker image to run CI * :wrench: add target for Valgrind * :construction_worker: add target for Valgrind tests * :alembic: add Dart * :rewind: remove Dart * :alembic: do not call ctest in test subdirectory * :alembic: download test data explicitly * :alembic: only execute Valgrind tests * :alembic: fix labels * :fire: remove unneeded jobs * :hammer: cleanup * :bug: fix OCLint call * :white_check_mark: add targets for offline and git-independent tests * :white_check_mark: add targets for C++ language versions and reproducible tests * :hammer: clean up * :construction_worker: add CI steps for cppcheck and cpplint * :rotating_light: fix warnings from Clang-Tidy * :construction_worker: add CI steps for Clang-Tidy * :rotating_light: fix warnings * :wrench: select proper binary * :rotating_light: fix warnings * :rotating_light: suppress some unhelpful warnings * :rotating_light: fix warnings * :art: fix format * :rotating_light: fix warnings * :construction_worker: add CI steps for Sanitizers * :rotating_light: fix warnings * :zap: add optimization to sanitizer build * :rotating_light: fix warnings * :rotating_light: add missing header * :rotating_light: fix warnings * :construction_worker: add CI step for coverage * :construction_worker: add CI steps for disabled exceptions and implicit conversions * :rotating_light: fix warnings * :construction_worker: add CI steps for checking indentation * :bug: fix variable use * :green_heart: fix build * :heavy_minus_sign: remove CircleCI * :construction_worker: add CI step for diagnostics * :rotating_light: fix warning * :fire: clean Travis
2021-03-24 14:15:18 +08:00
auto* result = &j;
// in case no reference tokens exist, return a reference to the JSON value
// j which will be overwritten by a primitive value
for (const auto& reference_token : reference_tokens)
{
switch (result->type())
{
case detail::value_t::null:
{
if (reference_token == "0")
{
// start a new array if reference token is 0
result = &result->operator[](0);
}
else
{
// start a new object otherwise
result = &result->operator[](reference_token);
}
break;
}
case detail::value_t::object:
{
// create an entry in the object
result = &result->operator[](reference_token);
break;
}
case detail::value_t::array:
{
// create an entry in the array
result = &result->operator[](array_index(reference_token));
break;
}
/*
The following code is only reached if there exists a reference
token _and_ the current value is primitive. In this case, we have
an error situation, because primitive values may only occur as
single value; that is, with an empty list of reference tokens.
*/
case detail::value_t::string:
case detail::value_t::boolean:
case detail::value_t::number_integer:
case detail::value_t::number_unsigned:
case detail::value_t::number_float:
case detail::value_t::binary:
case detail::value_t::discarded:
default:
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", j));
}
}
return *result;
}
/*!
@brief return a reference to the pointed to value
@note This version does not throw if a value is not present, but tries to
create nested values instead. For instance, calling this function
with pointer `"/this/that"` on a null value is equivalent to calling
`operator[]("this").operator[]("that")` on that value, effectively
changing the null value to an object.
@param[in] ptr a JSON value
@return reference to the JSON value pointed to by the JSON pointer
@complexity Linear in the length of the JSON pointer.
@throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index was not a number
@throw out_of_range.404 if the JSON pointer can not be resolved
*/
BasicJsonType& get_unchecked(BasicJsonType* ptr) const
{
for (const auto& reference_token : reference_tokens)
{
// convert null values to arrays or objects before continuing
if (ptr->is_null())
{
// check if reference token is a number
const bool nums =
std::all_of(reference_token.begin(), reference_token.end(),
[](const unsigned char x)
{
return std::isdigit(x);
});
// change value to array for numbers or "-" or to object otherwise
*ptr = (nums || reference_token == "-")
? detail::value_t::array
: detail::value_t::object;
}
switch (ptr->type())
{
case detail::value_t::object:
{
// use unchecked object access
ptr = &ptr->operator[](reference_token);
break;
}
case detail::value_t::array:
{
if (reference_token == "-")
{
// explicitly treat "-" as index beyond the end
ptr = &ptr->operator[](ptr->m_value.array->size());
}
else
{
// convert array index to number; unchecked access
ptr = &ptr->operator[](array_index(reference_token));
}
break;
}
case detail::value_t::null:
case detail::value_t::string:
case detail::value_t::boolean:
case detail::value_t::number_integer:
case detail::value_t::number_unsigned:
case detail::value_t::number_float:
case detail::value_t::binary:
case detail::value_t::discarded:
default:
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr));
}
}
return *ptr;
}
/*!
@throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index was not a number
@throw out_of_range.402 if the array index '-' is used
@throw out_of_range.404 if the JSON pointer can not be resolved
*/
BasicJsonType& get_checked(BasicJsonType* ptr) const
{
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
{
case detail::value_t::object:
{
// note: at performs range check
ptr = &ptr->at(reference_token);
break;
}
case detail::value_t::array:
{
2019-07-02 04:37:30 +08:00
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
{
// "-" always fails the range check
JSON_THROW(detail::out_of_range::create(402,
"array index '-' (" + std::to_string(ptr->m_value.array->size()) +
2021-01-25 20:47:50 +08:00
") is out of range", *ptr));
}
// note: at performs range check
ptr = &ptr->at(array_index(reference_token));
break;
}
case detail::value_t::null:
case detail::value_t::string:
case detail::value_t::boolean:
case detail::value_t::number_integer:
case detail::value_t::number_unsigned:
case detail::value_t::number_float:
case detail::value_t::binary:
case detail::value_t::discarded:
default:
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr));
}
}
return *ptr;
}
/*!
@brief return a const reference to the pointed to value
@param[in] ptr a JSON value
@return const reference to the JSON value pointed to by the JSON
pointer
@throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index was not a number
@throw out_of_range.402 if the array index '-' is used
@throw out_of_range.404 if the JSON pointer can not be resolved
*/
const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
{
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
{
case detail::value_t::object:
{
// use unchecked object access
ptr = &ptr->operator[](reference_token);
break;
}
case detail::value_t::array:
{
2019-07-02 04:37:30 +08:00
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
{
// "-" cannot be used for const access
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::out_of_range::create(402, "array index '-' (" + std::to_string(ptr->m_value.array->size()) + ") is out of range", *ptr));
}
// use unchecked array access
ptr = &ptr->operator[](array_index(reference_token));
break;
}
case detail::value_t::null:
case detail::value_t::string:
case detail::value_t::boolean:
case detail::value_t::number_integer:
case detail::value_t::number_unsigned:
case detail::value_t::number_float:
case detail::value_t::binary:
case detail::value_t::discarded:
default:
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr));
}
}
return *ptr;
}
/*!
@throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index was not a number
@throw out_of_range.402 if the array index '-' is used
@throw out_of_range.404 if the JSON pointer can not be resolved
*/
const BasicJsonType& get_checked(const BasicJsonType* ptr) const
{
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
{
case detail::value_t::object:
{
// note: at performs range check
ptr = &ptr->at(reference_token);
break;
}
case detail::value_t::array:
{
2019-07-02 04:37:30 +08:00
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
{
// "-" always fails the range check
JSON_THROW(detail::out_of_range::create(402,
"array index '-' (" + std::to_string(ptr->m_value.array->size()) +
2021-01-25 20:47:50 +08:00
") is out of range", *ptr));
}
// note: at performs range check
ptr = &ptr->at(array_index(reference_token));
break;
}
case detail::value_t::null:
case detail::value_t::string:
case detail::value_t::boolean:
case detail::value_t::number_integer:
case detail::value_t::number_unsigned:
case detail::value_t::number_float:
case detail::value_t::binary:
case detail::value_t::discarded:
default:
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr));
}
}
return *ptr;
}
/*!
@throw parse_error.106 if an array index begins with '0'
@throw parse_error.109 if an array index was not a number
*/
bool contains(const BasicJsonType* ptr) const
{
for (const auto& reference_token : reference_tokens)
{
switch (ptr->type())
{
case detail::value_t::object:
{
if (!ptr->contains(reference_token))
{
// we did not find the key in the object
return false;
}
ptr = &ptr->operator[](reference_token);
break;
}
case detail::value_t::array:
{
2019-07-15 03:19:55 +08:00
if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
{
// "-" always fails the range check
return false;
}
if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
{
// invalid char
return false;
}
if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))
{
if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))
{
// first char should be between '1' and '9'
return false;
}
for (std::size_t i = 1; i < reference_token.size(); i++)
{
if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))
{
// other char should be between '0' and '9'
return false;
}
}
}
const auto idx = array_index(reference_token);
if (idx >= ptr->size())
{
// index out of range
return false;
}
ptr = &ptr->operator[](idx);
break;
}
case detail::value_t::null:
case detail::value_t::string:
case detail::value_t::boolean:
case detail::value_t::number_integer:
case detail::value_t::number_unsigned:
case detail::value_t::number_float:
case detail::value_t::binary:
case detail::value_t::discarded:
default:
{
// we do not expect primitive values if there is still a
// reference token to process
return false;
}
}
}
// no reference token left means we found a primitive value
return true;
}
/*!
@brief split the string input to reference tokens
@note This function is only called by the json_pointer constructor.
All exceptions below are documented there.
@throw parse_error.107 if the pointer is not empty or begins with '/'
@throw parse_error.108 if character '~' is not followed by '0' or '1'
*/
static std::vector<std::string> split(const std::string& reference_string)
{
std::vector<std::string> result;
// special case: empty reference string -> no reference tokens
if (reference_string.empty())
{
return result;
}
// check if nonempty reference string begins with slash
2019-07-02 04:37:30 +08:00
if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
{
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::parse_error::create(107, 1, "JSON pointer must be empty or begin with '/' - was: '" + reference_string + "'", BasicJsonType()));
}
// extract the reference tokens:
// - slash: position of the last read slash (or end of string)
// - start: position after the previous slash
for (
// search for the first slash after the first character
std::size_t slash = reference_string.find_first_of('/', 1),
// set the beginning of the first reference token
start = 1;
// we can stop if start == 0 (if slash == std::string::npos)
start != 0;
// set the beginning of the next reference token
// (will eventually be 0 if slash == std::string::npos)
start = (slash == std::string::npos) ? 0 : slash + 1,
// find next slash
slash = reference_string.find_first_of('/', start))
{
// use the text between the beginning of the reference token
// (start) and the last slash (slash).
auto reference_token = reference_string.substr(start, slash - start);
// check reference tokens are properly escaped
for (std::size_t pos = reference_token.find_first_of('~');
pos != std::string::npos;
pos = reference_token.find_first_of('~', pos + 1))
{
JSON_ASSERT(reference_token[pos] == '~');
// ~ must be followed by 0 or 1
if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
(reference_token[pos + 1] != '0' &&
2019-07-02 04:37:30 +08:00
reference_token[pos + 1] != '1')))
{
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", BasicJsonType()));
}
}
// finally, store the reference token
detail::unescape(reference_token);
result.push_back(reference_token);
}
return result;
}
private:
/*!
@param[in] reference_string the reference string to the current value
@param[in] value the value to consider
@param[in,out] result the result object to insert values to
@note Empty objects or arrays are flattened to `null`.
*/
static void flatten(const std::string& reference_string,
const BasicJsonType& value,
BasicJsonType& result)
{
switch (value.type())
{
case detail::value_t::array:
{
if (value.m_value.array->empty())
{
// flatten empty array as null
result[reference_string] = nullptr;
}
else
{
// iterate array and use index as reference string
for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
{
flatten(reference_string + "/" + std::to_string(i),
value.m_value.array->operator[](i), result);
}
}
break;
}
case detail::value_t::object:
{
if (value.m_value.object->empty())
{
// flatten empty object as null
result[reference_string] = nullptr;
}
else
{
// iterate object and use keys as reference string
for (const auto& element : *value.m_value.object)
{
flatten(reference_string + "/" + detail::escape(element.first), element.second, result);
}
}
break;
}
case detail::value_t::null:
case detail::value_t::string:
case detail::value_t::boolean:
case detail::value_t::number_integer:
case detail::value_t::number_unsigned:
case detail::value_t::number_float:
case detail::value_t::binary:
case detail::value_t::discarded:
default:
{
// add primitive value with its reference string
result[reference_string] = value;
break;
}
}
}
/*!
@param[in] value flattened JSON
@return unflattened JSON
@throw parse_error.109 if array index is not a number
@throw type_error.314 if value is not an object
@throw type_error.315 if object values are not primitive
@throw type_error.313 if value cannot be unflattened
*/
static BasicJsonType
unflatten(const BasicJsonType& value)
{
if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
{
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", value));
}
BasicJsonType result;
// iterate the JSON object values
for (const auto& element : *value.m_value.object)
{
if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
{
2021-01-25 20:47:50 +08:00
JSON_THROW(detail::type_error::create(315, "values in object must be primitive", element.second));
}
// assign value to reference pointed to by JSON pointer; Note that if
// the JSON pointer is "" (i.e., points to the whole value), function
// get_and_create returns a reference to result itself. An assignment
// will then create a primitive value.
json_pointer(element.first).get_and_create(result) = element.second;
}
return result;
}
2019-03-19 17:06:35 +08:00
/*!
@brief compares two JSON pointers for equality
@param[in] lhs JSON pointer to compare
@param[in] rhs JSON pointer to compare
@return whether @a lhs is equal to @a rhs
@complexity Linear in the length of the JSON pointer
@exceptionsafety No-throw guarantee: this function never throws exceptions.
*/
friend bool operator==(json_pointer const& lhs,
json_pointer const& rhs) noexcept
{
2019-03-18 20:53:48 +08:00
return lhs.reference_tokens == rhs.reference_tokens;
}
2019-03-19 17:06:35 +08:00
/*!
@brief compares two JSON pointers for inequality
@param[in] lhs JSON pointer to compare
@param[in] rhs JSON pointer to compare
@return whether @a lhs is not equal @a rhs
@complexity Linear in the length of the JSON pointer
@exceptionsafety No-throw guarantee: this function never throws exceptions.
*/
friend bool operator!=(json_pointer const& lhs,
json_pointer const& rhs) noexcept
{
return !(lhs == rhs);
}
/// the reference tokens
std::vector<std::string> reference_tokens;
};
} // namespace nlohmann