summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2024-11-04 11:46:24 -0500
committerStar Rauchenberger <fefferburbia@gmail.com>2024-11-04 11:46:24 -0500
commit8375f92802d3aa7667bfc6f22f6d2a72361c9808 (patch)
treebb706d3493d1ed7043387a3cb9e6a4d1897acba4
parent460b99583bcf6da4462f13ad75856283849904e7 (diff)
downloadwizard-8375f92802d3aa7667bfc6f22f6d2a72361c9808.tar.gz
wizard-8375f92802d3aa7667bfc6f22f6d2a72361c9808.tar.bz2
wizard-8375f92802d3aa7667bfc6f22f6d2a72361c9808.zip
Websockets server!
-rw-r--r--.gitmodules9
-rw-r--r--CMakeLists.txt27
-rw-r--r--database.cpp91
-rw-r--r--database.h40
-rw-r--r--server_main.cpp230
m---------vendor/asio0
m---------vendor/base640
-rw-r--r--vendor/json/json.hpp30292
m---------vendor/stduuid0
-rw-r--r--wizard.cpp18
-rw-r--r--wizard.h7
11 files changed, 21846 insertions, 8868 deletions
diff --git a/.gitmodules b/.gitmodules index 3647a90..de49c9f 100644 --- a/.gitmodules +++ b/.gitmodules
@@ -4,3 +4,12 @@
4[submodule "vendor/curlcpp"] 4[submodule "vendor/curlcpp"]
5 path = vendor/curlcpp 5 path = vendor/curlcpp
6 url = git@github.com:JosephP91/curlcpp 6 url = git@github.com:JosephP91/curlcpp
7[submodule "vendor/asio"]
8 path = vendor/asio
9 url = https://github.com/chriskohlhoff/asio
10[submodule "vendor/base64"]
11 path = vendor/base64
12 url = https://github.com/tobiaslocker/base64
13[submodule "vendor/stduuid"]
14 path = vendor/stduuid
15 url = https://github.com/mariusbancila/stduuid
diff --git a/CMakeLists.txt b/CMakeLists.txt index ed3f7e7..b1a7b38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -9,15 +9,20 @@ pkg_check_modules(lept lept REQUIRED)
9pkg_check_modules(GraphicsMagick GraphicsMagick++ REQUIRED) 9pkg_check_modules(GraphicsMagick GraphicsMagick++ REQUIRED)
10pkg_check_modules(tclap tclap REQUIRED) 10pkg_check_modules(tclap tclap REQUIRED)
11pkg_check_modules(curlcpp curlcpp REQUIRED) 11pkg_check_modules(curlcpp curlcpp REQUIRED)
12find_package(websocketpp)
12 13
13include_directories( 14include_directories(
14 vendor/json 15 vendor/json
15 vendor/hkutil 16 vendor/hkutil
17 vendor/asio/asio/include
18 vendor/base64/include
19 vendor/stduuid
16 ${tesseract_INCLUDE_DIRS} 20 ${tesseract_INCLUDE_DIRS}
17 ${lept_INCLUDE_DIRS} 21 ${lept_INCLUDE_DIRS}
18 ${GraphicsMagick_INCLUDE_DIRS} 22 ${GraphicsMagick_INCLUDE_DIRS}
19 ${curlcpp_INCLUDE_DIRS} 23 ${curlcpp_INCLUDE_DIRS}
20 ${tclap_INCLUDE_DIRS} 24 ${tclap_INCLUDE_DIRS}
25 ${WEBSOCKETPP_INCLUDE_DIR}
21) 26)
22 27
23link_directories( 28link_directories(
@@ -25,10 +30,11 @@ link_directories(
25 ${lept_LIBRARY_DIRS} 30 ${lept_LIBRARY_DIRS}
26 ${GraphicsMagick_LIBRARY_DIRS} 31 ${GraphicsMagick_LIBRARY_DIRS}
27 ${curlcpp_LIBRARY_DIRS} 32 ${curlcpp_LIBRARY_DIRS}
33 ${websocketpp_LIBRARY_DIRS}
28) 34)
29 35
30add_executable(wizard cardset.cpp imagestore.cpp designer.cpp wizard.cpp main.cpp) 36add_library(wizard cardset.cpp imagestore.cpp designer.cpp wizard.cpp)
31set_property(TARGET wizard PROPERTY CXX_STANDARD 14) 37set_property(TARGET wizard PROPERTY CXX_STANDARD 17)
32set_property(TARGET wizard PROPERTY CXX_STANDARD_REQUIRED ON) 38set_property(TARGET wizard PROPERTY CXX_STANDARD_REQUIRED ON)
33target_link_libraries( 39target_link_libraries(
34 wizard 40 wizard
@@ -37,3 +43,20 @@ target_link_libraries(
37 ${GraphicsMagick_LIBRARIES} 43 ${GraphicsMagick_LIBRARIES}
38 ${curlcpp_LIBRARIES} 44 ${curlcpp_LIBRARIES}
39) 45)
46
47add_executable(wizard_gen main.cpp)
48set_property(TARGET wizard_gen PROPERTY CXX_STANDARD 17)
49set_property(TARGET wizard_gen PROPERTY CXX_STANDARD_REQUIRED ON)
50target_link_libraries(
51 wizard_gen
52 wizard
53)
54
55add_executable(wizard_server database.cpp server_main.cpp)
56set_property(TARGET wizard_server PROPERTY CXX_STANDARD 17)
57set_property(TARGET wizard_server PROPERTY CXX_STANDARD_REQUIRED ON)
58target_link_libraries(
59 wizard_server
60 wizard
61 ${websocketpp_LIBRARIES}
62)
diff --git a/database.cpp b/database.cpp new file mode 100644 index 0000000..037579b --- /dev/null +++ b/database.cpp
@@ -0,0 +1,91 @@
1#include "database.h"
2
3#include <include/uuid.h>
4
5#include <stdexcept>
6
7std::string database::create(std::mt19937& rng) {
8 std::lock_guard state_guard(mutex_);
9
10 std::string token = uuids::to_string(uuids::uuid_random_generator{rng}());
11 requests_[token] = request{};
12
13 return token;
14}
15
16void database::subscribe(const std::string& token,
17 subscribe_callback_type callback) {
18 std::lock_guard state_guard(mutex_);
19
20 if (!requests_.count(token)) {
21 throw std::invalid_argument("Could not find request.");
22 }
23
24 request& req = requests_[token];
25 size_t nextId = req.subscribers.size();
26 req.subscribers.push_back(callback);
27}
28
29void database::post(const std::string& token, const std::string& msg) {
30 std::lock_guard state_guard(mutex_);
31
32 if (!requests_.count(token)) {
33 throw std::invalid_argument("Could not find request.");
34 }
35
36 request& req = requests_.at(token);
37
38 for (std::optional<subscribe_callback_type>& callback : req.subscribers) {
39 if (callback) {
40 try {
41 (*callback)(msg);
42 } catch (const std::exception& ex) {
43 callback = std::nullopt;
44 }
45 }
46 }
47}
48
49void database::setResult(const std::string& token, const std::string& result) {
50 std::lock_guard state_guard(mutex_);
51
52 if (!requests_.count(token)) {
53 throw std::invalid_argument("Could not find request.");
54 }
55
56 request& req = requests_[token];
57 req.result = result;
58}
59
60const std::string& database::getResult(const std::string& token) {
61 std::lock_guard state_guard(mutex_);
62
63 if (!requests_.count(token)) {
64 throw std::invalid_argument("Could not find request.");
65 }
66
67 const request& req = requests_.at(token);
68 return req.result;
69}
70
71void database::mark_done(const std::string& token) {
72 std::lock_guard state_guard(mutex_);
73
74 if (!requests_.count(token)) {
75 throw std::invalid_argument("Could not find request.");
76 }
77
78 request& req = requests_[token];
79 req.done = true;
80}
81
82bool database::is_done(const std::string& token) {
83 std::lock_guard state_guard(mutex_);
84
85 if (!requests_.count(token)) {
86 throw std::invalid_argument("Could not find request.");
87 }
88
89 const request& req = requests_.at(token);
90 return req.done;
91}
diff --git a/database.h b/database.h new file mode 100644 index 0000000..d8d9b67 --- /dev/null +++ b/database.h
@@ -0,0 +1,40 @@
1#ifndef DATABASE_H_0A27B356
2#define DATABASE_H_0A27B356
3
4#include <functional>
5#include <map>
6#include <mutex>
7#include <optional>
8#include <random>
9#include <string>
10#include <vector>
11
12class database {
13 public:
14 // Feel free to throw an exception if the subscriber should be killed.
15 using subscribe_callback_type = std::function<void(const std::string&)>;
16
17 std::string create(std::mt19937& rng);
18
19 void subscribe(const std::string& token, subscribe_callback_type callback);
20 void post(const std::string& token, const std::string& msg);
21
22 void setResult(const std::string& token, const std::string& result);
23 const std::string& getResult(const std::string& token);
24
25 void mark_done(const std::string& token);
26 bool is_done(const std::string& token);
27
28 private:
29 struct request {
30 std::vector<std::optional<subscribe_callback_type>> subscribers;
31 std::string result;
32 bool done = false;
33 };
34
35 std::mutex mutex_;
36
37 std::map<std::string, request> requests_;
38};
39
40#endif /* end of include guard: DATABASE_H_0A27B356 */
diff --git a/server_main.cpp b/server_main.cpp new file mode 100644 index 0000000..8da6477 --- /dev/null +++ b/server_main.cpp
@@ -0,0 +1,230 @@
1#define ASIO_STANDALONE
2
3#include <base64.hpp>
4#include <chrono>
5#include <fstream>
6#include <functional>
7#include <json.hpp>
8#include <mutex>
9#include <random>
10#include <thread>
11#include <websocketpp/config/asio_no_tls.hpp>
12#include <websocketpp/server.hpp>
13
14#include "cardset.h"
15#include "database.h"
16#include "imagestore.h"
17#include "wizard.h"
18
19namespace {
20
21using socket_type = websocketpp::server<websocketpp::config::asio>;
22
23class server {
24 public:
25 server(const cardset& cards, const imagestore& images, std::mt19937& rng)
26 : cards_(cards), images_(images), rng_(rng) {
27 socket_.init_asio();
28
29 socket_.set_message_handler([this](websocketpp::connection_hdl connection,
30 socket_type::message_ptr message) {
31 on_message(connection, message);
32 });
33 }
34
35 void run() {
36 socket_.listen(9002);
37 socket_.start_accept();
38
39 asio::post(std::bind(&server::cleanup_thread, this));
40
41 socket_.run();
42 }
43
44 private:
45 void on_message(websocketpp::connection_hdl connection,
46 socket_type::message_ptr message) {
47 nlohmann::json msgJson;
48
49 try {
50 msgJson = nlohmann::json::parse(message->get_payload());
51 } catch (const std::exception& ex) {
52 std::string response = R"(
53 {
54 "type": "error",
55 "msg": "Could not parse message."
56 }
57 )";
58
59 socket_.send(connection, response,
60 websocketpp::frame::opcode::value::TEXT);
61 return;
62 }
63
64 std::string cmd = msgJson["cmd"];
65 if (cmd == "generate") {
66 cmd_generate(connection, msgJson["text"]);
67 } else if (cmd == "check") {
68 cmd_check(connection, msgJson["token"]);
69 } else {
70 std::string response = R"(
71 {
72 "type": "error",
73 "msg": "No command in message."
74 }
75 )";
76
77 socket_.send(connection, response,
78 websocketpp::frame::opcode::value::TEXT);
79 return;
80 }
81 }
82
83 void cmd_generate(websocketpp::connection_hdl connection, std::string text) {
84 std::string token;
85
86 {
87 std::lock_guard rng_guard(rng_mutex_);
88 token = database_.create(rng_);
89 }
90
91 nlohmann::json tokenMsg;
92 tokenMsg["type"] = "token";
93 tokenMsg["token"] = token;
94 socket_.send(connection, tokenMsg.dump(),
95 websocketpp::frame::opcode::value::TEXT);
96
97 database_.subscribe(token, [this, connection](const std::string& msg) {
98 socket_.send(connection, msg, websocketpp::frame::opcode::value::TEXT);
99 });
100
101 asio::post(std::bind(&server::generate_thread, this, token, text));
102 }
103
104 void cmd_check(websocketpp::connection_hdl connection, std::string token) {
105 bool failed = false;
106
107 try {
108 database_.subscribe(token, [this, connection](const std::string& msg) {
109 socket_.send(connection, msg, websocketpp::frame::opcode::value::TEXT);
110 });
111
112 if (!database_.is_done(token)) {
113 return;
114 }
115
116 std::string result = database_.getResult(token);
117 nlohmann::json resultMsg;
118 if (result.empty()) {
119 resultMsg["type"] = "error";
120 resultMsg["msg"] = "Unknown error occurred.";
121 } else {
122 resultMsg["type"] = "result";
123 resultMsg["image"] = database_.getResult(token);
124 resultMsg["msg"] = "Success!";
125 }
126
127 socket_.send(connection, resultMsg.dump(),
128 websocketpp::frame::opcode::value::TEXT);
129 } catch (const std::exception& ex) {
130 failed = true;
131 }
132
133 if (failed) {
134 try {
135 socket_.send(connection, R"(
136 {
137 "type": "error",
138 "msg": "Error retrieving request."
139 })",
140 websocketpp::frame::opcode::value::TEXT);
141 } catch (const std::exception& ex) {
142 // Well, okay
143 std::cout << ex.what() << std::endl;
144 }
145 }
146 }
147
148 void generate_thread(std::string token, std::string text) {
149 std::unique_ptr<wizard> generator;
150
151 {
152 std::lock_guard rng_guard(rng_mutex_);
153 generator = std::make_unique<wizard>(cards_, images_, text, rng_);
154 }
155
156 try {
157 generator->set_status_callback([this, token](const std::string& status) {
158 nlohmann::json msg;
159 msg["type"] = "status";
160 msg["msg"] = status;
161
162 database_.post(token, msg.dump());
163 });
164
165 Magick::Image resultImage = generator->run();
166 Magick::Blob resultBlob;
167 resultImage.write(&resultBlob);
168
169 std::string resultBytes((const char*)resultBlob.data(),
170 resultBlob.length());
171 std::string resultEncoded = base64::to_base64(resultBytes);
172
173 database_.setResult(token, resultEncoded);
174
175 nlohmann::json resultMsg;
176 resultMsg["type"] = "result";
177 resultMsg["image"] = resultEncoded;
178 resultMsg["msg"] = "Success!";
179
180 database_.post(token, resultMsg.dump());
181 } catch (const std::exception& ex) {
182 nlohmann::json response;
183 response["type"] = "error";
184 response["msg"] =
185 std::string("Error generating card (") + ex.what() + ")";
186
187 database_.post(token, response.dump());
188 }
189
190 database_.mark_done(token);
191 }
192
193 void cleanup_thread() {
194 for (;;) {
195 // sleep
196 }
197 }
198
199 const cardset& cards_;
200 const imagestore& images_;
201
202 std::mutex rng_mutex_;
203 std::mt19937& rng_;
204
205 socket_type socket_;
206 database database_;
207};
208
209} // namespace
210
211int main(int argc, char** argv) {
212 Magick::InitializeMagick(nullptr);
213
214 std::random_device randomDevice;
215 std::mt19937 rng(5); // randomDevice());
216
217 if (argc != 2) {
218 std::cout << "usage: wizard_server [configfile]" << std::endl;
219 return -1;
220 }
221
222 std::ifstream config_file(argv[1]);
223 nlohmann::json config_data = nlohmann::json::parse(config_file);
224
225 cardset cards(config_data["cards_path"]);
226 imagestore images(config_data["cache_path"]);
227
228 server app(cards, images, rng);
229 app.run();
230}
diff --git a/vendor/asio b/vendor/asio new file mode 160000
Subproject 66e76b9e4252ff4681227d0d8e34374ec1fa20e
diff --git a/vendor/base64 b/vendor/base64 new file mode 160000
Subproject 387b32f337b83d358ac1ffe574e596ba99c41d3
diff --git a/vendor/json/json.hpp b/vendor/json/json.hpp index 23058be..8b72ea6 100644 --- a/vendor/json/json.hpp +++ b/vendor/json/json.hpp
@@ -1,6422 +1,15208 @@
1/* 1// __ _____ _____ _____
2 __ _____ _____ _____ 2// __| | __| | | | JSON for Modern C++
3 __| | __| | | | JSON for Modern C++ 3// | | |__ | | | | | | version 3.11.3
4| | |__ | | | | | | version 2.0.9 4// |_____|_____|_____|_|___| https://github.com/nlohmann/json
5|_____|_____|_____|_|___| https://github.com/nlohmann/json 5//
6 6// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
7Licensed under the MIT License <http://opensource.org/licenses/MIT>. 7// SPDX-License-Identifier: MIT
8Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>. 8
9 9/****************************************************************************\
10Permission is hereby granted, free of charge, to any person obtaining a copy 10 * Note on documentation: The source files contain links to the online *
11of this software and associated documentation files (the "Software"), to deal 11 * documentation of the public API at https://json.nlohmann.me. This URL *
12in the Software without restriction, including without limitation the rights 12 * contains the most recent documentation and should also be applicable to *
13to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 * previous versions; documentation for deprecated functions is not *
14copies of the Software, and to permit persons to whom the Software is 14 * removed, but marked deprecated. See "Generate documentation" section in *
15furnished to do so, subject to the following conditions: 15 * file docs/README.md. *
16 16\****************************************************************************/
17The above copyright notice and this permission notice shall be included in all 17
18copies or substantial portions of the Software. 18#ifndef INCLUDE_NLOHMANN_JSON_HPP_
19 19#define INCLUDE_NLOHMANN_JSON_HPP_
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20
21IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21#include <algorithm> // all_of, find, for_each
22FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26SOFTWARE.
27*/
28
29#ifndef NLOHMANN_JSON_HPP
30#define NLOHMANN_JSON_HPP
31
32#include <algorithm> // all_of, for_each, transform
33#include <array> // array
34#include <cassert> // assert
35#include <cctype> // isdigit
36#include <ciso646> // and, not, or
37#include <cmath> // isfinite, ldexp, signbit
38#include <cstddef> // nullptr_t, ptrdiff_t, size_t 22#include <cstddef> // nullptr_t, ptrdiff_t, size_t
39#include <cstdint> // int64_t, uint64_t 23#include <functional> // hash, less
40#include <cstdlib> // strtod, strtof, strtold, strtoul
41#include <cstring> // strlen
42#include <functional> // function, hash, less
43#include <initializer_list> // initializer_list 24#include <initializer_list> // initializer_list
44#include <iomanip> // setw 25#ifndef JSON_NO_IO
45#include <iostream> // istream, ostream 26 #include <iosfwd> // istream, ostream
46#include <iterator> // advance, begin, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator 27#endif // JSON_NO_IO
47#include <limits> // numeric_limits 28#include <iterator> // random_access_iterator_tag
48#include <locale> // locale 29#include <memory> // unique_ptr
49#include <map> // map 30#include <string> // string, stoi, to_string
50#include <memory> // addressof, allocator, allocator_traits, unique_ptr 31#include <utility> // declval, forward, move, pair, swap
51#include <numeric> // accumulate
52#include <sstream> // stringstream
53#include <stdexcept> // domain_error, invalid_argument, out_of_range
54#include <string> // getline, stoi, string, to_string
55#include <type_traits> // add_pointer, enable_if, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_floating_point, is_integral, is_nothrow_move_assignable, std::is_nothrow_move_constructible, std::is_pointer, std::is_reference, std::is_same, remove_const, remove_pointer, remove_reference
56#include <utility> // declval, forward, make_pair, move, pair, swap
57#include <vector> // vector 32#include <vector> // vector
58 33
59// exclude unsupported compilers 34// #include <nlohmann/adl_serializer.hpp>
60#if defined(__clang__) 35// __ _____ _____ _____
61 #define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) 36// __| | __| | | | JSON for Modern C++
62 #if CLANG_VERSION < 30400 37// | | |__ | | | | | | version 3.11.3
63 #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" 38// |_____|_____|_____|_|___| https://github.com/nlohmann/json
64 #endif 39//
65#elif defined(__GNUC__) 40// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
66 #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 41// SPDX-License-Identifier: MIT
67 #if GCC_VERSION < 40900 42
68 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" 43
44
45#include <utility>
46
47// #include <nlohmann/detail/abi_macros.hpp>
48// __ _____ _____ _____
49// __| | __| | | | JSON for Modern C++
50// | | |__ | | | | | | version 3.11.3
51// |_____|_____|_____|_|___| https://github.com/nlohmann/json
52//
53// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
54// SPDX-License-Identifier: MIT
55
56
57
58// This file contains all macro definitions affecting or depending on the ABI
59
60#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
61 #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
62 #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3
63 #warning "Already included a different version of the library!"
64 #endif
69 #endif 65 #endif
70#endif 66#endif
71 67
72// disable float-equal warnings on GCC/clang 68#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
73#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) 69#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum)
74 #pragma GCC diagnostic push 70#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum)
75 #pragma GCC diagnostic ignored "-Wfloat-equal" 71
72#ifndef JSON_DIAGNOSTICS
73 #define JSON_DIAGNOSTICS 0
76#endif 74#endif
77 75
78// disable documentation warnings on clang 76#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
79#if defined(__clang__) 77 #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
80 #pragma GCC diagnostic push
81 #pragma GCC diagnostic ignored "-Wdocumentation"
82#endif 78#endif
83 79
84// allow for portable deprecation warnings 80#if JSON_DIAGNOSTICS
85#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) 81 #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
86 #define JSON_DEPRECATED __attribute__((deprecated))
87#elif defined(_MSC_VER)
88 #define JSON_DEPRECATED __declspec(deprecated)
89#else 82#else
90 #define JSON_DEPRECATED 83 #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
91#endif 84#endif
92 85
93/*! 86#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
94@brief namespace for Niels Lohmann 87 #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
95@see https://github.com/nlohmann 88#else
96@since version 1.0.0 89 #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
97*/ 90#endif
98namespace nlohmann
99{
100 91
92#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
93 #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
94#endif
101 95
102/*! 96// Construct the namespace ABI tags component
103@brief unnamed namespace with internal helper functions 97#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b
104@since version 1.0.0 98#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
105*/ 99 NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
106namespace
107{
108/*!
109@brief Helper to determine whether there's a key_type for T.
110 100
111Thus helper is used to tell associative containers apart from other containers 101#define NLOHMANN_JSON_ABI_TAGS \
112such as sequence containers. For instance, `std::map` passes the test as it 102 NLOHMANN_JSON_ABI_TAGS_CONCAT( \
113contains a `mapped_type`, whereas `std::vector` fails the test. 103 NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
104 NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
114 105
115@sa http://stackoverflow.com/a/7728728/266378 106// Construct the namespace version component
116@since version 1.0.0, overworked in version 2.0.6 107#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
117*/ 108 _v ## major ## _ ## minor ## _ ## patch
118template<typename T> 109#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
119struct has_mapped_type 110 NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
120{
121 private:
122 template <typename U, typename = typename U::mapped_type>
123 static int detect(U&&);
124 111
125 static void detect(...); 112#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
126 public: 113#define NLOHMANN_JSON_NAMESPACE_VERSION
127 static constexpr bool value = 114#else
128 std::is_integral<decltype(detect(std::declval<T>()))>::value; 115#define NLOHMANN_JSON_NAMESPACE_VERSION \
129}; 116 NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
117 NLOHMANN_JSON_VERSION_MINOR, \
118 NLOHMANN_JSON_VERSION_PATCH)
119#endif
130 120
131} 121// Combine namespace components
122#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
123#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
124 NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
132 125
133/*! 126#ifndef NLOHMANN_JSON_NAMESPACE
134@brief a class to store JSON values 127#define NLOHMANN_JSON_NAMESPACE \
128 nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
129 NLOHMANN_JSON_ABI_TAGS, \
130 NLOHMANN_JSON_NAMESPACE_VERSION)
131#endif
135 132
136@tparam ObjectType type for JSON objects (`std::map` by default; will be used 133#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
137in @ref object_t) 134#define NLOHMANN_JSON_NAMESPACE_BEGIN \
138@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used 135 namespace nlohmann \
139in @ref array_t) 136 { \
140@tparam StringType type for JSON strings and object keys (`std::string` by 137 inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
141default; will be used in @ref string_t) 138 NLOHMANN_JSON_ABI_TAGS, \
142@tparam BooleanType type for JSON booleans (`bool` by default; will be used 139 NLOHMANN_JSON_NAMESPACE_VERSION) \
143in @ref boolean_t) 140 {
144@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by 141#endif
145default; will be used in @ref number_integer_t)
146@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
147`uint64_t` by default; will be used in @ref number_unsigned_t)
148@tparam NumberFloatType type for JSON floating-point numbers (`double` by
149default; will be used in @ref number_float_t)
150@tparam AllocatorType type of the allocator to use (`std::allocator` by
151default)
152 142
153@requirement The class satisfies the following concept requirements: 143#ifndef NLOHMANN_JSON_NAMESPACE_END
154- Basic 144#define NLOHMANN_JSON_NAMESPACE_END \
155 - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): 145 } /* namespace (inline namespace) NOLINT(readability/namespace) */ \
156 JSON values can be default constructed. The result will be a JSON null value. 146 } // namespace nlohmann
157 - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): 147#endif
158 A JSON value can be constructed from an rvalue argument.
159 - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible):
160 A JSON value can be copy-constructed from an lvalue expression.
161 - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable):
162 A JSON value van be assigned from an rvalue argument.
163 - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable):
164 A JSON value can be copy-assigned from an lvalue expression.
165 - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible):
166 JSON values can be destructed.
167- Layout
168 - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType):
169 JSON values have
170 [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
171 All non-static data members are private and standard layout types, the class
172 has no virtual functions or (virtual) base classes.
173- Library-wide
174 - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable):
175 JSON values can be compared with `==`, see @ref
176 operator==(const_reference,const_reference).
177 - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable):
178 JSON values can be compared with `<`, see @ref
179 operator<(const_reference,const_reference).
180 - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable):
181 Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of
182 other compatible types, using unqualified function call @ref swap().
183 - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer):
184 JSON values can be compared against `std::nullptr_t` objects which are used
185 to model the `null` value.
186- Container
187 - [Container](http://en.cppreference.com/w/cpp/concept/Container):
188 JSON values can be used like STL containers and provide iterator access.
189 - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer);
190 JSON values can be used like STL containers and provide reverse iterator
191 access.
192 148
193@invariant The member variables @a m_value and @a m_type have the following 149// #include <nlohmann/detail/conversions/from_json.hpp>
194relationship: 150// __ _____ _____ _____
195- If `m_type == value_t::object`, then `m_value.object != nullptr`. 151// __| | __| | | | JSON for Modern C++
196- If `m_type == value_t::array`, then `m_value.array != nullptr`. 152// | | |__ | | | | | | version 3.11.3
197- If `m_type == value_t::string`, then `m_value.string != nullptr`. 153// |_____|_____|_____|_|___| https://github.com/nlohmann/json
198The invariants are checked by member function assert_invariant(). 154//
155// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
156// SPDX-License-Identifier: MIT
199 157
200@internal
201@note ObjectType trick from http://stackoverflow.com/a/9860911
202@endinternal
203 158
204@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange
205Format](http://rfc7159.net/rfc7159)
206 159
207@since version 1.0.0 160#include <algorithm> // transform
161#include <array> // array
162#include <forward_list> // forward_list
163#include <iterator> // inserter, front_inserter, end
164#include <map> // map
165#include <string> // string
166#include <tuple> // tuple, make_tuple
167#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
168#include <unordered_map> // unordered_map
169#include <utility> // pair, declval
170#include <valarray> // valarray
171
172// #include <nlohmann/detail/exceptions.hpp>
173// __ _____ _____ _____
174// __| | __| | | | JSON for Modern C++
175// | | |__ | | | | | | version 3.11.3
176// |_____|_____|_____|_|___| https://github.com/nlohmann/json
177//
178// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
179// SPDX-License-Identifier: MIT
180
181
182
183#include <cstddef> // nullptr_t
184#include <exception> // exception
185#if JSON_DIAGNOSTICS
186 #include <numeric> // accumulate
187#endif
188#include <stdexcept> // runtime_error
189#include <string> // to_string
190#include <vector> // vector
208 191
209@nosubgrouping 192// #include <nlohmann/detail/value_t.hpp>
210*/ 193// __ _____ _____ _____
211template < 194// __| | __| | | | JSON for Modern C++
212 template<typename U, typename V, typename... Args> class ObjectType = std::map, 195// | | |__ | | | | | | version 3.11.3
213 template<typename U, typename... Args> class ArrayType = std::vector, 196// |_____|_____|_____|_|___| https://github.com/nlohmann/json
214 class StringType = std::string, 197//
215 class BooleanType = bool, 198// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
216 class NumberIntegerType = std::int64_t, 199// SPDX-License-Identifier: MIT
217 class NumberUnsignedType = std::uint64_t,
218 class NumberFloatType = double,
219 template<typename U> class AllocatorType = std::allocator
220 >
221class basic_json
222{
223 private:
224 /// workaround type for MSVC
225 using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
226 BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
227 AllocatorType>;
228 200
229 public:
230 // forward declarations
231 template<typename U> class iter_impl;
232 template<typename Base> class json_reverse_iterator;
233 class json_pointer;
234 201
235 /////////////////////
236 // container types //
237 /////////////////////
238 202
239 /// @name container types 203#include <array> // array
240 /// The canonic container types to use @ref basic_json like any other STL 204#include <cstddef> // size_t
241 /// container. 205#include <cstdint> // uint8_t
242 /// @{ 206#include <string> // string
243 207
244 /// the type of elements in a basic_json container 208// #include <nlohmann/detail/macro_scope.hpp>
245 using value_type = basic_json; 209// __ _____ _____ _____
210// __| | __| | | | JSON for Modern C++
211// | | |__ | | | | | | version 3.11.3
212// |_____|_____|_____|_|___| https://github.com/nlohmann/json
213//
214// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
215// SPDX-License-Identifier: MIT
246 216
247 /// the type of an element reference
248 using reference = value_type&;
249 /// the type of an element const reference
250 using const_reference = const value_type&;
251 217
252 /// a type to represent differences between iterators
253 using difference_type = std::ptrdiff_t;
254 /// a type to represent container sizes
255 using size_type = std::size_t;
256 218
257 /// the allocator type 219#include <utility> // declval, pair
258 using allocator_type = AllocatorType<basic_json>; 220// #include <nlohmann/detail/meta/detected.hpp>
221// __ _____ _____ _____
222// __| | __| | | | JSON for Modern C++
223// | | |__ | | | | | | version 3.11.3
224// |_____|_____|_____|_|___| https://github.com/nlohmann/json
225//
226// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
227// SPDX-License-Identifier: MIT
259 228
260 /// the type of an element pointer
261 using pointer = typename std::allocator_traits<allocator_type>::pointer;
262 /// the type of an element const pointer
263 using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
264 229
265 /// an iterator for a basic_json container
266 using iterator = iter_impl<basic_json>;
267 /// a const iterator for a basic_json container
268 using const_iterator = iter_impl<const basic_json>;
269 /// a reverse iterator for a basic_json container
270 using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
271 /// a const reverse iterator for a basic_json container
272 using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
273 230
274 /// @} 231#include <type_traits>
275 232
233// #include <nlohmann/detail/meta/void_t.hpp>
234// __ _____ _____ _____
235// __| | __| | | | JSON for Modern C++
236// | | |__ | | | | | | version 3.11.3
237// |_____|_____|_____|_|___| https://github.com/nlohmann/json
238//
239// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
240// SPDX-License-Identifier: MIT
276 241
277 /*!
278 @brief returns the allocator associated with the container
279 */
280 static allocator_type get_allocator()
281 {
282 return allocator_type();
283 }
284 242
285 243
286 /////////////////////////// 244// #include <nlohmann/detail/abi_macros.hpp>
287 // JSON value data types //
288 ///////////////////////////
289 245
290 /// @name JSON value data types
291 /// The data types to store a JSON value. These types are derived from
292 /// the template arguments passed to class @ref basic_json.
293 /// @{
294 246
295 /*! 247NLOHMANN_JSON_NAMESPACE_BEGIN
296 @brief a type for an object 248namespace detail
249{
297 250
298 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: 251template<typename ...Ts> struct make_void
299 > An object is an unordered collection of zero or more name/value pairs, 252{
300 > where a name is a string and a value is a string, number, boolean, null, 253 using type = void;
301 > object, or array. 254};
255template<typename ...Ts> using void_t = typename make_void<Ts...>::type;
302 256
303 To store objects in C++, a type is defined by the template parameters 257} // namespace detail
304 described below. 258NLOHMANN_JSON_NAMESPACE_END
305 259
306 @tparam ObjectType the container to store objects (e.g., `std::map` or
307 `std::unordered_map`)
308 @tparam StringType the type of the keys or names (e.g., `std::string`).
309 The comparison function `std::less<StringType>` is used to order elements
310 inside the container.
311 @tparam AllocatorType the allocator to use for objects (e.g.,
312 `std::allocator`)
313 260
314 #### Default type 261NLOHMANN_JSON_NAMESPACE_BEGIN
262namespace detail
263{
315 264
316 With the default values for @a ObjectType (`std::map`), @a StringType 265// https://en.cppreference.com/w/cpp/experimental/is_detected
317 (`std::string`), and @a AllocatorType (`std::allocator`), the default 266struct nonesuch
318 value for @a object_t is: 267{
268 nonesuch() = delete;
269 ~nonesuch() = delete;
270 nonesuch(nonesuch const&) = delete;
271 nonesuch(nonesuch const&&) = delete;
272 void operator=(nonesuch const&) = delete;
273 void operator=(nonesuch&&) = delete;
274};
319 275
320 @code {.cpp} 276template<class Default,
321 std::map< 277 class AlwaysVoid,
322 std::string, // key_type 278 template<class...> class Op,
323 basic_json, // value_type 279 class... Args>
324 std::less<std::string>, // key_compare 280struct detector
325 std::allocator<std::pair<const std::string, basic_json>> // allocator_type 281{
326 > 282 using value_t = std::false_type;
327 @endcode 283 using type = Default;
284};
328 285
329 #### Behavior 286template<class Default, template<class...> class Op, class... Args>
287struct detector<Default, void_t<Op<Args...>>, Op, Args...>
288{
289 using value_t = std::true_type;
290 using type = Op<Args...>;
291};
330 292
331 The choice of @a object_t influences the behavior of the JSON class. With 293template<template<class...> class Op, class... Args>
332 the default type, objects have the following behavior: 294using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
333 295
334 - When all names are unique, objects will be interoperable in the sense 296template<template<class...> class Op, class... Args>
335 that all software implementations receiving that object will agree on 297struct is_detected_lazy : is_detected<Op, Args...> { };
336 the name-value mappings.
337 - When the names within an object are not unique, later stored name/value
338 pairs overwrite previously stored name/value pairs, leaving the used
339 names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will
340 be treated as equal and both stored as `{"key": 1}`.
341 - Internally, name/value pairs are stored in lexicographical order of the
342 names. Objects will also be serialized (see @ref dump) in this order.
343 For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored
344 and serialized as `{"a": 2, "b": 1}`.
345 - When comparing objects, the order of the name/value pairs is irrelevant.
346 This makes objects interoperable in the sense that they will not be
347 affected by these differences. For instance, `{"b": 1, "a": 2}` and
348 `{"a": 2, "b": 1}` will be treated as equal.
349 298
350 #### Limits 299template<template<class...> class Op, class... Args>
300using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
351 301
352 [RFC 7159](http://rfc7159.net/rfc7159) specifies: 302template<class Default, template<class...> class Op, class... Args>
353 > An implementation may set limits on the maximum depth of nesting. 303using detected_or = detector<Default, void, Op, Args...>;
354 304
355 In this class, the object's limit of nesting is not constraint explicitly. 305template<class Default, template<class...> class Op, class... Args>
356 However, a maximum depth of nesting may be introduced by the compiler or 306using detected_or_t = typename detected_or<Default, Op, Args...>::type;
357 runtime environment. A theoretical limit can be queried by calling the
358 @ref max_size function of a JSON object.
359 307
360 #### Storage 308template<class Expected, template<class...> class Op, class... Args>
309using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
361 310
362 Objects are stored as pointers in a @ref basic_json type. That is, for any 311template<class To, template<class...> class Op, class... Args>
363 access to object values, a pointer of type `object_t*` must be 312using is_detected_convertible =
364 dereferenced. 313 std::is_convertible<detected_t<Op, Args...>, To>;
365 314
366 @sa @ref array_t -- type for an array value 315} // namespace detail
316NLOHMANN_JSON_NAMESPACE_END
367 317
368 @since version 1.0.0 318// #include <nlohmann/thirdparty/hedley/hedley.hpp>
369 319
370 @note The order name/value pairs are added to the object is *not*
371 preserved by the library. Therefore, iterating an object may return
372 name/value pairs in a different order than they were originally stored. In
373 fact, keys will be traversed in alphabetical order as `std::map` with
374 `std::less` is used by default. Please note this behavior conforms to [RFC
375 7159](http://rfc7159.net/rfc7159), because any order implements the
376 specified "unordered" nature of JSON objects.
377 */
378 using object_t = ObjectType<StringType,
379 basic_json,
380 std::less<StringType>,
381 AllocatorType<std::pair<const StringType,
382 basic_json>>>;
383 320
384 /*! 321// __ _____ _____ _____
385 @brief a type for an array 322// __| | __| | | | JSON for Modern C++
323// | | |__ | | | | | | version 3.11.3
324// |_____|_____|_____|_|___| https://github.com/nlohmann/json
325//
326// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
327// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson <evan@nemerson.com>
328// SPDX-License-Identifier: MIT
386 329
387 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: 330/* Hedley - https://nemequ.github.io/hedley
388 > An array is an ordered sequence of zero or more values. 331 * Created by Evan Nemerson <evan@nemerson.com>
332 */
389 333
390 To store objects in C++, a type is defined by the template parameters 334#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15)
391 explained below. 335#if defined(JSON_HEDLEY_VERSION)
336 #undef JSON_HEDLEY_VERSION
337#endif
338#define JSON_HEDLEY_VERSION 15
392 339
393 @tparam ArrayType container type to store arrays (e.g., `std::vector` or 340#if defined(JSON_HEDLEY_STRINGIFY_EX)
394 `std::list`) 341 #undef JSON_HEDLEY_STRINGIFY_EX
395 @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) 342#endif
343#define JSON_HEDLEY_STRINGIFY_EX(x) #x
396 344
397 #### Default type 345#if defined(JSON_HEDLEY_STRINGIFY)
346 #undef JSON_HEDLEY_STRINGIFY
347#endif
348#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x)
398 349
399 With the default values for @a ArrayType (`std::vector`) and @a 350#if defined(JSON_HEDLEY_CONCAT_EX)
400 AllocatorType (`std::allocator`), the default value for @a array_t is: 351 #undef JSON_HEDLEY_CONCAT_EX
352#endif
353#define JSON_HEDLEY_CONCAT_EX(a,b) a##b
401 354
402 @code {.cpp} 355#if defined(JSON_HEDLEY_CONCAT)
403 std::vector< 356 #undef JSON_HEDLEY_CONCAT
404 basic_json, // value_type 357#endif
405 std::allocator<basic_json> // allocator_type 358#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b)
406 >
407 @endcode
408 359
409 #### Limits 360#if defined(JSON_HEDLEY_CONCAT3_EX)
361 #undef JSON_HEDLEY_CONCAT3_EX
362#endif
363#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c
410 364
411 [RFC 7159](http://rfc7159.net/rfc7159) specifies: 365#if defined(JSON_HEDLEY_CONCAT3)
412 > An implementation may set limits on the maximum depth of nesting. 366 #undef JSON_HEDLEY_CONCAT3
367#endif
368#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c)
413 369
414 In this class, the array's limit of nesting is not constraint explicitly. 370#if defined(JSON_HEDLEY_VERSION_ENCODE)
415 However, a maximum depth of nesting may be introduced by the compiler or 371 #undef JSON_HEDLEY_VERSION_ENCODE
416 runtime environment. A theoretical limit can be queried by calling the 372#endif
417 @ref max_size function of a JSON array. 373#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision))
418 374
419 #### Storage 375#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR)
376 #undef JSON_HEDLEY_VERSION_DECODE_MAJOR
377#endif
378#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000)
420 379
421 Arrays are stored as pointers in a @ref basic_json type. That is, for any 380#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR)
422 access to array values, a pointer of type `array_t*` must be dereferenced. 381 #undef JSON_HEDLEY_VERSION_DECODE_MINOR
382#endif
383#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000)
423 384
424 @sa @ref object_t -- type for an object value 385#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION)
386 #undef JSON_HEDLEY_VERSION_DECODE_REVISION
387#endif
388#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000)
425 389
426 @since version 1.0.0 390#if defined(JSON_HEDLEY_GNUC_VERSION)
427 */ 391 #undef JSON_HEDLEY_GNUC_VERSION
428 using array_t = ArrayType<basic_json, AllocatorType<basic_json>>; 392#endif
393#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)
394 #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
395#elif defined(__GNUC__)
396 #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0)
397#endif
429 398
430 /*! 399#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK)
431 @brief a type for a string 400 #undef JSON_HEDLEY_GNUC_VERSION_CHECK
401#endif
402#if defined(JSON_HEDLEY_GNUC_VERSION)
403 #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
404#else
405 #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0)
406#endif
432 407
433 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: 408#if defined(JSON_HEDLEY_MSVC_VERSION)
434 > A string is a sequence of zero or more Unicode characters. 409 #undef JSON_HEDLEY_MSVC_VERSION
410#endif
411#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL)
412 #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100)
413#elif defined(_MSC_FULL_VER) && !defined(__ICL)
414 #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10)
415#elif defined(_MSC_VER) && !defined(__ICL)
416 #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0)
417#endif
435 418
436 To store objects in C++, a type is defined by the template parameter 419#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK)
437 described below. Unicode values are split by the JSON class into 420 #undef JSON_HEDLEY_MSVC_VERSION_CHECK
438 byte-sized characters during deserialization. 421#endif
422#if !defined(JSON_HEDLEY_MSVC_VERSION)
423 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0)
424#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
425 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))
426#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
427 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))
428#else
429 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor)))
430#endif
439 431
440 @tparam StringType the container to store strings (e.g., `std::string`). 432#if defined(JSON_HEDLEY_INTEL_VERSION)
441 Note this container is used for keys/names in objects, see @ref object_t. 433 #undef JSON_HEDLEY_INTEL_VERSION
434#endif
435#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL)
436 #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE)
437#elif defined(__INTEL_COMPILER) && !defined(__ICL)
438 #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)
439#endif
442 440
443 #### Default type 441#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK)
442 #undef JSON_HEDLEY_INTEL_VERSION_CHECK
443#endif
444#if defined(JSON_HEDLEY_INTEL_VERSION)
445 #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
446#else
447 #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0)
448#endif
444 449
445 With the default values for @a StringType (`std::string`), the default 450#if defined(JSON_HEDLEY_INTEL_CL_VERSION)
446 value for @a string_t is: 451 #undef JSON_HEDLEY_INTEL_CL_VERSION
452#endif
453#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL)
454 #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0)
455#endif
447 456
448 @code {.cpp} 457#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK)
449 std::string 458 #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK
450 @endcode 459#endif
460#if defined(JSON_HEDLEY_INTEL_CL_VERSION)
461 #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
462#else
463 #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0)
464#endif
451 465
452 #### String comparison 466#if defined(JSON_HEDLEY_PGI_VERSION)
467 #undef JSON_HEDLEY_PGI_VERSION
468#endif
469#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)
470 #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)
471#endif
453 472
454 [RFC 7159](http://rfc7159.net/rfc7159) states: 473#if defined(JSON_HEDLEY_PGI_VERSION_CHECK)
455 > Software implementations are typically required to test names of object 474 #undef JSON_HEDLEY_PGI_VERSION_CHECK
456 > members for equality. Implementations that transform the textual 475#endif
457 > representation into sequences of Unicode code units and then perform the 476#if defined(JSON_HEDLEY_PGI_VERSION)
458 > comparison numerically, code unit by code unit, are interoperable in the 477 #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
459 > sense that implementations will agree in all cases on equality or 478#else
460 > inequality of two strings. For example, implementations that compare 479 #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0)
461 > strings with escaped characters unconverted may incorrectly find that 480#endif
462 > `"a\\b"` and `"a\u005Cb"` are not equal.
463 481
464 This implementation is interoperable as it does compare strings code unit 482#if defined(JSON_HEDLEY_SUNPRO_VERSION)
465 by code unit. 483 #undef JSON_HEDLEY_SUNPRO_VERSION
484#endif
485#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
486 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10)
487#elif defined(__SUNPRO_C)
488 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf)
489#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
490 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10)
491#elif defined(__SUNPRO_CC)
492 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf)
493#endif
466 494
467 #### Storage 495#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK)
496 #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK
497#endif
498#if defined(JSON_HEDLEY_SUNPRO_VERSION)
499 #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
500#else
501 #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0)
502#endif
468 503
469 String values are stored as pointers in a @ref basic_json type. That is, 504#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)
470 for any access to string values, a pointer of type `string_t*` must be 505 #undef JSON_HEDLEY_EMSCRIPTEN_VERSION
471 dereferenced. 506#endif
507#if defined(__EMSCRIPTEN__)
508 #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__)
509#endif
472 510
473 @since version 1.0.0 511#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK)
474 */ 512 #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK
475 using string_t = StringType; 513#endif
514#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)
515 #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
516#else
517 #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0)
518#endif
476 519
477 /*! 520#if defined(JSON_HEDLEY_ARM_VERSION)
478 @brief a type for a boolean 521 #undef JSON_HEDLEY_ARM_VERSION
522#endif
523#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)
524 #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100)
525#elif defined(__CC_ARM) && defined(__ARMCC_VERSION)
526 #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100)
527#endif
479 528
480 [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a 529#if defined(JSON_HEDLEY_ARM_VERSION_CHECK)
481 type which differentiates the two literals `true` and `false`. 530 #undef JSON_HEDLEY_ARM_VERSION_CHECK
531#endif
532#if defined(JSON_HEDLEY_ARM_VERSION)
533 #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
534#else
535 #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0)
536#endif
482 537
483 To store objects in C++, a type is defined by the template parameter @a 538#if defined(JSON_HEDLEY_IBM_VERSION)
484 BooleanType which chooses the type to use. 539 #undef JSON_HEDLEY_IBM_VERSION
540#endif
541#if defined(__ibmxl__)
542 #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__)
543#elif defined(__xlC__) && defined(__xlC_ver__)
544 #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)
545#elif defined(__xlC__)
546 #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0)
547#endif
485 548
486 #### Default type 549#if defined(JSON_HEDLEY_IBM_VERSION_CHECK)
550 #undef JSON_HEDLEY_IBM_VERSION_CHECK
551#endif
552#if defined(JSON_HEDLEY_IBM_VERSION)
553 #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
554#else
555 #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0)
556#endif
487 557
488 With the default values for @a BooleanType (`bool`), the default value for 558#if defined(JSON_HEDLEY_TI_VERSION)
489 @a boolean_t is: 559 #undef JSON_HEDLEY_TI_VERSION
560#endif
561#if \
562 defined(__TI_COMPILER_VERSION__) && \
563 ( \
564 defined(__TMS470__) || defined(__TI_ARM__) || \
565 defined(__MSP430__) || \
566 defined(__TMS320C2000__) \
567 )
568#if (__TI_COMPILER_VERSION__ >= 16000000)
569 #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
570#endif
571#endif
490 572
491 @code {.cpp} 573#if defined(JSON_HEDLEY_TI_VERSION_CHECK)
492 bool 574 #undef JSON_HEDLEY_TI_VERSION_CHECK
493 @endcode 575#endif
576#if defined(JSON_HEDLEY_TI_VERSION)
577 #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
578#else
579 #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0)
580#endif
494 581
495 #### Storage 582#if defined(JSON_HEDLEY_TI_CL2000_VERSION)
583 #undef JSON_HEDLEY_TI_CL2000_VERSION
584#endif
585#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__)
586 #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
587#endif
496 588
497 Boolean values are stored directly inside a @ref basic_json type. 589#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK)
590 #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK
591#endif
592#if defined(JSON_HEDLEY_TI_CL2000_VERSION)
593 #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
594#else
595 #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0)
596#endif
498 597
499 @since version 1.0.0 598#if defined(JSON_HEDLEY_TI_CL430_VERSION)
500 */ 599 #undef JSON_HEDLEY_TI_CL430_VERSION
501 using boolean_t = BooleanType; 600#endif
601#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__)
602 #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
603#endif
502 604
503 /*! 605#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK)
504 @brief a type for a number (integer) 606 #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK
607#endif
608#if defined(JSON_HEDLEY_TI_CL430_VERSION)
609 #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
610#else
611 #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0)
612#endif
505 613
506 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: 614#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)
507 > The representation of numbers is similar to that used in most 615 #undef JSON_HEDLEY_TI_ARMCL_VERSION
508 > programming languages. A number is represented in base 10 using decimal 616#endif
509 > digits. It contains an integer component that may be prefixed with an 617#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__))
510 > optional minus sign, which may be followed by a fraction part and/or an 618 #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
511 > exponent part. Leading zeros are not allowed. (...) Numeric values that 619#endif
512 > cannot be represented in the grammar below (such as Infinity and NaN)
513 > are not permitted.
514 620
515 This description includes both integer and floating-point numbers. 621#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK)
516 However, C++ allows more precise storage if it is known whether the number 622 #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK
517 is a signed integer, an unsigned integer or a floating-point number. 623#endif
518 Therefore, three different types, @ref number_integer_t, @ref 624#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)
519 number_unsigned_t and @ref number_float_t are used. 625 #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
626#else
627 #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0)
628#endif
520 629
521 To store integer numbers in C++, a type is defined by the template 630#if defined(JSON_HEDLEY_TI_CL6X_VERSION)
522 parameter @a NumberIntegerType which chooses the type to use. 631 #undef JSON_HEDLEY_TI_CL6X_VERSION
632#endif
633#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__)
634 #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
635#endif
523 636
524 #### Default type 637#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK)
638 #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK
639#endif
640#if defined(JSON_HEDLEY_TI_CL6X_VERSION)
641 #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
642#else
643 #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0)
644#endif
525 645
526 With the default values for @a NumberIntegerType (`int64_t`), the default 646#if defined(JSON_HEDLEY_TI_CL7X_VERSION)
527 value for @a number_integer_t is: 647 #undef JSON_HEDLEY_TI_CL7X_VERSION
648#endif
649#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__)
650 #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
651#endif
528 652
529 @code {.cpp} 653#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK)
530 int64_t 654 #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK
531 @endcode 655#endif
656#if defined(JSON_HEDLEY_TI_CL7X_VERSION)
657 #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
658#else
659 #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0)
660#endif
532 661
533 #### Default behavior 662#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)
663 #undef JSON_HEDLEY_TI_CLPRU_VERSION
664#endif
665#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__)
666 #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
667#endif
534 668
535 - The restrictions about leading zeros is not enforced in C++. Instead, 669#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK)
536 leading zeros in integer literals lead to an interpretation as octal 670 #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK
537 number. Internally, the value will be stored as decimal number. For 671#endif
538 instance, the C++ integer literal `010` will be serialized to `8`. 672#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)
539 During deserialization, leading zeros yield an error. 673 #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
540 - Not-a-number (NaN) values will be serialized to `null`. 674#else
675 #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0)
676#endif
541 677
542 #### Limits 678#if defined(JSON_HEDLEY_CRAY_VERSION)
679 #undef JSON_HEDLEY_CRAY_VERSION
680#endif
681#if defined(_CRAYC)
682 #if defined(_RELEASE_PATCHLEVEL)
683 #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL)
684 #else
685 #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0)
686 #endif
687#endif
543 688
544 [RFC 7159](http://rfc7159.net/rfc7159) specifies: 689#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK)
545 > An implementation may set limits on the range and precision of numbers. 690 #undef JSON_HEDLEY_CRAY_VERSION_CHECK
691#endif
692#if defined(JSON_HEDLEY_CRAY_VERSION)
693 #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
694#else
695 #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0)
696#endif
546 697
547 When the default type is used, the maximal integer number that can be 698#if defined(JSON_HEDLEY_IAR_VERSION)
548 stored is `9223372036854775807` (INT64_MAX) and the minimal integer number 699 #undef JSON_HEDLEY_IAR_VERSION
549 that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers 700#endif
550 that are out of range will yield over/underflow when used in a 701#if defined(__IAR_SYSTEMS_ICC__)
551 constructor. During deserialization, too large or small integer numbers 702 #if __VER__ > 1000
552 will be automatically be stored as @ref number_unsigned_t or @ref 703 #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000))
553 number_float_t. 704 #else
705 #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0)
706 #endif
707#endif
554 708
555 [RFC 7159](http://rfc7159.net/rfc7159) further states: 709#if defined(JSON_HEDLEY_IAR_VERSION_CHECK)
556 > Note that when such software is used, numbers that are integers and are 710 #undef JSON_HEDLEY_IAR_VERSION_CHECK
557 > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense 711#endif
558 > that implementations will agree exactly on their numeric values. 712#if defined(JSON_HEDLEY_IAR_VERSION)
713 #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
714#else
715 #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0)
716#endif
559 717
560 As this range is a subrange of the exactly supported range [INT64_MIN, 718#if defined(JSON_HEDLEY_TINYC_VERSION)
561 INT64_MAX], this class's integer type is interoperable. 719 #undef JSON_HEDLEY_TINYC_VERSION
720#endif
721#if defined(__TINYC__)
722 #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)
723#endif
562 724
563 #### Storage 725#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK)
726 #undef JSON_HEDLEY_TINYC_VERSION_CHECK
727#endif
728#if defined(JSON_HEDLEY_TINYC_VERSION)
729 #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
730#else
731 #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0)
732#endif
564 733
565 Integer number values are stored directly inside a @ref basic_json type. 734#if defined(JSON_HEDLEY_DMC_VERSION)
735 #undef JSON_HEDLEY_DMC_VERSION
736#endif
737#if defined(__DMC__)
738 #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf)
739#endif
566 740
567 @sa @ref number_float_t -- type for number values (floating-point) 741#if defined(JSON_HEDLEY_DMC_VERSION_CHECK)
742 #undef JSON_HEDLEY_DMC_VERSION_CHECK
743#endif
744#if defined(JSON_HEDLEY_DMC_VERSION)
745 #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
746#else
747 #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0)
748#endif
568 749
569 @sa @ref number_unsigned_t -- type for number values (unsigned integer) 750#if defined(JSON_HEDLEY_COMPCERT_VERSION)
751 #undef JSON_HEDLEY_COMPCERT_VERSION
752#endif
753#if defined(__COMPCERT_VERSION__)
754 #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100)
755#endif
570 756
571 @since version 1.0.0 757#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK)
572 */ 758 #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK
573 using number_integer_t = NumberIntegerType; 759#endif
760#if defined(JSON_HEDLEY_COMPCERT_VERSION)
761 #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
762#else
763 #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0)
764#endif
574 765
575 /*! 766#if defined(JSON_HEDLEY_PELLES_VERSION)
576 @brief a type for a number (unsigned) 767 #undef JSON_HEDLEY_PELLES_VERSION
768#endif
769#if defined(__POCC__)
770 #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0)
771#endif
577 772
578 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: 773#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK)
579 > The representation of numbers is similar to that used in most 774 #undef JSON_HEDLEY_PELLES_VERSION_CHECK
580 > programming languages. A number is represented in base 10 using decimal 775#endif
581 > digits. It contains an integer component that may be prefixed with an 776#if defined(JSON_HEDLEY_PELLES_VERSION)
582 > optional minus sign, which may be followed by a fraction part and/or an 777 #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
583 > exponent part. Leading zeros are not allowed. (...) Numeric values that 778#else
584 > cannot be represented in the grammar below (such as Infinity and NaN) 779 #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0)
585 > are not permitted. 780#endif
586 781
587 This description includes both integer and floating-point numbers. 782#if defined(JSON_HEDLEY_MCST_LCC_VERSION)
588 However, C++ allows more precise storage if it is known whether the number 783 #undef JSON_HEDLEY_MCST_LCC_VERSION
589 is a signed integer, an unsigned integer or a floating-point number. 784#endif
590 Therefore, three different types, @ref number_integer_t, @ref 785#if defined(__LCC__) && defined(__LCC_MINOR__)
591 number_unsigned_t and @ref number_float_t are used. 786 #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__)
787#endif
592 788
593 To store unsigned integer numbers in C++, a type is defined by the 789#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK)
594 template parameter @a NumberUnsignedType which chooses the type to use. 790 #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK
791#endif
792#if defined(JSON_HEDLEY_MCST_LCC_VERSION)
793 #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
794#else
795 #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0)
796#endif
595 797
596 #### Default type 798#if defined(JSON_HEDLEY_GCC_VERSION)
799 #undef JSON_HEDLEY_GCC_VERSION
800#endif
801#if \
802 defined(JSON_HEDLEY_GNUC_VERSION) && \
803 !defined(__clang__) && \
804 !defined(JSON_HEDLEY_INTEL_VERSION) && \
805 !defined(JSON_HEDLEY_PGI_VERSION) && \
806 !defined(JSON_HEDLEY_ARM_VERSION) && \
807 !defined(JSON_HEDLEY_CRAY_VERSION) && \
808 !defined(JSON_HEDLEY_TI_VERSION) && \
809 !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \
810 !defined(JSON_HEDLEY_TI_CL430_VERSION) && \
811 !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \
812 !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \
813 !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \
814 !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \
815 !defined(__COMPCERT__) && \
816 !defined(JSON_HEDLEY_MCST_LCC_VERSION)
817 #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION
818#endif
597 819
598 With the default values for @a NumberUnsignedType (`uint64_t`), the 820#if defined(JSON_HEDLEY_GCC_VERSION_CHECK)
599 default value for @a number_unsigned_t is: 821 #undef JSON_HEDLEY_GCC_VERSION_CHECK
822#endif
823#if defined(JSON_HEDLEY_GCC_VERSION)
824 #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
825#else
826 #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0)
827#endif
600 828
601 @code {.cpp} 829#if defined(JSON_HEDLEY_HAS_ATTRIBUTE)
602 uint64_t 830 #undef JSON_HEDLEY_HAS_ATTRIBUTE
603 @endcode 831#endif
832#if \
833 defined(__has_attribute) && \
834 ( \
835 (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \
836 )
837# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute)
838#else
839# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0)
840#endif
604 841
605 #### Default behavior 842#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE)
843 #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE
844#endif
845#if defined(__has_attribute)
846 #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
847#else
848 #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
849#endif
606 850
607 - The restrictions about leading zeros is not enforced in C++. Instead, 851#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE)
608 leading zeros in integer literals lead to an interpretation as octal 852 #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE
609 number. Internally, the value will be stored as decimal number. For 853#endif
610 instance, the C++ integer literal `010` will be serialized to `8`. 854#if defined(__has_attribute)
611 During deserialization, leading zeros yield an error. 855 #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
612 - Not-a-number (NaN) values will be serialized to `null`. 856#else
857 #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
858#endif
613 859
614 #### Limits 860#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE)
861 #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE
862#endif
863#if \
864 defined(__has_cpp_attribute) && \
865 defined(__cplusplus) && \
866 (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0))
867 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute)
868#else
869 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0)
870#endif
615 871
616 [RFC 7159](http://rfc7159.net/rfc7159) specifies: 872#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS)
617 > An implementation may set limits on the range and precision of numbers. 873 #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS
874#endif
875#if !defined(__cplusplus) || !defined(__has_cpp_attribute)
876 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)
877#elif \
878 !defined(JSON_HEDLEY_PGI_VERSION) && \
879 !defined(JSON_HEDLEY_IAR_VERSION) && \
880 (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \
881 (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0))
882 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute)
883#else
884 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)
885#endif
618 886
619 When the default type is used, the maximal integer number that can be 887#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE)
620 stored is `18446744073709551615` (UINT64_MAX) and the minimal integer 888 #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE
621 number that can be stored is `0`. Integer numbers that are out of range 889#endif
622 will yield over/underflow when used in a constructor. During 890#if defined(__has_cpp_attribute) && defined(__cplusplus)
623 deserialization, too large or small integer numbers will be automatically 891 #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
624 be stored as @ref number_integer_t or @ref number_float_t. 892#else
893 #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
894#endif
625 895
626 [RFC 7159](http://rfc7159.net/rfc7159) further states: 896#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE)
627 > Note that when such software is used, numbers that are integers and are 897 #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE
628 > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense 898#endif
629 > that implementations will agree exactly on their numeric values. 899#if defined(__has_cpp_attribute) && defined(__cplusplus)
900 #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
901#else
902 #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
903#endif
630 904
631 As this range is a subrange (when considered in conjunction with the 905#if defined(JSON_HEDLEY_HAS_BUILTIN)
632 number_integer_t type) of the exactly supported range [0, UINT64_MAX], 906 #undef JSON_HEDLEY_HAS_BUILTIN
633 this class's integer type is interoperable. 907#endif
908#if defined(__has_builtin)
909 #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin)
910#else
911 #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0)
912#endif
634 913
635 #### Storage 914#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN)
915 #undef JSON_HEDLEY_GNUC_HAS_BUILTIN
916#endif
917#if defined(__has_builtin)
918 #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
919#else
920 #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
921#endif
636 922
637 Integer number values are stored directly inside a @ref basic_json type. 923#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN)
924 #undef JSON_HEDLEY_GCC_HAS_BUILTIN
925#endif
926#if defined(__has_builtin)
927 #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
928#else
929 #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
930#endif
638 931
639 @sa @ref number_float_t -- type for number values (floating-point) 932#if defined(JSON_HEDLEY_HAS_FEATURE)
640 @sa @ref number_integer_t -- type for number values (integer) 933 #undef JSON_HEDLEY_HAS_FEATURE
934#endif
935#if defined(__has_feature)
936 #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature)
937#else
938 #define JSON_HEDLEY_HAS_FEATURE(feature) (0)
939#endif
641 940
642 @since version 2.0.0 941#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE)
643 */ 942 #undef JSON_HEDLEY_GNUC_HAS_FEATURE
644 using number_unsigned_t = NumberUnsignedType; 943#endif
944#if defined(__has_feature)
945 #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
946#else
947 #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
948#endif
645 949
646 /*! 950#if defined(JSON_HEDLEY_GCC_HAS_FEATURE)
647 @brief a type for a number (floating-point) 951 #undef JSON_HEDLEY_GCC_HAS_FEATURE
952#endif
953#if defined(__has_feature)
954 #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
955#else
956 #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
957#endif
648 958
649 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: 959#if defined(JSON_HEDLEY_HAS_EXTENSION)
650 > The representation of numbers is similar to that used in most 960 #undef JSON_HEDLEY_HAS_EXTENSION
651 > programming languages. A number is represented in base 10 using decimal 961#endif
652 > digits. It contains an integer component that may be prefixed with an 962#if defined(__has_extension)
653 > optional minus sign, which may be followed by a fraction part and/or an 963 #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension)
654 > exponent part. Leading zeros are not allowed. (...) Numeric values that 964#else
655 > cannot be represented in the grammar below (such as Infinity and NaN) 965 #define JSON_HEDLEY_HAS_EXTENSION(extension) (0)
656 > are not permitted. 966#endif
657 967
658 This description includes both integer and floating-point numbers. 968#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION)
659 However, C++ allows more precise storage if it is known whether the number 969 #undef JSON_HEDLEY_GNUC_HAS_EXTENSION
660 is a signed integer, an unsigned integer or a floating-point number. 970#endif
661 Therefore, three different types, @ref number_integer_t, @ref 971#if defined(__has_extension)
662 number_unsigned_t and @ref number_float_t are used. 972 #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
973#else
974 #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
975#endif
663 976
664 To store floating-point numbers in C++, a type is defined by the template 977#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION)
665 parameter @a NumberFloatType which chooses the type to use. 978 #undef JSON_HEDLEY_GCC_HAS_EXTENSION
979#endif
980#if defined(__has_extension)
981 #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
982#else
983 #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
984#endif
666 985
667 #### Default type 986#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE)
987 #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE
988#endif
989#if defined(__has_declspec_attribute)
990 #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute)
991#else
992 #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0)
993#endif
668 994
669 With the default values for @a NumberFloatType (`double`), the default 995#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE)
670 value for @a number_float_t is: 996 #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE
997#endif
998#if defined(__has_declspec_attribute)
999 #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
1000#else
1001 #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
1002#endif
671 1003
672 @code {.cpp} 1004#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE)
673 double 1005 #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE
674 @endcode 1006#endif
1007#if defined(__has_declspec_attribute)
1008 #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
1009#else
1010 #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
1011#endif
675 1012
676 #### Default behavior 1013#if defined(JSON_HEDLEY_HAS_WARNING)
1014 #undef JSON_HEDLEY_HAS_WARNING
1015#endif
1016#if defined(__has_warning)
1017 #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning)
1018#else
1019 #define JSON_HEDLEY_HAS_WARNING(warning) (0)
1020#endif
677 1021
678 - The restrictions about leading zeros is not enforced in C++. Instead, 1022#if defined(JSON_HEDLEY_GNUC_HAS_WARNING)
679 leading zeros in floating-point literals will be ignored. Internally, 1023 #undef JSON_HEDLEY_GNUC_HAS_WARNING
680 the value will be stored as decimal number. For instance, the C++ 1024#endif
681 floating-point literal `01.2` will be serialized to `1.2`. During 1025#if defined(__has_warning)
682 deserialization, leading zeros yield an error. 1026 #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
683 - Not-a-number (NaN) values will be serialized to `null`. 1027#else
1028 #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
1029#endif
684 1030
685 #### Limits 1031#if defined(JSON_HEDLEY_GCC_HAS_WARNING)
1032 #undef JSON_HEDLEY_GCC_HAS_WARNING
1033#endif
1034#if defined(__has_warning)
1035 #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
1036#else
1037 #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
1038#endif
686 1039
687 [RFC 7159](http://rfc7159.net/rfc7159) states: 1040#if \
688 > This specification allows implementations to set limits on the range and 1041 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
689 > precision of numbers accepted. Since software that implements IEEE 1042 defined(__clang__) || \
690 > 754-2008 binary64 (double precision) numbers is generally available and 1043 JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
691 > widely used, good interoperability can be achieved by implementations 1044 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
692 > that expect no more precision or range than these provide, in the sense 1045 JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
693 > that implementations will approximate JSON numbers within the expected 1046 JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
694 > precision. 1047 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1048 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1049 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \
1050 JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \
1051 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \
1052 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \
1053 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1054 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1055 JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \
1056 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \
1057 JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \
1058 (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR))
1059 #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value)
1060#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
1061 #define JSON_HEDLEY_PRAGMA(value) __pragma(value)
1062#else
1063 #define JSON_HEDLEY_PRAGMA(value)
1064#endif
695 1065
696 This implementation does exactly follow this approach, as it uses double 1066#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH)
697 precision floating-point numbers. Note values smaller than 1067 #undef JSON_HEDLEY_DIAGNOSTIC_PUSH
698 `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` 1068#endif
699 will be stored as NaN internally and be serialized to `null`. 1069#if defined(JSON_HEDLEY_DIAGNOSTIC_POP)
1070 #undef JSON_HEDLEY_DIAGNOSTIC_POP
1071#endif
1072#if defined(__clang__)
1073 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push")
1074 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop")
1075#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
1076 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
1077 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
1078#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)
1079 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
1080 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
1081#elif \
1082 JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \
1083 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1084 #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push))
1085 #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop))
1086#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0)
1087 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push")
1088 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop")
1089#elif \
1090 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1091 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1092 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \
1093 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \
1094 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1095 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
1096 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push")
1097 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop")
1098#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
1099 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
1100 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
1101#else
1102 #define JSON_HEDLEY_DIAGNOSTIC_PUSH
1103 #define JSON_HEDLEY_DIAGNOSTIC_POP
1104#endif
700 1105
701 #### Storage 1106/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for
1107 HEDLEY INTERNAL USE ONLY. API subject to change without notice. */
1108#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)
1109 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_
1110#endif
1111#if defined(__cplusplus)
1112# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat")
1113# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions")
1114# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions")
1115# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
1116 JSON_HEDLEY_DIAGNOSTIC_PUSH \
1117 _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
1118 _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \
1119 _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \
1120 xpr \
1121 JSON_HEDLEY_DIAGNOSTIC_POP
1122# else
1123# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
1124 JSON_HEDLEY_DIAGNOSTIC_PUSH \
1125 _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
1126 _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \
1127 xpr \
1128 JSON_HEDLEY_DIAGNOSTIC_POP
1129# endif
1130# else
1131# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
1132 JSON_HEDLEY_DIAGNOSTIC_PUSH \
1133 _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
1134 xpr \
1135 JSON_HEDLEY_DIAGNOSTIC_POP
1136# endif
1137# endif
1138#endif
1139#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)
1140 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x
1141#endif
702 1142
703 Floating-point number values are stored directly inside a @ref basic_json 1143#if defined(JSON_HEDLEY_CONST_CAST)
704 type. 1144 #undef JSON_HEDLEY_CONST_CAST
1145#endif
1146#if defined(__cplusplus)
1147# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast<T>(expr))
1148#elif \
1149 JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \
1150 JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \
1151 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
1152# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \
1153 JSON_HEDLEY_DIAGNOSTIC_PUSH \
1154 JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \
1155 ((T) (expr)); \
1156 JSON_HEDLEY_DIAGNOSTIC_POP \
1157 }))
1158#else
1159# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr))
1160#endif
705 1161
706 @sa @ref number_integer_t -- type for number values (integer) 1162#if defined(JSON_HEDLEY_REINTERPRET_CAST)
1163 #undef JSON_HEDLEY_REINTERPRET_CAST
1164#endif
1165#if defined(__cplusplus)
1166 #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast<T>(expr))
1167#else
1168 #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr))
1169#endif
707 1170
708 @sa @ref number_unsigned_t -- type for number values (unsigned integer) 1171#if defined(JSON_HEDLEY_STATIC_CAST)
1172 #undef JSON_HEDLEY_STATIC_CAST
1173#endif
1174#if defined(__cplusplus)
1175 #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast<T>(expr))
1176#else
1177 #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr))
1178#endif
709 1179
710 @since version 1.0.0 1180#if defined(JSON_HEDLEY_CPP_CAST)
711 */ 1181 #undef JSON_HEDLEY_CPP_CAST
712 using number_float_t = NumberFloatType; 1182#endif
1183#if defined(__cplusplus)
1184# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast")
1185# define JSON_HEDLEY_CPP_CAST(T, expr) \
1186 JSON_HEDLEY_DIAGNOSTIC_PUSH \
1187 _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \
1188 ((T) (expr)) \
1189 JSON_HEDLEY_DIAGNOSTIC_POP
1190# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0)
1191# define JSON_HEDLEY_CPP_CAST(T, expr) \
1192 JSON_HEDLEY_DIAGNOSTIC_PUSH \
1193 _Pragma("diag_suppress=Pe137") \
1194 JSON_HEDLEY_DIAGNOSTIC_POP
1195# else
1196# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr))
1197# endif
1198#else
1199# define JSON_HEDLEY_CPP_CAST(T, expr) (expr)
1200#endif
713 1201
714 /// @} 1202#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED)
1203 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
1204#endif
1205#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations")
1206 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
1207#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
1208 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)")
1209#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1210 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786))
1211#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)
1212 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445")
1213#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
1214 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444")
1215#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
1216 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
1217#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
1218 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996))
1219#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1220 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444")
1221#elif \
1222 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1223 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1224 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1225 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1226 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1227 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1228 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1229 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1230 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1231 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1232 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
1233 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718")
1234#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus)
1235 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)")
1236#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus)
1237 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)")
1238#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1239 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215")
1240#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
1241 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)")
1242#else
1243 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
1244#endif
715 1245
1246#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS)
1247 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
1248#endif
1249#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
1250 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"")
1251#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
1252 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)")
1253#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1254 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161))
1255#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
1256 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675")
1257#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
1258 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"")
1259#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
1260 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068))
1261#elif \
1262 JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \
1263 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \
1264 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1265 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0)
1266 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163")
1267#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0)
1268 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163")
1269#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1270 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161")
1271#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1272 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161")
1273#else
1274 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
1275#endif
716 1276
717 /////////////////////////// 1277#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES)
718 // JSON type enumeration // 1278 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
719 /////////////////////////// 1279#endif
1280#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes")
1281 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"")
1282#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)
1283 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
1284#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0)
1285 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)")
1286#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1287 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292))
1288#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0)
1289 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030))
1290#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)
1291 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098")
1292#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
1293 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097")
1294#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)
1295 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)")
1296#elif \
1297 JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \
1298 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \
1299 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0)
1300 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173")
1301#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1302 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097")
1303#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1304 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097")
1305#else
1306 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
1307#endif
720 1308
721 /*! 1309#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL)
722 @brief the JSON type enumeration 1310 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
1311#endif
1312#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual")
1313 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"")
1314#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
1315 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)")
1316#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0)
1317 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
1318#else
1319 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
1320#endif
723 1321
724 This enumeration collects the different JSON types. It is internally used 1322#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION)
725 to distinguish the stored values, and the functions @ref is_null(), @ref 1323 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
726 is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref 1324#endif
727 is_number() (with @ref is_number_integer(), @ref is_number_unsigned(), and 1325#if JSON_HEDLEY_HAS_WARNING("-Wunused-function")
728 @ref is_number_float()), @ref is_discarded(), @ref is_primitive(), and 1326 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"")
729 @ref is_structured() rely on it. 1327#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0)
1328 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"")
1329#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0)
1330 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505))
1331#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1332 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142")
1333#else
1334 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
1335#endif
730 1336
731 @note There are three enumeration entries (number_integer, 1337#if defined(JSON_HEDLEY_DEPRECATED)
732 number_unsigned, and number_float), because the library distinguishes 1338 #undef JSON_HEDLEY_DEPRECATED
733 these three types for numbers: @ref number_unsigned_t is used for unsigned 1339#endif
734 integers, @ref number_integer_t is used for signed integers, and @ref 1340#if defined(JSON_HEDLEY_DEPRECATED_FOR)
735 number_float_t is used for floating-point numbers or to approximate 1341 #undef JSON_HEDLEY_DEPRECATED_FOR
736 integers which do not fit in the limits of their respective type. 1342#endif
1343#if \
1344 JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
1345 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1346 #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since))
1347 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement))
1348#elif \
1349 (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \
1350 JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
1351 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1352 JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \
1353 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \
1354 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
1355 JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \
1356 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \
1357 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \
1358 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1359 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \
1360 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1361 #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since)))
1362 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement)))
1363#elif defined(__cplusplus) && (__cplusplus >= 201402L)
1364 #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]])
1365 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]])
1366#elif \
1367 JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \
1368 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
1369 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1370 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1371 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1372 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1373 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1374 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1375 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1376 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1377 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1378 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1379 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1380 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1381 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
1382 JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
1383 #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))
1384 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))
1385#elif \
1386 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
1387 JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \
1388 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1389 #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated)
1390 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)
1391#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1392 #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated")
1393 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated")
1394#else
1395 #define JSON_HEDLEY_DEPRECATED(since)
1396 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement)
1397#endif
737 1398
738 @sa @ref basic_json(const value_t value_type) -- create a JSON value with 1399#if defined(JSON_HEDLEY_UNAVAILABLE)
739 the default value for a given type 1400 #undef JSON_HEDLEY_UNAVAILABLE
1401#endif
1402#if \
1403 JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \
1404 JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \
1405 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1406 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1407 #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since)))
1408#else
1409 #define JSON_HEDLEY_UNAVAILABLE(available_since)
1410#endif
740 1411
741 @since version 1.0.0 1412#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT)
742 */ 1413 #undef JSON_HEDLEY_WARN_UNUSED_RESULT
743 enum class value_t : uint8_t 1414#endif
744 { 1415#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG)
745 null, ///< null value 1416 #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG
746 object, ///< object (unordered set of name/value pairs) 1417#endif
747 array, ///< array (ordered collection of values) 1418#if \
748 string, ///< string value 1419 JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \
749 boolean, ///< boolean value 1420 JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
750 number_integer, ///< number value (signed integer) 1421 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
751 number_unsigned, ///< number value (unsigned integer) 1422 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
752 number_float, ///< number value (floating-point) 1423 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
753 discarded ///< discarded by the the parser callback function 1424 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
754 }; 1425 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1426 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1427 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1428 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1429 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1430 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1431 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1432 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1433 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \
1434 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
1435 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1436 #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
1437 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__))
1438#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L)
1439 #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
1440 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]])
1441#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard)
1442 #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
1443 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
1444#elif defined(_Check_return_) /* SAL */
1445 #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_
1446 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_
1447#else
1448 #define JSON_HEDLEY_WARN_UNUSED_RESULT
1449 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg)
1450#endif
755 1451
1452#if defined(JSON_HEDLEY_SENTINEL)
1453 #undef JSON_HEDLEY_SENTINEL
1454#endif
1455#if \
1456 JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \
1457 JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
1458 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1459 JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \
1460 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1461 #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position)))
1462#else
1463 #define JSON_HEDLEY_SENTINEL(position)
1464#endif
756 1465
757 private: 1466#if defined(JSON_HEDLEY_NO_RETURN)
1467 #undef JSON_HEDLEY_NO_RETURN
1468#endif
1469#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1470 #define JSON_HEDLEY_NO_RETURN __noreturn
1471#elif \
1472 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1473 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1474 #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))
1475#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
1476 #define JSON_HEDLEY_NO_RETURN _Noreturn
1477#elif defined(__cplusplus) && (__cplusplus >= 201103L)
1478 #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]])
1479#elif \
1480 JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \
1481 JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \
1482 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
1483 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1484 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1485 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1486 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1487 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1488 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1489 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1490 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1491 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1492 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1493 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1494 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1495 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1496 JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
1497 #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))
1498#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
1499 #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return")
1500#elif \
1501 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
1502 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1503 #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)
1504#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)
1505 #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;")
1506#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)
1507 #define JSON_HEDLEY_NO_RETURN __attribute((noreturn))
1508#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)
1509 #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)
1510#else
1511 #define JSON_HEDLEY_NO_RETURN
1512#endif
758 1513
759 /// helper for exception-safe object creation 1514#if defined(JSON_HEDLEY_NO_ESCAPE)
760 template<typename T, typename... Args> 1515 #undef JSON_HEDLEY_NO_ESCAPE
761 static T* create(Args&& ... args) 1516#endif
762 { 1517#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape)
763 AllocatorType<T> alloc; 1518 #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__))
764 auto deleter = [&](T * object) 1519#else
765 { 1520 #define JSON_HEDLEY_NO_ESCAPE
766 alloc.deallocate(object, 1); 1521#endif
767 };
768 std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
769 alloc.construct(object.get(), std::forward<Args>(args)...);
770 assert(object.get() != nullptr);
771 return object.release();
772 }
773 1522
774 //////////////////////// 1523#if defined(JSON_HEDLEY_UNREACHABLE)
775 // JSON value storage // 1524 #undef JSON_HEDLEY_UNREACHABLE
776 //////////////////////// 1525#endif
1526#if defined(JSON_HEDLEY_UNREACHABLE_RETURN)
1527 #undef JSON_HEDLEY_UNREACHABLE_RETURN
1528#endif
1529#if defined(JSON_HEDLEY_ASSUME)
1530 #undef JSON_HEDLEY_ASSUME
1531#endif
1532#if \
1533 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
1534 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1535 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1536 #define JSON_HEDLEY_ASSUME(expr) __assume(expr)
1537#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume)
1538 #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr)
1539#elif \
1540 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
1541 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)
1542 #if defined(__cplusplus)
1543 #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr)
1544 #else
1545 #define JSON_HEDLEY_ASSUME(expr) _nassert(expr)
1546 #endif
1547#endif
1548#if \
1549 (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \
1550 JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
1551 JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \
1552 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1553 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \
1554 JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \
1555 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1556 #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable()
1557#elif defined(JSON_HEDLEY_ASSUME)
1558 #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)
1559#endif
1560#if !defined(JSON_HEDLEY_ASSUME)
1561 #if defined(JSON_HEDLEY_UNREACHABLE)
1562 #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1)))
1563 #else
1564 #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr)
1565 #endif
1566#endif
1567#if defined(JSON_HEDLEY_UNREACHABLE)
1568 #if \
1569 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
1570 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)
1571 #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value))
1572 #else
1573 #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE()
1574 #endif
1575#else
1576 #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value)
1577#endif
1578#if !defined(JSON_HEDLEY_UNREACHABLE)
1579 #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)
1580#endif
777 1581
778 /*! 1582JSON_HEDLEY_DIAGNOSTIC_PUSH
779 @brief a JSON value 1583#if JSON_HEDLEY_HAS_WARNING("-Wpedantic")
1584 #pragma clang diagnostic ignored "-Wpedantic"
1585#endif
1586#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus)
1587 #pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
1588#endif
1589#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0)
1590 #if defined(__clang__)
1591 #pragma clang diagnostic ignored "-Wvariadic-macros"
1592 #elif defined(JSON_HEDLEY_GCC_VERSION)
1593 #pragma GCC diagnostic ignored "-Wvariadic-macros"
1594 #endif
1595#endif
1596#if defined(JSON_HEDLEY_NON_NULL)
1597 #undef JSON_HEDLEY_NON_NULL
1598#endif
1599#if \
1600 JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \
1601 JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
1602 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1603 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)
1604 #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__)))
1605#else
1606 #define JSON_HEDLEY_NON_NULL(...)
1607#endif
1608JSON_HEDLEY_DIAGNOSTIC_POP
780 1609
781 The actual storage for a JSON value of the @ref basic_json class. This 1610#if defined(JSON_HEDLEY_PRINTF_FORMAT)
782 union combines the different storage types for the JSON value types 1611 #undef JSON_HEDLEY_PRINTF_FORMAT
783 defined in @ref value_t. 1612#endif
1613#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO)
1614 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check)))
1615#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO)
1616 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check)))
1617#elif \
1618 JSON_HEDLEY_HAS_ATTRIBUTE(format) || \
1619 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
1620 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1621 JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \
1622 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1623 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1624 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1625 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1626 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1627 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1628 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1629 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1630 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1631 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1632 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1633 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1634 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1635 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check)))
1636#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0)
1637 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check))
1638#else
1639 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check)
1640#endif
784 1641
785 JSON type | value_t type | used type 1642#if defined(JSON_HEDLEY_CONSTEXPR)
786 --------- | --------------- | ------------------------ 1643 #undef JSON_HEDLEY_CONSTEXPR
787 object | object | pointer to @ref object_t 1644#endif
788 array | array | pointer to @ref array_t 1645#if defined(__cplusplus)
789 string | string | pointer to @ref string_t 1646 #if __cplusplus >= 201103L
790 boolean | boolean | @ref boolean_t 1647 #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr)
791 number | number_integer | @ref number_integer_t 1648 #endif
792 number | number_unsigned | @ref number_unsigned_t 1649#endif
793 number | number_float | @ref number_float_t 1650#if !defined(JSON_HEDLEY_CONSTEXPR)
794 null | null | *no value is stored* 1651 #define JSON_HEDLEY_CONSTEXPR
1652#endif
795 1653
796 @note Variable-length types (objects, arrays, and strings) are stored as 1654#if defined(JSON_HEDLEY_PREDICT)
797 pointers. The size of the union should not exceed 64 bits if the default 1655 #undef JSON_HEDLEY_PREDICT
798 value types are used. 1656#endif
1657#if defined(JSON_HEDLEY_LIKELY)
1658 #undef JSON_HEDLEY_LIKELY
1659#endif
1660#if defined(JSON_HEDLEY_UNLIKELY)
1661 #undef JSON_HEDLEY_UNLIKELY
1662#endif
1663#if defined(JSON_HEDLEY_UNPREDICTABLE)
1664 #undef JSON_HEDLEY_UNPREDICTABLE
1665#endif
1666#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable)
1667 #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr))
1668#endif
1669#if \
1670 (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \
1671 JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \
1672 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1673# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability))
1674# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability))
1675# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability))
1676# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 )
1677# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 )
1678#elif \
1679 (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \
1680 JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
1681 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1682 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \
1683 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1684 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1685 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1686 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \
1687 JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \
1688 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \
1689 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
1690 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1691 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1692 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \
1693 JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
1694 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1695# define JSON_HEDLEY_PREDICT(expr, expected, probability) \
1696 (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)))
1697# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \
1698 (__extension__ ({ \
1699 double hedley_probability_ = (probability); \
1700 ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \
1701 }))
1702# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \
1703 (__extension__ ({ \
1704 double hedley_probability_ = (probability); \
1705 ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \
1706 }))
1707# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1)
1708# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0)
1709#else
1710# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))
1711# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr))
1712# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr))
1713# define JSON_HEDLEY_LIKELY(expr) (!!(expr))
1714# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr))
1715#endif
1716#if !defined(JSON_HEDLEY_UNPREDICTABLE)
1717 #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5)
1718#endif
799 1719
800 @since version 1.0.0 1720#if defined(JSON_HEDLEY_MALLOC)
801 */ 1721 #undef JSON_HEDLEY_MALLOC
802 union json_value 1722#endif
803 { 1723#if \
804 /// object (stored with pointer to save storage) 1724 JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \
805 object_t* object; 1725 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
806 /// array (stored with pointer to save storage) 1726 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
807 array_t* array; 1727 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
808 /// string (stored with pointer to save storage) 1728 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
809 string_t* string; 1729 JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \
810 /// boolean 1730 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
811 boolean_t boolean; 1731 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
812 /// number (integer) 1732 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
813 number_integer_t number_integer; 1733 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
814 /// number (unsigned integer) 1734 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
815 number_unsigned_t number_unsigned; 1735 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
816 /// number (floating-point) 1736 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
817 number_float_t number_float; 1737 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1738 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1739 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1740 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1741 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1742 #define JSON_HEDLEY_MALLOC __attribute__((__malloc__))
1743#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
1744 #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory")
1745#elif \
1746 JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
1747 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1748 #define JSON_HEDLEY_MALLOC __declspec(restrict)
1749#else
1750 #define JSON_HEDLEY_MALLOC
1751#endif
818 1752
819 /// default constructor (for null values) 1753#if defined(JSON_HEDLEY_PURE)
820 json_value() = default; 1754 #undef JSON_HEDLEY_PURE
821 /// constructor for booleans 1755#endif
822 json_value(boolean_t v) noexcept : boolean(v) {} 1756#if \
823 /// constructor for numbers (integer) 1757 JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \
824 json_value(number_integer_t v) noexcept : number_integer(v) {} 1758 JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \
825 /// constructor for numbers (unsigned) 1759 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
826 json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} 1760 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
827 /// constructor for numbers (floating-point) 1761 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
828 json_value(number_float_t v) noexcept : number_float(v) {} 1762 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
829 /// constructor for empty values of a given type 1763 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
830 json_value(value_t t) 1764 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
831 { 1765 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
832 switch (t) 1766 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
833 { 1767 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
834 case value_t::object: 1768 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
835 { 1769 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
836 object = create<object_t>(); 1770 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
837 break; 1771 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
838 } 1772 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1773 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1774 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
1775 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1776# define JSON_HEDLEY_PURE __attribute__((__pure__))
1777#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
1778# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data")
1779#elif defined(__cplusplus) && \
1780 ( \
1781 JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \
1782 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \
1783 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \
1784 )
1785# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;")
1786#else
1787# define JSON_HEDLEY_PURE
1788#endif
839 1789
840 case value_t::array: 1790#if defined(JSON_HEDLEY_CONST)
841 { 1791 #undef JSON_HEDLEY_CONST
842 array = create<array_t>(); 1792#endif
843 break; 1793#if \
844 } 1794 JSON_HEDLEY_HAS_ATTRIBUTE(const) || \
1795 JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \
1796 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1797 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
1798 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1799 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1800 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1801 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1802 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1803 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1804 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1805 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1806 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1807 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1808 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1809 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1810 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1811 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
1812 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1813 #define JSON_HEDLEY_CONST __attribute__((__const__))
1814#elif \
1815 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
1816 #define JSON_HEDLEY_CONST _Pragma("no_side_effect")
1817#else
1818 #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE
1819#endif
845 1820
846 case value_t::string: 1821#if defined(JSON_HEDLEY_RESTRICT)
847 { 1822 #undef JSON_HEDLEY_RESTRICT
848 string = create<string_t>(""); 1823#endif
849 break; 1824#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus)
850 } 1825 #define JSON_HEDLEY_RESTRICT restrict
1826#elif \
1827 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
1828 JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
1829 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1830 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
1831 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1832 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1833 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
1834 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1835 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \
1836 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \
1837 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1838 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \
1839 JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
1840 defined(__clang__) || \
1841 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1842 #define JSON_HEDLEY_RESTRICT __restrict
1843#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus)
1844 #define JSON_HEDLEY_RESTRICT _Restrict
1845#else
1846 #define JSON_HEDLEY_RESTRICT
1847#endif
851 1848
852 case value_t::boolean: 1849#if defined(JSON_HEDLEY_INLINE)
853 { 1850 #undef JSON_HEDLEY_INLINE
854 boolean = boolean_t(false); 1851#endif
855 break; 1852#if \
856 } 1853 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
1854 (defined(__cplusplus) && (__cplusplus >= 199711L))
1855 #define JSON_HEDLEY_INLINE inline
1856#elif \
1857 defined(JSON_HEDLEY_GCC_VERSION) || \
1858 JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0)
1859 #define JSON_HEDLEY_INLINE __inline__
1860#elif \
1861 JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \
1862 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
1863 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1864 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \
1865 JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \
1866 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
1867 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \
1868 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1869 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1870 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1871 #define JSON_HEDLEY_INLINE __inline
1872#else
1873 #define JSON_HEDLEY_INLINE
1874#endif
857 1875
858 case value_t::number_integer: 1876#if defined(JSON_HEDLEY_ALWAYS_INLINE)
859 { 1877 #undef JSON_HEDLEY_ALWAYS_INLINE
860 number_integer = number_integer_t(0); 1878#endif
861 break; 1879#if \
862 } 1880 JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \
1881 JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
1882 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1883 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
1884 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1885 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1886 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1887 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1888 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1889 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1890 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1891 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1892 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1893 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1894 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1895 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1896 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1897 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
1898 JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
1899# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE
1900#elif \
1901 JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \
1902 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1903# define JSON_HEDLEY_ALWAYS_INLINE __forceinline
1904#elif defined(__cplusplus) && \
1905 ( \
1906 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1907 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1908 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1909 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
1910 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1911 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \
1912 )
1913# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;")
1914#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1915# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced")
1916#else
1917# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE
1918#endif
863 1919
864 case value_t::number_unsigned: 1920#if defined(JSON_HEDLEY_NEVER_INLINE)
865 { 1921 #undef JSON_HEDLEY_NEVER_INLINE
866 number_unsigned = number_unsigned_t(0); 1922#endif
867 break; 1923#if \
868 } 1924 JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \
1925 JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
1926 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1927 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
1928 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1929 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1930 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1931 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1932 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1933 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1934 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1935 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1936 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1937 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1938 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1939 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1940 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1941 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
1942 JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
1943 #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__))
1944#elif \
1945 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
1946 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1947 #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)
1948#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0)
1949 #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline")
1950#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)
1951 #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
1952#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1953 #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never")
1954#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)
1955 #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline))
1956#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)
1957 #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)
1958#else
1959 #define JSON_HEDLEY_NEVER_INLINE
1960#endif
869 1961
870 case value_t::number_float: 1962#if defined(JSON_HEDLEY_PRIVATE)
871 { 1963 #undef JSON_HEDLEY_PRIVATE
872 number_float = number_float_t(0.0); 1964#endif
873 break; 1965#if defined(JSON_HEDLEY_PUBLIC)
874 } 1966 #undef JSON_HEDLEY_PUBLIC
1967#endif
1968#if defined(JSON_HEDLEY_IMPORT)
1969 #undef JSON_HEDLEY_IMPORT
1970#endif
1971#if defined(_WIN32) || defined(__CYGWIN__)
1972# define JSON_HEDLEY_PRIVATE
1973# define JSON_HEDLEY_PUBLIC __declspec(dllexport)
1974# define JSON_HEDLEY_IMPORT __declspec(dllimport)
1975#else
1976# if \
1977 JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \
1978 JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
1979 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
1980 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1981 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1982 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
1983 ( \
1984 defined(__TI_EABI__) && \
1985 ( \
1986 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1987 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \
1988 ) \
1989 ) || \
1990 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1991# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden")))
1992# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default")))
1993# else
1994# define JSON_HEDLEY_PRIVATE
1995# define JSON_HEDLEY_PUBLIC
1996# endif
1997# define JSON_HEDLEY_IMPORT extern
1998#endif
875 1999
876 default: 2000#if defined(JSON_HEDLEY_NO_THROW)
877 { 2001 #undef JSON_HEDLEY_NO_THROW
878 break; 2002#endif
879 } 2003#if \
880 } 2004 JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \
881 } 2005 JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
2006 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
2007 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
2008 #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__))
2009#elif \
2010 JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \
2011 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
2012 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)
2013 #define JSON_HEDLEY_NO_THROW __declspec(nothrow)
2014#else
2015 #define JSON_HEDLEY_NO_THROW
2016#endif
882 2017
883 /// constructor for strings 2018#if defined(JSON_HEDLEY_FALL_THROUGH)
884 json_value(const string_t& value) 2019 #undef JSON_HEDLEY_FALL_THROUGH
885 { 2020#endif
886 string = create<string_t>(value); 2021#if \
887 } 2022 JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \
2023 JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \
2024 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
2025 #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__))
2026#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough)
2027 #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]])
2028#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)
2029 #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]])
2030#elif defined(__fallthrough) /* SAL */
2031 #define JSON_HEDLEY_FALL_THROUGH __fallthrough
2032#else
2033 #define JSON_HEDLEY_FALL_THROUGH
2034#endif
888 2035
889 /// constructor for objects 2036#if defined(JSON_HEDLEY_RETURNS_NON_NULL)
890 json_value(const object_t& value) 2037 #undef JSON_HEDLEY_RETURNS_NON_NULL
891 { 2038#endif
892 object = create<object_t>(value); 2039#if \
893 } 2040 JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \
2041 JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \
2042 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
2043 #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__))
2044#elif defined(_Ret_notnull_) /* SAL */
2045 #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_
2046#else
2047 #define JSON_HEDLEY_RETURNS_NON_NULL
2048#endif
894 2049
895 /// constructor for arrays 2050#if defined(JSON_HEDLEY_ARRAY_PARAM)
896 json_value(const array_t& value) 2051 #undef JSON_HEDLEY_ARRAY_PARAM
897 { 2052#endif
898 array = create<array_t>(value); 2053#if \
899 } 2054 defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
900 }; 2055 !defined(__STDC_NO_VLA__) && \
2056 !defined(__cplusplus) && \
2057 !defined(JSON_HEDLEY_PGI_VERSION) && \
2058 !defined(JSON_HEDLEY_TINYC_VERSION)
2059 #define JSON_HEDLEY_ARRAY_PARAM(name) (name)
2060#else
2061 #define JSON_HEDLEY_ARRAY_PARAM(name)
2062#endif
901 2063
902 /*! 2064#if defined(JSON_HEDLEY_IS_CONSTANT)
903 @brief checks the class invariants 2065 #undef JSON_HEDLEY_IS_CONSTANT
2066#endif
2067#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR)
2068 #undef JSON_HEDLEY_REQUIRE_CONSTEXPR
2069#endif
2070/* JSON_HEDLEY_IS_CONSTEXPR_ is for
2071 HEDLEY INTERNAL USE ONLY. API subject to change without notice. */
2072#if defined(JSON_HEDLEY_IS_CONSTEXPR_)
2073 #undef JSON_HEDLEY_IS_CONSTEXPR_
2074#endif
2075#if \
2076 JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \
2077 JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
2078 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
2079 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \
2080 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
2081 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
2082 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
2083 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \
2084 JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
2085 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
2086 #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr)
2087#endif
2088#if !defined(__cplusplus)
2089# if \
2090 JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \
2091 JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
2092 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
2093 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
2094 JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
2095 JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \
2096 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24)
2097#if defined(__INTPTR_TYPE__)
2098 #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*)
2099#else
2100 #include <stdint.h>
2101 #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*)
2102#endif
2103# elif \
2104 ( \
2105 defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \
2106 !defined(JSON_HEDLEY_SUNPRO_VERSION) && \
2107 !defined(JSON_HEDLEY_PGI_VERSION) && \
2108 !defined(JSON_HEDLEY_IAR_VERSION)) || \
2109 (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \
2110 JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \
2111 JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \
2112 JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \
2113 JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0)
2114#if defined(__INTPTR_TYPE__)
2115 #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0)
2116#else
2117 #include <stdint.h>
2118 #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0)
2119#endif
2120# elif \
2121 defined(JSON_HEDLEY_GCC_VERSION) || \
2122 defined(JSON_HEDLEY_INTEL_VERSION) || \
2123 defined(JSON_HEDLEY_TINYC_VERSION) || \
2124 defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \
2125 JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \
2126 defined(JSON_HEDLEY_TI_CL2000_VERSION) || \
2127 defined(JSON_HEDLEY_TI_CL6X_VERSION) || \
2128 defined(JSON_HEDLEY_TI_CL7X_VERSION) || \
2129 defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \
2130 defined(__clang__)
2131# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \
2132 sizeof(void) != \
2133 sizeof(*( \
2134 1 ? \
2135 ((void*) ((expr) * 0L) ) : \
2136((struct { char v[sizeof(void) * 2]; } *) 1) \
2137 ) \
2138 ) \
2139 )
2140# endif
2141#endif
2142#if defined(JSON_HEDLEY_IS_CONSTEXPR_)
2143 #if !defined(JSON_HEDLEY_IS_CONSTANT)
2144 #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr)
2145 #endif
2146 #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1))
2147#else
2148 #if !defined(JSON_HEDLEY_IS_CONSTANT)
2149 #define JSON_HEDLEY_IS_CONSTANT(expr) (0)
2150 #endif
2151 #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr)
2152#endif
904 2153
905 This function asserts the class invariants. It needs to be called at the 2154#if defined(JSON_HEDLEY_BEGIN_C_DECLS)
906 end of every constructor to make sure that created objects respect the 2155 #undef JSON_HEDLEY_BEGIN_C_DECLS
907 invariant. Furthermore, it has to be called each time the type of a JSON 2156#endif
908 value is changed, because the invariant expresses a relationship between 2157#if defined(JSON_HEDLEY_END_C_DECLS)
909 @a m_type and @a m_value. 2158 #undef JSON_HEDLEY_END_C_DECLS
910 */ 2159#endif
911 void assert_invariant() const 2160#if defined(JSON_HEDLEY_C_DECL)
912 { 2161 #undef JSON_HEDLEY_C_DECL
913 assert(m_type != value_t::object or m_value.object != nullptr); 2162#endif
914 assert(m_type != value_t::array or m_value.array != nullptr); 2163#if defined(__cplusplus)
915 assert(m_type != value_t::string or m_value.string != nullptr); 2164 #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" {
916 } 2165 #define JSON_HEDLEY_END_C_DECLS }
2166 #define JSON_HEDLEY_C_DECL extern "C"
2167#else
2168 #define JSON_HEDLEY_BEGIN_C_DECLS
2169 #define JSON_HEDLEY_END_C_DECLS
2170 #define JSON_HEDLEY_C_DECL
2171#endif
917 2172
918 public: 2173#if defined(JSON_HEDLEY_STATIC_ASSERT)
919 ////////////////////////// 2174 #undef JSON_HEDLEY_STATIC_ASSERT
920 // JSON parser callback // 2175#endif
921 ////////////////////////// 2176#if \
2177 !defined(__cplusplus) && ( \
2178 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \
2179 (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \
2180 JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \
2181 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
2182 defined(_Static_assert) \
2183 )
2184# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message)
2185#elif \
2186 (defined(__cplusplus) && (__cplusplus >= 201103L)) || \
2187 JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \
2188 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
2189# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message))
2190#else
2191# define JSON_HEDLEY_STATIC_ASSERT(expr, message)
2192#endif
922 2193
923 /*! 2194#if defined(JSON_HEDLEY_NULL)
924 @brief JSON callback events 2195 #undef JSON_HEDLEY_NULL
2196#endif
2197#if defined(__cplusplus)
2198 #if __cplusplus >= 201103L
2199 #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr)
2200 #elif defined(NULL)
2201 #define JSON_HEDLEY_NULL NULL
2202 #else
2203 #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0)
2204 #endif
2205#elif defined(NULL)
2206 #define JSON_HEDLEY_NULL NULL
2207#else
2208 #define JSON_HEDLEY_NULL ((void*) 0)
2209#endif
925 2210
926 This enumeration lists the parser events that can trigger calling a 2211#if defined(JSON_HEDLEY_MESSAGE)
927 callback function of type @ref parser_callback_t during parsing. 2212 #undef JSON_HEDLEY_MESSAGE
2213#endif
2214#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
2215# define JSON_HEDLEY_MESSAGE(msg) \
2216 JSON_HEDLEY_DIAGNOSTIC_PUSH \
2217 JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
2218 JSON_HEDLEY_PRAGMA(message msg) \
2219 JSON_HEDLEY_DIAGNOSTIC_POP
2220#elif \
2221 JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \
2222 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
2223# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg)
2224#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0)
2225# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg)
2226#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
2227# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))
2228#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0)
2229# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))
2230#else
2231# define JSON_HEDLEY_MESSAGE(msg)
2232#endif
928 2233
929 @image html callback_events.png "Example when certain parse events are triggered" 2234#if defined(JSON_HEDLEY_WARNING)
2235 #undef JSON_HEDLEY_WARNING
2236#endif
2237#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
2238# define JSON_HEDLEY_WARNING(msg) \
2239 JSON_HEDLEY_DIAGNOSTIC_PUSH \
2240 JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
2241 JSON_HEDLEY_PRAGMA(clang warning msg) \
2242 JSON_HEDLEY_DIAGNOSTIC_POP
2243#elif \
2244 JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \
2245 JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
2246 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
2247# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg)
2248#elif \
2249 JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \
2250 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
2251# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg))
2252#else
2253# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg)
2254#endif
930 2255
931 @since version 1.0.0 2256#if defined(JSON_HEDLEY_REQUIRE)
932 */ 2257 #undef JSON_HEDLEY_REQUIRE
933 enum class parse_event_t : uint8_t 2258#endif
934 { 2259#if defined(JSON_HEDLEY_REQUIRE_MSG)
935 /// the parser read `{` and started to process a JSON object 2260 #undef JSON_HEDLEY_REQUIRE_MSG
936 object_start, 2261#endif
937 /// the parser read `}` and finished processing a JSON object 2262#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if)
938 object_end, 2263# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat")
939 /// the parser read `[` and started to process a JSON array 2264# define JSON_HEDLEY_REQUIRE(expr) \
940 array_start, 2265 JSON_HEDLEY_DIAGNOSTIC_PUSH \
941 /// the parser read `]` and finished processing a JSON array 2266 _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
942 array_end, 2267 __attribute__((diagnose_if(!(expr), #expr, "error"))) \
943 /// the parser read a key of a value in an object 2268 JSON_HEDLEY_DIAGNOSTIC_POP
944 key, 2269# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \
945 /// the parser finished reading a JSON value 2270 JSON_HEDLEY_DIAGNOSTIC_PUSH \
946 value 2271 _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
947 }; 2272 __attribute__((diagnose_if(!(expr), msg, "error"))) \
2273 JSON_HEDLEY_DIAGNOSTIC_POP
2274# else
2275# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error")))
2276# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error")))
2277# endif
2278#else
2279# define JSON_HEDLEY_REQUIRE(expr)
2280# define JSON_HEDLEY_REQUIRE_MSG(expr,msg)
2281#endif
948 2282
949 /*! 2283#if defined(JSON_HEDLEY_FLAGS)
950 @brief per-element parser callback type 2284 #undef JSON_HEDLEY_FLAGS
2285#endif
2286#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion"))
2287 #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__))
2288#else
2289 #define JSON_HEDLEY_FLAGS
2290#endif
951 2291
952 With a parser callback function, the result of parsing a JSON text can be 2292#if defined(JSON_HEDLEY_FLAGS_CAST)
953 influenced. When passed to @ref parse(std::istream&, const 2293 #undef JSON_HEDLEY_FLAGS_CAST
954 parser_callback_t) or @ref parse(const CharT, const parser_callback_t), 2294#endif
955 it is called on certain events (passed as @ref parse_event_t via parameter 2295#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0)
956 @a event) with a set recursion depth @a depth and context JSON value 2296# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \
957 @a parsed. The return value of the callback function is a boolean 2297 JSON_HEDLEY_DIAGNOSTIC_PUSH \
958 indicating whether the element that emitted the callback shall be kept or 2298 _Pragma("warning(disable:188)") \
959 not. 2299 ((T) (expr)); \
2300 JSON_HEDLEY_DIAGNOSTIC_POP \
2301 }))
2302#else
2303# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr)
2304#endif
960 2305
961 We distinguish six scenarios (determined by the event type) in which the 2306#if defined(JSON_HEDLEY_EMPTY_BASES)
962 callback function can be called. The following table describes the values 2307 #undef JSON_HEDLEY_EMPTY_BASES
963 of the parameters @a depth, @a event, and @a parsed. 2308#endif
2309#if \
2310 (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \
2311 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
2312 #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases)
2313#else
2314 #define JSON_HEDLEY_EMPTY_BASES
2315#endif
964 2316
965 parameter @a event | description | parameter @a depth | parameter @a parsed 2317/* Remaining macros are deprecated. */
966 ------------------ | ----------- | ------------------ | -------------------
967 parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded
968 parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key
969 parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object
970 parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded
971 parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array
972 parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value
973 2318
974 @image html callback_events.png "Example when certain parse events are triggered" 2319#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK)
2320 #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK
2321#endif
2322#if defined(__clang__)
2323 #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0)
2324#else
2325 #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
2326#endif
975 2327
976 Discarding a value (i.e., returning `false`) has different effects 2328#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE)
977 depending on the context in which function was called: 2329 #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
2330#endif
2331#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
978 2332
979 - Discarded values in structured types are skipped. That is, the parser 2333#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE)
980 will behave as if the discarded value was never read. 2334 #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
981 - In case a value outside a structured type is skipped, it is replaced 2335#endif
982 with `null`. This case happens if the top-level element is skipped. 2336#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute)
983 2337
984 @param[in] depth the depth of the recursion during parsing 2338#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN)
2339 #undef JSON_HEDLEY_CLANG_HAS_BUILTIN
2340#endif
2341#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin)
985 2342
986 @param[in] event an event of type parse_event_t indicating the context in 2343#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE)
987 the callback function has been called 2344 #undef JSON_HEDLEY_CLANG_HAS_FEATURE
2345#endif
2346#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature)
988 2347
989 @param[in,out] parsed the current intermediate parse result; note that 2348#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION)
990 writing to this value has no effect for parse_event_t::key events 2349 #undef JSON_HEDLEY_CLANG_HAS_EXTENSION
2350#endif
2351#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension)
991 2352
992 @return Whether the JSON value which called the function during parsing 2353#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE)
993 should be kept (`true`) or not (`false`). In the latter case, it is either 2354 #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
994 skipped completely or replaced by an empty discarded object. 2355#endif
2356#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute)
995 2357
996 @sa @ref parse(std::istream&, parser_callback_t) or 2358#if defined(JSON_HEDLEY_CLANG_HAS_WARNING)
997 @ref parse(const CharT, const parser_callback_t) for examples 2359 #undef JSON_HEDLEY_CLANG_HAS_WARNING
2360#endif
2361#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning)
998 2362
999 @since version 1.0.0 2363#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */
1000 */
1001 using parser_callback_t = std::function<bool(int depth,
1002 parse_event_t event,
1003 basic_json& parsed)>;
1004 2364
1005 2365
1006 ////////////////// 2366// This file contains all internal macro definitions (except those affecting ABI)
1007 // constructors // 2367// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
1008 //////////////////
1009 2368
1010 /// @name constructors and destructors 2369// #include <nlohmann/detail/abi_macros.hpp>
1011 /// Constructors of class @ref basic_json, copy/move constructor, copy
1012 /// assignment, static functions creating objects, and the destructor.
1013 /// @{
1014 2370
1015 /*!
1016 @brief create an empty value with a given type
1017 2371
1018 Create an empty JSON value with a given type. The value will be default 2372// exclude unsupported compilers
1019 initialized with an empty value which depends on the type: 2373#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)
2374 #if defined(__clang__)
2375 #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
2376 #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
2377 #endif
2378 #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
2379 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800
2380 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
2381 #endif
2382 #endif
2383#endif
1020 2384
1021 Value type | initial value 2385// C++ language standard detection
1022 ----------- | ------------- 2386// if the user manually specified the used c++ version this is skipped
1023 null | `null` 2387#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11)
1024 boolean | `false` 2388 #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
1025 string | `""` 2389 #define JSON_HAS_CPP_20
1026 number | `0` 2390 #define JSON_HAS_CPP_17
1027 object | `{}` 2391 #define JSON_HAS_CPP_14
1028 array | `[]` 2392 #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
2393 #define JSON_HAS_CPP_17
2394 #define JSON_HAS_CPP_14
2395 #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
2396 #define JSON_HAS_CPP_14
2397 #endif
2398 // the cpp 11 flag is always specified because it is the minimal required version
2399 #define JSON_HAS_CPP_11
2400#endif
1029 2401
1030 @param[in] value_type the type of the value to create 2402#ifdef __has_include
2403 #if __has_include(<version>)
2404 #include <version>
2405 #endif
2406#endif
1031 2407
1032 @complexity Constant. 2408#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM)
2409 #ifdef JSON_HAS_CPP_17
2410 #if defined(__cpp_lib_filesystem)
2411 #define JSON_HAS_FILESYSTEM 1
2412 #elif defined(__cpp_lib_experimental_filesystem)
2413 #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
2414 #elif !defined(__has_include)
2415 #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
2416 #elif __has_include(<filesystem>)
2417 #define JSON_HAS_FILESYSTEM 1
2418 #elif __has_include(<experimental/filesystem>)
2419 #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
2420 #endif
2421
2422 // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/
2423 #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8
2424 #undef JSON_HAS_FILESYSTEM
2425 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
2426 #endif
2427
2428 // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support
2429 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8
2430 #undef JSON_HAS_FILESYSTEM
2431 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
2432 #endif
2433
2434 // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support
2435 #if defined(__clang_major__) && __clang_major__ < 7
2436 #undef JSON_HAS_FILESYSTEM
2437 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
2438 #endif
2439
2440 // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support
2441 #if defined(_MSC_VER) && _MSC_VER < 1914
2442 #undef JSON_HAS_FILESYSTEM
2443 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
2444 #endif
2445
2446 // no filesystem support before iOS 13
2447 #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000
2448 #undef JSON_HAS_FILESYSTEM
2449 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
2450 #endif
2451
2452 // no filesystem support before macOS Catalina
2453 #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
2454 #undef JSON_HAS_FILESYSTEM
2455 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
2456 #endif
2457 #endif
2458#endif
1033 2459
1034 @throw std::bad_alloc if allocation for object, array, or string value 2460#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM
1035 fails 2461 #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0
2462#endif
1036 2463
1037 @liveexample{The following code shows the constructor for different @ref 2464#ifndef JSON_HAS_FILESYSTEM
1038 value_t values,basic_json__value_t} 2465 #define JSON_HAS_FILESYSTEM 0
2466#endif
1039 2467
1040 @sa @ref basic_json(std::nullptr_t) -- create a `null` value 2468#ifndef JSON_HAS_THREE_WAY_COMPARISON
1041 @sa @ref basic_json(boolean_t value) -- create a boolean value 2469 #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \
1042 @sa @ref basic_json(const string_t&) -- create a string value 2470 && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L
1043 @sa @ref basic_json(const object_t&) -- create a object value 2471 #define JSON_HAS_THREE_WAY_COMPARISON 1
1044 @sa @ref basic_json(const array_t&) -- create a array value 2472 #else
1045 @sa @ref basic_json(const number_float_t) -- create a number 2473 #define JSON_HAS_THREE_WAY_COMPARISON 0
1046 (floating-point) value 2474 #endif
1047 @sa @ref basic_json(const number_integer_t) -- create a number (integer) 2475#endif
1048 value
1049 @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned)
1050 value
1051 2476
1052 @since version 1.0.0 2477#ifndef JSON_HAS_RANGES
1053 */ 2478 // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error
1054 basic_json(const value_t value_type) 2479 #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427
1055 : m_type(value_type), m_value(value_type) 2480 #define JSON_HAS_RANGES 0
1056 { 2481 #elif defined(__cpp_lib_ranges)
1057 assert_invariant(); 2482 #define JSON_HAS_RANGES 1
1058 } 2483 #else
2484 #define JSON_HAS_RANGES 0
2485 #endif
2486#endif
1059 2487
1060 /*! 2488#ifndef JSON_HAS_STATIC_RTTI
1061 @brief create a null object 2489 #if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0
2490 #define JSON_HAS_STATIC_RTTI 1
2491 #else
2492 #define JSON_HAS_STATIC_RTTI 0
2493 #endif
2494#endif
1062 2495
1063 Create a `null` JSON value. It either takes a null pointer as parameter 2496#ifdef JSON_HAS_CPP_17
1064 (explicitly creating `null`) or no parameter (implicitly creating `null`). 2497 #define JSON_INLINE_VARIABLE inline
1065 The passed null pointer itself is not read -- it is only used to choose 2498#else
1066 the right constructor. 2499 #define JSON_INLINE_VARIABLE
2500#endif
1067 2501
1068 @complexity Constant. 2502#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address)
2503 #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]]
2504#else
2505 #define JSON_NO_UNIQUE_ADDRESS
2506#endif
1069 2507
1070 @exceptionsafety No-throw guarantee: this constructor never throws 2508// disable documentation warnings on clang
1071 exceptions. 2509#if defined(__clang__)
2510 #pragma clang diagnostic push
2511 #pragma clang diagnostic ignored "-Wdocumentation"
2512 #pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
2513#endif
1072 2514
1073 @liveexample{The following code shows the constructor with and without a 2515// allow disabling exceptions
1074 null pointer parameter.,basic_json__nullptr_t} 2516#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
2517 #define JSON_THROW(exception) throw exception
2518 #define JSON_TRY try
2519 #define JSON_CATCH(exception) catch(exception)
2520 #define JSON_INTERNAL_CATCH(exception) catch(exception)
2521#else
2522 #include <cstdlib>
2523 #define JSON_THROW(exception) std::abort()
2524 #define JSON_TRY if(true)
2525 #define JSON_CATCH(exception) if(false)
2526 #define JSON_INTERNAL_CATCH(exception) if(false)
2527#endif
1075 2528
1076 @since version 1.0.0 2529// override exception macros
1077 */ 2530#if defined(JSON_THROW_USER)
1078 basic_json(std::nullptr_t = nullptr) noexcept 2531 #undef JSON_THROW
1079 : basic_json(value_t::null) 2532 #define JSON_THROW JSON_THROW_USER
1080 { 2533#endif
1081 assert_invariant(); 2534#if defined(JSON_TRY_USER)
1082 } 2535 #undef JSON_TRY
2536 #define JSON_TRY JSON_TRY_USER
2537#endif
2538#if defined(JSON_CATCH_USER)
2539 #undef JSON_CATCH
2540 #define JSON_CATCH JSON_CATCH_USER
2541 #undef JSON_INTERNAL_CATCH
2542 #define JSON_INTERNAL_CATCH JSON_CATCH_USER
2543#endif
2544#if defined(JSON_INTERNAL_CATCH_USER)
2545 #undef JSON_INTERNAL_CATCH
2546 #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
2547#endif
1083 2548
1084 /*! 2549// allow overriding assert
1085 @brief create an object (explicit) 2550#if !defined(JSON_ASSERT)
2551 #include <cassert> // assert
2552 #define JSON_ASSERT(x) assert(x)
2553#endif
1086 2554
1087 Create an object JSON value with a given content. 2555// allow to access some private functions (needed by the test suite)
2556#if defined(JSON_TESTS_PRIVATE)
2557 #define JSON_PRIVATE_UNLESS_TESTED public
2558#else
2559 #define JSON_PRIVATE_UNLESS_TESTED private
2560#endif
1088 2561
1089 @param[in] val a value for the object 2562/*!
2563@brief macro to briefly define a mapping between an enum and JSON
2564@def NLOHMANN_JSON_SERIALIZE_ENUM
2565@since version 3.4.0
2566*/
2567#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \
2568 template<typename BasicJsonType> \
2569 inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \
2570 { \
2571 static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
2572 static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
2573 auto it = std::find_if(std::begin(m), std::end(m), \
2574 [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
2575 { \
2576 return ej_pair.first == e; \
2577 }); \
2578 j = ((it != std::end(m)) ? it : std::begin(m))->second; \
2579 } \
2580 template<typename BasicJsonType> \
2581 inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
2582 { \
2583 static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
2584 static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
2585 auto it = std::find_if(std::begin(m), std::end(m), \
2586 [&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
2587 { \
2588 return ej_pair.second == j; \
2589 }); \
2590 e = ((it != std::end(m)) ? it : std::begin(m))->first; \
2591 }
1090 2592
1091 @complexity Linear in the size of the passed @a val. 2593// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
2594// may be removed in the future once the class is split.
2595
2596#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \
2597 template<template<typename, typename, typename...> class ObjectType, \
2598 template<typename, typename...> class ArrayType, \
2599 class StringType, class BooleanType, class NumberIntegerType, \
2600 class NumberUnsignedType, class NumberFloatType, \
2601 template<typename> class AllocatorType, \
2602 template<typename, typename = void> class JSONSerializer, \
2603 class BinaryType, \
2604 class CustomBaseClass>
2605
2606#define NLOHMANN_BASIC_JSON_TPL \
2607 basic_json<ObjectType, ArrayType, StringType, BooleanType, \
2608 NumberIntegerType, NumberUnsignedType, NumberFloatType, \
2609 AllocatorType, JSONSerializer, BinaryType, CustomBaseClass>
2610
2611// Macros to simplify conversion from/to types
2612
2613#define NLOHMANN_JSON_EXPAND( x ) x
2614#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME
2615#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \
2616 NLOHMANN_JSON_PASTE64, \
2617 NLOHMANN_JSON_PASTE63, \
2618 NLOHMANN_JSON_PASTE62, \
2619 NLOHMANN_JSON_PASTE61, \
2620 NLOHMANN_JSON_PASTE60, \
2621 NLOHMANN_JSON_PASTE59, \
2622 NLOHMANN_JSON_PASTE58, \
2623 NLOHMANN_JSON_PASTE57, \
2624 NLOHMANN_JSON_PASTE56, \
2625 NLOHMANN_JSON_PASTE55, \
2626 NLOHMANN_JSON_PASTE54, \
2627 NLOHMANN_JSON_PASTE53, \
2628 NLOHMANN_JSON_PASTE52, \
2629 NLOHMANN_JSON_PASTE51, \
2630 NLOHMANN_JSON_PASTE50, \
2631 NLOHMANN_JSON_PASTE49, \
2632 NLOHMANN_JSON_PASTE48, \
2633 NLOHMANN_JSON_PASTE47, \
2634 NLOHMANN_JSON_PASTE46, \
2635 NLOHMANN_JSON_PASTE45, \
2636 NLOHMANN_JSON_PASTE44, \
2637 NLOHMANN_JSON_PASTE43, \
2638 NLOHMANN_JSON_PASTE42, \
2639 NLOHMANN_JSON_PASTE41, \
2640 NLOHMANN_JSON_PASTE40, \
2641 NLOHMANN_JSON_PASTE39, \
2642 NLOHMANN_JSON_PASTE38, \
2643 NLOHMANN_JSON_PASTE37, \
2644 NLOHMANN_JSON_PASTE36, \
2645 NLOHMANN_JSON_PASTE35, \
2646 NLOHMANN_JSON_PASTE34, \
2647 NLOHMANN_JSON_PASTE33, \
2648 NLOHMANN_JSON_PASTE32, \
2649 NLOHMANN_JSON_PASTE31, \
2650 NLOHMANN_JSON_PASTE30, \
2651 NLOHMANN_JSON_PASTE29, \
2652 NLOHMANN_JSON_PASTE28, \
2653 NLOHMANN_JSON_PASTE27, \
2654 NLOHMANN_JSON_PASTE26, \
2655 NLOHMANN_JSON_PASTE25, \
2656 NLOHMANN_JSON_PASTE24, \
2657 NLOHMANN_JSON_PASTE23, \
2658 NLOHMANN_JSON_PASTE22, \
2659 NLOHMANN_JSON_PASTE21, \
2660 NLOHMANN_JSON_PASTE20, \
2661 NLOHMANN_JSON_PASTE19, \
2662 NLOHMANN_JSON_PASTE18, \
2663 NLOHMANN_JSON_PASTE17, \
2664 NLOHMANN_JSON_PASTE16, \
2665 NLOHMANN_JSON_PASTE15, \
2666 NLOHMANN_JSON_PASTE14, \
2667 NLOHMANN_JSON_PASTE13, \
2668 NLOHMANN_JSON_PASTE12, \
2669 NLOHMANN_JSON_PASTE11, \
2670 NLOHMANN_JSON_PASTE10, \
2671 NLOHMANN_JSON_PASTE9, \
2672 NLOHMANN_JSON_PASTE8, \
2673 NLOHMANN_JSON_PASTE7, \
2674 NLOHMANN_JSON_PASTE6, \
2675 NLOHMANN_JSON_PASTE5, \
2676 NLOHMANN_JSON_PASTE4, \
2677 NLOHMANN_JSON_PASTE3, \
2678 NLOHMANN_JSON_PASTE2, \
2679 NLOHMANN_JSON_PASTE1)(__VA_ARGS__))
2680#define NLOHMANN_JSON_PASTE2(func, v1) func(v1)
2681#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2)
2682#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3)
2683#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4)
2684#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5)
2685#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6)
2686#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7)
2687#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8)
2688#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9)
2689#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10)
2690#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)
2691#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)
2692#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)
2693#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)
2694#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)
2695#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)
2696#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)
2697#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)
2698#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)
2699#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)
2700#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)
2701#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)
2702#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23)
2703#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24)
2704#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25)
2705#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26)
2706#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27)
2707#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)
2708#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29)
2709#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30)
2710#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31)
2711#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32)
2712#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33)
2713#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34)
2714#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35)
2715#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36)
2716#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37)
2717#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38)
2718#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39)
2719#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40)
2720#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41)
2721#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42)
2722#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43)
2723#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44)
2724#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45)
2725#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46)
2726#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47)
2727#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48)
2728#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49)
2729#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50)
2730#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51)
2731#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52)
2732#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53)
2733#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54)
2734#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55)
2735#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56)
2736#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57)
2737#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58)
2738#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59)
2739#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60)
2740#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61)
2741#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62)
2742#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63)
2743
2744#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1;
2745#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1);
2746#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1);
1092 2747
1093 @throw std::bad_alloc if allocation for object value fails 2748/*!
2749@brief macro
2750@def NLOHMANN_DEFINE_TYPE_INTRUSIVE
2751@since version 3.9.0
2752*/
2753#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \
2754 friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
2755 friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
1094 2756
1095 @liveexample{The following code shows the constructor with an @ref 2757#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \
1096 object_t parameter.,basic_json__object_t} 2758 friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
2759 friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
1097 2760
1098 @sa @ref basic_json(const CompatibleObjectType&) -- create an object value 2761#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
1099 from a compatible STL container 2762 friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
1100 2763
1101 @since version 1.0.0 2764/*!
1102 */ 2765@brief macro
1103 basic_json(const object_t& val) 2766@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
1104 : m_type(value_t::object), m_value(val) 2767@since version 3.9.0
1105 { 2768*/
1106 assert_invariant(); 2769#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \
2770 inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
2771 inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
2772
2773#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
2774 inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
2775
2776#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \
2777 inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
2778 inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
2779
2780// inspired from https://stackoverflow.com/a/26745591
2781// allows to call any std function as if (e.g. with begin):
2782// using std::begin; begin(x);
2783//
2784// it allows using the detected idiom to retrieve the return type
2785// of such an expression
2786#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \
2787 namespace detail { \
2788 using std::std_name; \
2789 \
2790 template<typename... T> \
2791 using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
2792 } \
2793 \
2794 namespace detail2 { \
2795 struct std_name##_tag \
2796 { \
2797 }; \
2798 \
2799 template<typename... T> \
2800 std_name##_tag std_name(T&&...); \
2801 \
2802 template<typename... T> \
2803 using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
2804 \
2805 template<typename... T> \
2806 struct would_call_std_##std_name \
2807 { \
2808 static constexpr auto const value = ::nlohmann::detail:: \
2809 is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \
2810 }; \
2811 } /* namespace detail2 */ \
2812 \
2813 template<typename... T> \
2814 struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...> \
2815 { \
1107 } 2816 }
1108 2817
1109 /*! 2818#ifndef JSON_USE_IMPLICIT_CONVERSIONS
1110 @brief create an object (implicit) 2819 #define JSON_USE_IMPLICIT_CONVERSIONS 1
2820#endif
1111 2821
1112 Create an object JSON value with a given content. This constructor allows 2822#if JSON_USE_IMPLICIT_CONVERSIONS
1113 any type @a CompatibleObjectType that can be used to construct values of 2823 #define JSON_EXPLICIT
1114 type @ref object_t. 2824#else
2825 #define JSON_EXPLICIT explicit
2826#endif
1115 2827
1116 @tparam CompatibleObjectType An object type whose `key_type` and 2828#ifndef JSON_DISABLE_ENUM_SERIALIZATION
1117 `value_type` is compatible to @ref object_t. Examples include `std::map`, 2829 #define JSON_DISABLE_ENUM_SERIALIZATION 0
1118 `std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with 2830#endif
1119 a `key_type` of `std::string`, and a `value_type` from which a @ref
1120 basic_json value can be constructed.
1121 2831
1122 @param[in] val a value for the object 2832#ifndef JSON_USE_GLOBAL_UDLS
2833 #define JSON_USE_GLOBAL_UDLS 1
2834#endif
1123 2835
1124 @complexity Linear in the size of the passed @a val. 2836#if JSON_HAS_THREE_WAY_COMPARISON
2837 #include <compare> // partial_ordering
2838#endif
1125 2839
1126 @throw std::bad_alloc if allocation for object value fails 2840NLOHMANN_JSON_NAMESPACE_BEGIN
2841namespace detail
2842{
1127 2843
1128 @liveexample{The following code shows the constructor with several 2844///////////////////////////
1129 compatible object type parameters.,basic_json__CompatibleObjectType} 2845// JSON type enumeration //
2846///////////////////////////
1130 2847
1131 @sa @ref basic_json(const object_t&) -- create an object value 2848/*!
2849@brief the JSON type enumeration
2850
2851This enumeration collects the different JSON types. It is internally used to
2852distinguish the stored values, and the functions @ref basic_json::is_null(),
2853@ref basic_json::is_object(), @ref basic_json::is_array(),
2854@ref basic_json::is_string(), @ref basic_json::is_boolean(),
2855@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),
2856@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),
2857@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and
2858@ref basic_json::is_structured() rely on it.
2859
2860@note There are three enumeration entries (number_integer, number_unsigned, and
2861number_float), because the library distinguishes these three types for numbers:
2862@ref basic_json::number_unsigned_t is used for unsigned integers,
2863@ref basic_json::number_integer_t is used for signed integers, and
2864@ref basic_json::number_float_t is used for floating-point numbers or to
2865approximate integers which do not fit in the limits of their respective type.
2866
2867@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON
2868value with the default value for a given type
1132 2869
1133 @since version 1.0.0 2870@since version 1.0.0
1134 */ 2871*/
1135 template<class CompatibleObjectType, typename std::enable_if< 2872enum class value_t : std::uint8_t
1136 std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and 2873{
1137 std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type = 0> 2874 null, ///< null value
1138 basic_json(const CompatibleObjectType& val) 2875 object, ///< object (unordered set of name/value pairs)
1139 : m_type(value_t::object) 2876 array, ///< array (ordered collection of values)
1140 { 2877 string, ///< string value
1141 using std::begin; 2878 boolean, ///< boolean value
1142 using std::end; 2879 number_integer, ///< number value (signed integer)
1143 m_value.object = create<object_t>(begin(val), end(val)); 2880 number_unsigned, ///< number value (unsigned integer)
1144 assert_invariant(); 2881 number_float, ///< number value (floating-point)
1145 } 2882 binary, ///< binary array (ordered collection of bytes)
2883 discarded ///< discarded by the parser callback function
2884};
1146 2885
1147 /*! 2886/*!
1148 @brief create an array (explicit) 2887@brief comparison operator for JSON types
1149 2888
1150 Create an array JSON value with a given content. 2889Returns an ordering that is similar to Python:
2890- order: null < boolean < number < object < array < string < binary
2891- furthermore, each type is not smaller than itself
2892- discarded values are not comparable
2893- binary is represented as a b"" string in python and directly comparable to a
2894 string; however, making a binary array directly comparable with a string would
2895 be surprising behavior in a JSON file.
1151 2896
1152 @param[in] val a value for the array 2897@since version 1.0.0
2898*/
2899#if JSON_HAS_THREE_WAY_COMPARISON
2900 inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD*
2901#else
2902 inline bool operator<(const value_t lhs, const value_t rhs) noexcept
2903#endif
2904{
2905 static constexpr std::array<std::uint8_t, 9> order = {{
2906 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,
2907 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */,
2908 6 /* binary */
2909 }
2910 };
1153 2911
1154 @complexity Linear in the size of the passed @a val. 2912 const auto l_index = static_cast<std::size_t>(lhs);
2913 const auto r_index = static_cast<std::size_t>(rhs);
2914#if JSON_HAS_THREE_WAY_COMPARISON
2915 if (l_index < order.size() && r_index < order.size())
2916 {
2917 return order[l_index] <=> order[r_index]; // *NOPAD*
2918 }
2919 return std::partial_ordering::unordered;
2920#else
2921 return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index];
2922#endif
2923}
1155 2924
1156 @throw std::bad_alloc if allocation for array value fails 2925// GCC selects the built-in operator< over an operator rewritten from
2926// a user-defined spaceship operator
2927// Clang, MSVC, and ICC select the rewritten candidate
2928// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200)
2929#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__)
2930inline bool operator<(const value_t lhs, const value_t rhs) noexcept
2931{
2932 return std::is_lt(lhs <=> rhs); // *NOPAD*
2933}
2934#endif
1157 2935
1158 @liveexample{The following code shows the constructor with an @ref array_t 2936} // namespace detail
1159 parameter.,basic_json__array_t} 2937NLOHMANN_JSON_NAMESPACE_END
1160 2938
1161 @sa @ref basic_json(const CompatibleArrayType&) -- create an array value 2939// #include <nlohmann/detail/string_escape.hpp>
1162 from a compatible STL containers 2940// __ _____ _____ _____
2941// __| | __| | | | JSON for Modern C++
2942// | | |__ | | | | | | version 3.11.3
2943// |_____|_____|_____|_|___| https://github.com/nlohmann/json
2944//
2945// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
2946// SPDX-License-Identifier: MIT
1163 2947
1164 @since version 1.0.0
1165 */
1166 basic_json(const array_t& val)
1167 : m_type(value_t::array), m_value(val)
1168 {
1169 assert_invariant();
1170 }
1171 2948
1172 /*!
1173 @brief create an array (implicit)
1174 2949
1175 Create an array JSON value with a given content. This constructor allows 2950// #include <nlohmann/detail/abi_macros.hpp>
1176 any type @a CompatibleArrayType that can be used to construct values of
1177 type @ref array_t.
1178 2951
1179 @tparam CompatibleArrayType An object type whose `value_type` is
1180 compatible to @ref array_t. Examples include `std::vector`, `std::deque`,
1181 `std::list`, `std::forward_list`, `std::array`, `std::set`,
1182 `std::unordered_set`, `std::multiset`, and `unordered_multiset` with a
1183 `value_type` from which a @ref basic_json value can be constructed.
1184 2952
1185 @param[in] val a value for the array 2953NLOHMANN_JSON_NAMESPACE_BEGIN
2954namespace detail
2955{
1186 2956
1187 @complexity Linear in the size of the passed @a val. 2957/*!
2958@brief replace all occurrences of a substring by another string
1188 2959
1189 @throw std::bad_alloc if allocation for array value fails 2960@param[in,out] s the string to manipulate; changed so that all
2961 occurrences of @a f are replaced with @a t
2962@param[in] f the substring to replace with @a t
2963@param[in] t the string to replace @a f
1190 2964
1191 @liveexample{The following code shows the constructor with several 2965@pre The search string @a f must not be empty. **This precondition is
1192 compatible array type parameters.,basic_json__CompatibleArrayType} 2966enforced with an assertion.**
1193 2967
1194 @sa @ref basic_json(const array_t&) -- create an array value 2968@since version 2.0.0
2969*/
2970template<typename StringType>
2971inline void replace_substring(StringType& s, const StringType& f,
2972 const StringType& t)
2973{
2974 JSON_ASSERT(!f.empty());
2975 for (auto pos = s.find(f); // find first occurrence of f
2976 pos != StringType::npos; // make sure f was found
2977 s.replace(pos, f.size(), t), // replace with t, and
2978 pos = s.find(f, pos + t.size())) // find next occurrence of f
2979 {}
2980}
1195 2981
1196 @since version 1.0.0 2982/*!
1197 */ 2983 * @brief string escaping as described in RFC 6901 (Sect. 4)
1198 template<class CompatibleArrayType, typename std::enable_if< 2984 * @param[in] s string to escape
1199 not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and 2985 * @return escaped string
1200 not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and 2986 *
1201 not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and 2987 * Note the order of escaping "~" to "~0" and "/" to "~1" is important.
1202 not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and 2988 */
1203 not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and 2989template<typename StringType>
1204 not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and 2990inline StringType escape(StringType s)
1205 std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type = 0> 2991{
1206 basic_json(const CompatibleArrayType& val) 2992 replace_substring(s, StringType{"~"}, StringType{"~0"});
1207 : m_type(value_t::array) 2993 replace_substring(s, StringType{"/"}, StringType{"~1"});
1208 { 2994 return s;
1209 using std::begin; 2995}
1210 using std::end;
1211 m_value.array = create<array_t>(begin(val), end(val));
1212 assert_invariant();
1213 }
1214 2996
1215 /*! 2997/*!
1216 @brief create a string (explicit) 2998 * @brief string unescaping as described in RFC 6901 (Sect. 4)
2999 * @param[in] s string to unescape
3000 * @return unescaped string
3001 *
3002 * Note the order of escaping "~1" to "/" and "~0" to "~" is important.
3003 */
3004template<typename StringType>
3005static void unescape(StringType& s)
3006{
3007 replace_substring(s, StringType{"~1"}, StringType{"/"});
3008 replace_substring(s, StringType{"~0"}, StringType{"~"});
3009}
1217 3010
1218 Create an string JSON value with a given content. 3011} // namespace detail
3012NLOHMANN_JSON_NAMESPACE_END
1219 3013
1220 @param[in] val a value for the string 3014// #include <nlohmann/detail/input/position_t.hpp>
3015// __ _____ _____ _____
3016// __| | __| | | | JSON for Modern C++
3017// | | |__ | | | | | | version 3.11.3
3018// |_____|_____|_____|_|___| https://github.com/nlohmann/json
3019//
3020// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
3021// SPDX-License-Identifier: MIT
1221 3022
1222 @complexity Linear in the size of the passed @a val.
1223 3023
1224 @throw std::bad_alloc if allocation for string value fails
1225 3024
1226 @liveexample{The following code shows the constructor with an @ref 3025#include <cstddef> // size_t
1227 string_t parameter.,basic_json__string_t}
1228 3026
1229 @sa @ref basic_json(const typename string_t::value_type*) -- create a 3027// #include <nlohmann/detail/abi_macros.hpp>
1230 string value from a character pointer
1231 @sa @ref basic_json(const CompatibleStringType&) -- create a string value
1232 from a compatible string container
1233 3028
1234 @since version 1.0.0 3029
1235 */ 3030NLOHMANN_JSON_NAMESPACE_BEGIN
1236 basic_json(const string_t& val) 3031namespace detail
1237 : m_type(value_t::string), m_value(val) 3032{
3033
3034/// struct to capture the start position of the current token
3035struct position_t
3036{
3037 /// the total number of characters read
3038 std::size_t chars_read_total = 0;
3039 /// the number of characters read in the current line
3040 std::size_t chars_read_current_line = 0;
3041 /// the number of lines read
3042 std::size_t lines_read = 0;
3043
3044 /// conversion to size_t to preserve SAX interface
3045 constexpr operator size_t() const
1238 { 3046 {
1239 assert_invariant(); 3047 return chars_read_total;
1240 } 3048 }
3049};
1241 3050
1242 /*! 3051} // namespace detail
1243 @brief create a string (explicit) 3052NLOHMANN_JSON_NAMESPACE_END
1244 3053
1245 Create a string JSON value with a given content. 3054// #include <nlohmann/detail/macro_scope.hpp>
1246 3055
1247 @param[in] val a literal value for the string 3056// #include <nlohmann/detail/meta/cpp_future.hpp>
3057// __ _____ _____ _____
3058// __| | __| | | | JSON for Modern C++
3059// | | |__ | | | | | | version 3.11.3
3060// |_____|_____|_____|_|___| https://github.com/nlohmann/json
3061//
3062// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
3063// SPDX-FileCopyrightText: 2018 The Abseil Authors
3064// SPDX-License-Identifier: MIT
1248 3065
1249 @complexity Linear in the size of the passed @a val.
1250 3066
1251 @throw std::bad_alloc if allocation for string value fails
1252 3067
1253 @liveexample{The following code shows the constructor with string literal 3068#include <array> // array
1254 parameter.,basic_json__string_t_value_type} 3069#include <cstddef> // size_t
3070#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
3071#include <utility> // index_sequence, make_index_sequence, index_sequence_for
1255 3072
1256 @sa @ref basic_json(const string_t&) -- create a string value 3073// #include <nlohmann/detail/macro_scope.hpp>
1257 @sa @ref basic_json(const CompatibleStringType&) -- create a string value
1258 from a compatible string container
1259 3074
1260 @since version 1.0.0 3075
1261 */ 3076NLOHMANN_JSON_NAMESPACE_BEGIN
1262 basic_json(const typename string_t::value_type* val) 3077namespace detail
1263 : basic_json(string_t(val)) 3078{
3079
3080template<typename T>
3081using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
3082
3083#ifdef JSON_HAS_CPP_14
3084
3085// the following utilities are natively available in C++14
3086using std::enable_if_t;
3087using std::index_sequence;
3088using std::make_index_sequence;
3089using std::index_sequence_for;
3090
3091#else
3092
3093// alias templates to reduce boilerplate
3094template<bool B, typename T = void>
3095using enable_if_t = typename std::enable_if<B, T>::type;
3096
3097// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h
3098// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0.
3099
3100//// START OF CODE FROM GOOGLE ABSEIL
3101
3102// integer_sequence
3103//
3104// Class template representing a compile-time integer sequence. An instantiation
3105// of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its
3106// type through its template arguments (which is a common need when
3107// working with C++11 variadic templates). `absl::integer_sequence` is designed
3108// to be a drop-in replacement for C++14's `std::integer_sequence`.
3109//
3110// Example:
3111//
3112// template< class T, T... Ints >
3113// void user_function(integer_sequence<T, Ints...>);
3114//
3115// int main()
3116// {
3117// // user_function's `T` will be deduced to `int` and `Ints...`
3118// // will be deduced to `0, 1, 2, 3, 4`.
3119// user_function(make_integer_sequence<int, 5>());
3120// }
3121template <typename T, T... Ints>
3122struct integer_sequence
3123{
3124 using value_type = T;
3125 static constexpr std::size_t size() noexcept
1264 { 3126 {
1265 assert_invariant(); 3127 return sizeof...(Ints);
1266 } 3128 }
3129};
1267 3130
1268 /*! 3131// index_sequence
1269 @brief create a string (implicit) 3132//
3133// A helper template for an `integer_sequence` of `size_t`,
3134// `absl::index_sequence` is designed to be a drop-in replacement for C++14's
3135// `std::index_sequence`.
3136template <size_t... Ints>
3137using index_sequence = integer_sequence<size_t, Ints...>;
3138
3139namespace utility_internal
3140{
1270 3141
1271 Create a string JSON value with a given content. 3142template <typename Seq, size_t SeqSize, size_t Rem>
3143struct Extend;
1272 3144
1273 @param[in] val a value for the string 3145// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency.
3146template <typename T, T... Ints, size_t SeqSize>
3147struct Extend<integer_sequence<T, Ints...>, SeqSize, 0>
3148{
3149 using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >;
3150};
1274 3151
1275 @tparam CompatibleStringType an string type which is compatible to @ref 3152template <typename T, T... Ints, size_t SeqSize>
1276 string_t, for instance `std::string`. 3153struct Extend<integer_sequence<T, Ints...>, SeqSize, 1>
3154{
3155 using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >;
3156};
1277 3157
1278 @complexity Linear in the size of the passed @a val. 3158// Recursion helper for 'make_integer_sequence<T, N>'.
3159// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'.
3160template <typename T, size_t N>
3161struct Gen
3162{
3163 using type =
3164 typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type;
3165};
1279 3166
1280 @throw std::bad_alloc if allocation for string value fails 3167template <typename T>
3168struct Gen<T, 0>
3169{
3170 using type = integer_sequence<T>;
3171};
1281 3172
1282 @liveexample{The following code shows the construction of a string value 3173} // namespace utility_internal
1283 from a compatible type.,basic_json__CompatibleStringType}
1284 3174
1285 @sa @ref basic_json(const string_t&) -- create a string value 3175// Compile-time sequences of integers
1286 @sa @ref basic_json(const typename string_t::value_type*) -- create a
1287 string value from a character pointer
1288 3176
1289 @since version 1.0.0 3177// make_integer_sequence
1290 */ 3178//
1291 template<class CompatibleStringType, typename std::enable_if< 3179// This template alias is equivalent to
1292 std::is_constructible<string_t, CompatibleStringType>::value, int>::type = 0> 3180// `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in
1293 basic_json(const CompatibleStringType& val) 3181// replacement for C++14's `std::make_integer_sequence`.
1294 : basic_json(string_t(val)) 3182template <typename T, T N>
1295 { 3183using make_integer_sequence = typename utility_internal::Gen<T, N>::type;
1296 assert_invariant();
1297 }
1298 3184
1299 /*! 3185// make_index_sequence
1300 @brief create a boolean (explicit) 3186//
3187// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`,
3188// and is designed to be a drop-in replacement for C++14's
3189// `std::make_index_sequence`.
3190template <size_t N>
3191using make_index_sequence = make_integer_sequence<size_t, N>;
1301 3192
1302 Creates a JSON boolean type from a given value. 3193// index_sequence_for
3194//
3195// Converts a typename pack into an index sequence of the same length, and
3196// is designed to be a drop-in replacement for C++14's
3197// `std::index_sequence_for()`
3198template <typename... Ts>
3199using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
1303 3200
1304 @param[in] val a boolean value to store 3201//// END OF CODE FROM GOOGLE ABSEIL
1305 3202
1306 @complexity Constant. 3203#endif
1307 3204
1308 @liveexample{The example below demonstrates boolean 3205// dispatch utility (taken from ranges-v3)
1309 values.,basic_json__boolean_t} 3206template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
3207template<> struct priority_tag<0> {};
1310 3208
1311 @since version 1.0.0 3209// taken from ranges-v3
1312 */ 3210template<typename T>
1313 basic_json(boolean_t val) noexcept 3211struct static_const
1314 : m_type(value_t::boolean), m_value(val) 3212{
1315 { 3213 static JSON_INLINE_VARIABLE constexpr T value{};
1316 assert_invariant(); 3214};
1317 }
1318 3215
1319 /*! 3216#ifndef JSON_HAS_CPP_17
1320 @brief create an integer number (explicit) 3217 template<typename T>
3218 constexpr T static_const<T>::value;
3219#endif
1321 3220
1322 Create an integer number JSON value with a given content. 3221template<typename T, typename... Args>
3222inline constexpr std::array<T, sizeof...(Args)> make_array(Args&& ... args)
3223{
3224 return std::array<T, sizeof...(Args)> {{static_cast<T>(std::forward<Args>(args))...}};
3225}
1323 3226
1324 @tparam T A helper type to remove this function via SFINAE in case @ref 3227} // namespace detail
1325 number_integer_t is the same as `int`. In this case, this constructor 3228NLOHMANN_JSON_NAMESPACE_END
1326 would have the same signature as @ref basic_json(const int value). Note
1327 the helper type @a T is not visible in this constructor's interface.
1328 3229
1329 @param[in] val an integer to create a JSON number from 3230// #include <nlohmann/detail/meta/type_traits.hpp>
3231// __ _____ _____ _____
3232// __| | __| | | | JSON for Modern C++
3233// | | |__ | | | | | | version 3.11.3
3234// |_____|_____|_____|_|___| https://github.com/nlohmann/json
3235//
3236// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
3237// SPDX-License-Identifier: MIT
1330 3238
1331 @complexity Constant.
1332 3239
1333 @liveexample{The example below shows the construction of an integer
1334 number value.,basic_json__number_integer_t}
1335 3240
1336 @sa @ref basic_json(const int) -- create a number value (integer) 3241#include <limits> // numeric_limits
1337 @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number 3242#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
1338 value (integer) from a compatible number type 3243#include <utility> // declval
3244#include <tuple> // tuple
3245#include <string> // char_traits
1339 3246
1340 @since version 1.0.0 3247// #include <nlohmann/detail/iterators/iterator_traits.hpp>
1341 */ 3248// __ _____ _____ _____
1342 template<typename T, typename std::enable_if< 3249// __| | __| | | | JSON for Modern C++
1343 not (std::is_same<T, int>::value) and 3250// | | |__ | | | | | | version 3.11.3
1344 std::is_same<T, number_integer_t>::value, int>::type = 0> 3251// |_____|_____|_____|_|___| https://github.com/nlohmann/json
1345 basic_json(const number_integer_t val) noexcept 3252//
1346 : m_type(value_t::number_integer), m_value(val) 3253// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
1347 { 3254// SPDX-License-Identifier: MIT
1348 assert_invariant();
1349 }
1350 3255
1351 /*!
1352 @brief create an integer number from an enum type (explicit)
1353 3256
1354 Create an integer number JSON value with a given content.
1355 3257
1356 @param[in] val an integer to create a JSON number from 3258#include <iterator> // random_access_iterator_tag
1357 3259
1358 @note This constructor allows to pass enums directly to a constructor. As 3260// #include <nlohmann/detail/abi_macros.hpp>
1359 C++ has no way of specifying the type of an anonymous enum explicitly, we
1360 can only rely on the fact that such values implicitly convert to int. As
1361 int may already be the same type of number_integer_t, we may need to
1362 switch off the constructor @ref basic_json(const number_integer_t).
1363 3261
1364 @complexity Constant. 3262// #include <nlohmann/detail/meta/void_t.hpp>
1365 3263
1366 @liveexample{The example below shows the construction of an integer 3264// #include <nlohmann/detail/meta/cpp_future.hpp>
1367 number value from an anonymous enum.,basic_json__const_int}
1368 3265
1369 @sa @ref basic_json(const number_integer_t) -- create a number value
1370 (integer)
1371 @sa @ref basic_json(const CompatibleNumberIntegerType) -- create a number
1372 value (integer) from a compatible number type
1373 3266
1374 @since version 1.0.0 3267NLOHMANN_JSON_NAMESPACE_BEGIN
1375 */ 3268namespace detail
1376 basic_json(const int val) noexcept 3269{
1377 : m_type(value_t::number_integer),
1378 m_value(static_cast<number_integer_t>(val))
1379 {
1380 assert_invariant();
1381 }
1382 3270
1383 /*! 3271template<typename It, typename = void>
1384 @brief create an integer number (implicit) 3272struct iterator_types {};
1385 3273
1386 Create an integer number JSON value with a given content. This constructor 3274template<typename It>
1387 allows any type @a CompatibleNumberIntegerType that can be used to 3275struct iterator_types <
1388 construct values of type @ref number_integer_t. 3276 It,
3277 void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
3278 typename It::reference, typename It::iterator_category >>
3279{
3280 using difference_type = typename It::difference_type;
3281 using value_type = typename It::value_type;
3282 using pointer = typename It::pointer;
3283 using reference = typename It::reference;
3284 using iterator_category = typename It::iterator_category;
3285};
1389 3286
1390 @tparam CompatibleNumberIntegerType An integer type which is compatible to 3287// This is required as some compilers implement std::iterator_traits in a way that
1391 @ref number_integer_t. Examples include the types `int`, `int32_t`, 3288// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.
1392 `long`, and `short`. 3289template<typename T, typename = void>
3290struct iterator_traits
3291{
3292};
1393 3293
1394 @param[in] val an integer to create a JSON number from 3294template<typename T>
3295struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>
3296 : iterator_types<T>
3297{
3298};
1395 3299
1396 @complexity Constant. 3300template<typename T>
3301struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>
3302{
3303 using iterator_category = std::random_access_iterator_tag;
3304 using value_type = T;
3305 using difference_type = ptrdiff_t;
3306 using pointer = T*;
3307 using reference = T&;
3308};
1397 3309
1398 @liveexample{The example below shows the construction of several integer 3310} // namespace detail
1399 number values from compatible 3311NLOHMANN_JSON_NAMESPACE_END
1400 types.,basic_json__CompatibleIntegerNumberType}
1401 3312
1402 @sa @ref basic_json(const number_integer_t) -- create a number value 3313// #include <nlohmann/detail/macro_scope.hpp>
1403 (integer)
1404 @sa @ref basic_json(const int) -- create a number value (integer)
1405 3314
1406 @since version 1.0.0 3315// #include <nlohmann/detail/meta/call_std/begin.hpp>
1407 */ 3316// __ _____ _____ _____
1408 template<typename CompatibleNumberIntegerType, typename std::enable_if< 3317// __| | __| | | | JSON for Modern C++
1409 std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and 3318// | | |__ | | | | | | version 3.11.3
1410 std::numeric_limits<CompatibleNumberIntegerType>::is_integer and 3319// |_____|_____|_____|_|___| https://github.com/nlohmann/json
1411 std::numeric_limits<CompatibleNumberIntegerType>::is_signed, 3320//
1412 CompatibleNumberIntegerType>::type = 0> 3321// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
1413 basic_json(const CompatibleNumberIntegerType val) noexcept 3322// SPDX-License-Identifier: MIT
1414 : m_type(value_t::number_integer),
1415 m_value(static_cast<number_integer_t>(val))
1416 {
1417 assert_invariant();
1418 }
1419 3323
1420 /*!
1421 @brief create an unsigned integer number (explicit)
1422 3324
1423 Create an unsigned integer number JSON value with a given content.
1424 3325
1425 @tparam T helper type to compare number_unsigned_t and unsigned int (not 3326// #include <nlohmann/detail/macro_scope.hpp>
1426 visible in) the interface.
1427 3327
1428 @param[in] val an integer to create a JSON number from
1429 3328
1430 @complexity Constant. 3329NLOHMANN_JSON_NAMESPACE_BEGIN
1431 3330
1432 @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number 3331NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin);
1433 value (unsigned integer) from a compatible number type
1434 3332
1435 @since version 2.0.0 3333NLOHMANN_JSON_NAMESPACE_END
1436 */
1437 template<typename T, typename std::enable_if<
1438 not (std::is_same<T, int>::value) and
1439 std::is_same<T, number_unsigned_t>::value, int>::type = 0>
1440 basic_json(const number_unsigned_t val) noexcept
1441 : m_type(value_t::number_unsigned), m_value(val)
1442 {
1443 assert_invariant();
1444 }
1445 3334
1446 /*! 3335// #include <nlohmann/detail/meta/call_std/end.hpp>
1447 @brief create an unsigned number (implicit) 3336// __ _____ _____ _____
3337// __| | __| | | | JSON for Modern C++
3338// | | |__ | | | | | | version 3.11.3
3339// |_____|_____|_____|_|___| https://github.com/nlohmann/json
3340//
3341// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
3342// SPDX-License-Identifier: MIT
1448 3343
1449 Create an unsigned number JSON value with a given content. This
1450 constructor allows any type @a CompatibleNumberUnsignedType that can be
1451 used to construct values of type @ref number_unsigned_t.
1452 3344
1453 @tparam CompatibleNumberUnsignedType An integer type which is compatible
1454 to @ref number_unsigned_t. Examples may include the types `unsigned int`,
1455 `uint32_t`, or `unsigned short`.
1456 3345
1457 @param[in] val an unsigned integer to create a JSON number from 3346// #include <nlohmann/detail/macro_scope.hpp>
1458 3347
1459 @complexity Constant.
1460 3348
1461 @sa @ref basic_json(const number_unsigned_t) -- create a number value 3349NLOHMANN_JSON_NAMESPACE_BEGIN
1462 (unsigned)
1463 3350
1464 @since version 2.0.0 3351NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end);
1465 */
1466 template<typename CompatibleNumberUnsignedType, typename std::enable_if <
1467 std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
1468 std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
1469 not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
1470 CompatibleNumberUnsignedType>::type = 0>
1471 basic_json(const CompatibleNumberUnsignedType val) noexcept
1472 : m_type(value_t::number_unsigned),
1473 m_value(static_cast<number_unsigned_t>(val))
1474 {
1475 assert_invariant();
1476 }
1477 3352
1478 /*! 3353NLOHMANN_JSON_NAMESPACE_END
1479 @brief create a floating-point number (explicit)
1480 3354
1481 Create a floating-point number JSON value with a given content. 3355// #include <nlohmann/detail/meta/cpp_future.hpp>
1482 3356
1483 @param[in] val a floating-point value to create a JSON number from 3357// #include <nlohmann/detail/meta/detected.hpp>
1484 3358
1485 @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 3359// #include <nlohmann/json_fwd.hpp>
1486 disallows NaN values: 3360// __ _____ _____ _____
1487 > Numeric values that cannot be represented in the grammar below (such as 3361// __| | __| | | | JSON for Modern C++
1488 > Infinity and NaN) are not permitted. 3362// | | |__ | | | | | | version 3.11.3
1489 In case the parameter @a val is not a number, a JSON null value is created 3363// |_____|_____|_____|_|___| https://github.com/nlohmann/json
1490 instead. 3364//
3365// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
3366// SPDX-License-Identifier: MIT
1491 3367
1492 @complexity Constant. 3368#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
3369 #define INCLUDE_NLOHMANN_JSON_FWD_HPP_
1493 3370
1494 @liveexample{The following example creates several floating-point 3371 #include <cstdint> // int64_t, uint64_t
1495 values.,basic_json__number_float_t} 3372 #include <map> // map
3373 #include <memory> // allocator
3374 #include <string> // string
3375 #include <vector> // vector
1496 3376
1497 @sa @ref basic_json(const CompatibleNumberFloatType) -- create a number 3377 // #include <nlohmann/detail/abi_macros.hpp>
1498 value (floating-point) from a compatible number type
1499 3378
3379
3380 /*!
3381 @brief namespace for Niels Lohmann
3382 @see https://github.com/nlohmann
1500 @since version 1.0.0 3383 @since version 1.0.0
1501 */ 3384 */
1502 basic_json(const number_float_t val) noexcept 3385 NLOHMANN_JSON_NAMESPACE_BEGIN
1503 : m_type(value_t::number_float), m_value(val)
1504 {
1505 // replace infinity and NAN by null
1506 if (not std::isfinite(val))
1507 {
1508 m_type = value_t::null;
1509 m_value = json_value();
1510 }
1511
1512 assert_invariant();
1513 }
1514 3386
1515 /*! 3387 /*!
1516 @brief create an floating-point number (implicit) 3388 @brief default JSONSerializer template argument
1517 3389
1518 Create an floating-point number JSON value with a given content. This 3390 This serializer ignores the template arguments and uses ADL
1519 constructor allows any type @a CompatibleNumberFloatType that can be used 3391 ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
1520 to construct values of type @ref number_float_t. 3392 for serialization.
3393 */
3394 template<typename T = void, typename SFINAE = void>
3395 struct adl_serializer;
1521 3396
1522 @tparam CompatibleNumberFloatType A floating-point type which is 3397 /// a class to store JSON values
1523 compatible to @ref number_float_t. Examples may include the types `float` 3398 /// @sa https://json.nlohmann.me/api/basic_json/
1524 or `double`. 3399 template<template<typename U, typename V, typename... Args> class ObjectType =
3400 std::map,
3401 template<typename U, typename... Args> class ArrayType = std::vector,
3402 class StringType = std::string, class BooleanType = bool,
3403 class NumberIntegerType = std::int64_t,
3404 class NumberUnsignedType = std::uint64_t,
3405 class NumberFloatType = double,
3406 template<typename U> class AllocatorType = std::allocator,
3407 template<typename T, typename SFINAE = void> class JSONSerializer =
3408 adl_serializer,
3409 class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError
3410 class CustomBaseClass = void>
3411 class basic_json;
3412
3413 /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
3414 /// @sa https://json.nlohmann.me/api/json_pointer/
3415 template<typename RefStringType>
3416 class json_pointer;
1525 3417
1526 @param[in] val a floating-point to create a JSON number from 3418 /*!
3419 @brief default specialization
3420 @sa https://json.nlohmann.me/api/json/
3421 */
3422 using json = basic_json<>;
1527 3423
1528 @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6 3424 /// @brief a minimal map-like container that preserves insertion order
1529 disallows NaN values: 3425 /// @sa https://json.nlohmann.me/api/ordered_map/
1530 > Numeric values that cannot be represented in the grammar below (such as 3426 template<class Key, class T, class IgnoredLess, class Allocator>
1531 > Infinity and NaN) are not permitted. 3427 struct ordered_map;
1532 In case the parameter @a val is not a number, a JSON null value is
1533 created instead.
1534 3428
1535 @complexity Constant. 3429 /// @brief specialization that maintains the insertion order of object keys
3430 /// @sa https://json.nlohmann.me/api/ordered_json/
3431 using ordered_json = basic_json<nlohmann::ordered_map>;
1536 3432
1537 @liveexample{The example below shows the construction of several 3433 NLOHMANN_JSON_NAMESPACE_END
1538 floating-point number values from compatible
1539 types.,basic_json__CompatibleNumberFloatType}
1540 3434
1541 @sa @ref basic_json(const number_float_t) -- create a number value 3435#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_
1542 (floating-point)
1543 3436
1544 @since version 1.0.0
1545 */
1546 template<typename CompatibleNumberFloatType, typename = typename std::enable_if<
1547 std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
1548 std::is_floating_point<CompatibleNumberFloatType>::value>::type>
1549 basic_json(const CompatibleNumberFloatType val) noexcept
1550 : basic_json(number_float_t(val))
1551 {
1552 assert_invariant();
1553 }
1554 3437
1555 /*! 3438NLOHMANN_JSON_NAMESPACE_BEGIN
1556 @brief create a container (array or object) from an initializer list 3439/*!
3440@brief detail namespace with internal helper functions
1557 3441
1558 Creates a JSON value of type array or object from the passed initializer 3442This namespace collects functions that should not be exposed,
1559 list @a init. In case @a type_deduction is `true` (default), the type of 3443implementations of some @ref basic_json methods, and meta-programming helpers.
1560 the JSON value to be created is deducted from the initializer list @a init
1561 according to the following rules:
1562 3444
1563 1. If the list is empty, an empty JSON object value `{}` is created. 3445@since version 2.1.0
1564 2. If the list consists of pairs whose first element is a string, a JSON 3446*/
1565 object value is created where the first elements of the pairs are 3447namespace detail
1566 treated as keys and the second elements are as values. 3448{
1567 3. In all other cases, an array is created.
1568 3449
1569 The rules aim to create the best fit between a C++ initializer list and 3450/////////////
1570 JSON values. The rationale is as follows: 3451// helpers //
3452/////////////
1571 3453
1572 1. The empty initializer list is written as `{}` which is exactly an empty 3454// Note to maintainers:
1573 JSON object. 3455//
1574 2. C++ has now way of describing mapped types other than to list a list of 3456// Every trait in this file expects a non CV-qualified type.
1575 pairs. As JSON requires that keys must be of type string, rule 2 is the 3457// The only exceptions are in the 'aliases for detected' section
1576 weakest constraint one can pose on initializer lists to interpret them 3458// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))
1577 as an object. 3459//
1578 3. In all other cases, the initializer list could not be interpreted as 3460// In this case, T has to be properly CV-qualified to constraint the function arguments
1579 JSON object type, so interpreting it as JSON array type is safe. 3461// (e.g. to_json(BasicJsonType&, const T&))
1580 3462
1581 With the rules described above, the following JSON values cannot be 3463template<typename> struct is_basic_json : std::false_type {};
1582 expressed by an initializer list:
1583 3464
1584 - the empty array (`[]`): use @ref array(std::initializer_list<basic_json>) 3465NLOHMANN_BASIC_JSON_TPL_DECLARATION
1585 with an empty initializer list in this case 3466struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
1586 - arrays whose elements satisfy rule 2: use @ref
1587 array(std::initializer_list<basic_json>) with the same initializer list
1588 in this case
1589 3467
1590 @note When used without parentheses around an empty initializer list, @ref 3468// used by exceptions create() member functions
1591 basic_json() is called instead of this function, yielding the JSON null 3469// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t
1592 value. 3470// false_type otherwise
3471template<typename BasicJsonContext>
3472struct is_basic_json_context :
3473 std::integral_constant < bool,
3474 is_basic_json<typename std::remove_cv<typename std::remove_pointer<BasicJsonContext>::type>::type>::value
3475 || std::is_same<BasicJsonContext, std::nullptr_t>::value >
3476{};
1593 3477
1594 @param[in] init initializer list with JSON values 3478//////////////////////
3479// json_ref helpers //
3480//////////////////////
1595 3481
1596 @param[in] type_deduction internal parameter; when set to `true`, the type 3482template<typename>
1597 of the JSON value is deducted from the initializer list @a init; when set 3483class json_ref;
1598 to `false`, the type provided via @a manual_type is forced. This mode is
1599 used by the functions @ref array(std::initializer_list<basic_json>) and
1600 @ref object(std::initializer_list<basic_json>).
1601 3484
1602 @param[in] manual_type internal parameter; when @a type_deduction is set 3485template<typename>
1603 to `false`, the created JSON value will use the provided type (only @ref 3486struct is_json_ref : std::false_type {};
1604 value_t::array and @ref value_t::object are valid); when @a type_deduction
1605 is set to `true`, this parameter has no effect
1606 3487
1607 @throw std::domain_error if @a type_deduction is `false`, @a manual_type 3488template<typename T>
1608 is `value_t::object`, but @a init contains an element which is not a pair 3489struct is_json_ref<json_ref<T>> : std::true_type {};
1609 whose first element is a string; example: `"cannot create object from
1610 initializer list"`
1611 3490
1612 @complexity Linear in the size of the initializer list @a init. 3491//////////////////////////
3492// aliases for detected //
3493//////////////////////////
1613 3494
1614 @liveexample{The example below shows how JSON values are created from 3495template<typename T>
1615 initializer lists.,basic_json__list_init_t} 3496using mapped_type_t = typename T::mapped_type;
1616 3497
1617 @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array 3498template<typename T>
1618 value from an initializer list 3499using key_type_t = typename T::key_type;
1619 @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object
1620 value from an initializer list
1621 3500
1622 @since version 1.0.0 3501template<typename T>
1623 */ 3502using value_type_t = typename T::value_type;
1624 basic_json(std::initializer_list<basic_json> init,
1625 bool type_deduction = true,
1626 value_t manual_type = value_t::array)
1627 {
1628 // check if each element is an array with two elements whose first
1629 // element is a string
1630 bool is_an_object = std::all_of(init.begin(), init.end(),
1631 [](const basic_json & element)
1632 {
1633 return element.is_array() and element.size() == 2 and element[0].is_string();
1634 });
1635 3503
1636 // adjust type if type deduction is not wanted 3504template<typename T>
1637 if (not type_deduction) 3505using difference_type_t = typename T::difference_type;
1638 {
1639 // if array is wanted, do not create an object though possible
1640 if (manual_type == value_t::array)
1641 {
1642 is_an_object = false;
1643 }
1644 3506
1645 // if object is wanted but impossible, throw an exception 3507template<typename T>
1646 if (manual_type == value_t::object and not is_an_object) 3508using pointer_t = typename T::pointer;
1647 {
1648 throw std::domain_error("cannot create object from initializer list");
1649 }
1650 }
1651 3509
1652 if (is_an_object) 3510template<typename T>
1653 { 3511using reference_t = typename T::reference;
1654 // the initializer list is a list of pairs -> create object
1655 m_type = value_t::object;
1656 m_value = value_t::object;
1657 3512
1658 std::for_each(init.begin(), init.end(), [this](const basic_json & element) 3513template<typename T>
1659 { 3514using iterator_category_t = typename T::iterator_category;
1660 m_value.object->emplace(*(element[0].m_value.string), element[1]);
1661 });
1662 }
1663 else
1664 {
1665 // the initializer list describes an array -> create array
1666 m_type = value_t::array;
1667 m_value.array = create<array_t>(init);
1668 }
1669 3515
1670 assert_invariant(); 3516template<typename T, typename... Args>
1671 } 3517using to_json_function = decltype(T::to_json(std::declval<Args>()...));
1672 3518
1673 /*! 3519template<typename T, typename... Args>
1674 @brief explicitly create an array from an initializer list 3520using from_json_function = decltype(T::from_json(std::declval<Args>()...));
1675 3521
1676 Creates a JSON array value from a given initializer list. That is, given a 3522template<typename T, typename U>
1677 list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the 3523using get_template_function = decltype(std::declval<T>().template get<U>());
1678 initializer list is empty, the empty array `[]` is created.
1679 3524
1680 @note This function is only needed to express two edge cases that cannot 3525// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
1681 be realized with the initializer list constructor (@ref 3526template<typename BasicJsonType, typename T, typename = void>
1682 basic_json(std::initializer_list<basic_json>, bool, value_t)). These cases 3527struct has_from_json : std::false_type {};
1683 are:
1684 1. creating an array whose elements are all pairs whose first element is a
1685 string -- in this case, the initializer list constructor would create an
1686 object, taking the first elements as keys
1687 2. creating an empty array -- passing the empty initializer list to the
1688 initializer list constructor yields an empty object
1689 3528
1690 @param[in] init initializer list with JSON values to create an array from 3529// trait checking if j.get<T> is valid
1691 (optional) 3530// use this trait instead of std::is_constructible or std::is_convertible,
3531// both rely on, or make use of implicit conversions, and thus fail when T
3532// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)
3533template <typename BasicJsonType, typename T>
3534struct is_getable
3535{
3536 static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;
3537};
1692 3538
1693 @return JSON array value 3539template<typename BasicJsonType, typename T>
3540struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
3541{
3542 using serializer = typename BasicJsonType::template json_serializer<T, void>;
1694 3543
1695 @complexity Linear in the size of @a init. 3544 static constexpr bool value =
3545 is_detected_exact<void, from_json_function, serializer,
3546 const BasicJsonType&, T&>::value;
3547};
1696 3548
1697 @liveexample{The following code shows an example for the `array` 3549// This trait checks if JSONSerializer<T>::from_json(json const&) exists
1698 function.,array} 3550// this overload is used for non-default-constructible user-defined-types
3551template<typename BasicJsonType, typename T, typename = void>
3552struct has_non_default_from_json : std::false_type {};
1699 3553
1700 @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) -- 3554template<typename BasicJsonType, typename T>
1701 create a JSON value from an initializer list 3555struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
1702 @sa @ref object(std::initializer_list<basic_json>) -- create a JSON object 3556{
1703 value from an initializer list 3557 using serializer = typename BasicJsonType::template json_serializer<T, void>;
1704 3558
1705 @since version 1.0.0 3559 static constexpr bool value =
1706 */ 3560 is_detected_exact<T, from_json_function, serializer,
1707 static basic_json array(std::initializer_list<basic_json> init = 3561 const BasicJsonType&>::value;
1708 std::initializer_list<basic_json>()) 3562};
1709 {
1710 return basic_json(init, false, value_t::array);
1711 }
1712 3563
1713 /*! 3564// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
1714 @brief explicitly create an object from an initializer list 3565// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
3566template<typename BasicJsonType, typename T, typename = void>
3567struct has_to_json : std::false_type {};
3568
3569template<typename BasicJsonType, typename T>
3570struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
3571{
3572 using serializer = typename BasicJsonType::template json_serializer<T, void>;
1715 3573
1716 Creates a JSON object value from a given initializer list. The initializer 3574 static constexpr bool value =
1717 lists elements must be pairs, and their first elements must be strings. If 3575 is_detected_exact<void, to_json_function, serializer, BasicJsonType&,
1718 the initializer list is empty, the empty object `{}` is created. 3576 T>::value;
3577};
1719 3578
1720 @note This function is only added for symmetry reasons. In contrast to the 3579template<typename T>
1721 related function @ref array(std::initializer_list<basic_json>), there are 3580using detect_key_compare = typename T::key_compare;
1722 no cases which can only be expressed by this function. That is, any
1723 initializer list @a init can also be passed to the initializer list
1724 constructor @ref basic_json(std::initializer_list<basic_json>, bool,
1725 value_t).
1726 3581
1727 @param[in] init initializer list to create an object from (optional) 3582template<typename T>
3583struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {};
1728 3584
1729 @return JSON object value 3585// obtains the actual object key comparator
3586template<typename BasicJsonType>
3587struct actual_object_comparator
3588{
3589 using object_t = typename BasicJsonType::object_t;
3590 using object_comparator_t = typename BasicJsonType::default_object_comparator_t;
3591 using type = typename std::conditional < has_key_compare<object_t>::value,
3592 typename object_t::key_compare, object_comparator_t>::type;
3593};
1730 3594
1731 @throw std::domain_error if @a init is not a pair whose first elements are 3595template<typename BasicJsonType>
1732 strings; thrown by 3596using actual_object_comparator_t = typename actual_object_comparator<BasicJsonType>::type;
1733 @ref basic_json(std::initializer_list<basic_json>, bool, value_t)
1734 3597
1735 @complexity Linear in the size of @a init. 3598/////////////////
3599// char_traits //
3600/////////////////
1736 3601
1737 @liveexample{The following code shows an example for the `object` 3602// Primary template of char_traits calls std char_traits
1738 function.,object} 3603template<typename T>
3604struct char_traits : std::char_traits<T>
3605{};
1739 3606
1740 @sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) -- 3607// Explicitly define char traits for unsigned char since it is not standard
1741 create a JSON value from an initializer list 3608template<>
1742 @sa @ref array(std::initializer_list<basic_json>) -- create a JSON array 3609struct char_traits<unsigned char> : std::char_traits<char>
1743 value from an initializer list 3610{
3611 using char_type = unsigned char;
3612 using int_type = uint64_t;
1744 3613
1745 @since version 1.0.0 3614 // Redefine to_int_type function
1746 */ 3615 static int_type to_int_type(char_type c) noexcept
1747 static basic_json object(std::initializer_list<basic_json> init =
1748 std::initializer_list<basic_json>())
1749 { 3616 {
1750 return basic_json(init, false, value_t::object); 3617 return static_cast<int_type>(c);
1751 } 3618 }
1752 3619
1753 /*! 3620 static char_type to_char_type(int_type i) noexcept
1754 @brief construct an array with count copies of given value 3621 {
3622 return static_cast<char_type>(i);
3623 }
1755 3624
1756 Constructs a JSON array value by creating @a cnt copies of a passed value. 3625 static constexpr int_type eof() noexcept
1757 In case @a cnt is `0`, an empty array is created. As postcondition, 3626 {
1758 `std::distance(begin(),end()) == cnt` holds. 3627 return static_cast<int_type>(EOF);
3628 }
3629};
1759 3630
1760 @param[in] cnt the number of JSON copies of @a val to create 3631// Explicitly define char traits for signed char since it is not standard
1761 @param[in] val the JSON value to copy 3632template<>
3633struct char_traits<signed char> : std::char_traits<char>
3634{
3635 using char_type = signed char;
3636 using int_type = uint64_t;
1762 3637
1763 @complexity Linear in @a cnt. 3638 // Redefine to_int_type function
3639 static int_type to_int_type(char_type c) noexcept
3640 {
3641 return static_cast<int_type>(c);
3642 }
1764 3643
1765 @liveexample{The following code shows examples for the @ref 3644 static char_type to_char_type(int_type i) noexcept
1766 basic_json(size_type\, const basic_json&) 3645 {
1767 constructor.,basic_json__size_type_basic_json} 3646 return static_cast<char_type>(i);
3647 }
1768 3648
1769 @since version 1.0.0 3649 static constexpr int_type eof() noexcept
1770 */
1771 basic_json(size_type cnt, const basic_json& val)
1772 : m_type(value_t::array)
1773 { 3650 {
1774 m_value.array = create<array_t>(cnt, val); 3651 return static_cast<int_type>(EOF);
1775 assert_invariant();
1776 } 3652 }
3653};
1777 3654
1778 /*! 3655///////////////////
1779 @brief construct a JSON container given an iterator range 3656// is_ functions //
3657///////////////////
1780 3658
1781 Constructs the JSON value with the contents of the range `[first, last)`. 3659// https://en.cppreference.com/w/cpp/types/conjunction
1782 The semantics depends on the different types a JSON value can have: 3660template<class...> struct conjunction : std::true_type { };
1783 - In case of primitive types (number, boolean, or string), @a first must 3661template<class B> struct conjunction<B> : B { };
1784 be `begin()` and @a last must be `end()`. In this case, the value is 3662template<class B, class... Bn>
1785 copied. Otherwise, std::out_of_range is thrown. 3663struct conjunction<B, Bn...>
1786 - In case of structured types (array, object), the constructor behaves as 3664: std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {};
1787 similar versions for `std::vector`.
1788 - In case of a null type, std::domain_error is thrown.
1789 3665
1790 @tparam InputIT an input iterator type (@ref iterator or @ref 3666// https://en.cppreference.com/w/cpp/types/negation
1791 const_iterator) 3667template<class B> struct negation : std::integral_constant < bool, !B::value > { };
1792 3668
1793 @param[in] first begin of the range to copy from (included) 3669// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
1794 @param[in] last end of the range to copy from (excluded) 3670// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
3671// This causes compile errors in e.g. clang 3.5 or gcc 4.9.
3672template <typename T>
3673struct is_default_constructible : std::is_default_constructible<T> {};
1795 3674
1796 @pre Iterators @a first and @a last must be initialized. **This 3675template <typename T1, typename T2>
1797 precondition is enforced with an assertion.** 3676struct is_default_constructible<std::pair<T1, T2>>
3677 : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
1798 3678
1799 @throw std::domain_error if iterators are not compatible; that is, do not 3679template <typename T1, typename T2>
1800 belong to the same JSON value; example: `"iterators are not compatible"` 3680struct is_default_constructible<const std::pair<T1, T2>>
1801 @throw std::out_of_range if iterators are for a primitive type (number, 3681 : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
1802 boolean, or string) where an out of range error can be detected easily;
1803 example: `"iterators out of range"`
1804 @throw std::bad_alloc if allocation for object, array, or string fails
1805 @throw std::domain_error if called with a null value; example: `"cannot
1806 use construct with iterators from null"`
1807 3682
1808 @complexity Linear in distance between @a first and @a last. 3683template <typename... Ts>
3684struct is_default_constructible<std::tuple<Ts...>>
3685 : conjunction<is_default_constructible<Ts>...> {};
1809 3686
1810 @liveexample{The example below shows several ways to create JSON values by 3687template <typename... Ts>
1811 specifying a subrange with iterators.,basic_json__InputIt_InputIt} 3688struct is_default_constructible<const std::tuple<Ts...>>
3689 : conjunction<is_default_constructible<Ts>...> {};
1812 3690
1813 @since version 1.0.0 3691template <typename T, typename... Args>
1814 */ 3692struct is_constructible : std::is_constructible<T, Args...> {};
1815 template<class InputIT, typename std::enable_if<
1816 std::is_same<InputIT, typename basic_json_t::iterator>::value or
1817 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>
1818 basic_json(InputIT first, InputIT last)
1819 {
1820 assert(first.m_object != nullptr);
1821 assert(last.m_object != nullptr);
1822 3693
1823 // make sure iterator fits the current value 3694template <typename T1, typename T2>
1824 if (first.m_object != last.m_object) 3695struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {};
1825 {
1826 throw std::domain_error("iterators are not compatible");
1827 }
1828 3696
1829 // copy type from first iterator 3697template <typename T1, typename T2>
1830 m_type = first.m_object->m_type; 3698struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {};
1831 3699
1832 // check if iterator range is complete for primitive values 3700template <typename... Ts>
1833 switch (m_type) 3701struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {};
1834 {
1835 case value_t::boolean:
1836 case value_t::number_float:
1837 case value_t::number_integer:
1838 case value_t::number_unsigned:
1839 case value_t::string:
1840 {
1841 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
1842 {
1843 throw std::out_of_range("iterators out of range");
1844 }
1845 break;
1846 }
1847 3702
1848 default: 3703template <typename... Ts>
1849 { 3704struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {};
1850 break;
1851 }
1852 }
1853 3705
1854 switch (m_type) 3706template<typename T, typename = void>
1855 { 3707struct is_iterator_traits : std::false_type {};
1856 case value_t::number_integer:
1857 {
1858 m_value.number_integer = first.m_object->m_value.number_integer;
1859 break;
1860 }
1861 3708
1862 case value_t::number_unsigned: 3709template<typename T>
1863 { 3710struct is_iterator_traits<iterator_traits<T>>
1864 m_value.number_unsigned = first.m_object->m_value.number_unsigned; 3711{
1865 break; 3712 private:
1866 } 3713 using traits = iterator_traits<T>;
1867 3714
1868 case value_t::number_float: 3715 public:
1869 { 3716 static constexpr auto value =
1870 m_value.number_float = first.m_object->m_value.number_float; 3717 is_detected<value_type_t, traits>::value &&
1871 break; 3718 is_detected<difference_type_t, traits>::value &&
1872 } 3719 is_detected<pointer_t, traits>::value &&
3720 is_detected<iterator_category_t, traits>::value &&
3721 is_detected<reference_t, traits>::value;
3722};
1873 3723
1874 case value_t::boolean: 3724template<typename T>
1875 { 3725struct is_range
1876 m_value.boolean = first.m_object->m_value.boolean; 3726{
1877 break; 3727 private:
1878 } 3728 using t_ref = typename std::add_lvalue_reference<T>::type;
1879 3729
1880 case value_t::string: 3730 using iterator = detected_t<result_of_begin, t_ref>;
1881 { 3731 using sentinel = detected_t<result_of_end, t_ref>;
1882 m_value = *first.m_object->m_value.string;
1883 break;
1884 }
1885 3732
1886 case value_t::object: 3733 // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator
1887 { 3734 // and https://en.cppreference.com/w/cpp/iterator/sentinel_for
1888 m_value.object = create<object_t>(first.m_it.object_iterator, last.m_it.object_iterator); 3735 // but reimplementing these would be too much work, as a lot of other concepts are used underneath
1889 break; 3736 static constexpr auto is_iterator_begin =
1890 } 3737 is_iterator_traits<iterator_traits<iterator>>::value;
1891 3738
1892 case value_t::array: 3739 public:
1893 { 3740 static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin;
1894 m_value.array = create<array_t>(first.m_it.array_iterator, last.m_it.array_iterator); 3741};
1895 break;
1896 }
1897 3742
1898 default: 3743template<typename R>
1899 { 3744using iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>;
1900 throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
1901 }
1902 }
1903 3745
1904 assert_invariant(); 3746template<typename T>
1905 } 3747using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>;
1906 3748
1907 /*! 3749// The following implementation of is_complete_type is taken from
1908 @brief construct a JSON value given an input stream 3750// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
3751// and is written by Xiang Fan who agreed to using it in this library.
1909 3752
1910 @param[in,out] i stream to read a serialized JSON value from 3753template<typename T, typename = void>
1911 @param[in] cb a parser callback function of type @ref parser_callback_t 3754struct is_complete_type : std::false_type {};
1912 which is used to control the deserialization by filtering unwanted values
1913 (optional)
1914 3755
1915 @complexity Linear in the length of the input. The parser is a predictive 3756template<typename T>
1916 LL(1) parser. The complexity can be higher if the parser callback function 3757struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
1917 @a cb has a super-linear complexity.
1918 3758
1919 @note A UTF-8 byte order mark is silently ignored. 3759template<typename BasicJsonType, typename CompatibleObjectType,
3760 typename = void>
3761struct is_compatible_object_type_impl : std::false_type {};
1920 3762
1921 @deprecated This constructor is deprecated and will be removed in version 3763template<typename BasicJsonType, typename CompatibleObjectType>
1922 3.0.0 to unify the interface of the library. Deserialization will be 3764struct is_compatible_object_type_impl <
1923 done by stream operators or by calling one of the `parse` functions, 3765 BasicJsonType, CompatibleObjectType,
1924 e.g. @ref parse(std::istream&, const parser_callback_t). That is, calls 3766 enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&
1925 like `json j(i);` for an input stream @a i need to be replaced by 3767 is_detected<key_type_t, CompatibleObjectType>::value >>
1926 `json j = json::parse(i);`. See the example below. 3768{
3769 using object_t = typename BasicJsonType::object_t;
1927 3770
1928 @liveexample{The example below demonstrates constructing a JSON value from 3771 // macOS's is_constructible does not play well with nonesuch...
1929 a `std::stringstream` with and without callback 3772 static constexpr bool value =
1930 function.,basic_json__istream} 3773 is_constructible<typename object_t::key_type,
3774 typename CompatibleObjectType::key_type>::value &&
3775 is_constructible<typename object_t::mapped_type,
3776 typename CompatibleObjectType::mapped_type>::value;
3777};
1931 3778
1932 @since version 2.0.0, deprecated in version 2.0.3, to be removed in 3779template<typename BasicJsonType, typename CompatibleObjectType>
1933 version 3.0.0 3780struct is_compatible_object_type
1934 */ 3781 : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
1935 JSON_DEPRECATED
1936 explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr)
1937 {
1938 *this = parser(i, cb).parse();
1939 assert_invariant();
1940 }
1941 3782
1942 /////////////////////////////////////// 3783template<typename BasicJsonType, typename ConstructibleObjectType,
1943 // other constructors and destructor // 3784 typename = void>
1944 /////////////////////////////////////// 3785struct is_constructible_object_type_impl : std::false_type {};
1945 3786
1946 /*! 3787template<typename BasicJsonType, typename ConstructibleObjectType>
1947 @brief copy constructor 3788struct is_constructible_object_type_impl <
3789 BasicJsonType, ConstructibleObjectType,
3790 enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&
3791 is_detected<key_type_t, ConstructibleObjectType>::value >>
3792{
3793 using object_t = typename BasicJsonType::object_t;
1948 3794
1949 Creates a copy of a given JSON value. 3795 static constexpr bool value =
3796 (is_default_constructible<ConstructibleObjectType>::value &&
3797 (std::is_move_assignable<ConstructibleObjectType>::value ||
3798 std::is_copy_assignable<ConstructibleObjectType>::value) &&
3799 (is_constructible<typename ConstructibleObjectType::key_type,
3800 typename object_t::key_type>::value &&
3801 std::is_same <
3802 typename object_t::mapped_type,
3803 typename ConstructibleObjectType::mapped_type >::value)) ||
3804 (has_from_json<BasicJsonType,
3805 typename ConstructibleObjectType::mapped_type>::value ||
3806 has_non_default_from_json <
3807 BasicJsonType,
3808 typename ConstructibleObjectType::mapped_type >::value);
3809};
1950 3810
1951 @param[in] other the JSON value to copy 3811template<typename BasicJsonType, typename ConstructibleObjectType>
3812struct is_constructible_object_type
3813 : is_constructible_object_type_impl<BasicJsonType,
3814 ConstructibleObjectType> {};
1952 3815
1953 @complexity Linear in the size of @a other. 3816template<typename BasicJsonType, typename CompatibleStringType>
3817struct is_compatible_string_type
3818{
3819 static constexpr auto value =
3820 is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
3821};
1954 3822
1955 @requirement This function helps `basic_json` satisfying the 3823template<typename BasicJsonType, typename ConstructibleStringType>
1956 [Container](http://en.cppreference.com/w/cpp/concept/Container) 3824struct is_constructible_string_type
1957 requirements: 3825{
1958 - The complexity is linear. 3826 // launder type through decltype() to fix compilation failure on ICPC
1959 - As postcondition, it holds: `other == basic_json(other)`. 3827#ifdef __INTEL_COMPILER
3828 using laundered_type = decltype(std::declval<ConstructibleStringType>());
3829#else
3830 using laundered_type = ConstructibleStringType;
3831#endif
1960 3832
1961 @throw std::bad_alloc if allocation for object, array, or string fails. 3833 static constexpr auto value =
3834 conjunction <
3835 is_constructible<laundered_type, typename BasicJsonType::string_t>,
3836 is_detected_exact<typename BasicJsonType::string_t::value_type,
3837 value_type_t, laundered_type >>::value;
3838};
1962 3839
1963 @liveexample{The following code shows an example for the copy 3840template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
1964 constructor.,basic_json__basic_json} 3841struct is_compatible_array_type_impl : std::false_type {};
3842
3843template<typename BasicJsonType, typename CompatibleArrayType>
3844struct is_compatible_array_type_impl <
3845 BasicJsonType, CompatibleArrayType,
3846 enable_if_t <
3847 is_detected<iterator_t, CompatibleArrayType>::value&&
3848 is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&
3849// special case for types like std::filesystem::path whose iterator's value_type are themselves
3850// c.f. https://github.com/nlohmann/json/pull/3073
3851 !std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >>
3852{
3853 static constexpr bool value =
3854 is_constructible<BasicJsonType,
3855 range_value_t<CompatibleArrayType>>::value;
3856};
1965 3857
1966 @since version 1.0.0 3858template<typename BasicJsonType, typename CompatibleArrayType>
1967 */ 3859struct is_compatible_array_type
1968 basic_json(const basic_json& other) 3860 : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
1969 : m_type(other.m_type) 3861
1970 { 3862template<typename BasicJsonType, typename ConstructibleArrayType, typename = void>
1971 // check of passed value is valid 3863struct is_constructible_array_type_impl : std::false_type {};
1972 other.assert_invariant(); 3864
3865template<typename BasicJsonType, typename ConstructibleArrayType>
3866struct is_constructible_array_type_impl <
3867 BasicJsonType, ConstructibleArrayType,
3868 enable_if_t<std::is_same<ConstructibleArrayType,
3869 typename BasicJsonType::value_type>::value >>
3870 : std::true_type {};
3871
3872template<typename BasicJsonType, typename ConstructibleArrayType>
3873struct is_constructible_array_type_impl <
3874 BasicJsonType, ConstructibleArrayType,
3875 enable_if_t < !std::is_same<ConstructibleArrayType,
3876 typename BasicJsonType::value_type>::value&&
3877 !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
3878 is_default_constructible<ConstructibleArrayType>::value&&
3879(std::is_move_assignable<ConstructibleArrayType>::value ||
3880 std::is_copy_assignable<ConstructibleArrayType>::value)&&
3881is_detected<iterator_t, ConstructibleArrayType>::value&&
3882is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&
3883is_detected<range_value_t, ConstructibleArrayType>::value&&
3884// special case for types like std::filesystem::path whose iterator's value_type are themselves
3885// c.f. https://github.com/nlohmann/json/pull/3073
3886!std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&&
3887 is_complete_type <
3888 detected_t<range_value_t, ConstructibleArrayType >>::value >>
3889{
3890 using value_type = range_value_t<ConstructibleArrayType>;
1973 3891
1974 switch (m_type) 3892 static constexpr bool value =
1975 { 3893 std::is_same<value_type,
1976 case value_t::object: 3894 typename BasicJsonType::array_t::value_type>::value ||
1977 { 3895 has_from_json<BasicJsonType,
1978 m_value = *other.m_value.object; 3896 value_type>::value ||
1979 break; 3897 has_non_default_from_json <
1980 } 3898 BasicJsonType,
3899 value_type >::value;
3900};
1981 3901
1982 case value_t::array: 3902template<typename BasicJsonType, typename ConstructibleArrayType>
1983 { 3903struct is_constructible_array_type
1984 m_value = *other.m_value.array; 3904 : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};
1985 break;
1986 }
1987 3905
1988 case value_t::string: 3906template<typename RealIntegerType, typename CompatibleNumberIntegerType,
1989 { 3907 typename = void>
1990 m_value = *other.m_value.string; 3908struct is_compatible_integer_type_impl : std::false_type {};
1991 break;
1992 }
1993 3909
1994 case value_t::boolean: 3910template<typename RealIntegerType, typename CompatibleNumberIntegerType>
1995 { 3911struct is_compatible_integer_type_impl <
1996 m_value = other.m_value.boolean; 3912 RealIntegerType, CompatibleNumberIntegerType,
1997 break; 3913 enable_if_t < std::is_integral<RealIntegerType>::value&&
1998 } 3914 std::is_integral<CompatibleNumberIntegerType>::value&&
3915 !std::is_same<bool, CompatibleNumberIntegerType>::value >>
3916{
3917 // is there an assert somewhere on overflows?
3918 using RealLimits = std::numeric_limits<RealIntegerType>;
3919 using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
3920
3921 static constexpr auto value =
3922 is_constructible<RealIntegerType,
3923 CompatibleNumberIntegerType>::value &&
3924 CompatibleLimits::is_integer &&
3925 RealLimits::is_signed == CompatibleLimits::is_signed;
3926};
1999 3927
2000 case value_t::number_integer: 3928template<typename RealIntegerType, typename CompatibleNumberIntegerType>
2001 { 3929struct is_compatible_integer_type
2002 m_value = other.m_value.number_integer; 3930 : is_compatible_integer_type_impl<RealIntegerType,
2003 break; 3931 CompatibleNumberIntegerType> {};
2004 }
2005 3932
2006 case value_t::number_unsigned: 3933template<typename BasicJsonType, typename CompatibleType, typename = void>
2007 { 3934struct is_compatible_type_impl: std::false_type {};
2008 m_value = other.m_value.number_unsigned;
2009 break;
2010 }
2011 3935
2012 case value_t::number_float: 3936template<typename BasicJsonType, typename CompatibleType>
2013 { 3937struct is_compatible_type_impl <
2014 m_value = other.m_value.number_float; 3938 BasicJsonType, CompatibleType,
2015 break; 3939 enable_if_t<is_complete_type<CompatibleType>::value >>
2016 } 3940{
3941 static constexpr bool value =
3942 has_to_json<BasicJsonType, CompatibleType>::value;
3943};
2017 3944
2018 default: 3945template<typename BasicJsonType, typename CompatibleType>
2019 { 3946struct is_compatible_type
2020 break; 3947 : is_compatible_type_impl<BasicJsonType, CompatibleType> {};
2021 }
2022 }
2023 3948
2024 assert_invariant(); 3949template<typename T1, typename T2>
2025 } 3950struct is_constructible_tuple : std::false_type {};
2026 3951
2027 /*! 3952template<typename T1, typename... Args>
2028 @brief move constructor 3953struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};
2029 3954
2030 Move constructor. Constructs a JSON value with the contents of the given 3955template<typename BasicJsonType, typename T>
2031 value @a other using move semantics. It "steals" the resources from @a 3956struct is_json_iterator_of : std::false_type {};
2032 other and leaves it as JSON null value.
2033 3957
2034 @param[in,out] other value to move to this object 3958template<typename BasicJsonType>
3959struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {};
2035 3960
2036 @post @a other is a JSON null value 3961template<typename BasicJsonType>
3962struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type
3963{};
2037 3964
2038 @complexity Constant. 3965// checks if a given type T is a template specialization of Primary
3966template<template <typename...> class Primary, typename T>
3967struct is_specialization_of : std::false_type {};
2039 3968
2040 @liveexample{The code below shows the move constructor explicitly called 3969template<template <typename...> class Primary, typename... Args>
2041 via std::move.,basic_json__moveconstructor} 3970struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {};
2042 3971
2043 @since version 1.0.0 3972template<typename T>
2044 */ 3973using is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>;
2045 basic_json(basic_json&& other) noexcept 3974
2046 : m_type(std::move(other.m_type)), 3975// checks if A and B are comparable using Compare functor
2047 m_value(std::move(other.m_value)) 3976template<typename Compare, typename A, typename B, typename = void>
3977struct is_comparable : std::false_type {};
3978
3979template<typename Compare, typename A, typename B>
3980struct is_comparable<Compare, A, B, void_t<
3981decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())),
3982decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>()))
3983>> : std::true_type {};
3984
3985template<typename T>
3986using detect_is_transparent = typename T::is_transparent;
3987
3988// type trait to check if KeyType can be used as object key (without a BasicJsonType)
3989// see is_usable_as_basic_json_key_type below
3990template<typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
3991 bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
3992using is_usable_as_key_type = typename std::conditional <
3993 is_comparable<Comparator, ObjectKeyType, KeyTypeCVRef>::value
3994 && !(ExcludeObjectKeyType && std::is_same<KeyType,
3995 ObjectKeyType>::value)
3996 && (!RequireTransparentComparator
3997 || is_detected <detect_is_transparent, Comparator>::value)
3998 && !is_json_pointer<KeyType>::value,
3999 std::true_type,
4000 std::false_type >::type;
4001
4002// type trait to check if KeyType can be used as object key
4003// true if:
4004// - KeyType is comparable with BasicJsonType::object_t::key_type
4005// - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type
4006// - the comparator is transparent or RequireTransparentComparator is false
4007// - KeyType is not a JSON iterator or json_pointer
4008template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
4009 bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
4010using is_usable_as_basic_json_key_type = typename std::conditional <
4011 is_usable_as_key_type<typename BasicJsonType::object_comparator_t,
4012 typename BasicJsonType::object_t::key_type, KeyTypeCVRef,
4013 RequireTransparentComparator, ExcludeObjectKeyType>::value
4014 && !is_json_iterator_of<BasicJsonType, KeyType>::value,
4015 std::true_type,
4016 std::false_type >::type;
4017
4018template<typename ObjectType, typename KeyType>
4019using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>()));
4020
4021// type trait to check if object_t has an erase() member functions accepting KeyType
4022template<typename BasicJsonType, typename KeyType>
4023using has_erase_with_key_type = typename std::conditional <
4024 is_detected <
4025 detect_erase_with_key_type,
4026 typename BasicJsonType::object_t, KeyType >::value,
4027 std::true_type,
4028 std::false_type >::type;
4029
4030// a naive helper to check if a type is an ordered_map (exploits the fact that
4031// ordered_map inherits capacity() from std::vector)
4032template <typename T>
4033struct is_ordered_map
4034{
4035 using one = char;
4036
4037 struct two
2048 { 4038 {
2049 // check that passed value is valid 4039 char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
2050 other.assert_invariant(); 4040 };
2051 4041
2052 // invalidate payload 4042 template <typename C> static one test( decltype(&C::capacity) ) ;
2053 other.m_type = value_t::null; 4043 template <typename C> static two test(...);
2054 other.m_value = {};
2055 4044
2056 assert_invariant(); 4045 enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
2057 } 4046};
2058 4047
2059 /*! 4048// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
2060 @brief copy assignment 4049template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
4050T conditional_static_cast(U value)
4051{
4052 return static_cast<T>(value);
4053}
2061 4054
2062 Copy assignment operator. Copies a JSON value via the "copy and swap" 4055template<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0>
2063 strategy: It is expressed in terms of the copy constructor, destructor, 4056T conditional_static_cast(U value)
2064 and the swap() member function. 4057{
4058 return value;
4059}
2065 4060
2066 @param[in] other value to copy from 4061template<typename... Types>
4062using all_integral = conjunction<std::is_integral<Types>...>;
2067 4063
2068 @complexity Linear. 4064template<typename... Types>
4065using all_signed = conjunction<std::is_signed<Types>...>;
2069 4066
2070 @requirement This function helps `basic_json` satisfying the 4067template<typename... Types>
2071 [Container](http://en.cppreference.com/w/cpp/concept/Container) 4068using all_unsigned = conjunction<std::is_unsigned<Types>...>;
2072 requirements:
2073 - The complexity is linear.
2074 4069
2075 @liveexample{The code below shows and example for the copy assignment. It 4070// there's a disjunction trait in another PR; replace when merged
2076 creates a copy of value `a` which is then swapped with `b`. Finally\, the 4071template<typename... Types>
2077 copy of `a` (which is the null value after the swap) is 4072using same_sign = std::integral_constant < bool,
2078 destroyed.,basic_json__copyassignment} 4073 all_signed<Types...>::value || all_unsigned<Types...>::value >;
2079 4074
2080 @since version 1.0.0 4075template<typename OfType, typename T>
2081 */ 4076using never_out_of_range = std::integral_constant < bool,
2082 reference& operator=(basic_json other) noexcept ( 4077 (std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType)))
2083 std::is_nothrow_move_constructible<value_t>::value and 4078 || (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T)) >;
2084 std::is_nothrow_move_assignable<value_t>::value and
2085 std::is_nothrow_move_constructible<json_value>::value and
2086 std::is_nothrow_move_assignable<json_value>::value
2087 )
2088 {
2089 // check that passed value is valid
2090 other.assert_invariant();
2091 4079
2092 using std::swap; 4080template<typename OfType, typename T,
2093 swap(m_type, other.m_type); 4081 bool OfTypeSigned = std::is_signed<OfType>::value,
2094 swap(m_value, other.m_value); 4082 bool TSigned = std::is_signed<T>::value>
4083struct value_in_range_of_impl2;
2095 4084
2096 assert_invariant(); 4085template<typename OfType, typename T>
2097 return *this; 4086struct value_in_range_of_impl2<OfType, T, false, false>
4087{
4088 static constexpr bool test(T val)
4089 {
4090 using CommonType = typename std::common_type<OfType, T>::type;
4091 return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
2098 } 4092 }
4093};
2099 4094
2100 /*! 4095template<typename OfType, typename T>
2101 @brief destructor 4096struct value_in_range_of_impl2<OfType, T, true, false>
4097{
4098 static constexpr bool test(T val)
4099 {
4100 using CommonType = typename std::common_type<OfType, T>::type;
4101 return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
4102 }
4103};
2102 4104
2103 Destroys the JSON value and frees all allocated memory. 4105template<typename OfType, typename T>
4106struct value_in_range_of_impl2<OfType, T, false, true>
4107{
4108 static constexpr bool test(T val)
4109 {
4110 using CommonType = typename std::common_type<OfType, T>::type;
4111 return val >= 0 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
4112 }
4113};
2104 4114
2105 @complexity Linear. 4115template<typename OfType, typename T>
4116struct value_in_range_of_impl2<OfType, T, true, true>
4117{
4118 static constexpr bool test(T val)
4119 {
4120 using CommonType = typename std::common_type<OfType, T>::type;
4121 return static_cast<CommonType>(val) >= static_cast<CommonType>((std::numeric_limits<OfType>::min)())
4122 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
4123 }
4124};
2106 4125
2107 @requirement This function helps `basic_json` satisfying the 4126template<typename OfType, typename T,
2108 [Container](http://en.cppreference.com/w/cpp/concept/Container) 4127 bool NeverOutOfRange = never_out_of_range<OfType, T>::value,
2109 requirements: 4128 typename = detail::enable_if_t<all_integral<OfType, T>::value>>
2110 - The complexity is linear. 4129struct value_in_range_of_impl1;
2111 - All stored elements are destroyed and all memory is freed.
2112 4130
2113 @since version 1.0.0 4131template<typename OfType, typename T>
2114 */ 4132struct value_in_range_of_impl1<OfType, T, false>
2115 ~basic_json() 4133{
4134 static constexpr bool test(T val)
2116 { 4135 {
2117 assert_invariant(); 4136 return value_in_range_of_impl2<OfType, T>::test(val);
4137 }
4138};
2118 4139
2119 switch (m_type) 4140template<typename OfType, typename T>
2120 { 4141struct value_in_range_of_impl1<OfType, T, true>
2121 case value_t::object: 4142{
2122 { 4143 static constexpr bool test(T /*val*/)
2123 AllocatorType<object_t> alloc; 4144 {
2124 alloc.destroy(m_value.object); 4145 return true;
2125 alloc.deallocate(m_value.object, 1); 4146 }
2126 break; 4147};
2127 }
2128 4148
2129 case value_t::array: 4149template<typename OfType, typename T>
2130 { 4150inline constexpr bool value_in_range_of(T val)
2131 AllocatorType<array_t> alloc; 4151{
2132 alloc.destroy(m_value.array); 4152 return value_in_range_of_impl1<OfType, T>::test(val);
2133 alloc.deallocate(m_value.array, 1); 4153}
2134 break;
2135 }
2136 4154
2137 case value_t::string: 4155template<bool Value>
2138 { 4156using bool_constant = std::integral_constant<bool, Value>;
2139 AllocatorType<string_t> alloc;
2140 alloc.destroy(m_value.string);
2141 alloc.deallocate(m_value.string, 1);
2142 break;
2143 }
2144 4157
2145 default: 4158///////////////////////////////////////////////////////////////////////////////
2146 { 4159// is_c_string
2147 // all other types need no specific destructor 4160///////////////////////////////////////////////////////////////////////////////
2148 break;
2149 }
2150 }
2151 }
2152 4161
2153 /// @} 4162namespace impl
4163{
2154 4164
2155 public: 4165template<typename T>
2156 /////////////////////// 4166inline constexpr bool is_c_string()
2157 // object inspection // 4167{
2158 /////////////////////// 4168 using TUnExt = typename std::remove_extent<T>::type;
4169 using TUnCVExt = typename std::remove_cv<TUnExt>::type;
4170 using TUnPtr = typename std::remove_pointer<T>::type;
4171 using TUnCVPtr = typename std::remove_cv<TUnPtr>::type;
4172 return
4173 (std::is_array<T>::value && std::is_same<TUnCVExt, char>::value)
4174 || (std::is_pointer<T>::value && std::is_same<TUnCVPtr, char>::value);
4175}
2159 4176
2160 /// @name object inspection 4177} // namespace impl
2161 /// Functions to inspect the type of a JSON value.
2162 /// @{
2163 4178
2164 /*! 4179// checks whether T is a [cv] char */[cv] char[] C string
2165 @brief serialization 4180template<typename T>
4181struct is_c_string : bool_constant<impl::is_c_string<T>()> {};
2166 4182
2167 Serialization function for JSON values. The function tries to mimic 4183template<typename T>
2168 Python's `json.dumps()` function, and currently supports its @a indent 4184using is_c_string_uncvref = is_c_string<uncvref_t<T>>;
2169 parameter.
2170 4185
2171 @param[in] indent If indent is nonnegative, then array elements and object 4186///////////////////////////////////////////////////////////////////////////////
2172 members will be pretty-printed with that indent level. An indent level of 4187// is_transparent
2173 `0` will only insert newlines. `-1` (the default) selects the most compact 4188///////////////////////////////////////////////////////////////////////////////
2174 representation.
2175 4189
2176 @return string containing the serialization of the JSON value 4190namespace impl
4191{
2177 4192
2178 @complexity Linear. 4193template<typename T>
4194inline constexpr bool is_transparent()
4195{
4196 return is_detected<detect_is_transparent, T>::value;
4197}
2179 4198
2180 @liveexample{The following example shows the effect of different @a indent 4199} // namespace impl
2181 parameters to the result of the serialization.,dump}
2182 4200
2183 @see https://docs.python.org/2/library/json.html#json.dump 4201// checks whether T has a member named is_transparent
4202template<typename T>
4203struct is_transparent : bool_constant<impl::is_transparent<T>()> {};
2184 4204
2185 @since version 1.0.0 4205///////////////////////////////////////////////////////////////////////////////
2186 */
2187 string_t dump(const int indent = -1) const
2188 {
2189 std::stringstream ss;
2190 // fix locale problems
2191 ss.imbue(std::locale::classic());
2192 4206
2193 // 6, 15 or 16 digits of precision allows round-trip IEEE 754 4207} // namespace detail
2194 // string->float->string, string->double->string or string->long 4208NLOHMANN_JSON_NAMESPACE_END
2195 // double->string; to be safe, we read this value from
2196 // std::numeric_limits<number_float_t>::digits10
2197 ss.precision(std::numeric_limits<double>::digits10);
2198 4209
2199 if (indent >= 0) 4210// #include <nlohmann/detail/string_concat.hpp>
2200 { 4211// __ _____ _____ _____
2201 dump(ss, true, static_cast<unsigned int>(indent)); 4212// __| | __| | | | JSON for Modern C++
2202 } 4213// | | |__ | | | | | | version 3.11.3
2203 else 4214// |_____|_____|_____|_|___| https://github.com/nlohmann/json
2204 { 4215//
2205 dump(ss, false, 0); 4216// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
2206 } 4217// SPDX-License-Identifier: MIT
2207 4218
2208 return ss.str();
2209 }
2210 4219
2211 /*!
2212 @brief return the type of the JSON value (explicit)
2213 4220
2214 Return the type of the JSON value as a value from the @ref value_t 4221#include <cstring> // strlen
2215 enumeration. 4222#include <string> // string
4223#include <utility> // forward
2216 4224
2217 @return the type of the JSON value 4225// #include <nlohmann/detail/meta/cpp_future.hpp>
2218 4226
2219 @complexity Constant. 4227// #include <nlohmann/detail/meta/detected.hpp>
2220 4228
2221 @exceptionsafety No-throw guarantee: this member function never throws
2222 exceptions.
2223 4229
2224 @liveexample{The following code exemplifies `type()` for all JSON 4230NLOHMANN_JSON_NAMESPACE_BEGIN
2225 types.,type} 4231namespace detail
4232{
2226 4233
2227 @since version 1.0.0 4234inline std::size_t concat_length()
2228 */ 4235{
2229 constexpr value_t type() const noexcept 4236 return 0;
2230 { 4237}
2231 return m_type;
2232 }
2233 4238
2234 /*! 4239template<typename... Args>
2235 @brief return whether type is primitive 4240inline std::size_t concat_length(const char* cstr, const Args& ... rest);
2236 4241
2237 This function returns true iff the JSON type is primitive (string, number, 4242template<typename StringType, typename... Args>
2238 boolean, or null). 4243inline std::size_t concat_length(const StringType& str, const Args& ... rest);
2239 4244
2240 @return `true` if type is primitive (string, number, boolean, or null), 4245template<typename... Args>
2241 `false` otherwise. 4246inline std::size_t concat_length(const char /*c*/, const Args& ... rest)
4247{
4248 return 1 + concat_length(rest...);
4249}
2242 4250
2243 @complexity Constant. 4251template<typename... Args>
4252inline std::size_t concat_length(const char* cstr, const Args& ... rest)
4253{
4254 // cppcheck-suppress ignoredReturnValue
4255 return ::strlen(cstr) + concat_length(rest...);
4256}
2244 4257
2245 @exceptionsafety No-throw guarantee: this member function never throws 4258template<typename StringType, typename... Args>
2246 exceptions. 4259inline std::size_t concat_length(const StringType& str, const Args& ... rest)
4260{
4261 return str.size() + concat_length(rest...);
4262}
2247 4263
2248 @liveexample{The following code exemplifies `is_primitive()` for all JSON 4264template<typename OutStringType>
2249 types.,is_primitive} 4265inline void concat_into(OutStringType& /*out*/)
4266{}
2250 4267
2251 @sa @ref is_structured() -- returns whether JSON value is structured 4268template<typename StringType, typename Arg>
2252 @sa @ref is_null() -- returns whether JSON value is `null` 4269using string_can_append = decltype(std::declval<StringType&>().append(std::declval < Arg && > ()));
2253 @sa @ref is_string() -- returns whether JSON value is a string
2254 @sa @ref is_boolean() -- returns whether JSON value is a boolean
2255 @sa @ref is_number() -- returns whether JSON value is a number
2256 4270
2257 @since version 1.0.0 4271template<typename StringType, typename Arg>
2258 */ 4272using detect_string_can_append = is_detected<string_can_append, StringType, Arg>;
2259 constexpr bool is_primitive() const noexcept
2260 {
2261 return is_null() or is_string() or is_boolean() or is_number();
2262 }
2263 4273
2264 /*! 4274template<typename StringType, typename Arg>
2265 @brief return whether type is structured 4275using string_can_append_op = decltype(std::declval<StringType&>() += std::declval < Arg && > ());
2266 4276
2267 This function returns true iff the JSON type is structured (array or 4277template<typename StringType, typename Arg>
2268 object). 4278using detect_string_can_append_op = is_detected<string_can_append_op, StringType, Arg>;
2269 4279
2270 @return `true` if type is structured (array or object), `false` otherwise. 4280template<typename StringType, typename Arg>
4281using string_can_append_iter = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().begin(), std::declval<const Arg&>().end()));
2271 4282
2272 @complexity Constant. 4283template<typename StringType, typename Arg>
4284using detect_string_can_append_iter = is_detected<string_can_append_iter, StringType, Arg>;
2273 4285
2274 @exceptionsafety No-throw guarantee: this member function never throws 4286template<typename StringType, typename Arg>
2275 exceptions. 4287using string_can_append_data = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().data(), std::declval<const Arg&>().size()));
2276 4288
2277 @liveexample{The following code exemplifies `is_structured()` for all JSON 4289template<typename StringType, typename Arg>
2278 types.,is_structured} 4290using detect_string_can_append_data = is_detected<string_can_append_data, StringType, Arg>;
2279 4291
2280 @sa @ref is_primitive() -- returns whether value is primitive 4292template < typename OutStringType, typename Arg, typename... Args,
2281 @sa @ref is_array() -- returns whether value is an array 4293 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
2282 @sa @ref is_object() -- returns whether value is an object 4294 && detect_string_can_append_op<OutStringType, Arg>::value, int > = 0 >
4295inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest);
2283 4296
2284 @since version 1.0.0 4297template < typename OutStringType, typename Arg, typename... Args,
2285 */ 4298 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
2286 constexpr bool is_structured() const noexcept 4299 && !detect_string_can_append_op<OutStringType, Arg>::value
2287 { 4300 && detect_string_can_append_iter<OutStringType, Arg>::value, int > = 0 >
2288 return is_array() or is_object(); 4301inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
2289 }
2290 4302
2291 /*! 4303template < typename OutStringType, typename Arg, typename... Args,
2292 @brief return whether value is null 4304 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
4305 && !detect_string_can_append_op<OutStringType, Arg>::value
4306 && !detect_string_can_append_iter<OutStringType, Arg>::value
4307 && detect_string_can_append_data<OutStringType, Arg>::value, int > = 0 >
4308inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
2293 4309
2294 This function returns true iff the JSON value is null. 4310template<typename OutStringType, typename Arg, typename... Args,
4311 enable_if_t<detect_string_can_append<OutStringType, Arg>::value, int> = 0>
4312inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest)
4313{
4314 out.append(std::forward<Arg>(arg));
4315 concat_into(out, std::forward<Args>(rest)...);
4316}
2295 4317
2296 @return `true` if type is null, `false` otherwise. 4318template < typename OutStringType, typename Arg, typename... Args,
4319 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
4320 && detect_string_can_append_op<OutStringType, Arg>::value, int > >
4321inline void concat_into(OutStringType& out, Arg&& arg, Args&& ... rest)
4322{
4323 out += std::forward<Arg>(arg);
4324 concat_into(out, std::forward<Args>(rest)...);
4325}
2297 4326
2298 @complexity Constant. 4327template < typename OutStringType, typename Arg, typename... Args,
4328 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
4329 && !detect_string_can_append_op<OutStringType, Arg>::value
4330 && detect_string_can_append_iter<OutStringType, Arg>::value, int > >
4331inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
4332{
4333 out.append(arg.begin(), arg.end());
4334 concat_into(out, std::forward<Args>(rest)...);
4335}
2299 4336
2300 @exceptionsafety No-throw guarantee: this member function never throws 4337template < typename OutStringType, typename Arg, typename... Args,
2301 exceptions. 4338 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
4339 && !detect_string_can_append_op<OutStringType, Arg>::value
4340 && !detect_string_can_append_iter<OutStringType, Arg>::value
4341 && detect_string_can_append_data<OutStringType, Arg>::value, int > >
4342inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
4343{
4344 out.append(arg.data(), arg.size());
4345 concat_into(out, std::forward<Args>(rest)...);
4346}
2302 4347
2303 @liveexample{The following code exemplifies `is_null()` for all JSON 4348template<typename OutStringType = std::string, typename... Args>
2304 types.,is_null} 4349inline OutStringType concat(Args && ... args)
4350{
4351 OutStringType str;
4352 str.reserve(concat_length(args...));
4353 concat_into(str, std::forward<Args>(args)...);
4354 return str;
4355}
2305 4356
2306 @since version 1.0.0 4357} // namespace detail
2307 */ 4358NLOHMANN_JSON_NAMESPACE_END
2308 constexpr bool is_null() const noexcept
2309 {
2310 return m_type == value_t::null;
2311 }
2312 4359
2313 /*!
2314 @brief return whether value is a boolean
2315 4360
2316 This function returns true iff the JSON value is a boolean. 4361NLOHMANN_JSON_NAMESPACE_BEGIN
4362namespace detail
4363{
2317 4364
2318 @return `true` if type is boolean, `false` otherwise. 4365////////////////
4366// exceptions //
4367////////////////
2319 4368
2320 @complexity Constant. 4369/// @brief general exception of the @ref basic_json class
4370/// @sa https://json.nlohmann.me/api/basic_json/exception/
4371class exception : public std::exception
4372{
4373 public:
4374 /// returns the explanatory string
4375 const char* what() const noexcept override
4376 {
4377 return m.what();
4378 }
2321 4379
2322 @exceptionsafety No-throw guarantee: this member function never throws 4380 /// the id of the exception
2323 exceptions. 4381 const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
2324 4382
2325 @liveexample{The following code exemplifies `is_boolean()` for all JSON 4383 protected:
2326 types.,is_boolean} 4384 JSON_HEDLEY_NON_NULL(3)
4385 exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing)
2327 4386
2328 @since version 1.0.0 4387 static std::string name(const std::string& ename, int id_)
2329 */
2330 constexpr bool is_boolean() const noexcept
2331 { 4388 {
2332 return m_type == value_t::boolean; 4389 return concat("[json.exception.", ename, '.', std::to_string(id_), "] ");
2333 } 4390 }
2334 4391
2335 /*! 4392 static std::string diagnostics(std::nullptr_t /*leaf_element*/)
2336 @brief return whether value is a number 4393 {
4394 return "";
4395 }
2337 4396
2338 This function returns true iff the JSON value is a number. This includes 4397 template<typename BasicJsonType>
2339 both integer and floating-point values. 4398 static std::string diagnostics(const BasicJsonType* leaf_element)
4399 {
4400#if JSON_DIAGNOSTICS
4401 std::vector<std::string> tokens;
4402 for (const auto* current = leaf_element; current != nullptr && current->m_parent != nullptr; current = current->m_parent)
4403 {
4404 switch (current->m_parent->type())
4405 {
4406 case value_t::array:
4407 {
4408 for (std::size_t i = 0; i < current->m_parent->m_data.m_value.array->size(); ++i)
4409 {
4410 if (&current->m_parent->m_data.m_value.array->operator[](i) == current)
4411 {
4412 tokens.emplace_back(std::to_string(i));
4413 break;
4414 }
4415 }
4416 break;
4417 }
2340 4418
2341 @return `true` if type is number (regardless whether integer, unsigned 4419 case value_t::object:
2342 integer or floating-type), `false` otherwise. 4420 {
4421 for (const auto& element : *current->m_parent->m_data.m_value.object)
4422 {
4423 if (&element.second == current)
4424 {
4425 tokens.emplace_back(element.first.c_str());
4426 break;
4427 }
4428 }
4429 break;
4430 }
2343 4431
2344 @complexity Constant. 4432 case value_t::null: // LCOV_EXCL_LINE
4433 case value_t::string: // LCOV_EXCL_LINE
4434 case value_t::boolean: // LCOV_EXCL_LINE
4435 case value_t::number_integer: // LCOV_EXCL_LINE
4436 case value_t::number_unsigned: // LCOV_EXCL_LINE
4437 case value_t::number_float: // LCOV_EXCL_LINE
4438 case value_t::binary: // LCOV_EXCL_LINE
4439 case value_t::discarded: // LCOV_EXCL_LINE
4440 default: // LCOV_EXCL_LINE
4441 break; // LCOV_EXCL_LINE
4442 }
4443 }
2345 4444
2346 @exceptionsafety No-throw guarantee: this member function never throws 4445 if (tokens.empty())
2347 exceptions. 4446 {
4447 return "";
4448 }
2348 4449
2349 @liveexample{The following code exemplifies `is_number()` for all JSON 4450 auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{},
2350 types.,is_number} 4451 [](const std::string & a, const std::string & b)
4452 {
4453 return concat(a, '/', detail::escape(b));
4454 });
4455 return concat('(', str, ") ");
4456#else
4457 static_cast<void>(leaf_element);
4458 return "";
4459#endif
4460 }
2351 4461
2352 @sa @ref is_number_integer() -- check if value is an integer or unsigned 4462 private:
2353 integer number 4463 /// an exception object as storage for error messages
2354 @sa @ref is_number_unsigned() -- check if value is an unsigned integer 4464 std::runtime_error m;
2355 number 4465};
2356 @sa @ref is_number_float() -- check if value is a floating-point number
2357 4466
2358 @since version 1.0.0 4467/// @brief exception indicating a parse error
4468/// @sa https://json.nlohmann.me/api/basic_json/parse_error/
4469class parse_error : public exception
4470{
4471 public:
4472 /*!
4473 @brief create a parse error exception
4474 @param[in] id_ the id of the exception
4475 @param[in] pos the position where the error occurred (or with
4476 chars_read_total=0 if the position cannot be
4477 determined)
4478 @param[in] what_arg the explanatory string
4479 @return parse_error object
2359 */ 4480 */
2360 constexpr bool is_number() const noexcept 4481 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
4482 static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context)
2361 { 4483 {
2362 return is_number_integer() or is_number_float(); 4484 const std::string w = concat(exception::name("parse_error", id_), "parse error",
4485 position_string(pos), ": ", exception::diagnostics(context), what_arg);
4486 return {id_, pos.chars_read_total, w.c_str()};
4487 }
4488
4489 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
4490 static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context)
4491 {
4492 const std::string w = concat(exception::name("parse_error", id_), "parse error",
4493 (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""),
4494 ": ", exception::diagnostics(context), what_arg);
4495 return {id_, byte_, w.c_str()};
2363 } 4496 }
2364 4497
2365 /*! 4498 /*!
2366 @brief return whether value is an integer number 4499 @brief byte index of the parse error
2367 4500
2368 This function returns true iff the JSON value is an integer or unsigned 4501 The byte index of the last read character in the input file.
2369 integer number. This excludes floating-point values.
2370 4502
2371 @return `true` if type is an integer or unsigned integer number, `false` 4503 @note For an input with n bytes, 1 is the index of the first character and
2372 otherwise. 4504 n+1 is the index of the terminating null byte or the end of file.
4505 This also holds true when reading a byte vector (CBOR or MessagePack).
4506 */
4507 const std::size_t byte;
2373 4508
2374 @complexity Constant. 4509 private:
4510 parse_error(int id_, std::size_t byte_, const char* what_arg)
4511 : exception(id_, what_arg), byte(byte_) {}
2375 4512
2376 @exceptionsafety No-throw guarantee: this member function never throws 4513 static std::string position_string(const position_t& pos)
2377 exceptions. 4514 {
4515 return concat(" at line ", std::to_string(pos.lines_read + 1),
4516 ", column ", std::to_string(pos.chars_read_current_line));
4517 }
4518};
2378 4519
2379 @liveexample{The following code exemplifies `is_number_integer()` for all 4520/// @brief exception indicating errors with iterators
2380 JSON types.,is_number_integer} 4521/// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/
4522class invalid_iterator : public exception
4523{
4524 public:
4525 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
4526 static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context)
4527 {
4528 const std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg);
4529 return {id_, w.c_str()};
4530 }
2381 4531
2382 @sa @ref is_number() -- check if value is a number 4532 private:
2383 @sa @ref is_number_unsigned() -- check if value is an unsigned integer 4533 JSON_HEDLEY_NON_NULL(3)
2384 number 4534 invalid_iterator(int id_, const char* what_arg)
2385 @sa @ref is_number_float() -- check if value is a floating-point number 4535 : exception(id_, what_arg) {}
4536};
2386 4537
2387 @since version 1.0.0 4538/// @brief exception indicating executing a member function with a wrong type
2388 */ 4539/// @sa https://json.nlohmann.me/api/basic_json/type_error/
2389 constexpr bool is_number_integer() const noexcept 4540class type_error : public exception
4541{
4542 public:
4543 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
4544 static type_error create(int id_, const std::string& what_arg, BasicJsonContext context)
2390 { 4545 {
2391 return m_type == value_t::number_integer or m_type == value_t::number_unsigned; 4546 const std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg);
4547 return {id_, w.c_str()};
2392 } 4548 }
2393 4549
2394 /*! 4550 private:
2395 @brief return whether value is an unsigned integer number 4551 JSON_HEDLEY_NON_NULL(3)
4552 type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
4553};
2396 4554
2397 This function returns true iff the JSON value is an unsigned integer 4555/// @brief exception indicating access out of the defined range
2398 number. This excludes floating-point and (signed) integer values. 4556/// @sa https://json.nlohmann.me/api/basic_json/out_of_range/
4557class out_of_range : public exception
4558{
4559 public:
4560 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
4561 static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context)
4562 {
4563 const std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg);
4564 return {id_, w.c_str()};
4565 }
2399 4566
2400 @return `true` if type is an unsigned integer number, `false` otherwise. 4567 private:
4568 JSON_HEDLEY_NON_NULL(3)
4569 out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
4570};
2401 4571
2402 @complexity Constant. 4572/// @brief exception indicating other library errors
4573/// @sa https://json.nlohmann.me/api/basic_json/other_error/
4574class other_error : public exception
4575{
4576 public:
4577 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
4578 static other_error create(int id_, const std::string& what_arg, BasicJsonContext context)
4579 {
4580 const std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg);
4581 return {id_, w.c_str()};
4582 }
2403 4583
2404 @exceptionsafety No-throw guarantee: this member function never throws 4584 private:
2405 exceptions. 4585 JSON_HEDLEY_NON_NULL(3)
4586 other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
4587};
2406 4588
2407 @liveexample{The following code exemplifies `is_number_unsigned()` for all 4589} // namespace detail
2408 JSON types.,is_number_unsigned} 4590NLOHMANN_JSON_NAMESPACE_END
2409 4591
2410 @sa @ref is_number() -- check if value is a number 4592// #include <nlohmann/detail/macro_scope.hpp>
2411 @sa @ref is_number_integer() -- check if value is an integer or unsigned
2412 integer number
2413 @sa @ref is_number_float() -- check if value is a floating-point number
2414 4593
2415 @since version 2.0.0 4594// #include <nlohmann/detail/meta/cpp_future.hpp>
2416 */
2417 constexpr bool is_number_unsigned() const noexcept
2418 {
2419 return m_type == value_t::number_unsigned;
2420 }
2421 4595
2422 /*! 4596// #include <nlohmann/detail/meta/identity_tag.hpp>
2423 @brief return whether value is a floating-point number 4597// __ _____ _____ _____
4598// __| | __| | | | JSON for Modern C++
4599// | | |__ | | | | | | version 3.11.3
4600// |_____|_____|_____|_|___| https://github.com/nlohmann/json
4601//
4602// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
4603// SPDX-License-Identifier: MIT
2424 4604
2425 This function returns true iff the JSON value is a floating-point number.
2426 This excludes integer and unsigned integer values.
2427 4605
2428 @return `true` if type is a floating-point number, `false` otherwise.
2429 4606
2430 @complexity Constant. 4607// #include <nlohmann/detail/abi_macros.hpp>
2431 4608
2432 @exceptionsafety No-throw guarantee: this member function never throws
2433 exceptions.
2434 4609
2435 @liveexample{The following code exemplifies `is_number_float()` for all 4610NLOHMANN_JSON_NAMESPACE_BEGIN
2436 JSON types.,is_number_float} 4611namespace detail
4612{
2437 4613
2438 @sa @ref is_number() -- check if value is number 4614// dispatching helper struct
2439 @sa @ref is_number_integer() -- check if value is an integer number 4615template <class T> struct identity_tag {};
2440 @sa @ref is_number_unsigned() -- check if value is an unsigned integer
2441 number
2442 4616
2443 @since version 1.0.0 4617} // namespace detail
2444 */ 4618NLOHMANN_JSON_NAMESPACE_END
2445 constexpr bool is_number_float() const noexcept
2446 {
2447 return m_type == value_t::number_float;
2448 }
2449 4619
2450 /*! 4620// #include <nlohmann/detail/meta/std_fs.hpp>
2451 @brief return whether value is an object 4621// __ _____ _____ _____
4622// __| | __| | | | JSON for Modern C++
4623// | | |__ | | | | | | version 3.11.3
4624// |_____|_____|_____|_|___| https://github.com/nlohmann/json
4625//
4626// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
4627// SPDX-License-Identifier: MIT
2452 4628
2453 This function returns true iff the JSON value is an object.
2454 4629
2455 @return `true` if type is object, `false` otherwise.
2456 4630
2457 @complexity Constant. 4631// #include <nlohmann/detail/macro_scope.hpp>
2458 4632
2459 @exceptionsafety No-throw guarantee: this member function never throws
2460 exceptions.
2461 4633
2462 @liveexample{The following code exemplifies `is_object()` for all JSON 4634#if JSON_HAS_EXPERIMENTAL_FILESYSTEM
2463 types.,is_object} 4635#include <experimental/filesystem>
4636NLOHMANN_JSON_NAMESPACE_BEGIN
4637namespace detail
4638{
4639namespace std_fs = std::experimental::filesystem;
4640} // namespace detail
4641NLOHMANN_JSON_NAMESPACE_END
4642#elif JSON_HAS_FILESYSTEM
4643#include <filesystem>
4644NLOHMANN_JSON_NAMESPACE_BEGIN
4645namespace detail
4646{
4647namespace std_fs = std::filesystem;
4648} // namespace detail
4649NLOHMANN_JSON_NAMESPACE_END
4650#endif
2464 4651
2465 @since version 1.0.0 4652// #include <nlohmann/detail/meta/type_traits.hpp>
2466 */
2467 constexpr bool is_object() const noexcept
2468 {
2469 return m_type == value_t::object;
2470 }
2471 4653
2472 /*! 4654// #include <nlohmann/detail/string_concat.hpp>
2473 @brief return whether value is an array
2474 4655
2475 This function returns true iff the JSON value is an array. 4656// #include <nlohmann/detail/value_t.hpp>
2476 4657
2477 @return `true` if type is array, `false` otherwise.
2478 4658
2479 @complexity Constant. 4659NLOHMANN_JSON_NAMESPACE_BEGIN
4660namespace detail
4661{
4662
4663template<typename BasicJsonType>
4664inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
4665{
4666 if (JSON_HEDLEY_UNLIKELY(!j.is_null()))
4667 {
4668 JSON_THROW(type_error::create(302, concat("type must be null, but is ", j.type_name()), &j));
4669 }
4670 n = nullptr;
4671}
4672
4673// overloads for basic_json template parameters
4674template < typename BasicJsonType, typename ArithmeticType,
4675 enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
4676 !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
4677 int > = 0 >
4678void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
4679{
4680 switch (static_cast<value_t>(j))
4681 {
4682 case value_t::number_unsigned:
4683 {
4684 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
4685 break;
4686 }
4687 case value_t::number_integer:
4688 {
4689 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
4690 break;
4691 }
4692 case value_t::number_float:
4693 {
4694 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
4695 break;
4696 }
2480 4697
2481 @exceptionsafety No-throw guarantee: this member function never throws 4698 case value_t::null:
2482 exceptions. 4699 case value_t::object:
4700 case value_t::array:
4701 case value_t::string:
4702 case value_t::boolean:
4703 case value_t::binary:
4704 case value_t::discarded:
4705 default:
4706 JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
4707 }
4708}
2483 4709
2484 @liveexample{The following code exemplifies `is_array()` for all JSON 4710template<typename BasicJsonType>
2485 types.,is_array} 4711inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
4712{
4713 if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
4714 {
4715 JSON_THROW(type_error::create(302, concat("type must be boolean, but is ", j.type_name()), &j));
4716 }
4717 b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
4718}
2486 4719
2487 @since version 1.0.0 4720template<typename BasicJsonType>
2488 */ 4721inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
2489 constexpr bool is_array() const noexcept 4722{
4723 if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
2490 { 4724 {
2491 return m_type == value_t::array; 4725 JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
2492 } 4726 }
4727 s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
4728}
2493 4729
2494 /*! 4730template <
2495 @brief return whether value is a string 4731 typename BasicJsonType, typename StringType,
4732 enable_if_t <
4733 std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value
4734 && is_detected_exact<typename BasicJsonType::string_t::value_type, value_type_t, StringType>::value
4735 && !std::is_same<typename BasicJsonType::string_t, StringType>::value
4736 && !is_json_ref<StringType>::value, int > = 0 >
4737inline void from_json(const BasicJsonType& j, StringType& s)
4738{
4739 if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
4740 {
4741 JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
4742 }
2496 4743
2497 This function returns true iff the JSON value is a string. 4744 s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
4745}
2498 4746
2499 @return `true` if type is string, `false` otherwise. 4747template<typename BasicJsonType>
4748inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
4749{
4750 get_arithmetic_value(j, val);
4751}
2500 4752
2501 @complexity Constant. 4753template<typename BasicJsonType>
4754inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
4755{
4756 get_arithmetic_value(j, val);
4757}
2502 4758
2503 @exceptionsafety No-throw guarantee: this member function never throws 4759template<typename BasicJsonType>
2504 exceptions. 4760inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
4761{
4762 get_arithmetic_value(j, val);
4763}
2505 4764
2506 @liveexample{The following code exemplifies `is_string()` for all JSON 4765#if !JSON_DISABLE_ENUM_SERIALIZATION
2507 types.,is_string} 4766template<typename BasicJsonType, typename EnumType,
4767 enable_if_t<std::is_enum<EnumType>::value, int> = 0>
4768inline void from_json(const BasicJsonType& j, EnumType& e)
4769{
4770 typename std::underlying_type<EnumType>::type val;
4771 get_arithmetic_value(j, val);
4772 e = static_cast<EnumType>(val);
4773}
4774#endif // JSON_DISABLE_ENUM_SERIALIZATION
2508 4775
2509 @since version 1.0.0 4776// forward_list doesn't have an insert method
2510 */ 4777template<typename BasicJsonType, typename T, typename Allocator,
2511 constexpr bool is_string() const noexcept 4778 enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
4779inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
4780{
4781 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
2512 { 4782 {
2513 return m_type == value_t::string; 4783 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
2514 } 4784 }
4785 l.clear();
4786 std::transform(j.rbegin(), j.rend(),
4787 std::front_inserter(l), [](const BasicJsonType & i)
4788 {
4789 return i.template get<T>();
4790 });
4791}
2515 4792
2516 /*! 4793// valarray doesn't have an insert method
2517 @brief return whether value is discarded 4794template<typename BasicJsonType, typename T,
4795 enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
4796inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
4797{
4798 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
4799 {
4800 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
4801 }
4802 l.resize(j.size());
4803 std::transform(j.begin(), j.end(), std::begin(l),
4804 [](const BasicJsonType & elem)
4805 {
4806 return elem.template get<T>();
4807 });
4808}
2518 4809
2519 This function returns true iff the JSON value was discarded during parsing 4810template<typename BasicJsonType, typename T, std::size_t N>
2520 with a callback function (see @ref parser_callback_t). 4811auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
4812-> decltype(j.template get<T>(), void())
4813{
4814 for (std::size_t i = 0; i < N; ++i)
4815 {
4816 arr[i] = j.at(i).template get<T>();
4817 }
4818}
2521 4819
2522 @note This function will always be `false` for JSON values after parsing. 4820template<typename BasicJsonType>
2523 That is, discarded values can only occur during parsing, but will be 4821inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
2524 removed when inside a structured value or replaced by null in other cases. 4822{
4823 arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
4824}
2525 4825
2526 @return `true` if type is discarded, `false` otherwise. 4826template<typename BasicJsonType, typename T, std::size_t N>
4827auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
4828 priority_tag<2> /*unused*/)
4829-> decltype(j.template get<T>(), void())
4830{
4831 for (std::size_t i = 0; i < N; ++i)
4832 {
4833 arr[i] = j.at(i).template get<T>();
4834 }
4835}
2527 4836
2528 @complexity Constant. 4837template<typename BasicJsonType, typename ConstructibleArrayType,
4838 enable_if_t<
4839 std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
4840 int> = 0>
4841auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
4842-> decltype(
4843 arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),
4844 j.template get<typename ConstructibleArrayType::value_type>(),
4845 void())
4846{
4847 using std::end;
2529 4848
2530 @exceptionsafety No-throw guarantee: this member function never throws 4849 ConstructibleArrayType ret;
2531 exceptions. 4850 ret.reserve(j.size());
4851 std::transform(j.begin(), j.end(),
4852 std::inserter(ret, end(ret)), [](const BasicJsonType & i)
4853 {
4854 // get<BasicJsonType>() returns *this, this won't call a from_json
4855 // method when value_type is BasicJsonType
4856 return i.template get<typename ConstructibleArrayType::value_type>();
4857 });
4858 arr = std::move(ret);
4859}
2532 4860
2533 @liveexample{The following code exemplifies `is_discarded()` for all JSON 4861template<typename BasicJsonType, typename ConstructibleArrayType,
2534 types.,is_discarded} 4862 enable_if_t<
4863 std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
4864 int> = 0>
4865inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
4866 priority_tag<0> /*unused*/)
4867{
4868 using std::end;
2535 4869
2536 @since version 1.0.0 4870 ConstructibleArrayType ret;
2537 */ 4871 std::transform(
2538 constexpr bool is_discarded() const noexcept 4872 j.begin(), j.end(), std::inserter(ret, end(ret)),
4873 [](const BasicJsonType & i)
4874 {
4875 // get<BasicJsonType>() returns *this, this won't call a from_json
4876 // method when value_type is BasicJsonType
4877 return i.template get<typename ConstructibleArrayType::value_type>();
4878 });
4879 arr = std::move(ret);
4880}
4881
4882template < typename BasicJsonType, typename ConstructibleArrayType,
4883 enable_if_t <
4884 is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
4885 !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
4886 !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
4887 !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
4888 !is_basic_json<ConstructibleArrayType>::value,
4889 int > = 0 >
4890auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
4891-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
4892j.template get<typename ConstructibleArrayType::value_type>(),
4893void())
4894{
4895 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
2539 { 4896 {
2540 return m_type == value_t::discarded; 4897 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
2541 } 4898 }
2542 4899
2543 /*! 4900 from_json_array_impl(j, arr, priority_tag<3> {});
2544 @brief return the type of the JSON value (implicit) 4901}
2545 4902
2546 Implicitly return the type of the JSON value as a value from the @ref 4903template < typename BasicJsonType, typename T, std::size_t... Idx >
2547 value_t enumeration. 4904std::array<T, sizeof...(Idx)> from_json_inplace_array_impl(BasicJsonType&& j,
4905 identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/, index_sequence<Idx...> /*unused*/)
4906{
4907 return { { std::forward<BasicJsonType>(j).at(Idx).template get<T>()... } };
4908}
2548 4909
2549 @return the type of the JSON value 4910template < typename BasicJsonType, typename T, std::size_t N >
4911auto from_json(BasicJsonType&& j, identity_tag<std::array<T, N>> tag)
4912-> decltype(from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {}))
4913{
4914 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
4915 {
4916 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
4917 }
2550 4918
2551 @complexity Constant. 4919 return from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {});
4920}
2552 4921
2553 @exceptionsafety No-throw guarantee: this member function never throws 4922template<typename BasicJsonType>
2554 exceptions. 4923inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
4924{
4925 if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
4926 {
4927 JSON_THROW(type_error::create(302, concat("type must be binary, but is ", j.type_name()), &j));
4928 }
2555 4929
2556 @liveexample{The following code exemplifies the @ref value_t operator for 4930 bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
2557 all JSON types.,operator__value_t} 4931}
2558 4932
2559 @since version 1.0.0 4933template<typename BasicJsonType, typename ConstructibleObjectType,
2560 */ 4934 enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
2561 constexpr operator value_t() const noexcept 4935inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
4936{
4937 if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
2562 { 4938 {
2563 return m_type; 4939 JSON_THROW(type_error::create(302, concat("type must be object, but is ", j.type_name()), &j));
2564 } 4940 }
2565 4941
2566 /// @} 4942 ConstructibleObjectType ret;
2567 4943 const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
2568 private: 4944 using value_type = typename ConstructibleObjectType::value_type;
2569 ////////////////// 4945 std::transform(
2570 // value access // 4946 inner_object->begin(), inner_object->end(),
2571 ////////////////// 4947 std::inserter(ret, ret.begin()),
4948 [](typename BasicJsonType::object_t::value_type const & p)
4949 {
4950 return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());
4951 });
4952 obj = std::move(ret);
4953}
2572 4954
2573 /// get an object (explicit) 4955// overload for arithmetic types, not chosen for basic_json template arguments
2574 template<class T, typename std::enable_if< 4956// (BooleanType, etc..); note: Is it really necessary to provide explicit
2575 std::is_convertible<typename object_t::key_type, typename T::key_type>::value and 4957// overloads for boolean_t etc. in case of a custom BooleanType which is not
2576 std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0> 4958// an arithmetic type?
2577 T get_impl(T*) const 4959template < typename BasicJsonType, typename ArithmeticType,
4960 enable_if_t <
4961 std::is_arithmetic<ArithmeticType>::value&&
4962 !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
4963 !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
4964 !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
4965 !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
4966 int > = 0 >
4967inline void from_json(const BasicJsonType& j, ArithmeticType& val)
4968{
4969 switch (static_cast<value_t>(j))
2578 { 4970 {
2579 if (is_object()) 4971 case value_t::number_unsigned:
2580 { 4972 {
2581 return T(m_value.object->begin(), m_value.object->end()); 4973 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
4974 break;
2582 } 4975 }
2583 else 4976 case value_t::number_integer:
2584 { 4977 {
2585 throw std::domain_error("type must be object, but is " + type_name()); 4978 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
4979 break;
2586 } 4980 }
2587 } 4981 case value_t::number_float:
2588
2589 /// get an object (explicit)
2590 object_t get_impl(object_t*) const
2591 {
2592 if (is_object())
2593 { 4982 {
2594 return *(m_value.object); 4983 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
4984 break;
2595 } 4985 }
2596 else 4986 case value_t::boolean:
2597 { 4987 {
2598 throw std::domain_error("type must be object, but is " + type_name()); 4988 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
4989 break;
2599 } 4990 }
4991
4992 case value_t::null:
4993 case value_t::object:
4994 case value_t::array:
4995 case value_t::string:
4996 case value_t::binary:
4997 case value_t::discarded:
4998 default:
4999 JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
2600 } 5000 }
5001}
5002
5003template<typename BasicJsonType, typename... Args, std::size_t... Idx>
5004std::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/)
5005{
5006 return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...);
5007}
5008
5009template < typename BasicJsonType, class A1, class A2 >
5010std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/)
5011{
5012 return {std::forward<BasicJsonType>(j).at(0).template get<A1>(),
5013 std::forward<BasicJsonType>(j).at(1).template get<A2>()};
5014}
5015
5016template<typename BasicJsonType, typename A1, typename A2>
5017inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/)
5018{
5019 p = from_json_tuple_impl(std::forward<BasicJsonType>(j), identity_tag<std::pair<A1, A2>> {}, priority_tag<0> {});
5020}
2601 5021
2602 /// get an array (explicit) 5022template<typename BasicJsonType, typename... Args>
2603 template<class T, typename std::enable_if< 5023std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
2604 std::is_convertible<basic_json_t, typename T::value_type>::value and 5024{
2605 not std::is_same<basic_json_t, typename T::value_type>::value and 5025 return from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
2606 not std::is_arithmetic<T>::value and 5026}
2607 not std::is_convertible<std::string, T>::value and 5027
2608 not has_mapped_type<T>::value, int>::type = 0> 5028template<typename BasicJsonType, typename... Args>
2609 T get_impl(T*) const 5029inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)
5030{
5031 t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
5032}
5033
5034template<typename BasicJsonType, typename TupleRelated>
5035auto from_json(BasicJsonType&& j, TupleRelated&& t)
5036-> decltype(from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {}))
5037{
5038 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
2610 { 5039 {
2611 if (is_array()) 5040 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
2612 {
2613 T to_vector;
2614 std::transform(m_value.array->begin(), m_value.array->end(),
2615 std::inserter(to_vector, to_vector.end()), [](basic_json i)
2616 {
2617 return i.get<typename T::value_type>();
2618 });
2619 return to_vector;
2620 }
2621 else
2622 {
2623 throw std::domain_error("type must be array, but is " + type_name());
2624 }
2625 } 5041 }
2626 5042
2627 /// get an array (explicit) 5043 return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});
2628 template<class T, typename std::enable_if< 5044}
2629 std::is_convertible<basic_json_t, T>::value and 5045
2630 not std::is_same<basic_json_t, T>::value, int>::type = 0> 5046template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
2631 std::vector<T> get_impl(std::vector<T>*) const 5047 typename = enable_if_t < !std::is_constructible <
5048 typename BasicJsonType::string_t, Key >::value >>
5049inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
5050{
5051 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
2632 { 5052 {
2633 if (is_array()) 5053 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
2634 { 5054 }
2635 std::vector<T> to_vector; 5055 m.clear();
2636 to_vector.reserve(m_value.array->size()); 5056 for (const auto& p : j)
2637 std::transform(m_value.array->begin(), m_value.array->end(), 5057 {
2638 std::inserter(to_vector, to_vector.end()), [](basic_json i) 5058 if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
2639 {
2640 return i.get<T>();
2641 });
2642 return to_vector;
2643 }
2644 else
2645 { 5059 {
2646 throw std::domain_error("type must be array, but is " + type_name()); 5060 JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
2647 } 5061 }
5062 m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
2648 } 5063 }
5064}
2649 5065
2650 /// get an array (explicit) 5066template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
2651 template<class T, typename std::enable_if< 5067 typename = enable_if_t < !std::is_constructible <
2652 std::is_same<basic_json, typename T::value_type>::value and 5068 typename BasicJsonType::string_t, Key >::value >>
2653 not has_mapped_type<T>::value, int>::type = 0> 5069inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
2654 T get_impl(T*) const 5070{
5071 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
2655 { 5072 {
2656 if (is_array()) 5073 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
2657 { 5074 }
2658 return T(m_value.array->begin(), m_value.array->end()); 5075 m.clear();
2659 } 5076 for (const auto& p : j)
2660 else 5077 {
5078 if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
2661 { 5079 {
2662 throw std::domain_error("type must be array, but is " + type_name()); 5080 JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
2663 } 5081 }
5082 m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
2664 } 5083 }
5084}
2665 5085
2666 /// get an array (explicit) 5086#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
2667 array_t get_impl(array_t*) const 5087template<typename BasicJsonType>
5088inline void from_json(const BasicJsonType& j, std_fs::path& p)
5089{
5090 if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
2668 { 5091 {
2669 if (is_array()) 5092 JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
2670 {
2671 return *(m_value.array);
2672 }
2673 else
2674 {
2675 throw std::domain_error("type must be array, but is " + type_name());
2676 }
2677 } 5093 }
5094 p = *j.template get_ptr<const typename BasicJsonType::string_t*>();
5095}
5096#endif
2678 5097
2679 /// get a string (explicit) 5098struct from_json_fn
2680 template<typename T, typename std::enable_if< 5099{
2681 std::is_convertible<string_t, T>::value, int>::type = 0> 5100 template<typename BasicJsonType, typename T>
2682 T get_impl(T*) const 5101 auto operator()(const BasicJsonType& j, T&& val) const
5102 noexcept(noexcept(from_json(j, std::forward<T>(val))))
5103 -> decltype(from_json(j, std::forward<T>(val)))
2683 { 5104 {
2684 if (is_string()) 5105 return from_json(j, std::forward<T>(val));
2685 { 5106 }
2686 return *m_value.string; 5107};
2687 } 5108
2688 else 5109} // namespace detail
2689 { 5110
2690 throw std::domain_error("type must be string, but is " + type_name()); 5111#ifndef JSON_HAS_CPP_17
2691 } 5112/// namespace to hold default `from_json` function
5113/// to see why this is required:
5114/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
5115namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
5116{
5117#endif
5118JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers)
5119 detail::static_const<detail::from_json_fn>::value;
5120#ifndef JSON_HAS_CPP_17
5121} // namespace
5122#endif
5123
5124NLOHMANN_JSON_NAMESPACE_END
5125
5126// #include <nlohmann/detail/conversions/to_json.hpp>
5127// __ _____ _____ _____
5128// __| | __| | | | JSON for Modern C++
5129// | | |__ | | | | | | version 3.11.3
5130// |_____|_____|_____|_|___| https://github.com/nlohmann/json
5131//
5132// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
5133// SPDX-License-Identifier: MIT
5134
5135
5136
5137#include <algorithm> // copy
5138#include <iterator> // begin, end
5139#include <string> // string
5140#include <tuple> // tuple, get
5141#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
5142#include <utility> // move, forward, declval, pair
5143#include <valarray> // valarray
5144#include <vector> // vector
5145
5146// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
5147// __ _____ _____ _____
5148// __| | __| | | | JSON for Modern C++
5149// | | |__ | | | | | | version 3.11.3
5150// |_____|_____|_____|_|___| https://github.com/nlohmann/json
5151//
5152// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
5153// SPDX-License-Identifier: MIT
5154
5155
5156
5157#include <cstddef> // size_t
5158#include <iterator> // input_iterator_tag
5159#include <string> // string, to_string
5160#include <tuple> // tuple_size, get, tuple_element
5161#include <utility> // move
5162
5163#if JSON_HAS_RANGES
5164 #include <ranges> // enable_borrowed_range
5165#endif
5166
5167// #include <nlohmann/detail/abi_macros.hpp>
5168
5169// #include <nlohmann/detail/meta/type_traits.hpp>
5170
5171// #include <nlohmann/detail/value_t.hpp>
5172
5173
5174NLOHMANN_JSON_NAMESPACE_BEGIN
5175namespace detail
5176{
5177
5178template<typename string_type>
5179void int_to_string( string_type& target, std::size_t value )
5180{
5181 // For ADL
5182 using std::to_string;
5183 target = to_string(value);
5184}
5185template<typename IteratorType> class iteration_proxy_value
5186{
5187 public:
5188 using difference_type = std::ptrdiff_t;
5189 using value_type = iteration_proxy_value;
5190 using pointer = value_type *;
5191 using reference = value_type &;
5192 using iterator_category = std::input_iterator_tag;
5193 using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;
5194
5195 private:
5196 /// the iterator
5197 IteratorType anchor{};
5198 /// an index for arrays (used to create key names)
5199 std::size_t array_index = 0;
5200 /// last stringified array index
5201 mutable std::size_t array_index_last = 0;
5202 /// a string representation of the array index
5203 mutable string_type array_index_str = "0";
5204 /// an empty string (to return a reference for primitive values)
5205 string_type empty_str{};
5206
5207 public:
5208 explicit iteration_proxy_value() = default;
5209 explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0)
5210 noexcept(std::is_nothrow_move_constructible<IteratorType>::value
5211 && std::is_nothrow_default_constructible<string_type>::value)
5212 : anchor(std::move(it))
5213 , array_index(array_index_)
5214 {}
5215
5216 iteration_proxy_value(iteration_proxy_value const&) = default;
5217 iteration_proxy_value& operator=(iteration_proxy_value const&) = default;
5218 // older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions
5219 iteration_proxy_value(iteration_proxy_value&&)
5220 noexcept(std::is_nothrow_move_constructible<IteratorType>::value
5221 && std::is_nothrow_move_constructible<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
5222 iteration_proxy_value& operator=(iteration_proxy_value&&)
5223 noexcept(std::is_nothrow_move_assignable<IteratorType>::value
5224 && std::is_nothrow_move_assignable<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
5225 ~iteration_proxy_value() = default;
5226
5227 /// dereference operator (needed for range-based for)
5228 const iteration_proxy_value& operator*() const
5229 {
5230 return *this;
5231 }
5232
5233 /// increment operator (needed for range-based for)
5234 iteration_proxy_value& operator++()
5235 {
5236 ++anchor;
5237 ++array_index;
5238
5239 return *this;
5240 }
5241
5242 iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp)
5243 {
5244 auto tmp = iteration_proxy_value(anchor, array_index);
5245 ++anchor;
5246 ++array_index;
5247 return tmp;
5248 }
5249
5250 /// equality operator (needed for InputIterator)
5251 bool operator==(const iteration_proxy_value& o) const
5252 {
5253 return anchor == o.anchor;
5254 }
5255
5256 /// inequality operator (needed for range-based for)
5257 bool operator!=(const iteration_proxy_value& o) const
5258 {
5259 return anchor != o.anchor;
2692 } 5260 }
2693 5261
2694 /// get a number (explicit) 5262 /// return key of the iterator
2695 template<typename T, typename std::enable_if< 5263 const string_type& key() const
2696 std::is_arithmetic<T>::value, int>::type = 0>
2697 T get_impl(T*) const
2698 { 5264 {
2699 switch (m_type) 5265 JSON_ASSERT(anchor.m_object != nullptr);
5266
5267 switch (anchor.m_object->type())
2700 { 5268 {
2701 case value_t::number_integer: 5269 // use integer array index as key
5270 case value_t::array:
2702 { 5271 {
2703 return static_cast<T>(m_value.number_integer); 5272 if (array_index != array_index_last)
5273 {
5274 int_to_string( array_index_str, array_index );
5275 array_index_last = array_index;
5276 }
5277 return array_index_str;
2704 } 5278 }
2705 5279
2706 case value_t::number_unsigned: 5280 // use key from the object
2707 { 5281 case value_t::object:
2708 return static_cast<T>(m_value.number_unsigned); 5282 return anchor.key();
2709 }
2710 5283
5284 // use an empty key for all primitive types
5285 case value_t::null:
5286 case value_t::string:
5287 case value_t::boolean:
5288 case value_t::number_integer:
5289 case value_t::number_unsigned:
2711 case value_t::number_float: 5290 case value_t::number_float:
2712 { 5291 case value_t::binary:
2713 return static_cast<T>(m_value.number_float); 5292 case value_t::discarded:
2714 }
2715
2716 default: 5293 default:
2717 { 5294 return empty_str;
2718 throw std::domain_error("type must be number, but is " + type_name());
2719 }
2720 } 5295 }
2721 } 5296 }
2722 5297
2723 /// get a boolean (explicit) 5298 /// return value of the iterator
2724 constexpr boolean_t get_impl(boolean_t*) const 5299 typename IteratorType::reference value() const
2725 { 5300 {
2726 return is_boolean() 5301 return anchor.value();
2727 ? m_value.boolean
2728 : throw std::domain_error("type must be boolean, but is " + type_name());
2729 } 5302 }
5303};
2730 5304
2731 /// get a pointer to the value (object) 5305/// proxy class for the items() function
2732 object_t* get_impl_ptr(object_t*) noexcept 5306template<typename IteratorType> class iteration_proxy
5307{
5308 private:
5309 /// the container to iterate
5310 typename IteratorType::pointer container = nullptr;
5311
5312 public:
5313 explicit iteration_proxy() = default;
5314
5315 /// construct iteration proxy from a container
5316 explicit iteration_proxy(typename IteratorType::reference cont) noexcept
5317 : container(&cont) {}
5318
5319 iteration_proxy(iteration_proxy const&) = default;
5320 iteration_proxy& operator=(iteration_proxy const&) = default;
5321 iteration_proxy(iteration_proxy&&) noexcept = default;
5322 iteration_proxy& operator=(iteration_proxy&&) noexcept = default;
5323 ~iteration_proxy() = default;
5324
5325 /// return iterator begin (needed for range-based for)
5326 iteration_proxy_value<IteratorType> begin() const noexcept
2733 { 5327 {
2734 return is_object() ? m_value.object : nullptr; 5328 return iteration_proxy_value<IteratorType>(container->begin());
2735 } 5329 }
2736 5330
2737 /// get a pointer to the value (object) 5331 /// return iterator end (needed for range-based for)
2738 constexpr const object_t* get_impl_ptr(const object_t*) const noexcept 5332 iteration_proxy_value<IteratorType> end() const noexcept
2739 { 5333 {
2740 return is_object() ? m_value.object : nullptr; 5334 return iteration_proxy_value<IteratorType>(container->end());
2741 } 5335 }
5336};
2742 5337
2743 /// get a pointer to the value (array) 5338// Structured Bindings Support
2744 array_t* get_impl_ptr(array_t*) noexcept 5339// For further reference see https://blog.tartanllama.xyz/structured-bindings/
5340// And see https://github.com/nlohmann/json/pull/1391
5341template<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
5342auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())
5343{
5344 return i.key();
5345}
5346// Structured Bindings Support
5347// For further reference see https://blog.tartanllama.xyz/structured-bindings/
5348// And see https://github.com/nlohmann/json/pull/1391
5349template<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
5350auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())
5351{
5352 return i.value();
5353}
5354
5355} // namespace detail
5356NLOHMANN_JSON_NAMESPACE_END
5357
5358// The Addition to the STD Namespace is required to add
5359// Structured Bindings Support to the iteration_proxy_value class
5360// For further reference see https://blog.tartanllama.xyz/structured-bindings/
5361// And see https://github.com/nlohmann/json/pull/1391
5362namespace std
5363{
5364
5365#if defined(__clang__)
5366 // Fix: https://github.com/nlohmann/json/issues/1401
5367 #pragma clang diagnostic push
5368 #pragma clang diagnostic ignored "-Wmismatched-tags"
5369#endif
5370template<typename IteratorType>
5371class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp)
5372 : public std::integral_constant<std::size_t, 2> {};
5373
5374template<std::size_t N, typename IteratorType>
5375class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> // NOLINT(cert-dcl58-cpp)
5376{
5377 public:
5378 using type = decltype(
5379 get<N>(std::declval <
5380 ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
5381};
5382#if defined(__clang__)
5383 #pragma clang diagnostic pop
5384#endif
5385
5386} // namespace std
5387
5388#if JSON_HAS_RANGES
5389 template <typename IteratorType>
5390 inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy<IteratorType>> = true;
5391#endif
5392
5393// #include <nlohmann/detail/macro_scope.hpp>
5394
5395// #include <nlohmann/detail/meta/cpp_future.hpp>
5396
5397// #include <nlohmann/detail/meta/std_fs.hpp>
5398
5399// #include <nlohmann/detail/meta/type_traits.hpp>
5400
5401// #include <nlohmann/detail/value_t.hpp>
5402
5403
5404NLOHMANN_JSON_NAMESPACE_BEGIN
5405namespace detail
5406{
5407
5408//////////////////
5409// constructors //
5410//////////////////
5411
5412/*
5413 * Note all external_constructor<>::construct functions need to call
5414 * j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an
5415 * allocated value (e.g., a string). See bug issue
5416 * https://github.com/nlohmann/json/issues/2865 for more information.
5417 */
5418
5419template<value_t> struct external_constructor;
5420
5421template<>
5422struct external_constructor<value_t::boolean>
5423{
5424 template<typename BasicJsonType>
5425 static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
2745 { 5426 {
2746 return is_array() ? m_value.array : nullptr; 5427 j.m_data.m_value.destroy(j.m_data.m_type);
5428 j.m_data.m_type = value_t::boolean;
5429 j.m_data.m_value = b;
5430 j.assert_invariant();
2747 } 5431 }
5432};
2748 5433
2749 /// get a pointer to the value (array) 5434template<>
2750 constexpr const array_t* get_impl_ptr(const array_t*) const noexcept 5435struct external_constructor<value_t::string>
5436{
5437 template<typename BasicJsonType>
5438 static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
2751 { 5439 {
2752 return is_array() ? m_value.array : nullptr; 5440 j.m_data.m_value.destroy(j.m_data.m_type);
5441 j.m_data.m_type = value_t::string;
5442 j.m_data.m_value = s;
5443 j.assert_invariant();
2753 } 5444 }
2754 5445
2755 /// get a pointer to the value (string) 5446 template<typename BasicJsonType>
2756 string_t* get_impl_ptr(string_t*) noexcept 5447 static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
2757 { 5448 {
2758 return is_string() ? m_value.string : nullptr; 5449 j.m_data.m_value.destroy(j.m_data.m_type);
5450 j.m_data.m_type = value_t::string;
5451 j.m_data.m_value = std::move(s);
5452 j.assert_invariant();
2759 } 5453 }
2760 5454
2761 /// get a pointer to the value (string) 5455 template < typename BasicJsonType, typename CompatibleStringType,
2762 constexpr const string_t* get_impl_ptr(const string_t*) const noexcept 5456 enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
5457 int > = 0 >
5458 static void construct(BasicJsonType& j, const CompatibleStringType& str)
2763 { 5459 {
2764 return is_string() ? m_value.string : nullptr; 5460 j.m_data.m_value.destroy(j.m_data.m_type);
5461 j.m_data.m_type = value_t::string;
5462 j.m_data.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
5463 j.assert_invariant();
2765 } 5464 }
5465};
2766 5466
2767 /// get a pointer to the value (boolean) 5467template<>
2768 boolean_t* get_impl_ptr(boolean_t*) noexcept 5468struct external_constructor<value_t::binary>
5469{
5470 template<typename BasicJsonType>
5471 static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
2769 { 5472 {
2770 return is_boolean() ? &m_value.boolean : nullptr; 5473 j.m_data.m_value.destroy(j.m_data.m_type);
5474 j.m_data.m_type = value_t::binary;
5475 j.m_data.m_value = typename BasicJsonType::binary_t(b);
5476 j.assert_invariant();
2771 } 5477 }
2772 5478
2773 /// get a pointer to the value (boolean) 5479 template<typename BasicJsonType>
2774 constexpr const boolean_t* get_impl_ptr(const boolean_t*) const noexcept 5480 static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
2775 { 5481 {
2776 return is_boolean() ? &m_value.boolean : nullptr; 5482 j.m_data.m_value.destroy(j.m_data.m_type);
5483 j.m_data.m_type = value_t::binary;
5484 j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b));
5485 j.assert_invariant();
2777 } 5486 }
5487};
2778 5488
2779 /// get a pointer to the value (integer number) 5489template<>
2780 number_integer_t* get_impl_ptr(number_integer_t*) noexcept 5490struct external_constructor<value_t::number_float>
5491{
5492 template<typename BasicJsonType>
5493 static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
2781 { 5494 {
2782 return is_number_integer() ? &m_value.number_integer : nullptr; 5495 j.m_data.m_value.destroy(j.m_data.m_type);
5496 j.m_data.m_type = value_t::number_float;
5497 j.m_data.m_value = val;
5498 j.assert_invariant();
2783 } 5499 }
5500};
2784 5501
2785 /// get a pointer to the value (integer number) 5502template<>
2786 constexpr const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept 5503struct external_constructor<value_t::number_unsigned>
5504{
5505 template<typename BasicJsonType>
5506 static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
2787 { 5507 {
2788 return is_number_integer() ? &m_value.number_integer : nullptr; 5508 j.m_data.m_value.destroy(j.m_data.m_type);
5509 j.m_data.m_type = value_t::number_unsigned;
5510 j.m_data.m_value = val;
5511 j.assert_invariant();
2789 } 5512 }
5513};
2790 5514
2791 /// get a pointer to the value (unsigned number) 5515template<>
2792 number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept 5516struct external_constructor<value_t::number_integer>
5517{
5518 template<typename BasicJsonType>
5519 static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
2793 { 5520 {
2794 return is_number_unsigned() ? &m_value.number_unsigned : nullptr; 5521 j.m_data.m_value.destroy(j.m_data.m_type);
5522 j.m_data.m_type = value_t::number_integer;
5523 j.m_data.m_value = val;
5524 j.assert_invariant();
2795 } 5525 }
5526};
2796 5527
2797 /// get a pointer to the value (unsigned number) 5528template<>
2798 constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept 5529struct external_constructor<value_t::array>
5530{
5531 template<typename BasicJsonType>
5532 static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
2799 { 5533 {
2800 return is_number_unsigned() ? &m_value.number_unsigned : nullptr; 5534 j.m_data.m_value.destroy(j.m_data.m_type);
5535 j.m_data.m_type = value_t::array;
5536 j.m_data.m_value = arr;
5537 j.set_parents();
5538 j.assert_invariant();
2801 } 5539 }
2802 5540
2803 /// get a pointer to the value (floating-point number) 5541 template<typename BasicJsonType>
2804 number_float_t* get_impl_ptr(number_float_t*) noexcept 5542 static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
2805 { 5543 {
2806 return is_number_float() ? &m_value.number_float : nullptr; 5544 j.m_data.m_value.destroy(j.m_data.m_type);
5545 j.m_data.m_type = value_t::array;
5546 j.m_data.m_value = std::move(arr);
5547 j.set_parents();
5548 j.assert_invariant();
2807 } 5549 }
2808 5550
2809 /// get a pointer to the value (floating-point number) 5551 template < typename BasicJsonType, typename CompatibleArrayType,
2810 constexpr const number_float_t* get_impl_ptr(const number_float_t*) const noexcept 5552 enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
5553 int > = 0 >
5554 static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
2811 { 5555 {
2812 return is_number_float() ? &m_value.number_float : nullptr; 5556 using std::begin;
5557 using std::end;
5558
5559 j.m_data.m_value.destroy(j.m_data.m_type);
5560 j.m_data.m_type = value_t::array;
5561 j.m_data.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
5562 j.set_parents();
5563 j.assert_invariant();
2813 } 5564 }
2814 5565
2815 /*! 5566 template<typename BasicJsonType>
2816 @brief helper function to implement get_ref() 5567 static void construct(BasicJsonType& j, const std::vector<bool>& arr)
5568 {
5569 j.m_data.m_value.destroy(j.m_data.m_type);
5570 j.m_data.m_type = value_t::array;
5571 j.m_data.m_value = value_t::array;
5572 j.m_data.m_value.array->reserve(arr.size());
5573 for (const bool x : arr)
5574 {
5575 j.m_data.m_value.array->push_back(x);
5576 j.set_parent(j.m_data.m_value.array->back());
5577 }
5578 j.assert_invariant();
5579 }
2817 5580
2818 This funcion helps to implement get_ref() without code duplication for 5581 template<typename BasicJsonType, typename T,
2819 const and non-const overloads 5582 enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
5583 static void construct(BasicJsonType& j, const std::valarray<T>& arr)
5584 {
5585 j.m_data.m_value.destroy(j.m_data.m_type);
5586 j.m_data.m_type = value_t::array;
5587 j.m_data.m_value = value_t::array;
5588 j.m_data.m_value.array->resize(arr.size());
5589 if (arr.size() > 0)
5590 {
5591 std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin());
5592 }
5593 j.set_parents();
5594 j.assert_invariant();
5595 }
5596};
2820 5597
2821 @tparam ThisType will be deduced as `basic_json` or `const basic_json` 5598template<>
5599struct external_constructor<value_t::object>
5600{
5601 template<typename BasicJsonType>
5602 static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
5603 {
5604 j.m_data.m_value.destroy(j.m_data.m_type);
5605 j.m_data.m_type = value_t::object;
5606 j.m_data.m_value = obj;
5607 j.set_parents();
5608 j.assert_invariant();
5609 }
2822 5610
2823 @throw std::domain_error if ReferenceType does not match underlying value 5611 template<typename BasicJsonType>
2824 type of the current JSON 5612 static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
2825 */
2826 template<typename ReferenceType, typename ThisType>
2827 static ReferenceType get_ref_impl(ThisType& obj)
2828 { 5613 {
2829 // helper type 5614 j.m_data.m_value.destroy(j.m_data.m_type);
2830 using PointerType = typename std::add_pointer<ReferenceType>::type; 5615 j.m_data.m_type = value_t::object;
5616 j.m_data.m_value = std::move(obj);
5617 j.set_parents();
5618 j.assert_invariant();
5619 }
2831 5620
2832 // delegate the call to get_ptr<>() 5621 template < typename BasicJsonType, typename CompatibleObjectType,
2833 auto ptr = obj.template get_ptr<PointerType>(); 5622 enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 >
5623 static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
5624 {
5625 using std::begin;
5626 using std::end;
2834 5627
2835 if (ptr != nullptr) 5628 j.m_data.m_value.destroy(j.m_data.m_type);
2836 { 5629 j.m_data.m_type = value_t::object;
2837 return *ptr; 5630 j.m_data.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
2838 } 5631 j.set_parents();
2839 else 5632 j.assert_invariant();
2840 {
2841 throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " +
2842 obj.type_name());
2843 }
2844 } 5633 }
5634};
2845 5635
2846 public: 5636/////////////
5637// to_json //
5638/////////////
2847 5639
2848 /// @name value access 5640template<typename BasicJsonType, typename T,
2849 /// Direct access to the stored value of a JSON value. 5641 enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>
2850 /// @{ 5642inline void to_json(BasicJsonType& j, T b) noexcept
5643{
5644 external_constructor<value_t::boolean>::construct(j, b);
5645}
2851 5646
2852 /*! 5647template < typename BasicJsonType, typename BoolRef,
2853 @brief get a value (explicit) 5648 enable_if_t <
5649 ((std::is_same<std::vector<bool>::reference, BoolRef>::value
5650 && !std::is_same <std::vector<bool>::reference, typename BasicJsonType::boolean_t&>::value)
5651 || (std::is_same<std::vector<bool>::const_reference, BoolRef>::value
5652 && !std::is_same <detail::uncvref_t<std::vector<bool>::const_reference>,
5653 typename BasicJsonType::boolean_t >::value))
5654 && std::is_convertible<const BoolRef&, typename BasicJsonType::boolean_t>::value, int > = 0 >
5655inline void to_json(BasicJsonType& j, const BoolRef& b) noexcept
5656{
5657 external_constructor<value_t::boolean>::construct(j, static_cast<typename BasicJsonType::boolean_t>(b));
5658}
2854 5659
2855 Explicit type conversion between the JSON value and a compatible value. 5660template<typename BasicJsonType, typename CompatibleString,
5661 enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>
5662inline void to_json(BasicJsonType& j, const CompatibleString& s)
5663{
5664 external_constructor<value_t::string>::construct(j, s);
5665}
2856 5666
2857 @tparam ValueType non-pointer type compatible to the JSON value, for 5667template<typename BasicJsonType>
2858 instance `int` for JSON integer numbers, `bool` for JSON booleans, or 5668inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)
2859 `std::vector` types for JSON arrays 5669{
5670 external_constructor<value_t::string>::construct(j, std::move(s));
5671}
2860 5672
2861 @return copy of the JSON value, converted to type @a ValueType 5673template<typename BasicJsonType, typename FloatType,
5674 enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
5675inline void to_json(BasicJsonType& j, FloatType val) noexcept
5676{
5677 external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
5678}
2862 5679
2863 @throw std::domain_error in case passed type @a ValueType is incompatible 5680template<typename BasicJsonType, typename CompatibleNumberUnsignedType,
2864 to JSON; example: `"type must be object, but is null"` 5681 enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>
5682inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
5683{
5684 external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
5685}
2865 5686
2866 @complexity Linear in the size of the JSON value. 5687template<typename BasicJsonType, typename CompatibleNumberIntegerType,
5688 enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>
5689inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
5690{
5691 external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
5692}
2867 5693
2868 @liveexample{The example below shows several conversions from JSON values 5694#if !JSON_DISABLE_ENUM_SERIALIZATION
2869 to other types. There a few things to note: (1) Floating-point numbers can 5695template<typename BasicJsonType, typename EnumType,
2870 be converted to integers\, (2) A JSON array can be converted to a standard 5696 enable_if_t<std::is_enum<EnumType>::value, int> = 0>
2871 `std::vector<short>`\, (3) A JSON object can be converted to C++ 5697inline void to_json(BasicJsonType& j, EnumType e) noexcept
2872 associative containers such as `std::unordered_map<std::string\, 5698{
2873 json>`.,get__ValueType_const} 5699 using underlying_type = typename std::underlying_type<EnumType>::type;
5700 external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));
5701}
5702#endif // JSON_DISABLE_ENUM_SERIALIZATION
2874 5703
2875 @internal 5704template<typename BasicJsonType>
2876 The idea of using a casted null pointer to choose the correct 5705inline void to_json(BasicJsonType& j, const std::vector<bool>& e)
2877 implementation is from <http://stackoverflow.com/a/8315197/266378>. 5706{
2878 @endinternal 5707 external_constructor<value_t::array>::construct(j, e);
5708}
2879 5709
2880 @sa @ref operator ValueType() const for implicit conversion 5710template < typename BasicJsonType, typename CompatibleArrayType,
2881 @sa @ref get() for pointer-member access 5711 enable_if_t < is_compatible_array_type<BasicJsonType,
5712 CompatibleArrayType>::value&&
5713 !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
5714 !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
5715 !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
5716 !is_basic_json<CompatibleArrayType>::value,
5717 int > = 0 >
5718inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
5719{
5720 external_constructor<value_t::array>::construct(j, arr);
5721}
2882 5722
2883 @since version 1.0.0 5723template<typename BasicJsonType>
2884 */ 5724inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
2885 template<typename ValueType, typename std::enable_if< 5725{
2886 not std::is_pointer<ValueType>::value, int>::type = 0> 5726 external_constructor<value_t::binary>::construct(j, bin);
2887 ValueType get() const 5727}
2888 {
2889 return get_impl(static_cast<ValueType*>(nullptr));
2890 }
2891 5728
2892 /*! 5729template<typename BasicJsonType, typename T,
2893 @brief get a pointer value (explicit) 5730 enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
5731inline void to_json(BasicJsonType& j, const std::valarray<T>& arr)
5732{
5733 external_constructor<value_t::array>::construct(j, std::move(arr));
5734}
2894 5735
2895 Explicit pointer access to the internally stored JSON value. No copies are 5736template<typename BasicJsonType>
2896 made. 5737inline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
5738{
5739 external_constructor<value_t::array>::construct(j, std::move(arr));
5740}
2897 5741
2898 @warning The pointer becomes invalid if the underlying JSON object 5742template < typename BasicJsonType, typename CompatibleObjectType,
2899 changes. 5743 enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >
5744inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
5745{
5746 external_constructor<value_t::object>::construct(j, obj);
5747}
2900 5748
2901 @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref 5749template<typename BasicJsonType>
2902 object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, 5750inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
2903 @ref number_unsigned_t, or @ref number_float_t. 5751{
5752 external_constructor<value_t::object>::construct(j, std::move(obj));
5753}
2904 5754
2905 @return pointer to the internally stored JSON value if the requested 5755template <
2906 pointer type @a PointerType fits to the JSON value; `nullptr` otherwise 5756 typename BasicJsonType, typename T, std::size_t N,
5757 enable_if_t < !std::is_constructible<typename BasicJsonType::string_t,
5758 const T(&)[N]>::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
5759 int > = 0 >
5760inline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
5761{
5762 external_constructor<value_t::array>::construct(j, arr);
5763}
2907 5764
2908 @complexity Constant. 5765template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 >
5766inline void to_json(BasicJsonType& j, const std::pair<T1, T2>& p)
5767{
5768 j = { p.first, p.second };
5769}
2909 5770
2910 @liveexample{The example below shows how pointers to internal values of a 5771// for https://github.com/nlohmann/json/pull/1134
2911 JSON value can be requested. Note that no type conversions are made and a 5772template<typename BasicJsonType, typename T,
2912 `nullptr` is returned if the value and the requested pointer type does not 5773 enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
2913 match.,get__PointerType} 5774inline void to_json(BasicJsonType& j, const T& b)
5775{
5776 j = { {b.key(), b.value()} };
5777}
2914 5778
2915 @sa @ref get_ptr() for explicit pointer-member access 5779template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
5780inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)
5781{
5782 j = { std::get<Idx>(t)... };
5783}
2916 5784
2917 @since version 1.0.0 5785template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0>
2918 */ 5786inline void to_json(BasicJsonType& j, const T& t)
2919 template<typename PointerType, typename std::enable_if< 5787{
2920 std::is_pointer<PointerType>::value, int>::type = 0> 5788 to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {});
2921 PointerType get() noexcept 5789}
2922 {
2923 // delegate the call to get_ptr
2924 return get_ptr<PointerType>();
2925 }
2926 5790
2927 /*! 5791#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
2928 @brief get a pointer value (explicit) 5792template<typename BasicJsonType>
2929 @copydoc get() 5793inline void to_json(BasicJsonType& j, const std_fs::path& p)
2930 */ 5794{
2931 template<typename PointerType, typename std::enable_if< 5795 j = p.string();
2932 std::is_pointer<PointerType>::value, int>::type = 0> 5796}
2933 constexpr const PointerType get() const noexcept 5797#endif
5798
5799struct to_json_fn
5800{
5801 template<typename BasicJsonType, typename T>
5802 auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
5803 -> decltype(to_json(j, std::forward<T>(val)), void())
2934 { 5804 {
2935 // delegate the call to get_ptr 5805 return to_json(j, std::forward<T>(val));
2936 return get_ptr<PointerType>();
2937 } 5806 }
5807};
5808} // namespace detail
2938 5809
2939 /*! 5810#ifndef JSON_HAS_CPP_17
2940 @brief get a pointer value (implicit) 5811/// namespace to hold default `to_json` function
5812/// to see why this is required:
5813/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
5814namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
5815{
5816#endif
5817JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers)
5818 detail::static_const<detail::to_json_fn>::value;
5819#ifndef JSON_HAS_CPP_17
5820} // namespace
5821#endif
2941 5822
2942 Implicit pointer access to the internally stored JSON value. No copies are 5823NLOHMANN_JSON_NAMESPACE_END
2943 made.
2944 5824
2945 @warning Writing data to the pointee of the result yields an undefined 5825// #include <nlohmann/detail/meta/identity_tag.hpp>
2946 state.
2947 5826
2948 @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
2949 object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
2950 @ref number_unsigned_t, or @ref number_float_t. Enforced by a static
2951 assertion.
2952 5827
2953 @return pointer to the internally stored JSON value if the requested 5828NLOHMANN_JSON_NAMESPACE_BEGIN
2954 pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
2955 5829
2956 @complexity Constant. 5830/// @sa https://json.nlohmann.me/api/adl_serializer/
2957 5831template<typename ValueType, typename>
2958 @liveexample{The example below shows how pointers to internal values of a 5832struct adl_serializer
2959 JSON value can be requested. Note that no type conversions are made and a 5833{
2960 `nullptr` is returned if the value and the requested pointer type does not 5834 /// @brief convert a JSON value to any value type
2961 match.,get_ptr} 5835 /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/
5836 template<typename BasicJsonType, typename TargetType = ValueType>
5837 static auto from_json(BasicJsonType && j, TargetType& val) noexcept(
5838 noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))
5839 -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void())
5840 {
5841 ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
5842 }
2962 5843
2963 @since version 1.0.0 5844 /// @brief convert a JSON value to any value type
2964 */ 5845 /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/
2965 template<typename PointerType, typename std::enable_if< 5846 template<typename BasicJsonType, typename TargetType = ValueType>
2966 std::is_pointer<PointerType>::value, int>::type = 0> 5847 static auto from_json(BasicJsonType && j) noexcept(
2967 PointerType get_ptr() noexcept 5848 noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {})))
2968 { 5849 -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {}))
2969 // get the type of the PointerType (remove pointer and const) 5850 {
2970 using pointee_t = typename std::remove_const<typename 5851 return ::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {});
2971 std::remove_pointer<typename 5852 }
2972 std::remove_const<PointerType>::type>::type>::type;
2973 // make sure the type matches the allowed types
2974 static_assert(
2975 std::is_same<object_t, pointee_t>::value
2976 or std::is_same<array_t, pointee_t>::value
2977 or std::is_same<string_t, pointee_t>::value
2978 or std::is_same<boolean_t, pointee_t>::value
2979 or std::is_same<number_integer_t, pointee_t>::value
2980 or std::is_same<number_unsigned_t, pointee_t>::value
2981 or std::is_same<number_float_t, pointee_t>::value
2982 , "incompatible pointer type");
2983 5853
2984 // delegate the call to get_impl_ptr<>() 5854 /// @brief convert any value type to a JSON value
2985 return get_impl_ptr(static_cast<PointerType>(nullptr)); 5855 /// @sa https://json.nlohmann.me/api/adl_serializer/to_json/
5856 template<typename BasicJsonType, typename TargetType = ValueType>
5857 static auto to_json(BasicJsonType& j, TargetType && val) noexcept(
5858 noexcept(::nlohmann::to_json(j, std::forward<TargetType>(val))))
5859 -> decltype(::nlohmann::to_json(j, std::forward<TargetType>(val)), void())
5860 {
5861 ::nlohmann::to_json(j, std::forward<TargetType>(val));
2986 } 5862 }
5863};
2987 5864
2988 /*! 5865NLOHMANN_JSON_NAMESPACE_END
2989 @brief get a pointer value (implicit)
2990 @copydoc get_ptr()
2991 */
2992 template<typename PointerType, typename std::enable_if<
2993 std::is_pointer<PointerType>::value and
2994 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
2995 constexpr const PointerType get_ptr() const noexcept
2996 {
2997 // get the type of the PointerType (remove pointer and const)
2998 using pointee_t = typename std::remove_const<typename
2999 std::remove_pointer<typename
3000 std::remove_const<PointerType>::type>::type>::type;
3001 // make sure the type matches the allowed types
3002 static_assert(
3003 std::is_same<object_t, pointee_t>::value
3004 or std::is_same<array_t, pointee_t>::value
3005 or std::is_same<string_t, pointee_t>::value
3006 or std::is_same<boolean_t, pointee_t>::value
3007 or std::is_same<number_integer_t, pointee_t>::value
3008 or std::is_same<number_unsigned_t, pointee_t>::value
3009 or std::is_same<number_float_t, pointee_t>::value
3010 , "incompatible pointer type");
3011 5866
3012 // delegate the call to get_impl_ptr<>() const 5867// #include <nlohmann/byte_container_with_subtype.hpp>
3013 return get_impl_ptr(static_cast<const PointerType>(nullptr)); 5868// __ _____ _____ _____
3014 } 5869// __| | __| | | | JSON for Modern C++
5870// | | |__ | | | | | | version 3.11.3
5871// |_____|_____|_____|_|___| https://github.com/nlohmann/json
5872//
5873// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
5874// SPDX-License-Identifier: MIT
3015 5875
3016 /*!
3017 @brief get a reference value (implicit)
3018 5876
3019 Implict reference access to the internally stored JSON value. No copies
3020 are made.
3021 5877
3022 @warning Writing data to the referee of the result yields an undefined 5878#include <cstdint> // uint8_t, uint64_t
3023 state. 5879#include <tuple> // tie
5880#include <utility> // move
3024 5881
3025 @tparam ReferenceType reference type; must be a reference to @ref array_t, 5882// #include <nlohmann/detail/abi_macros.hpp>
3026 @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or
3027 @ref number_float_t. Enforced by static assertion.
3028 5883
3029 @return reference to the internally stored JSON value if the requested
3030 reference type @a ReferenceType fits to the JSON value; throws
3031 std::domain_error otherwise
3032 5884
3033 @throw std::domain_error in case passed type @a ReferenceType is 5885NLOHMANN_JSON_NAMESPACE_BEGIN
3034 incompatible with the stored JSON value
3035 5886
3036 @complexity Constant. 5887/// @brief an internal type for a backed binary type
5888/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/
5889template<typename BinaryType>
5890class byte_container_with_subtype : public BinaryType
5891{
5892 public:
5893 using container_type = BinaryType;
5894 using subtype_type = std::uint64_t;
5895
5896 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
5897 byte_container_with_subtype() noexcept(noexcept(container_type()))
5898 : container_type()
5899 {}
5900
5901 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
5902 byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b)))
5903 : container_type(b)
5904 {}
5905
5906 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
5907 byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b))))
5908 : container_type(std::move(b))
5909 {}
5910
5911 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
5912 byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b)))
5913 : container_type(b)
5914 , m_subtype(subtype_)
5915 , m_has_subtype(true)
5916 {}
5917
5918 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
5919 byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b))))
5920 : container_type(std::move(b))
5921 , m_subtype(subtype_)
5922 , m_has_subtype(true)
5923 {}
5924
5925 bool operator==(const byte_container_with_subtype& rhs) const
5926 {
5927 return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) ==
5928 std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype);
5929 }
3037 5930
3038 @liveexample{The example shows several calls to `get_ref()`.,get_ref} 5931 bool operator!=(const byte_container_with_subtype& rhs) const
5932 {
5933 return !(rhs == *this);
5934 }
3039 5935
3040 @since version 1.1.0 5936 /// @brief sets the binary subtype
3041 */ 5937 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/set_subtype/
3042 template<typename ReferenceType, typename std::enable_if< 5938 void set_subtype(subtype_type subtype_) noexcept
3043 std::is_reference<ReferenceType>::value, int>::type = 0>
3044 ReferenceType get_ref()
3045 { 5939 {
3046 // delegate call to get_ref_impl 5940 m_subtype = subtype_;
3047 return get_ref_impl<ReferenceType>(*this); 5941 m_has_subtype = true;
3048 } 5942 }
3049 5943
3050 /*! 5944 /// @brief return the binary subtype
3051 @brief get a reference value (implicit) 5945 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype/
3052 @copydoc get_ref() 5946 constexpr subtype_type subtype() const noexcept
3053 */
3054 template<typename ReferenceType, typename std::enable_if<
3055 std::is_reference<ReferenceType>::value and
3056 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
3057 ReferenceType get_ref() const
3058 { 5947 {
3059 // delegate call to get_ref_impl 5948 return m_has_subtype ? m_subtype : static_cast<subtype_type>(-1);
3060 return get_ref_impl<ReferenceType>(*this);
3061 } 5949 }
3062 5950
3063 /*! 5951 /// @brief return whether the value has a subtype
3064 @brief get a value (implicit) 5952 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/has_subtype/
5953 constexpr bool has_subtype() const noexcept
5954 {
5955 return m_has_subtype;
5956 }
3065 5957
3066 Implicit type conversion between the JSON value and a compatible value. 5958 /// @brief clears the binary subtype
3067 The call is realized by calling @ref get() const. 5959 /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/clear_subtype/
5960 void clear_subtype() noexcept
5961 {
5962 m_subtype = 0;
5963 m_has_subtype = false;
5964 }
3068 5965
3069 @tparam ValueType non-pointer type compatible to the JSON value, for 5966 private:
3070 instance `int` for JSON integer numbers, `bool` for JSON booleans, or 5967 subtype_type m_subtype = 0;
3071 `std::vector` types for JSON arrays. The character type of @ref string_t 5968 bool m_has_subtype = false;
3072 as well as an initializer list of this type is excluded to avoid 5969};
3073 ambiguities as these types implicitly convert to `std::string`.
3074 5970
3075 @return copy of the JSON value, converted to type @a ValueType 5971NLOHMANN_JSON_NAMESPACE_END
3076 5972
3077 @throw std::domain_error in case passed type @a ValueType is incompatible 5973// #include <nlohmann/detail/conversions/from_json.hpp>
3078 to JSON, thrown by @ref get() const
3079 5974
3080 @complexity Linear in the size of the JSON value. 5975// #include <nlohmann/detail/conversions/to_json.hpp>
3081 5976
3082 @liveexample{The example below shows several conversions from JSON values 5977// #include <nlohmann/detail/exceptions.hpp>
3083 to other types. There a few things to note: (1) Floating-point numbers can
3084 be converted to integers\, (2) A JSON array can be converted to a standard
3085 `std::vector<short>`\, (3) A JSON object can be converted to C++
3086 associative containers such as `std::unordered_map<std::string\,
3087 json>`.,operator__ValueType}
3088 5978
3089 @since version 1.0.0 5979// #include <nlohmann/detail/hash.hpp>
3090 */ 5980// __ _____ _____ _____
3091 template < typename ValueType, typename std::enable_if < 5981// __| | __| | | | JSON for Modern C++
3092 not std::is_pointer<ValueType>::value and 5982// | | |__ | | | | | | version 3.11.3
3093 not std::is_same<ValueType, typename string_t::value_type>::value 5983// |_____|_____|_____|_|___| https://github.com/nlohmann/json
3094#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015 5984//
3095 and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value 5985// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
3096#endif 5986// SPDX-License-Identifier: MIT
3097 , int >::type = 0 >
3098 operator ValueType() const
3099 {
3100 // delegate the call to get<>() const
3101 return get<ValueType>();
3102 }
3103 5987
3104 /// @}
3105 5988
3106 5989
3107 //////////////////// 5990#include <cstdint> // uint8_t
3108 // element access // 5991#include <cstddef> // size_t
3109 //////////////////// 5992#include <functional> // hash
3110 5993
3111 /// @name element access 5994// #include <nlohmann/detail/abi_macros.hpp>
3112 /// Access to the JSON value.
3113 /// @{
3114 5995
3115 /*! 5996// #include <nlohmann/detail/value_t.hpp>
3116 @brief access specified array element with bounds checking
3117 5997
3118 Returns a reference to the element at specified location @a idx, with
3119 bounds checking.
3120 5998
3121 @param[in] idx index of the element to access 5999NLOHMANN_JSON_NAMESPACE_BEGIN
6000namespace detail
6001{
3122 6002
3123 @return reference to the element at index @a idx 6003// boost::hash_combine
6004inline std::size_t combine(std::size_t seed, std::size_t h) noexcept
6005{
6006 seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);
6007 return seed;
6008}
3124 6009
3125 @throw std::domain_error if the JSON value is not an array; example: 6010/*!
3126 `"cannot use at() with string"` 6011@brief hash a JSON value
3127 @throw std::out_of_range if the index @a idx is out of range of the array;
3128 that is, `idx >= size()`; example: `"array index 7 is out of range"`
3129 6012
3130 @complexity Constant. 6013The hash function tries to rely on std::hash where possible. Furthermore, the
6014type of the JSON value is taken into account to have different hash values for
6015null, 0, 0U, and false, etc.
3131 6016
3132 @liveexample{The example below shows how array elements can be read and 6017@tparam BasicJsonType basic_json specialization
3133 written using `at()`.,at__size_type} 6018@param j JSON value to hash
6019@return hash value of j
6020*/
6021template<typename BasicJsonType>
6022std::size_t hash(const BasicJsonType& j)
6023{
6024 using string_t = typename BasicJsonType::string_t;
6025 using number_integer_t = typename BasicJsonType::number_integer_t;
6026 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
6027 using number_float_t = typename BasicJsonType::number_float_t;
3134 6028
3135 @since version 1.0.0 6029 const auto type = static_cast<std::size_t>(j.type());
3136 */ 6030 switch (j.type())
3137 reference at(size_type idx)
3138 { 6031 {
3139 // at only works for arrays 6032 case BasicJsonType::value_t::null:
3140 if (is_array()) 6033 case BasicJsonType::value_t::discarded:
6034 {
6035 return combine(type, 0);
6036 }
6037
6038 case BasicJsonType::value_t::object:
3141 { 6039 {
3142 try 6040 auto seed = combine(type, j.size());
6041 for (const auto& element : j.items())
3143 { 6042 {
3144 return m_value.array->at(idx); 6043 const auto h = std::hash<string_t> {}(element.key());
6044 seed = combine(seed, h);
6045 seed = combine(seed, hash(element.value()));
3145 } 6046 }
3146 catch (std::out_of_range&) 6047 return seed;
6048 }
6049
6050 case BasicJsonType::value_t::array:
6051 {
6052 auto seed = combine(type, j.size());
6053 for (const auto& element : j)
3147 { 6054 {
3148 // create better exception explanation 6055 seed = combine(seed, hash(element));
3149 throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
3150 } 6056 }
6057 return seed;
3151 } 6058 }
3152 else 6059
6060 case BasicJsonType::value_t::string:
3153 { 6061 {
3154 throw std::domain_error("cannot use at() with " + type_name()); 6062 const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>());
6063 return combine(type, h);
3155 } 6064 }
3156 }
3157
3158 /*!
3159 @brief access specified array element with bounds checking
3160
3161 Returns a const reference to the element at specified location @a idx,
3162 with bounds checking.
3163 6065
3164 @param[in] idx index of the element to access 6066 case BasicJsonType::value_t::boolean:
3165 6067 {
3166 @return const reference to the element at index @a idx 6068 const auto h = std::hash<bool> {}(j.template get<bool>());
6069 return combine(type, h);
6070 }
3167 6071
3168 @throw std::domain_error if the JSON value is not an array; example: 6072 case BasicJsonType::value_t::number_integer:
3169 `"cannot use at() with string"` 6073 {
3170 @throw std::out_of_range if the index @a idx is out of range of the array; 6074 const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>());
3171 that is, `idx >= size()`; example: `"array index 7 is out of range"` 6075 return combine(type, h);
6076 }
3172 6077
3173 @complexity Constant. 6078 case BasicJsonType::value_t::number_unsigned:
6079 {
6080 const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>());
6081 return combine(type, h);
6082 }
3174 6083
3175 @liveexample{The example below shows how array elements can be read using 6084 case BasicJsonType::value_t::number_float:
3176 `at()`.,at__size_type_const} 6085 {
6086 const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>());
6087 return combine(type, h);
6088 }
3177 6089
3178 @since version 1.0.0 6090 case BasicJsonType::value_t::binary:
3179 */
3180 const_reference at(size_type idx) const
3181 {
3182 // at only works for arrays
3183 if (is_array())
3184 { 6091 {
3185 try 6092 auto seed = combine(type, j.get_binary().size());
6093 const auto h = std::hash<bool> {}(j.get_binary().has_subtype());
6094 seed = combine(seed, h);
6095 seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype()));
6096 for (const auto byte : j.get_binary())
3186 { 6097 {
3187 return m_value.array->at(idx); 6098 seed = combine(seed, std::hash<std::uint8_t> {}(byte));
3188 } 6099 }
3189 catch (std::out_of_range&) 6100 return seed;
3190 {
3191 // create better exception explanation
3192 throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
3193 }
3194 }
3195 else
3196 {
3197 throw std::domain_error("cannot use at() with " + type_name());
3198 } 6101 }
6102
6103 default: // LCOV_EXCL_LINE
6104 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
6105 return 0; // LCOV_EXCL_LINE
3199 } 6106 }
6107}
3200 6108
3201 /*! 6109} // namespace detail
3202 @brief access specified object element with bounds checking 6110NLOHMANN_JSON_NAMESPACE_END
3203 6111
3204 Returns a reference to the element at with specified key @a key, with 6112// #include <nlohmann/detail/input/binary_reader.hpp>
3205 bounds checking. 6113// __ _____ _____ _____
6114// __| | __| | | | JSON for Modern C++
6115// | | |__ | | | | | | version 3.11.3
6116// |_____|_____|_____|_|___| https://github.com/nlohmann/json
6117//
6118// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
6119// SPDX-License-Identifier: MIT
3206 6120
3207 @param[in] key key of the element to access
3208 6121
3209 @return reference to the element at key @a key
3210 6122
3211 @throw std::domain_error if the JSON value is not an object; example: 6123#include <algorithm> // generate_n
3212 `"cannot use at() with boolean"` 6124#include <array> // array
3213 @throw std::out_of_range if the key @a key is is not stored in the object; 6125#include <cmath> // ldexp
3214 that is, `find(key) == end()`; example: `"key "the fast" not found"` 6126#include <cstddef> // size_t
6127#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
6128#include <cstdio> // snprintf
6129#include <cstring> // memcpy
6130#include <iterator> // back_inserter
6131#include <limits> // numeric_limits
6132#include <string> // char_traits, string
6133#include <utility> // make_pair, move
6134#include <vector> // vector
3215 6135
3216 @complexity Logarithmic in the size of the container. 6136// #include <nlohmann/detail/exceptions.hpp>
3217 6137
3218 @liveexample{The example below shows how object elements can be read and 6138// #include <nlohmann/detail/input/input_adapters.hpp>
3219 written using `at()`.,at__object_t_key_type} 6139// __ _____ _____ _____
6140// __| | __| | | | JSON for Modern C++
6141// | | |__ | | | | | | version 3.11.3
6142// |_____|_____|_____|_|___| https://github.com/nlohmann/json
6143//
6144// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
6145// SPDX-License-Identifier: MIT
3220 6146
3221 @sa @ref operator[](const typename object_t::key_type&) for unchecked
3222 access by reference
3223 @sa @ref value() for access by value with a default value
3224 6147
3225 @since version 1.0.0
3226 */
3227 reference at(const typename object_t::key_type& key)
3228 {
3229 // at only works for objects
3230 if (is_object())
3231 {
3232 try
3233 {
3234 return m_value.object->at(key);
3235 }
3236 catch (std::out_of_range&)
3237 {
3238 // create better exception explanation
3239 throw std::out_of_range("key '" + key + "' not found");
3240 }
3241 }
3242 else
3243 {
3244 throw std::domain_error("cannot use at() with " + type_name());
3245 }
3246 }
3247 6148
3248 /*! 6149#include <array> // array
3249 @brief access specified object element with bounds checking 6150#include <cstddef> // size_t
6151#include <cstring> // strlen
6152#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
6153#include <memory> // shared_ptr, make_shared, addressof
6154#include <numeric> // accumulate
6155#include <string> // string, char_traits
6156#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
6157#include <utility> // pair, declval
3250 6158
3251 Returns a const reference to the element at with specified key @a key, 6159#ifndef JSON_NO_IO
3252 with bounds checking. 6160 #include <cstdio> // FILE *
6161 #include <istream> // istream
6162#endif // JSON_NO_IO
3253 6163
3254 @param[in] key key of the element to access 6164// #include <nlohmann/detail/iterators/iterator_traits.hpp>
3255 6165
3256 @return const reference to the element at key @a key 6166// #include <nlohmann/detail/macro_scope.hpp>
3257 6167
3258 @throw std::domain_error if the JSON value is not an object; example: 6168// #include <nlohmann/detail/meta/type_traits.hpp>
3259 `"cannot use at() with boolean"`
3260 @throw std::out_of_range if the key @a key is is not stored in the object;
3261 that is, `find(key) == end()`; example: `"key "the fast" not found"`
3262 6169
3263 @complexity Logarithmic in the size of the container.
3264 6170
3265 @liveexample{The example below shows how object elements can be read using 6171NLOHMANN_JSON_NAMESPACE_BEGIN
3266 `at()`.,at__object_t_key_type_const} 6172namespace detail
6173{
3267 6174
3268 @sa @ref operator[](const typename object_t::key_type&) for unchecked 6175/// the supported input formats
3269 access by reference 6176enum class input_format_t { json, cbor, msgpack, ubjson, bson, bjdata };
3270 @sa @ref value() for access by value with a default value
3271 6177
3272 @since version 1.0.0 6178////////////////////
3273 */ 6179// input adapters //
3274 const_reference at(const typename object_t::key_type& key) const 6180////////////////////
6181
6182#ifndef JSON_NO_IO
6183/*!
6184Input adapter for stdio file access. This adapter read only 1 byte and do not use any
6185 buffer. This adapter is a very low level adapter.
6186*/
6187class file_input_adapter
6188{
6189 public:
6190 using char_type = char;
6191
6192 JSON_HEDLEY_NON_NULL(2)
6193 explicit file_input_adapter(std::FILE* f) noexcept
6194 : m_file(f)
3275 { 6195 {
3276 // at only works for objects 6196 JSON_ASSERT(m_file != nullptr);
3277 if (is_object())
3278 {
3279 try
3280 {
3281 return m_value.object->at(key);
3282 }
3283 catch (std::out_of_range&)
3284 {
3285 // create better exception explanation
3286 throw std::out_of_range("key '" + key + "' not found");
3287 }
3288 }
3289 else
3290 {
3291 throw std::domain_error("cannot use at() with " + type_name());
3292 }
3293 } 6197 }
3294 6198
3295 /*! 6199 // make class move-only
3296 @brief access specified array element 6200 file_input_adapter(const file_input_adapter&) = delete;
6201 file_input_adapter(file_input_adapter&&) noexcept = default;
6202 file_input_adapter& operator=(const file_input_adapter&) = delete;
6203 file_input_adapter& operator=(file_input_adapter&&) = delete;
6204 ~file_input_adapter() = default;
3297 6205
3298 Returns a reference to the element at specified location @a idx. 6206 std::char_traits<char>::int_type get_character() noexcept
6207 {
6208 return std::fgetc(m_file);
6209 }
3299 6210
3300 @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), 6211 private:
3301 then the array is silently filled up with `null` values to make `idx` a 6212 /// the file pointer to read from
3302 valid reference to the last stored element. 6213 std::FILE* m_file;
6214};
3303 6215
3304 @param[in] idx index of the element to access 6216/*!
6217Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at
6218beginning of input. Does not support changing the underlying std::streambuf
6219in mid-input. Maintains underlying std::istream and std::streambuf to support
6220subsequent use of standard std::istream operations to process any input
6221characters following those used in parsing the JSON input. Clears the
6222std::istream flags; any input errors (e.g., EOF) will be detected by the first
6223subsequent call for input from the std::istream.
6224*/
6225class input_stream_adapter
6226{
6227 public:
6228 using char_type = char;
3305 6229
3306 @return reference to the element at index @a idx 6230 ~input_stream_adapter()
6231 {
6232 // clear stream flags; we use underlying streambuf I/O, do not
6233 // maintain ifstream flags, except eof
6234 if (is != nullptr)
6235 {
6236 is->clear(is->rdstate() & std::ios::eofbit);
6237 }
6238 }
3307 6239
3308 @throw std::domain_error if JSON is not an array or null; example: 6240 explicit input_stream_adapter(std::istream& i)
3309 `"cannot use operator[] with string"` 6241 : is(&i), sb(i.rdbuf())
6242 {}
3310 6243
3311 @complexity Constant if @a idx is in the range of the array. Otherwise 6244 // delete because of pointer members
3312 linear in `idx - size()`. 6245 input_stream_adapter(const input_stream_adapter&) = delete;
6246 input_stream_adapter& operator=(input_stream_adapter&) = delete;
6247 input_stream_adapter& operator=(input_stream_adapter&&) = delete;
3313 6248
3314 @liveexample{The example below shows how array elements can be read and 6249 input_stream_adapter(input_stream_adapter&& rhs) noexcept
3315 written using `[]` operator. Note the addition of `null` 6250 : is(rhs.is), sb(rhs.sb)
3316 values.,operatorarray__size_type} 6251 {
6252 rhs.is = nullptr;
6253 rhs.sb = nullptr;
6254 }
3317 6255
3318 @since version 1.0.0 6256 // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
3319 */ 6257 // ensure that std::char_traits<char>::eof() and the character 0xFF do not
3320 reference operator[](size_type idx) 6258 // end up as the same value, e.g. 0xFFFFFFFF.
6259 std::char_traits<char>::int_type get_character()
3321 { 6260 {
3322 // implicitly convert null value to an empty array 6261 auto res = sb->sbumpc();
3323 if (is_null()) 6262 // set eof manually, as we don't use the istream interface.
6263 if (JSON_HEDLEY_UNLIKELY(res == std::char_traits<char>::eof()))
3324 { 6264 {
3325 m_type = value_t::array; 6265 is->clear(is->rdstate() | std::ios::eofbit);
3326 m_value.array = create<array_t>();
3327 assert_invariant();
3328 } 6266 }
6267 return res;
6268 }
3329 6269
3330 // operator[] only works for arrays 6270 private:
3331 if (is_array()) 6271 /// the associated input stream
3332 { 6272 std::istream* is = nullptr;
3333 // fill up array with null values if given idx is outside range 6273 std::streambuf* sb = nullptr;
3334 if (idx >= m_value.array->size()) 6274};
3335 { 6275#endif // JSON_NO_IO
3336 m_value.array->insert(m_value.array->end(),
3337 idx - m_value.array->size() + 1,
3338 basic_json());
3339 }
3340 6276
3341 return m_value.array->operator[](idx); 6277// General-purpose iterator-based adapter. It might not be as fast as
3342 } 6278// theoretically possible for some containers, but it is extremely versatile.
3343 else 6279template<typename IteratorType>
6280class iterator_input_adapter
6281{
6282 public:
6283 using char_type = typename std::iterator_traits<IteratorType>::value_type;
6284
6285 iterator_input_adapter(IteratorType first, IteratorType last)
6286 : current(std::move(first)), end(std::move(last))
6287 {}
6288
6289 typename char_traits<char_type>::int_type get_character()
6290 {
6291 if (JSON_HEDLEY_LIKELY(current != end))
3344 { 6292 {
3345 throw std::domain_error("cannot use operator[] with " + type_name()); 6293 auto result = char_traits<char_type>::to_int_type(*current);
6294 std::advance(current, 1);
6295 return result;
3346 } 6296 }
6297
6298 return char_traits<char_type>::eof();
3347 } 6299 }
3348 6300
3349 /*! 6301 private:
3350 @brief access specified array element 6302 IteratorType current;
6303 IteratorType end;
3351 6304
3352 Returns a const reference to the element at specified location @a idx. 6305 template<typename BaseInputAdapter, size_t T>
6306 friend struct wide_string_input_helper;
3353 6307
3354 @param[in] idx index of the element to access 6308 bool empty() const
6309 {
6310 return current == end;
6311 }
6312};
3355 6313
3356 @return const reference to the element at index @a idx 6314template<typename BaseInputAdapter, size_t T>
6315struct wide_string_input_helper;
3357 6316
3358 @throw std::domain_error if JSON is not an array; example: `"cannot use 6317template<typename BaseInputAdapter>
3359 operator[] with null"` 6318struct wide_string_input_helper<BaseInputAdapter, 4>
6319{
6320 // UTF-32
6321 static void fill_buffer(BaseInputAdapter& input,
6322 std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
6323 size_t& utf8_bytes_index,
6324 size_t& utf8_bytes_filled)
6325 {
6326 utf8_bytes_index = 0;
3360 6327
3361 @complexity Constant. 6328 if (JSON_HEDLEY_UNLIKELY(input.empty()))
6329 {
6330 utf8_bytes[0] = std::char_traits<char>::eof();
6331 utf8_bytes_filled = 1;
6332 }
6333 else
6334 {
6335 // get the current character
6336 const auto wc = input.get_character();
3362 6337
3363 @liveexample{The example below shows how array elements can be read using 6338 // UTF-32 to UTF-8 encoding
3364 the `[]` operator.,operatorarray__size_type_const} 6339 if (wc < 0x80)
6340 {
6341 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
6342 utf8_bytes_filled = 1;
6343 }
6344 else if (wc <= 0x7FF)
6345 {
6346 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u) & 0x1Fu));
6347 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
6348 utf8_bytes_filled = 2;
6349 }
6350 else if (wc <= 0xFFFF)
6351 {
6352 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u) & 0x0Fu));
6353 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
6354 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
6355 utf8_bytes_filled = 3;
6356 }
6357 else if (wc <= 0x10FFFF)
6358 {
6359 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((static_cast<unsigned int>(wc) >> 18u) & 0x07u));
6360 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 12u) & 0x3Fu));
6361 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
6362 utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
6363 utf8_bytes_filled = 4;
6364 }
6365 else
6366 {
6367 // unknown character
6368 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
6369 utf8_bytes_filled = 1;
6370 }
6371 }
6372 }
6373};
3365 6374
3366 @since version 1.0.0 6375template<typename BaseInputAdapter>
3367 */ 6376struct wide_string_input_helper<BaseInputAdapter, 2>
3368 const_reference operator[](size_type idx) const 6377{
6378 // UTF-16
6379 static void fill_buffer(BaseInputAdapter& input,
6380 std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
6381 size_t& utf8_bytes_index,
6382 size_t& utf8_bytes_filled)
3369 { 6383 {
3370 // const operator[] only works for arrays 6384 utf8_bytes_index = 0;
3371 if (is_array()) 6385
6386 if (JSON_HEDLEY_UNLIKELY(input.empty()))
3372 { 6387 {
3373 return m_value.array->operator[](idx); 6388 utf8_bytes[0] = std::char_traits<char>::eof();
6389 utf8_bytes_filled = 1;
3374 } 6390 }
3375 else 6391 else
3376 { 6392 {
3377 throw std::domain_error("cannot use operator[] with " + type_name()); 6393 // get the current character
6394 const auto wc = input.get_character();
6395
6396 // UTF-16 to UTF-8 encoding
6397 if (wc < 0x80)
6398 {
6399 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
6400 utf8_bytes_filled = 1;
6401 }
6402 else if (wc <= 0x7FF)
6403 {
6404 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u)));
6405 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
6406 utf8_bytes_filled = 2;
6407 }
6408 else if (0xD800 > wc || wc >= 0xE000)
6409 {
6410 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u)));
6411 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
6412 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
6413 utf8_bytes_filled = 3;
6414 }
6415 else
6416 {
6417 if (JSON_HEDLEY_UNLIKELY(!input.empty()))
6418 {
6419 const auto wc2 = static_cast<unsigned int>(input.get_character());
6420 const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
6421 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));
6422 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));
6423 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));
6424 utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));
6425 utf8_bytes_filled = 4;
6426 }
6427 else
6428 {
6429 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
6430 utf8_bytes_filled = 1;
6431 }
6432 }
3378 } 6433 }
3379 } 6434 }
6435};
3380 6436
3381 /*! 6437// Wraps another input adapter to convert wide character types into individual bytes.
3382 @brief access specified object element 6438template<typename BaseInputAdapter, typename WideCharType>
6439class wide_string_input_adapter
6440{
6441 public:
6442 using char_type = char;
6443
6444 wide_string_input_adapter(BaseInputAdapter base)
6445 : base_adapter(base) {}
3383 6446
3384 Returns a reference to the element at with specified key @a key. 6447 typename std::char_traits<char>::int_type get_character() noexcept
6448 {
6449 // check if buffer needs to be filled
6450 if (utf8_bytes_index == utf8_bytes_filled)
6451 {
6452 fill_buffer<sizeof(WideCharType)>();
3385 6453
3386 @note If @a key is not found in the object, then it is silently added to 6454 JSON_ASSERT(utf8_bytes_filled > 0);
3387 the object and filled with a `null` value to make `key` a valid reference. 6455 JSON_ASSERT(utf8_bytes_index == 0);
3388 In case the value was `null` before, it is converted to an object. 6456 }
6457
6458 // use buffer
6459 JSON_ASSERT(utf8_bytes_filled > 0);
6460 JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled);
6461 return utf8_bytes[utf8_bytes_index++];
6462 }
3389 6463
3390 @param[in] key key of the element to access 6464 private:
6465 BaseInputAdapter base_adapter;
3391 6466
3392 @return reference to the element at key @a key 6467 template<size_t T>
6468 void fill_buffer()
6469 {
6470 wide_string_input_helper<BaseInputAdapter, T>::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);
6471 }
3393 6472
3394 @throw std::domain_error if JSON is not an object or null; example: 6473 /// a buffer for UTF-8 bytes
3395 `"cannot use operator[] with string"` 6474 std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};
3396 6475
3397 @complexity Logarithmic in the size of the container. 6476 /// index to the utf8_codes array for the next valid byte
6477 std::size_t utf8_bytes_index = 0;
6478 /// number of valid bytes in the utf8_codes array
6479 std::size_t utf8_bytes_filled = 0;
6480};
3398 6481
3399 @liveexample{The example below shows how object elements can be read and 6482template<typename IteratorType, typename Enable = void>
3400 written using the `[]` operator.,operatorarray__key_type} 6483struct iterator_input_adapter_factory
6484{
6485 using iterator_type = IteratorType;
6486 using char_type = typename std::iterator_traits<iterator_type>::value_type;
6487 using adapter_type = iterator_input_adapter<iterator_type>;
3401 6488
3402 @sa @ref at(const typename object_t::key_type&) for access by reference 6489 static adapter_type create(IteratorType first, IteratorType last)
3403 with range checking 6490 {
3404 @sa @ref value() for access by value with a default value 6491 return adapter_type(std::move(first), std::move(last));
6492 }
6493};
3405 6494
3406 @since version 1.0.0 6495template<typename T>
3407 */ 6496struct is_iterator_of_multibyte
3408 reference operator[](const typename object_t::key_type& key) 6497{
6498 using value_type = typename std::iterator_traits<T>::value_type;
6499 enum
3409 { 6500 {
3410 // implicitly convert null value to an empty object 6501 value = sizeof(value_type) > 1
3411 if (is_null()) 6502 };
3412 { 6503};
3413 m_type = value_t::object;
3414 m_value.object = create<object_t>();
3415 assert_invariant();
3416 }
3417 6504
3418 // operator[] only works for objects 6505template<typename IteratorType>
3419 if (is_object()) 6506struct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>
3420 { 6507{
3421 return m_value.object->operator[](key); 6508 using iterator_type = IteratorType;
3422 } 6509 using char_type = typename std::iterator_traits<iterator_type>::value_type;
3423 else 6510 using base_adapter_type = iterator_input_adapter<iterator_type>;
3424 { 6511 using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>;
3425 throw std::domain_error("cannot use operator[] with " + type_name()); 6512
3426 } 6513 static adapter_type create(IteratorType first, IteratorType last)
6514 {
6515 return adapter_type(base_adapter_type(std::move(first), std::move(last)));
3427 } 6516 }
6517};
3428 6518
3429 /*! 6519// General purpose iterator-based input
3430 @brief read-only access specified object element 6520template<typename IteratorType>
6521typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)
6522{
6523 using factory_type = iterator_input_adapter_factory<IteratorType>;
6524 return factory_type::create(first, last);
6525}
3431 6526
3432 Returns a const reference to the element at with specified key @a key. No 6527// Convenience shorthand from container to iterator
3433 bounds checking is performed. 6528// Enables ADL on begin(container) and end(container)
6529// Encloses the using declarations in namespace for not to leak them to outside scope
3434 6530
3435 @warning If the element with key @a key does not exist, the behavior is 6531namespace container_input_adapter_factory_impl
3436 undefined. 6532{
3437 6533
3438 @param[in] key key of the element to access 6534using std::begin;
6535using std::end;
3439 6536
3440 @return const reference to the element at key @a key 6537template<typename ContainerType, typename Enable = void>
6538struct container_input_adapter_factory {};
3441 6539
3442 @pre The element with key @a key must exist. **This precondition is 6540template<typename ContainerType>
3443 enforced with an assertion.** 6541struct container_input_adapter_factory< ContainerType,
6542 void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>>
6543 {
6544 using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));
3444 6545
3445 @throw std::domain_error if JSON is not an object; example: `"cannot use 6546 static adapter_type create(const ContainerType& container)
3446 operator[] with null"` 6547{
6548 return input_adapter(begin(container), end(container));
6549}
6550 };
3447 6551
3448 @complexity Logarithmic in the size of the container. 6552} // namespace container_input_adapter_factory_impl
3449 6553
3450 @liveexample{The example below shows how object elements can be read using 6554template<typename ContainerType>
3451 the `[]` operator.,operatorarray__key_type_const} 6555typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)
6556{
6557 return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
6558}
3452 6559
3453 @sa @ref at(const typename object_t::key_type&) for access by reference 6560#ifndef JSON_NO_IO
3454 with range checking 6561// Special cases with fast paths
3455 @sa @ref value() for access by value with a default value 6562inline file_input_adapter input_adapter(std::FILE* file)
6563{
6564 return file_input_adapter(file);
6565}
3456 6566
3457 @since version 1.0.0 6567inline input_stream_adapter input_adapter(std::istream& stream)
3458 */ 6568{
3459 const_reference operator[](const typename object_t::key_type& key) const 6569 return input_stream_adapter(stream);
6570}
6571
6572inline input_stream_adapter input_adapter(std::istream&& stream)
6573{
6574 return input_stream_adapter(stream);
6575}
6576#endif // JSON_NO_IO
6577
6578using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>()));
6579
6580// Null-delimited strings, and the like.
6581template < typename CharT,
6582 typename std::enable_if <
6583 std::is_pointer<CharT>::value&&
6584 !std::is_array<CharT>::value&&
6585 std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
6586 sizeof(typename std::remove_pointer<CharT>::type) == 1,
6587 int >::type = 0 >
6588contiguous_bytes_input_adapter input_adapter(CharT b)
6589{
6590 auto length = std::strlen(reinterpret_cast<const char*>(b));
6591 const auto* ptr = reinterpret_cast<const char*>(b);
6592 return input_adapter(ptr, ptr + length);
6593}
6594
6595template<typename T, std::size_t N>
6596auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
6597{
6598 return input_adapter(array, array + N);
6599}
6600
6601// This class only handles inputs of input_buffer_adapter type.
6602// It's required so that expressions like {ptr, len} can be implicitly cast
6603// to the correct adapter.
6604class span_input_adapter
6605{
6606 public:
6607 template < typename CharT,
6608 typename std::enable_if <
6609 std::is_pointer<CharT>::value&&
6610 std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
6611 sizeof(typename std::remove_pointer<CharT>::type) == 1,
6612 int >::type = 0 >
6613 span_input_adapter(CharT b, std::size_t l)
6614 : ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {}
6615
6616 template<class IteratorType,
6617 typename std::enable_if<
6618 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
6619 int>::type = 0>
6620 span_input_adapter(IteratorType first, IteratorType last)
6621 : ia(input_adapter(first, last)) {}
6622
6623 contiguous_bytes_input_adapter&& get()
3460 { 6624 {
3461 // const operator[] only works for objects 6625 return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
3462 if (is_object())
3463 {
3464 assert(m_value.object->find(key) != m_value.object->end());
3465 return m_value.object->find(key)->second;
3466 }
3467 else
3468 {
3469 throw std::domain_error("cannot use operator[] with " + type_name());
3470 }
3471 } 6626 }
3472 6627
3473 /*! 6628 private:
3474 @brief access specified object element 6629 contiguous_bytes_input_adapter ia;
6630};
3475 6631
3476 Returns a reference to the element at with specified key @a key. 6632} // namespace detail
6633NLOHMANN_JSON_NAMESPACE_END
3477 6634
3478 @note If @a key is not found in the object, then it is silently added to 6635// #include <nlohmann/detail/input/json_sax.hpp>
3479 the object and filled with a `null` value to make `key` a valid reference. 6636// __ _____ _____ _____
3480 In case the value was `null` before, it is converted to an object. 6637// __| | __| | | | JSON for Modern C++
6638// | | |__ | | | | | | version 3.11.3
6639// |_____|_____|_____|_|___| https://github.com/nlohmann/json
6640//
6641// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
6642// SPDX-License-Identifier: MIT
3481 6643
3482 @param[in] key key of the element to access
3483 6644
3484 @return reference to the element at key @a key
3485 6645
3486 @throw std::domain_error if JSON is not an object or null; example: 6646#include <cstddef>
3487 `"cannot use operator[] with string"` 6647#include <string> // string
6648#include <utility> // move
6649#include <vector> // vector
3488 6650
3489 @complexity Logarithmic in the size of the container. 6651// #include <nlohmann/detail/exceptions.hpp>
3490 6652
3491 @liveexample{The example below shows how object elements can be read and 6653// #include <nlohmann/detail/macro_scope.hpp>
3492 written using the `[]` operator.,operatorarray__key_type}
3493 6654
3494 @sa @ref at(const typename object_t::key_type&) for access by reference 6655// #include <nlohmann/detail/string_concat.hpp>
3495 with range checking
3496 @sa @ref value() for access by value with a default value
3497 6656
3498 @since version 1.0.0 6657
6658NLOHMANN_JSON_NAMESPACE_BEGIN
6659
6660/*!
6661@brief SAX interface
6662
6663This class describes the SAX interface used by @ref nlohmann::json::sax_parse.
6664Each function is called in different situations while the input is parsed. The
6665boolean return value informs the parser whether to continue processing the
6666input.
6667*/
6668template<typename BasicJsonType>
6669struct json_sax
6670{
6671 using number_integer_t = typename BasicJsonType::number_integer_t;
6672 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
6673 using number_float_t = typename BasicJsonType::number_float_t;
6674 using string_t = typename BasicJsonType::string_t;
6675 using binary_t = typename BasicJsonType::binary_t;
6676
6677 /*!
6678 @brief a null value was read
6679 @return whether parsing should proceed
3499 */ 6680 */
3500 template<typename T, std::size_t n> 6681 virtual bool null() = 0;
3501 reference operator[](T * (&key)[n])
3502 {
3503 return operator[](static_cast<const T>(key));
3504 }
3505 6682
3506 /*! 6683 /*!
3507 @brief read-only access specified object element 6684 @brief a boolean value was read
6685 @param[in] val boolean value
6686 @return whether parsing should proceed
6687 */
6688 virtual bool boolean(bool val) = 0;
3508 6689
3509 Returns a const reference to the element at with specified key @a key. No 6690 /*!
3510 bounds checking is performed. 6691 @brief an integer number was read
6692 @param[in] val integer value
6693 @return whether parsing should proceed
6694 */
6695 virtual bool number_integer(number_integer_t val) = 0;
3511 6696
3512 @warning If the element with key @a key does not exist, the behavior is 6697 /*!
3513 undefined. 6698 @brief an unsigned integer number was read
6699 @param[in] val unsigned integer value
6700 @return whether parsing should proceed
6701 */
6702 virtual bool number_unsigned(number_unsigned_t val) = 0;
3514 6703
3515 @note This function is required for compatibility reasons with Clang. 6704 /*!
6705 @brief a floating-point number was read
6706 @param[in] val floating-point value
6707 @param[in] s raw token value
6708 @return whether parsing should proceed
6709 */
6710 virtual bool number_float(number_float_t val, const string_t& s) = 0;
3516 6711
3517 @param[in] key key of the element to access 6712 /*!
6713 @brief a string value was read
6714 @param[in] val string value
6715 @return whether parsing should proceed
6716 @note It is safe to move the passed string value.
6717 */
6718 virtual bool string(string_t& val) = 0;
3518 6719
3519 @return const reference to the element at key @a key 6720 /*!
6721 @brief a binary value was read
6722 @param[in] val binary value
6723 @return whether parsing should proceed
6724 @note It is safe to move the passed binary value.
6725 */
6726 virtual bool binary(binary_t& val) = 0;
3520 6727
3521 @throw std::domain_error if JSON is not an object; example: `"cannot use 6728 /*!
3522 operator[] with null"` 6729 @brief the beginning of an object was read
6730 @param[in] elements number of object elements or -1 if unknown
6731 @return whether parsing should proceed
6732 @note binary formats may report the number of elements
6733 */
6734 virtual bool start_object(std::size_t elements) = 0;
3523 6735
3524 @complexity Logarithmic in the size of the container. 6736 /*!
6737 @brief an object key was read
6738 @param[in] val object key
6739 @return whether parsing should proceed
6740 @note It is safe to move the passed string.
6741 */
6742 virtual bool key(string_t& val) = 0;
3525 6743
3526 @liveexample{The example below shows how object elements can be read using 6744 /*!
3527 the `[]` operator.,operatorarray__key_type_const} 6745 @brief the end of an object was read
6746 @return whether parsing should proceed
6747 */
6748 virtual bool end_object() = 0;
3528 6749
3529 @sa @ref at(const typename object_t::key_type&) for access by reference 6750 /*!
3530 with range checking 6751 @brief the beginning of an array was read
3531 @sa @ref value() for access by value with a default value 6752 @param[in] elements number of array elements or -1 if unknown
6753 @return whether parsing should proceed
6754 @note binary formats may report the number of elements
6755 */
6756 virtual bool start_array(std::size_t elements) = 0;
3532 6757
3533 @since version 1.0.0 6758 /*!
6759 @brief the end of an array was read
6760 @return whether parsing should proceed
3534 */ 6761 */
3535 template<typename T, std::size_t n> 6762 virtual bool end_array() = 0;
3536 const_reference operator[](T * (&key)[n]) const
3537 {
3538 return operator[](static_cast<const T>(key));
3539 }
3540 6763
3541 /*! 6764 /*!
3542 @brief access specified object element 6765 @brief a parse error occurred
6766 @param[in] position the position in the input where the error occurs
6767 @param[in] last_token the last read token
6768 @param[in] ex an exception object describing the error
6769 @return whether parsing should proceed (must return false)
6770 */
6771 virtual bool parse_error(std::size_t position,
6772 const std::string& last_token,
6773 const detail::exception& ex) = 0;
6774
6775 json_sax() = default;
6776 json_sax(const json_sax&) = default;
6777 json_sax(json_sax&&) noexcept = default;
6778 json_sax& operator=(const json_sax&) = default;
6779 json_sax& operator=(json_sax&&) noexcept = default;
6780 virtual ~json_sax() = default;
6781};
3543 6782
3544 Returns a reference to the element at with specified key @a key. 6783namespace detail
6784{
6785/*!
6786@brief SAX implementation to create a JSON value from SAX events
3545 6787
3546 @note If @a key is not found in the object, then it is silently added to 6788This class implements the @ref json_sax interface and processes the SAX events
3547 the object and filled with a `null` value to make `key` a valid reference. 6789to create a JSON value which makes it basically a DOM parser. The structure or
3548 In case the value was `null` before, it is converted to an object. 6790hierarchy of the JSON value is managed by the stack `ref_stack` which contains
6791a pointer to the respective array or object for each recursion depth.
3549 6792
3550 @param[in] key key of the element to access 6793After successful parsing, the value that is passed by reference to the
6794constructor contains the parsed value.
3551 6795
3552 @return reference to the element at key @a key 6796@tparam BasicJsonType the JSON type
6797*/
6798template<typename BasicJsonType>
6799class json_sax_dom_parser
6800{
6801 public:
6802 using number_integer_t = typename BasicJsonType::number_integer_t;
6803 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
6804 using number_float_t = typename BasicJsonType::number_float_t;
6805 using string_t = typename BasicJsonType::string_t;
6806 using binary_t = typename BasicJsonType::binary_t;
3553 6807
3554 @throw std::domain_error if JSON is not an object or null; example: 6808 /*!
3555 `"cannot use operator[] with string"` 6809 @param[in,out] r reference to a JSON value that is manipulated while
6810 parsing
6811 @param[in] allow_exceptions_ whether parse errors yield exceptions
6812 */
6813 explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
6814 : root(r), allow_exceptions(allow_exceptions_)
6815 {}
6816
6817 // make class move-only
6818 json_sax_dom_parser(const json_sax_dom_parser&) = delete;
6819 json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
6820 json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;
6821 json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
6822 ~json_sax_dom_parser() = default;
6823
6824 bool null()
6825 {
6826 handle_value(nullptr);
6827 return true;
6828 }
3556 6829
3557 @complexity Logarithmic in the size of the container. 6830 bool boolean(bool val)
6831 {
6832 handle_value(val);
6833 return true;
6834 }
3558 6835
3559 @liveexample{The example below shows how object elements can be read and 6836 bool number_integer(number_integer_t val)
3560 written using the `[]` operator.,operatorarray__key_type} 6837 {
6838 handle_value(val);
6839 return true;
6840 }
3561 6841
3562 @sa @ref at(const typename object_t::key_type&) for access by reference 6842 bool number_unsigned(number_unsigned_t val)
3563 with range checking 6843 {
3564 @sa @ref value() for access by value with a default value 6844 handle_value(val);
6845 return true;
6846 }
3565 6847
3566 @since version 1.1.0 6848 bool number_float(number_float_t val, const string_t& /*unused*/)
3567 */
3568 template<typename T>
3569 reference operator[](T* key)
3570 { 6849 {
3571 // implicitly convert null to object 6850 handle_value(val);
3572 if (is_null()) 6851 return true;
3573 { 6852 }
3574 m_type = value_t::object;
3575 m_value = value_t::object;
3576 assert_invariant();
3577 }
3578 6853
3579 // at only works for objects 6854 bool string(string_t& val)
3580 if (is_object()) 6855 {
3581 { 6856 handle_value(val);
3582 return m_value.object->operator[](key); 6857 return true;
3583 } 6858 }
3584 else 6859
6860 bool binary(binary_t& val)
6861 {
6862 handle_value(std::move(val));
6863 return true;
6864 }
6865
6866 bool start_object(std::size_t len)
6867 {
6868 ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
6869
6870 if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
3585 { 6871 {
3586 throw std::domain_error("cannot use operator[] with " + type_name()); 6872 JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
3587 } 6873 }
6874
6875 return true;
3588 } 6876 }
3589 6877
3590 /*! 6878 bool key(string_t& val)
3591 @brief read-only access specified object element 6879 {
6880 JSON_ASSERT(!ref_stack.empty());
6881 JSON_ASSERT(ref_stack.back()->is_object());
3592 6882
3593 Returns a const reference to the element at with specified key @a key. No 6883 // add null at given key and store the reference for later
3594 bounds checking is performed. 6884 object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val));
6885 return true;
6886 }
6887
6888 bool end_object()
6889 {
6890 JSON_ASSERT(!ref_stack.empty());
6891 JSON_ASSERT(ref_stack.back()->is_object());
3595 6892
3596 @warning If the element with key @a key does not exist, the behavior is 6893 ref_stack.back()->set_parents();
3597 undefined. 6894 ref_stack.pop_back();
6895 return true;
6896 }
3598 6897
3599 @param[in] key key of the element to access 6898 bool start_array(std::size_t len)
6899 {
6900 ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
3600 6901
3601 @return const reference to the element at key @a key 6902 if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
6903 {
6904 JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
6905 }
3602 6906
3603 @pre The element with key @a key must exist. **This precondition is 6907 return true;
3604 enforced with an assertion.** 6908 }
3605 6909
3606 @throw std::domain_error if JSON is not an object; example: `"cannot use 6910 bool end_array()
3607 operator[] with null"` 6911 {
6912 JSON_ASSERT(!ref_stack.empty());
6913 JSON_ASSERT(ref_stack.back()->is_array());
3608 6914
3609 @complexity Logarithmic in the size of the container. 6915 ref_stack.back()->set_parents();
6916 ref_stack.pop_back();
6917 return true;
6918 }
3610 6919
3611 @liveexample{The example below shows how object elements can be read using 6920 template<class Exception>
3612 the `[]` operator.,operatorarray__key_type_const} 6921 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
6922 const Exception& ex)
6923 {
6924 errored = true;
6925 static_cast<void>(ex);
6926 if (allow_exceptions)
6927 {
6928 JSON_THROW(ex);
6929 }
6930 return false;
6931 }
3613 6932
3614 @sa @ref at(const typename object_t::key_type&) for access by reference 6933 constexpr bool is_errored() const
3615 with range checking 6934 {
3616 @sa @ref value() for access by value with a default value 6935 return errored;
6936 }
3617 6937
3618 @since version 1.1.0 6938 private:
6939 /*!
6940 @invariant If the ref stack is empty, then the passed value will be the new
6941 root.
6942 @invariant If the ref stack contains a value, then it is an array or an
6943 object to which we can add elements
3619 */ 6944 */
3620 template<typename T> 6945 template<typename Value>
3621 const_reference operator[](T* key) const 6946 JSON_HEDLEY_RETURNS_NON_NULL
6947 BasicJsonType* handle_value(Value&& v)
3622 { 6948 {
3623 // at only works for objects 6949 if (ref_stack.empty())
3624 if (is_object())
3625 { 6950 {
3626 assert(m_value.object->find(key) != m_value.object->end()); 6951 root = BasicJsonType(std::forward<Value>(v));
3627 return m_value.object->find(key)->second; 6952 return &root;
3628 } 6953 }
3629 else 6954
6955 JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
6956
6957 if (ref_stack.back()->is_array())
3630 { 6958 {
3631 throw std::domain_error("cannot use operator[] with " + type_name()); 6959 ref_stack.back()->m_data.m_value.array->emplace_back(std::forward<Value>(v));
6960 return &(ref_stack.back()->m_data.m_value.array->back());
3632 } 6961 }
6962
6963 JSON_ASSERT(ref_stack.back()->is_object());
6964 JSON_ASSERT(object_element);
6965 *object_element = BasicJsonType(std::forward<Value>(v));
6966 return object_element;
3633 } 6967 }
3634 6968
3635 /*! 6969 /// the parsed JSON value
3636 @brief access specified object element with default value 6970 BasicJsonType& root;
6971 /// stack to model hierarchy of values
6972 std::vector<BasicJsonType*> ref_stack {};
6973 /// helper to hold the reference for the next object element
6974 BasicJsonType* object_element = nullptr;
6975 /// whether a syntax error occurred
6976 bool errored = false;
6977 /// whether to throw exceptions in case of errors
6978 const bool allow_exceptions = true;
6979};
6980
6981template<typename BasicJsonType>
6982class json_sax_dom_callback_parser
6983{
6984 public:
6985 using number_integer_t = typename BasicJsonType::number_integer_t;
6986 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
6987 using number_float_t = typename BasicJsonType::number_float_t;
6988 using string_t = typename BasicJsonType::string_t;
6989 using binary_t = typename BasicJsonType::binary_t;
6990 using parser_callback_t = typename BasicJsonType::parser_callback_t;
6991 using parse_event_t = typename BasicJsonType::parse_event_t;
6992
6993 json_sax_dom_callback_parser(BasicJsonType& r,
6994 const parser_callback_t cb,
6995 const bool allow_exceptions_ = true)
6996 : root(r), callback(cb), allow_exceptions(allow_exceptions_)
6997 {
6998 keep_stack.push_back(true);
6999 }
3637 7000
3638 Returns either a copy of an object's element at the specified key @a key 7001 // make class move-only
3639 or a given default value if no element with key @a key exists. 7002 json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;
7003 json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
7004 json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;
7005 json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
7006 ~json_sax_dom_callback_parser() = default;
3640 7007
3641 The function is basically equivalent to executing 7008 bool null()
3642 @code {.cpp} 7009 {
3643 try { 7010 handle_value(nullptr);
3644 return at(key); 7011 return true;
3645 } catch(std::out_of_range) {
3646 return default_value;
3647 } 7012 }
3648 @endcode
3649 7013
3650 @note Unlike @ref at(const typename object_t::key_type&), this function 7014 bool boolean(bool val)
3651 does not throw if the given key @a key was not found. 7015 {
7016 handle_value(val);
7017 return true;
7018 }
7019
7020 bool number_integer(number_integer_t val)
7021 {
7022 handle_value(val);
7023 return true;
7024 }
3652 7025
3653 @note Unlike @ref operator[](const typename object_t::key_type& key), this 7026 bool number_unsigned(number_unsigned_t val)
3654 function does not implicitly add an element to the position defined by @a 7027 {
3655 key. This function is furthermore also applicable to const objects. 7028 handle_value(val);
7029 return true;
7030 }
3656 7031
3657 @param[in] key key of the element to access 7032 bool number_float(number_float_t val, const string_t& /*unused*/)
3658 @param[in] default_value the value to return if @a key is not found 7033 {
7034 handle_value(val);
7035 return true;
7036 }
3659 7037
3660 @tparam ValueType type compatible to JSON values, for instance `int` for 7038 bool string(string_t& val)
3661 JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for 7039 {
3662 JSON arrays. Note the type of the expected value at @a key and the default 7040 handle_value(val);
3663 value @a default_value must be compatible. 7041 return true;
7042 }
3664 7043
3665 @return copy of the element at key @a key or @a default_value if @a key 7044 bool binary(binary_t& val)
3666 is not found 7045 {
7046 handle_value(std::move(val));
7047 return true;
7048 }
3667 7049
3668 @throw std::domain_error if JSON is not an object; example: `"cannot use 7050 bool start_object(std::size_t len)
3669 value() with null"` 7051 {
7052 // check callback for object start
7053 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
7054 keep_stack.push_back(keep);
3670 7055
3671 @complexity Logarithmic in the size of the container. 7056 auto val = handle_value(BasicJsonType::value_t::object, true);
7057 ref_stack.push_back(val.second);
3672 7058
3673 @liveexample{The example below shows how object elements can be queried 7059 // check object limit
3674 with a default value.,basic_json__value} 7060 if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
7061 {
7062 JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
7063 }
3675 7064
3676 @sa @ref at(const typename object_t::key_type&) for access by reference 7065 return true;
3677 with range checking 7066 }
3678 @sa @ref operator[](const typename object_t::key_type&) for unchecked
3679 access by reference
3680 7067
3681 @since version 1.0.0 7068 bool key(string_t& val)
3682 */
3683 template<class ValueType, typename std::enable_if<
3684 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
3685 ValueType value(const typename object_t::key_type& key, ValueType default_value) const
3686 { 7069 {
3687 // at only works for objects 7070 BasicJsonType k = BasicJsonType(val);
3688 if (is_object()) 7071
7072 // check callback for key
7073 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);
7074 key_keep_stack.push_back(keep);
7075
7076 // add discarded value at given key and store the reference for later
7077 if (keep && ref_stack.back())
3689 { 7078 {
3690 // if key is found, return value and given default value otherwise 7079 object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded);
3691 const auto it = find(key); 7080 }
3692 if (it != end()) 7081
7082 return true;
7083 }
7084
7085 bool end_object()
7086 {
7087 if (ref_stack.back())
7088 {
7089 if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
3693 { 7090 {
3694 return *it; 7091 // discard object
7092 *ref_stack.back() = discarded;
3695 } 7093 }
3696 else 7094 else
3697 { 7095 {
3698 return default_value; 7096 ref_stack.back()->set_parents();
3699 } 7097 }
3700 } 7098 }
3701 else 7099
7100 JSON_ASSERT(!ref_stack.empty());
7101 JSON_ASSERT(!keep_stack.empty());
7102 ref_stack.pop_back();
7103 keep_stack.pop_back();
7104
7105 if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
3702 { 7106 {
3703 throw std::domain_error("cannot use value() with " + type_name()); 7107 // remove discarded value
7108 for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
7109 {
7110 if (it->is_discarded())
7111 {
7112 ref_stack.back()->erase(it);
7113 break;
7114 }
7115 }
3704 } 7116 }
7117
7118 return true;
3705 } 7119 }
3706 7120
3707 /*! 7121 bool start_array(std::size_t len)
3708 @brief overload for a default value of type const char*
3709 @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const
3710 */
3711 string_t value(const typename object_t::key_type& key, const char* default_value) const
3712 { 7122 {
3713 return value(key, string_t(default_value)); 7123 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
3714 } 7124 keep_stack.push_back(keep);
3715 7125
3716 /*! 7126 auto val = handle_value(BasicJsonType::value_t::array, true);
3717 @brief access specified object element via JSON Pointer with default value 7127 ref_stack.push_back(val.second);
3718 7128
3719 Returns either a copy of an object's element at the specified key @a key 7129 // check array limit
3720 or a given default value if no element with key @a key exists. 7130 if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
7131 {
7132 JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
7133 }
3721 7134
3722 The function is basically equivalent to executing 7135 return true;
3723 @code {.cpp}
3724 try {
3725 return at(ptr);
3726 } catch(std::out_of_range) {
3727 return default_value;
3728 } 7136 }
3729 @endcode
3730 7137
3731 @note Unlike @ref at(const json_pointer&), this function does not throw 7138 bool end_array()
3732 if the given key @a key was not found. 7139 {
3733 7140 bool keep = true;
3734 @param[in] ptr a JSON pointer to the element to access
3735 @param[in] default_value the value to return if @a ptr found no value
3736 7141
3737 @tparam ValueType type compatible to JSON values, for instance `int` for 7142 if (ref_stack.back())
3738 JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for 7143 {
3739 JSON arrays. Note the type of the expected value at @a key and the default 7144 keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
3740 value @a default_value must be compatible. 7145 if (keep)
7146 {
7147 ref_stack.back()->set_parents();
7148 }
7149 else
7150 {
7151 // discard array
7152 *ref_stack.back() = discarded;
7153 }
7154 }
3741 7155
3742 @return copy of the element at key @a key or @a default_value if @a key 7156 JSON_ASSERT(!ref_stack.empty());
3743 is not found 7157 JSON_ASSERT(!keep_stack.empty());
7158 ref_stack.pop_back();
7159 keep_stack.pop_back();
3744 7160
3745 @throw std::domain_error if JSON is not an object; example: `"cannot use 7161 // remove discarded value
3746 value() with null"` 7162 if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())
7163 {
7164 ref_stack.back()->m_data.m_value.array->pop_back();
7165 }
3747 7166
3748 @complexity Logarithmic in the size of the container. 7167 return true;
7168 }
3749 7169
3750 @liveexample{The example below shows how object elements can be queried 7170 template<class Exception>
3751 with a default value.,basic_json__value_ptr} 7171 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
7172 const Exception& ex)
7173 {
7174 errored = true;
7175 static_cast<void>(ex);
7176 if (allow_exceptions)
7177 {
7178 JSON_THROW(ex);
7179 }
7180 return false;
7181 }
3752 7182
3753 @sa @ref operator[](const json_pointer&) for unchecked access by reference 7183 constexpr bool is_errored() const
7184 {
7185 return errored;
7186 }
3754 7187
3755 @since version 2.0.2 7188 private:
7189 /*!
7190 @param[in] v value to add to the JSON value we build during parsing
7191 @param[in] skip_callback whether we should skip calling the callback
7192 function; this is required after start_array() and
7193 start_object() SAX events, because otherwise we would call the
7194 callback function with an empty array or object, respectively.
7195
7196 @invariant If the ref stack is empty, then the passed value will be the new
7197 root.
7198 @invariant If the ref stack contains a value, then it is an array or an
7199 object to which we can add elements
7200
7201 @return pair of boolean (whether value should be kept) and pointer (to the
7202 passed value in the ref_stack hierarchy; nullptr if not kept)
3756 */ 7203 */
3757 template<class ValueType, typename std::enable_if< 7204 template<typename Value>
3758 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0> 7205 std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
3759 ValueType value(const json_pointer& ptr, ValueType default_value) const
3760 { 7206 {
3761 // at only works for objects 7207 JSON_ASSERT(!keep_stack.empty());
3762 if (is_object()) 7208
7209 // do not handle this value if we know it would be added to a discarded
7210 // container
7211 if (!keep_stack.back())
3763 { 7212 {
3764 // if pointer resolves a value, return it or use default value 7213 return {false, nullptr};
3765 try
3766 {
3767 return ptr.get_checked(this);
3768 }
3769 catch (std::out_of_range&)
3770 {
3771 return default_value;
3772 }
3773 } 7214 }
3774 else 7215
7216 // create value
7217 auto value = BasicJsonType(std::forward<Value>(v));
7218
7219 // check callback
7220 const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
7221
7222 // do not handle this value if we just learnt it shall be discarded
7223 if (!keep)
7224 {
7225 return {false, nullptr};
7226 }
7227
7228 if (ref_stack.empty())
7229 {
7230 root = std::move(value);
7231 return {true, & root};
7232 }
7233
7234 // skip this value if we already decided to skip the parent
7235 // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
7236 if (!ref_stack.back())
3775 { 7237 {
3776 throw std::domain_error("cannot use value() with " + type_name()); 7238 return {false, nullptr};
3777 } 7239 }
7240
7241 // we now only expect arrays and objects
7242 JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
7243
7244 // array
7245 if (ref_stack.back()->is_array())
7246 {
7247 ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value));
7248 return {true, & (ref_stack.back()->m_data.m_value.array->back())};
7249 }
7250
7251 // object
7252 JSON_ASSERT(ref_stack.back()->is_object());
7253 // check if we should store an element for the current key
7254 JSON_ASSERT(!key_keep_stack.empty());
7255 const bool store_element = key_keep_stack.back();
7256 key_keep_stack.pop_back();
7257
7258 if (!store_element)
7259 {
7260 return {false, nullptr};
7261 }
7262
7263 JSON_ASSERT(object_element);
7264 *object_element = std::move(value);
7265 return {true, object_element};
3778 } 7266 }
3779 7267
3780 /*! 7268 /// the parsed JSON value
3781 @brief overload for a default value of type const char* 7269 BasicJsonType& root;
3782 @copydoc basic_json::value(const json_pointer&, ValueType) const 7270 /// stack to model hierarchy of values
3783 */ 7271 std::vector<BasicJsonType*> ref_stack {};
3784 string_t value(const json_pointer& ptr, const char* default_value) const 7272 /// stack to manage which values to keep
7273 std::vector<bool> keep_stack {};
7274 /// stack to manage which object keys to keep
7275 std::vector<bool> key_keep_stack {};
7276 /// helper to hold the reference for the next object element
7277 BasicJsonType* object_element = nullptr;
7278 /// whether a syntax error occurred
7279 bool errored = false;
7280 /// callback function
7281 const parser_callback_t callback = nullptr;
7282 /// whether to throw exceptions in case of errors
7283 const bool allow_exceptions = true;
7284 /// a discarded value for the callback
7285 BasicJsonType discarded = BasicJsonType::value_t::discarded;
7286};
7287
7288template<typename BasicJsonType>
7289class json_sax_acceptor
7290{
7291 public:
7292 using number_integer_t = typename BasicJsonType::number_integer_t;
7293 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
7294 using number_float_t = typename BasicJsonType::number_float_t;
7295 using string_t = typename BasicJsonType::string_t;
7296 using binary_t = typename BasicJsonType::binary_t;
7297
7298 bool null()
3785 { 7299 {
3786 return value(ptr, string_t(default_value)); 7300 return true;
3787 } 7301 }
3788 7302
3789 /*! 7303 bool boolean(bool /*unused*/)
3790 @brief access the first element 7304 {
7305 return true;
7306 }
3791 7307
3792 Returns a reference to the first element in the container. For a JSON 7308 bool number_integer(number_integer_t /*unused*/)
3793 container `c`, the expression `c.front()` is equivalent to `*c.begin()`. 7309 {
7310 return true;
7311 }
3794 7312
3795 @return In case of a structured type (array or object), a reference to the 7313 bool number_unsigned(number_unsigned_t /*unused*/)
3796 first element is returned. In cast of number, string, or boolean values, a 7314 {
3797 reference to the value is returned. 7315 return true;
7316 }
3798 7317
3799 @complexity Constant. 7318 bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
7319 {
7320 return true;
7321 }
3800 7322
3801 @pre The JSON value must not be `null` (would throw `std::out_of_range`) 7323 bool string(string_t& /*unused*/)
3802 or an empty array or object (undefined behavior, **guarded by 7324 {
3803 assertions**). 7325 return true;
3804 @post The JSON value remains unchanged. 7326 }
3805 7327
3806 @throw std::out_of_range when called on `null` value 7328 bool binary(binary_t& /*unused*/)
7329 {
7330 return true;
7331 }
3807 7332
3808 @liveexample{The following code shows an example for `front()`.,front} 7333 bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
7334 {
7335 return true;
7336 }
3809 7337
3810 @sa @ref back() -- access the last element 7338 bool key(string_t& /*unused*/)
7339 {
7340 return true;
7341 }
3811 7342
3812 @since version 1.0.0 7343 bool end_object()
3813 */
3814 reference front()
3815 { 7344 {
3816 return *begin(); 7345 return true;
3817 } 7346 }
3818 7347
3819 /*! 7348 bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
3820 @copydoc basic_json::front()
3821 */
3822 const_reference front() const
3823 { 7349 {
3824 return *cbegin(); 7350 return true;
3825 } 7351 }
3826 7352
3827 /*! 7353 bool end_array()
3828 @brief access the last element 7354 {
7355 return true;
7356 }
3829 7357
3830 Returns a reference to the last element in the container. For a JSON 7358 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)
3831 container `c`, the expression `c.back()` is equivalent to 7359 {
3832 @code {.cpp} 7360 return false;
3833 auto tmp = c.end(); 7361 }
3834 --tmp; 7362};
3835 return *tmp;
3836 @endcode
3837 7363
3838 @return In case of a structured type (array or object), a reference to the 7364} // namespace detail
3839 last element is returned. In cast of number, string, or boolean values, a 7365NLOHMANN_JSON_NAMESPACE_END
3840 reference to the value is returned. 7366
7367// #include <nlohmann/detail/input/lexer.hpp>
7368// __ _____ _____ _____
7369// __| | __| | | | JSON for Modern C++
7370// | | |__ | | | | | | version 3.11.3
7371// |_____|_____|_____|_|___| https://github.com/nlohmann/json
7372//
7373// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
7374// SPDX-License-Identifier: MIT
3841 7375
3842 @complexity Constant.
3843 7376
3844 @pre The JSON value must not be `null` (would throw `std::out_of_range`)
3845 or an empty array or object (undefined behavior, **guarded by
3846 assertions**).
3847 @post The JSON value remains unchanged.
3848 7377
3849 @throw std::out_of_range when called on `null` value. 7378#include <array> // array
7379#include <clocale> // localeconv
7380#include <cstddef> // size_t
7381#include <cstdio> // snprintf
7382#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
7383#include <initializer_list> // initializer_list
7384#include <string> // char_traits, string
7385#include <utility> // move
7386#include <vector> // vector
7387
7388// #include <nlohmann/detail/input/input_adapters.hpp>
3850 7389
3851 @liveexample{The following code shows an example for `back()`.,back} 7390// #include <nlohmann/detail/input/position_t.hpp>
3852 7391
3853 @sa @ref front() -- access the first element 7392// #include <nlohmann/detail/macro_scope.hpp>
3854 7393
3855 @since version 1.0.0 7394// #include <nlohmann/detail/meta/type_traits.hpp>
3856 */ 7395
3857 reference back() 7396
7397NLOHMANN_JSON_NAMESPACE_BEGIN
7398namespace detail
7399{
7400
7401///////////
7402// lexer //
7403///////////
7404
7405template<typename BasicJsonType>
7406class lexer_base
7407{
7408 public:
7409 /// token types for the parser
7410 enum class token_type
3858 { 7411 {
3859 auto tmp = end(); 7412 uninitialized, ///< indicating the scanner is uninitialized
3860 --tmp; 7413 literal_true, ///< the `true` literal
3861 return *tmp; 7414 literal_false, ///< the `false` literal
7415 literal_null, ///< the `null` literal
7416 value_string, ///< a string -- use get_string() for actual value
7417 value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value
7418 value_integer, ///< a signed integer -- use get_number_integer() for actual value
7419 value_float, ///< an floating point number -- use get_number_float() for actual value
7420 begin_array, ///< the character for array begin `[`
7421 begin_object, ///< the character for object begin `{`
7422 end_array, ///< the character for array end `]`
7423 end_object, ///< the character for object end `}`
7424 name_separator, ///< the name separator `:`
7425 value_separator, ///< the value separator `,`
7426 parse_error, ///< indicating a parse error
7427 end_of_input, ///< indicating the end of the input buffer
7428 literal_or_value ///< a literal or the begin of a value (only for diagnostics)
7429 };
7430
7431 /// return name of values of type token_type (only used for errors)
7432 JSON_HEDLEY_RETURNS_NON_NULL
7433 JSON_HEDLEY_CONST
7434 static const char* token_type_name(const token_type t) noexcept
7435 {
7436 switch (t)
7437 {
7438 case token_type::uninitialized:
7439 return "<uninitialized>";
7440 case token_type::literal_true:
7441 return "true literal";
7442 case token_type::literal_false:
7443 return "false literal";
7444 case token_type::literal_null:
7445 return "null literal";
7446 case token_type::value_string:
7447 return "string literal";
7448 case token_type::value_unsigned:
7449 case token_type::value_integer:
7450 case token_type::value_float:
7451 return "number literal";
7452 case token_type::begin_array:
7453 return "'['";
7454 case token_type::begin_object:
7455 return "'{'";
7456 case token_type::end_array:
7457 return "']'";
7458 case token_type::end_object:
7459 return "'}'";
7460 case token_type::name_separator:
7461 return "':'";
7462 case token_type::value_separator:
7463 return "','";
7464 case token_type::parse_error:
7465 return "<parse error>";
7466 case token_type::end_of_input:
7467 return "end of input";
7468 case token_type::literal_or_value:
7469 return "'[', '{', or a literal";
7470 // LCOV_EXCL_START
7471 default: // catch non-enum values
7472 return "unknown token";
7473 // LCOV_EXCL_STOP
7474 }
3862 } 7475 }
7476};
7477/*!
7478@brief lexical analysis
3863 7479
3864 /*! 7480This class organizes the lexical analysis during JSON deserialization.
3865 @copydoc basic_json::back() 7481*/
3866 */ 7482template<typename BasicJsonType, typename InputAdapterType>
3867 const_reference back() const 7483class lexer : public lexer_base<BasicJsonType>
7484{
7485 using number_integer_t = typename BasicJsonType::number_integer_t;
7486 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
7487 using number_float_t = typename BasicJsonType::number_float_t;
7488 using string_t = typename BasicJsonType::string_t;
7489 using char_type = typename InputAdapterType::char_type;
7490 using char_int_type = typename char_traits<char_type>::int_type;
7491
7492 public:
7493 using token_type = typename lexer_base<BasicJsonType>::token_type;
7494
7495 explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept
7496 : ia(std::move(adapter))
7497 , ignore_comments(ignore_comments_)
7498 , decimal_point_char(static_cast<char_int_type>(get_decimal_point()))
7499 {}
7500
7501 // delete because of pointer members
7502 lexer(const lexer&) = delete;
7503 lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
7504 lexer& operator=(lexer&) = delete;
7505 lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
7506 ~lexer() = default;
7507
7508 private:
7509 /////////////////////
7510 // locales
7511 /////////////////////
7512
7513 /// return the locale-dependent decimal point
7514 JSON_HEDLEY_PURE
7515 static char get_decimal_point() noexcept
3868 { 7516 {
3869 auto tmp = cend(); 7517 const auto* loc = localeconv();
3870 --tmp; 7518 JSON_ASSERT(loc != nullptr);
3871 return *tmp; 7519 return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
3872 } 7520 }
3873 7521
7522 /////////////////////
7523 // scan functions
7524 /////////////////////
7525
3874 /*! 7526 /*!
3875 @brief remove element given an iterator 7527 @brief get codepoint from 4 hex characters following `\u`
3876 7528
3877 Removes the element specified by iterator @a pos. The iterator @a pos must 7529 For input "\u c1 c2 c3 c4" the codepoint is:
3878 be valid and dereferenceable. Thus the `end()` iterator (which is valid, 7530 (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4
3879 but is not dereferenceable) cannot be used as a value for @a pos. 7531 = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)
3880 7532
3881 If called on a primitive type other than `null`, the resulting JSON value 7533 Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'
3882 will be `null`. 7534 must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The
7535 conversion is done by subtracting the offset (0x30, 0x37, and 0x57)
7536 between the ASCII value of the character and the desired integer value.
3883 7537
3884 @param[in] pos iterator to the element to remove 7538 @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or
3885 @return Iterator following the last removed element. If the iterator @a 7539 non-hex character)
3886 pos refers to the last element, the `end()` iterator is returned. 7540 */
7541 int get_codepoint()
7542 {
7543 // this function only makes sense after reading `\u`
7544 JSON_ASSERT(current == 'u');
7545 int codepoint = 0;
3887 7546
3888 @tparam IteratorType an @ref iterator or @ref const_iterator 7547 const auto factors = { 12u, 8u, 4u, 0u };
7548 for (const auto factor : factors)
7549 {
7550 get();
3889 7551
3890 @post Invalidates iterators and references at or after the point of the 7552 if (current >= '0' && current <= '9')
3891 erase, including the `end()` iterator. 7553 {
7554 codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);
7555 }
7556 else if (current >= 'A' && current <= 'F')
7557 {
7558 codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);
7559 }
7560 else if (current >= 'a' && current <= 'f')
7561 {
7562 codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);
7563 }
7564 else
7565 {
7566 return -1;
7567 }
7568 }
3892 7569
3893 @throw std::domain_error if called on a `null` value; example: `"cannot 7570 JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF);
3894 use erase() with null"` 7571 return codepoint;
3895 @throw std::domain_error if called on an iterator which does not belong to 7572 }
3896 the current JSON value; example: `"iterator does not fit current value"`
3897 @throw std::out_of_range if called on a primitive type with invalid
3898 iterator (i.e., any iterator which is not `begin()`); example: `"iterator
3899 out of range"`
3900 7573
3901 @complexity The complexity depends on the type: 7574 /*!
3902 - objects: amortized constant 7575 @brief check if the next byte(s) are inside a given range
3903 - arrays: linear in distance between pos and the end of the container
3904 - strings: linear in the length of the string
3905 - other types: constant
3906 7576
3907 @liveexample{The example shows the result of `erase()` for different JSON 7577 Adds the current byte and, for each passed range, reads a new byte and
3908 types.,erase__IteratorType} 7578 checks if it is inside the range. If a violation was detected, set up an
7579 error message and return false. Otherwise, return true.
3909 7580
3910 @sa @ref erase(IteratorType, IteratorType) -- removes the elements in 7581 @param[in] ranges list of integers; interpreted as list of pairs of
3911 the given range 7582 inclusive lower and upper bound, respectively
3912 @sa @ref erase(const typename object_t::key_type&) -- removes the element
3913 from an object at the given key
3914 @sa @ref erase(const size_type) -- removes the element from an array at
3915 the given index
3916 7583
3917 @since version 1.0.0 7584 @pre The passed list @a ranges must have 2, 4, or 6 elements; that is,
7585 1, 2, or 3 pairs. This precondition is enforced by an assertion.
7586
7587 @return true if and only if no range violation was detected
3918 */ 7588 */
3919 template<class IteratorType, typename std::enable_if< 7589 bool next_byte_in_range(std::initializer_list<char_int_type> ranges)
3920 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
3921 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
3922 = 0>
3923 IteratorType erase(IteratorType pos)
3924 { 7590 {
3925 // make sure iterator fits the current value 7591 JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6);
3926 if (this != pos.m_object) 7592 add(current);
7593
7594 for (auto range = ranges.begin(); range != ranges.end(); ++range)
3927 { 7595 {
3928 throw std::domain_error("iterator does not fit current value"); 7596 get();
7597 if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) // NOLINT(bugprone-inc-dec-in-conditions)
7598 {
7599 add(current);
7600 }
7601 else
7602 {
7603 error_message = "invalid string: ill-formed UTF-8 byte";
7604 return false;
7605 }
3929 } 7606 }
3930 7607
3931 IteratorType result = end(); 7608 return true;
7609 }
3932 7610
3933 switch (m_type) 7611 /*!
7612 @brief scan a string literal
7613
7614 This function scans a string according to Sect. 7 of RFC 8259. While
7615 scanning, bytes are escaped and copied into buffer token_buffer. Then the
7616 function returns successfully, token_buffer is *not* null-terminated (as it
7617 may contain \0 bytes), and token_buffer.size() is the number of bytes in the
7618 string.
7619
7620 @return token_type::value_string if string could be successfully scanned,
7621 token_type::parse_error otherwise
7622
7623 @note In case of errors, variable error_message contains a textual
7624 description.
7625 */
7626 token_type scan_string()
7627 {
7628 // reset token_buffer (ignore opening quote)
7629 reset();
7630
7631 // we entered the function by reading an open quote
7632 JSON_ASSERT(current == '\"');
7633
7634 while (true)
3934 { 7635 {
3935 case value_t::boolean: 7636 // get next character
3936 case value_t::number_float: 7637 switch (get())
3937 case value_t::number_integer:
3938 case value_t::number_unsigned:
3939 case value_t::string:
3940 { 7638 {
3941 if (not pos.m_it.primitive_iterator.is_begin()) 7639 // end of file while parsing string
7640 case char_traits<char_type>::eof():
3942 { 7641 {
3943 throw std::out_of_range("iterator out of range"); 7642 error_message = "invalid string: missing closing quote";
7643 return token_type::parse_error;
3944 } 7644 }
3945 7645
3946 if (is_string()) 7646 // closing quote
7647 case '\"':
3947 { 7648 {
3948 AllocatorType<string_t> alloc; 7649 return token_type::value_string;
3949 alloc.destroy(m_value.string);
3950 alloc.deallocate(m_value.string, 1);
3951 m_value.string = nullptr;
3952 } 7650 }
3953 7651
3954 m_type = value_t::null; 7652 // escapes
3955 assert_invariant(); 7653 case '\\':
3956 break; 7654 {
7655 switch (get())
7656 {
7657 // quotation mark
7658 case '\"':
7659 add('\"');
7660 break;
7661 // reverse solidus
7662 case '\\':
7663 add('\\');
7664 break;
7665 // solidus
7666 case '/':
7667 add('/');
7668 break;
7669 // backspace
7670 case 'b':
7671 add('\b');
7672 break;
7673 // form feed
7674 case 'f':
7675 add('\f');
7676 break;
7677 // line feed
7678 case 'n':
7679 add('\n');
7680 break;
7681 // carriage return
7682 case 'r':
7683 add('\r');
7684 break;
7685 // tab
7686 case 't':
7687 add('\t');
7688 break;
7689
7690 // unicode escapes
7691 case 'u':
7692 {
7693 const int codepoint1 = get_codepoint();
7694 int codepoint = codepoint1; // start with codepoint1
7695
7696 if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1))
7697 {
7698 error_message = "invalid string: '\\u' must be followed by 4 hex digits";
7699 return token_type::parse_error;
7700 }
7701
7702 // check if code point is a high surrogate
7703 if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF)
7704 {
7705 // expect next \uxxxx entry
7706 if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u'))
7707 {
7708 const int codepoint2 = get_codepoint();
7709
7710 if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1))
7711 {
7712 error_message = "invalid string: '\\u' must be followed by 4 hex digits";
7713 return token_type::parse_error;
7714 }
7715
7716 // check if codepoint2 is a low surrogate
7717 if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF))
7718 {
7719 // overwrite codepoint
7720 codepoint = static_cast<int>(
7721 // high surrogate occupies the most significant 22 bits
7722 (static_cast<unsigned int>(codepoint1) << 10u)
7723 // low surrogate occupies the least significant 15 bits
7724 + static_cast<unsigned int>(codepoint2)
7725 // there is still the 0xD800, 0xDC00 and 0x10000 noise
7726 // in the result, so we have to subtract with:
7727 // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
7728 - 0x35FDC00u);
7729 }
7730 else
7731 {
7732 error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF";
7733 return token_type::parse_error;
7734 }
7735 }
7736 else
7737 {
7738 error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF";
7739 return token_type::parse_error;
7740 }
7741 }
7742 else
7743 {
7744 if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF))
7745 {
7746 error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
7747 return token_type::parse_error;
7748 }
7749 }
7750
7751 // result of the above calculation yields a proper codepoint
7752 JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF);
7753
7754 // translate codepoint into bytes
7755 if (codepoint < 0x80)
7756 {
7757 // 1-byte characters: 0xxxxxxx (ASCII)
7758 add(static_cast<char_int_type>(codepoint));
7759 }
7760 else if (codepoint <= 0x7FF)
7761 {
7762 // 2-byte characters: 110xxxxx 10xxxxxx
7763 add(static_cast<char_int_type>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u)));
7764 add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
7765 }
7766 else if (codepoint <= 0xFFFF)
7767 {
7768 // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
7769 add(static_cast<char_int_type>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u)));
7770 add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
7771 add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
7772 }
7773 else
7774 {
7775 // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
7776 add(static_cast<char_int_type>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u)));
7777 add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu)));
7778 add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
7779 add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
7780 }
7781
7782 break;
7783 }
7784
7785 // other characters after escape
7786 default:
7787 error_message = "invalid string: forbidden character after backslash";
7788 return token_type::parse_error;
7789 }
7790
7791 break;
7792 }
7793
7794 // invalid control characters
7795 case 0x00:
7796 {
7797 error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000";
7798 return token_type::parse_error;
7799 }
7800
7801 case 0x01:
7802 {
7803 error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001";
7804 return token_type::parse_error;
7805 }
7806
7807 case 0x02:
7808 {
7809 error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002";
7810 return token_type::parse_error;
7811 }
7812
7813 case 0x03:
7814 {
7815 error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003";
7816 return token_type::parse_error;
7817 }
7818
7819 case 0x04:
7820 {
7821 error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004";
7822 return token_type::parse_error;
7823 }
7824
7825 case 0x05:
7826 {
7827 error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005";
7828 return token_type::parse_error;
7829 }
7830
7831 case 0x06:
7832 {
7833 error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006";
7834 return token_type::parse_error;
7835 }
7836
7837 case 0x07:
7838 {
7839 error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007";
7840 return token_type::parse_error;
7841 }
7842
7843 case 0x08:
7844 {
7845 error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b";
7846 return token_type::parse_error;
7847 }
7848
7849 case 0x09:
7850 {
7851 error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t";
7852 return token_type::parse_error;
7853 }
7854
7855 case 0x0A:
7856 {
7857 error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n";
7858 return token_type::parse_error;
7859 }
7860
7861 case 0x0B:
7862 {
7863 error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B";
7864 return token_type::parse_error;
7865 }
7866
7867 case 0x0C:
7868 {
7869 error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f";
7870 return token_type::parse_error;
7871 }
7872
7873 case 0x0D:
7874 {
7875 error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r";
7876 return token_type::parse_error;
7877 }
7878
7879 case 0x0E:
7880 {
7881 error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E";
7882 return token_type::parse_error;
7883 }
7884
7885 case 0x0F:
7886 {
7887 error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F";
7888 return token_type::parse_error;
7889 }
7890
7891 case 0x10:
7892 {
7893 error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010";
7894 return token_type::parse_error;
7895 }
7896
7897 case 0x11:
7898 {
7899 error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011";
7900 return token_type::parse_error;
7901 }
7902
7903 case 0x12:
7904 {
7905 error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012";
7906 return token_type::parse_error;
7907 }
7908
7909 case 0x13:
7910 {
7911 error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013";
7912 return token_type::parse_error;
7913 }
7914
7915 case 0x14:
7916 {
7917 error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014";
7918 return token_type::parse_error;
7919 }
7920
7921 case 0x15:
7922 {
7923 error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015";
7924 return token_type::parse_error;
7925 }
7926
7927 case 0x16:
7928 {
7929 error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016";
7930 return token_type::parse_error;
7931 }
7932
7933 case 0x17:
7934 {
7935 error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017";
7936 return token_type::parse_error;
7937 }
7938
7939 case 0x18:
7940 {
7941 error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018";
7942 return token_type::parse_error;
7943 }
7944
7945 case 0x19:
7946 {
7947 error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019";
7948 return token_type::parse_error;
7949 }
7950
7951 case 0x1A:
7952 {
7953 error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A";
7954 return token_type::parse_error;
7955 }
7956
7957 case 0x1B:
7958 {
7959 error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B";
7960 return token_type::parse_error;
7961 }
7962
7963 case 0x1C:
7964 {
7965 error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C";
7966 return token_type::parse_error;
7967 }
7968
7969 case 0x1D:
7970 {
7971 error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D";
7972 return token_type::parse_error;
7973 }
7974
7975 case 0x1E:
7976 {
7977 error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E";
7978 return token_type::parse_error;
7979 }
7980
7981 case 0x1F:
7982 {
7983 error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F";
7984 return token_type::parse_error;
7985 }
7986
7987 // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))
7988 case 0x20:
7989 case 0x21:
7990 case 0x23:
7991 case 0x24:
7992 case 0x25:
7993 case 0x26:
7994 case 0x27:
7995 case 0x28:
7996 case 0x29:
7997 case 0x2A:
7998 case 0x2B:
7999 case 0x2C:
8000 case 0x2D:
8001 case 0x2E:
8002 case 0x2F:
8003 case 0x30:
8004 case 0x31:
8005 case 0x32:
8006 case 0x33:
8007 case 0x34:
8008 case 0x35:
8009 case 0x36:
8010 case 0x37:
8011 case 0x38:
8012 case 0x39:
8013 case 0x3A:
8014 case 0x3B:
8015 case 0x3C:
8016 case 0x3D:
8017 case 0x3E:
8018 case 0x3F:
8019 case 0x40:
8020 case 0x41:
8021 case 0x42:
8022 case 0x43:
8023 case 0x44:
8024 case 0x45:
8025 case 0x46:
8026 case 0x47:
8027 case 0x48:
8028 case 0x49:
8029 case 0x4A:
8030 case 0x4B:
8031 case 0x4C:
8032 case 0x4D:
8033 case 0x4E:
8034 case 0x4F:
8035 case 0x50:
8036 case 0x51:
8037 case 0x52:
8038 case 0x53:
8039 case 0x54:
8040 case 0x55:
8041 case 0x56:
8042 case 0x57:
8043 case 0x58:
8044 case 0x59:
8045 case 0x5A:
8046 case 0x5B:
8047 case 0x5D:
8048 case 0x5E:
8049 case 0x5F:
8050 case 0x60:
8051 case 0x61:
8052 case 0x62:
8053 case 0x63:
8054 case 0x64:
8055 case 0x65:
8056 case 0x66:
8057 case 0x67:
8058 case 0x68:
8059 case 0x69:
8060 case 0x6A:
8061 case 0x6B:
8062 case 0x6C:
8063 case 0x6D:
8064 case 0x6E:
8065 case 0x6F:
8066 case 0x70:
8067 case 0x71:
8068 case 0x72:
8069 case 0x73:
8070 case 0x74:
8071 case 0x75:
8072 case 0x76:
8073 case 0x77:
8074 case 0x78:
8075 case 0x79:
8076 case 0x7A:
8077 case 0x7B:
8078 case 0x7C:
8079 case 0x7D:
8080 case 0x7E:
8081 case 0x7F:
8082 {
8083 add(current);
8084 break;
8085 }
8086
8087 // U+0080..U+07FF: bytes C2..DF 80..BF
8088 case 0xC2:
8089 case 0xC3:
8090 case 0xC4:
8091 case 0xC5:
8092 case 0xC6:
8093 case 0xC7:
8094 case 0xC8:
8095 case 0xC9:
8096 case 0xCA:
8097 case 0xCB:
8098 case 0xCC:
8099 case 0xCD:
8100 case 0xCE:
8101 case 0xCF:
8102 case 0xD0:
8103 case 0xD1:
8104 case 0xD2:
8105 case 0xD3:
8106 case 0xD4:
8107 case 0xD5:
8108 case 0xD6:
8109 case 0xD7:
8110 case 0xD8:
8111 case 0xD9:
8112 case 0xDA:
8113 case 0xDB:
8114 case 0xDC:
8115 case 0xDD:
8116 case 0xDE:
8117 case 0xDF:
8118 {
8119 if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF})))
8120 {
8121 return token_type::parse_error;
8122 }
8123 break;
8124 }
8125
8126 // U+0800..U+0FFF: bytes E0 A0..BF 80..BF
8127 case 0xE0:
8128 {
8129 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
8130 {
8131 return token_type::parse_error;
8132 }
8133 break;
8134 }
8135
8136 // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF
8137 // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF
8138 case 0xE1:
8139 case 0xE2:
8140 case 0xE3:
8141 case 0xE4:
8142 case 0xE5:
8143 case 0xE6:
8144 case 0xE7:
8145 case 0xE8:
8146 case 0xE9:
8147 case 0xEA:
8148 case 0xEB:
8149 case 0xEC:
8150 case 0xEE:
8151 case 0xEF:
8152 {
8153 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
8154 {
8155 return token_type::parse_error;
8156 }
8157 break;
8158 }
8159
8160 // U+D000..U+D7FF: bytes ED 80..9F 80..BF
8161 case 0xED:
8162 {
8163 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
8164 {
8165 return token_type::parse_error;
8166 }
8167 break;
8168 }
8169
8170 // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
8171 case 0xF0:
8172 {
8173 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
8174 {
8175 return token_type::parse_error;
8176 }
8177 break;
8178 }
8179
8180 // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
8181 case 0xF1:
8182 case 0xF2:
8183 case 0xF3:
8184 {
8185 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
8186 {
8187 return token_type::parse_error;
8188 }
8189 break;
8190 }
8191
8192 // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
8193 case 0xF4:
8194 {
8195 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
8196 {
8197 return token_type::parse_error;
8198 }
8199 break;
8200 }
8201
8202 // remaining bytes (80..C1 and F5..FF) are ill-formed
8203 default:
8204 {
8205 error_message = "invalid string: ill-formed UTF-8 byte";
8206 return token_type::parse_error;
8207 }
3957 } 8208 }
8209 }
8210 }
3958 8211
3959 case value_t::object: 8212 /*!
8213 * @brief scan a comment
8214 * @return whether comment could be scanned successfully
8215 */
8216 bool scan_comment()
8217 {
8218 switch (get())
8219 {
8220 // single-line comments skip input until a newline or EOF is read
8221 case '/':
3960 { 8222 {
3961 result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); 8223 while (true)
3962 break; 8224 {
8225 switch (get())
8226 {
8227 case '\n':
8228 case '\r':
8229 case char_traits<char_type>::eof():
8230 case '\0':
8231 return true;
8232
8233 default:
8234 break;
8235 }
8236 }
3963 } 8237 }
3964 8238
3965 case value_t::array: 8239 // multi-line comments skip input until */ is read
8240 case '*':
3966 { 8241 {
3967 result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); 8242 while (true)
3968 break; 8243 {
8244 switch (get())
8245 {
8246 case char_traits<char_type>::eof():
8247 case '\0':
8248 {
8249 error_message = "invalid comment; missing closing '*/'";
8250 return false;
8251 }
8252
8253 case '*':
8254 {
8255 switch (get())
8256 {
8257 case '/':
8258 return true;
8259
8260 default:
8261 {
8262 unget();
8263 continue;
8264 }
8265 }
8266 }
8267
8268 default:
8269 continue;
8270 }
8271 }
3969 } 8272 }
3970 8273
8274 // unexpected character after reading '/'
3971 default: 8275 default:
3972 { 8276 {
3973 throw std::domain_error("cannot use erase() with " + type_name()); 8277 error_message = "invalid comment; expecting '/' or '*' after '/'";
8278 return false;
3974 } 8279 }
3975 } 8280 }
8281 }
3976 8282
3977 return result; 8283 JSON_HEDLEY_NON_NULL(2)
8284 static void strtof(float& f, const char* str, char** endptr) noexcept
8285 {
8286 f = std::strtof(str, endptr);
8287 }
8288
8289 JSON_HEDLEY_NON_NULL(2)
8290 static void strtof(double& f, const char* str, char** endptr) noexcept
8291 {
8292 f = std::strtod(str, endptr);
8293 }
8294
8295 JSON_HEDLEY_NON_NULL(2)
8296 static void strtof(long double& f, const char* str, char** endptr) noexcept
8297 {
8298 f = std::strtold(str, endptr);
3978 } 8299 }
3979 8300
3980 /*! 8301 /*!
3981 @brief remove elements given an iterator range 8302 @brief scan a number literal
8303
8304 This function scans a string according to Sect. 6 of RFC 8259.
8305
8306 The function is realized with a deterministic finite state machine derived
8307 from the grammar described in RFC 8259. Starting in state "init", the
8308 input is read and used to determined the next state. Only state "done"
8309 accepts the number. State "error" is a trap state to model errors. In the
8310 table below, "anything" means any character but the ones listed before.
8311
8312 state | 0 | 1-9 | e E | + | - | . | anything
8313 ---------|----------|----------|----------|---------|---------|----------|-----------
8314 init | zero | any1 | [error] | [error] | minus | [error] | [error]
8315 minus | zero | any1 | [error] | [error] | [error] | [error] | [error]
8316 zero | done | done | exponent | done | done | decimal1 | done
8317 any1 | any1 | any1 | exponent | done | done | decimal1 | done
8318 decimal1 | decimal2 | decimal2 | [error] | [error] | [error] | [error] | [error]
8319 decimal2 | decimal2 | decimal2 | exponent | done | done | done | done
8320 exponent | any2 | any2 | [error] | sign | sign | [error] | [error]
8321 sign | any2 | any2 | [error] | [error] | [error] | [error] | [error]
8322 any2 | any2 | any2 | done | done | done | done | done
8323
8324 The state machine is realized with one label per state (prefixed with
8325 "scan_number_") and `goto` statements between them. The state machine
8326 contains cycles, but any cycle can be left when EOF is read. Therefore,
8327 the function is guaranteed to terminate.
8328
8329 During scanning, the read bytes are stored in token_buffer. This string is
8330 then converted to a signed integer, an unsigned integer, or a
8331 floating-point number.
8332
8333 @return token_type::value_unsigned, token_type::value_integer, or
8334 token_type::value_float if number could be successfully scanned,
8335 token_type::parse_error otherwise
8336
8337 @note The scanner is independent of the current locale. Internally, the
8338 locale's decimal point is used instead of `.` to work with the
8339 locale-dependent converters.
8340 */
8341 token_type scan_number() // lgtm [cpp/use-of-goto]
8342 {
8343 // reset token_buffer to store the number's bytes
8344 reset();
3982 8345
3983 Removes the element specified by the range `[first; last)`. The iterator 8346 // the type of the parsed number; initially set to unsigned; will be
3984 @a first does not need to be dereferenceable if `first == last`: erasing 8347 // changed if minus sign, decimal point or exponent is read
3985 an empty range is a no-op. 8348 token_type number_type = token_type::value_unsigned;
3986 8349
3987 If called on a primitive type other than `null`, the resulting JSON value 8350 // state (init): we just found out we need to scan a number
3988 will be `null`. 8351 switch (current)
8352 {
8353 case '-':
8354 {
8355 add(current);
8356 goto scan_number_minus;
8357 }
3989 8358
3990 @param[in] first iterator to the beginning of the range to remove 8359 case '0':
3991 @param[in] last iterator past the end of the range to remove 8360 {
3992 @return Iterator following the last removed element. If the iterator @a 8361 add(current);
3993 second refers to the last element, the `end()` iterator is returned. 8362 goto scan_number_zero;
8363 }
3994 8364
3995 @tparam IteratorType an @ref iterator or @ref const_iterator 8365 case '1':
8366 case '2':
8367 case '3':
8368 case '4':
8369 case '5':
8370 case '6':
8371 case '7':
8372 case '8':
8373 case '9':
8374 {
8375 add(current);
8376 goto scan_number_any1;
8377 }
3996 8378
3997 @post Invalidates iterators and references at or after the point of the 8379 // all other characters are rejected outside scan_number()
3998 erase, including the `end()` iterator. 8380 default: // LCOV_EXCL_LINE
8381 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
8382 }
3999 8383
4000 @throw std::domain_error if called on a `null` value; example: `"cannot 8384scan_number_minus:
4001 use erase() with null"` 8385 // state: we just parsed a leading minus sign
4002 @throw std::domain_error if called on iterators which does not belong to 8386 number_type = token_type::value_integer;
4003 the current JSON value; example: `"iterators do not fit current value"` 8387 switch (get())
4004 @throw std::out_of_range if called on a primitive type with invalid 8388 {
4005 iterators (i.e., if `first != begin()` and `last != end()`); example: 8389 case '0':
4006 `"iterators out of range"` 8390 {
8391 add(current);
8392 goto scan_number_zero;
8393 }
4007 8394
4008 @complexity The complexity depends on the type: 8395 case '1':
4009 - objects: `log(size()) + std::distance(first, last)` 8396 case '2':
4010 - arrays: linear in the distance between @a first and @a last, plus linear 8397 case '3':
4011 in the distance between @a last and end of the container 8398 case '4':
4012 - strings: linear in the length of the string 8399 case '5':
4013 - other types: constant 8400 case '6':
8401 case '7':
8402 case '8':
8403 case '9':
8404 {
8405 add(current);
8406 goto scan_number_any1;
8407 }
4014 8408
4015 @liveexample{The example shows the result of `erase()` for different JSON 8409 default:
4016 types.,erase__IteratorType_IteratorType} 8410 {
8411 error_message = "invalid number; expected digit after '-'";
8412 return token_type::parse_error;
8413 }
8414 }
4017 8415
4018 @sa @ref erase(IteratorType) -- removes the element at a given position 8416scan_number_zero:
4019 @sa @ref erase(const typename object_t::key_type&) -- removes the element 8417 // state: we just parse a zero (maybe with a leading minus sign)
4020 from an object at the given key 8418 switch (get())
4021 @sa @ref erase(const size_type) -- removes the element from an array at 8419 {
4022 the given index 8420 case '.':
8421 {
8422 add(decimal_point_char);
8423 goto scan_number_decimal1;
8424 }
4023 8425
4024 @since version 1.0.0 8426 case 'e':
4025 */ 8427 case 'E':
4026 template<class IteratorType, typename std::enable_if< 8428 {
4027 std::is_same<IteratorType, typename basic_json_t::iterator>::value or 8429 add(current);
4028 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type 8430 goto scan_number_exponent;
4029 = 0> 8431 }
4030 IteratorType erase(IteratorType first, IteratorType last) 8432
4031 { 8433 default:
4032 // make sure iterator fits the current value 8434 goto scan_number_done;
4033 if (this != first.m_object or this != last.m_object) 8435 }
8436
8437scan_number_any1:
8438 // state: we just parsed a number 0-9 (maybe with a leading minus sign)
8439 switch (get())
4034 { 8440 {
4035 throw std::domain_error("iterators do not fit current value"); 8441 case '0':
8442 case '1':
8443 case '2':
8444 case '3':
8445 case '4':
8446 case '5':
8447 case '6':
8448 case '7':
8449 case '8':
8450 case '9':
8451 {
8452 add(current);
8453 goto scan_number_any1;
8454 }
8455
8456 case '.':
8457 {
8458 add(decimal_point_char);
8459 goto scan_number_decimal1;
8460 }
8461
8462 case 'e':
8463 case 'E':
8464 {
8465 add(current);
8466 goto scan_number_exponent;
8467 }
8468
8469 default:
8470 goto scan_number_done;
4036 } 8471 }
4037 8472
4038 IteratorType result = end(); 8473scan_number_decimal1:
8474 // state: we just parsed a decimal point
8475 number_type = token_type::value_float;
8476 switch (get())
8477 {
8478 case '0':
8479 case '1':
8480 case '2':
8481 case '3':
8482 case '4':
8483 case '5':
8484 case '6':
8485 case '7':
8486 case '8':
8487 case '9':
8488 {
8489 add(current);
8490 goto scan_number_decimal2;
8491 }
4039 8492
4040 switch (m_type) 8493 default:
8494 {
8495 error_message = "invalid number; expected digit after '.'";
8496 return token_type::parse_error;
8497 }
8498 }
8499
8500scan_number_decimal2:
8501 // we just parsed at least one number after a decimal point
8502 switch (get())
4041 { 8503 {
4042 case value_t::boolean: 8504 case '0':
4043 case value_t::number_float: 8505 case '1':
4044 case value_t::number_integer: 8506 case '2':
4045 case value_t::number_unsigned: 8507 case '3':
4046 case value_t::string: 8508 case '4':
8509 case '5':
8510 case '6':
8511 case '7':
8512 case '8':
8513 case '9':
4047 { 8514 {
4048 if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) 8515 add(current);
4049 { 8516 goto scan_number_decimal2;
4050 throw std::out_of_range("iterators out of range"); 8517 }
4051 }
4052 8518
4053 if (is_string()) 8519 case 'e':
4054 { 8520 case 'E':
4055 AllocatorType<string_t> alloc; 8521 {
4056 alloc.destroy(m_value.string); 8522 add(current);
4057 alloc.deallocate(m_value.string, 1); 8523 goto scan_number_exponent;
4058 m_value.string = nullptr; 8524 }
4059 }
4060 8525
4061 m_type = value_t::null; 8526 default:
4062 assert_invariant(); 8527 goto scan_number_done;
4063 break; 8528 }
8529
8530scan_number_exponent:
8531 // we just parsed an exponent
8532 number_type = token_type::value_float;
8533 switch (get())
8534 {
8535 case '+':
8536 case '-':
8537 {
8538 add(current);
8539 goto scan_number_sign;
4064 } 8540 }
4065 8541
4066 case value_t::object: 8542 case '0':
8543 case '1':
8544 case '2':
8545 case '3':
8546 case '4':
8547 case '5':
8548 case '6':
8549 case '7':
8550 case '8':
8551 case '9':
4067 { 8552 {
4068 result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, 8553 add(current);
4069 last.m_it.object_iterator); 8554 goto scan_number_any2;
4070 break;
4071 } 8555 }
4072 8556
4073 case value_t::array: 8557 default:
4074 { 8558 {
4075 result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, 8559 error_message =
4076 last.m_it.array_iterator); 8560 "invalid number; expected '+', '-', or digit after exponent";
4077 break; 8561 return token_type::parse_error;
8562 }
8563 }
8564
8565scan_number_sign:
8566 // we just parsed an exponent sign
8567 switch (get())
8568 {
8569 case '0':
8570 case '1':
8571 case '2':
8572 case '3':
8573 case '4':
8574 case '5':
8575 case '6':
8576 case '7':
8577 case '8':
8578 case '9':
8579 {
8580 add(current);
8581 goto scan_number_any2;
4078 } 8582 }
4079 8583
4080 default: 8584 default:
4081 { 8585 {
4082 throw std::domain_error("cannot use erase() with " + type_name()); 8586 error_message = "invalid number; expected digit after exponent sign";
8587 return token_type::parse_error;
4083 } 8588 }
4084 } 8589 }
4085 8590
4086 return result; 8591scan_number_any2:
4087 } 8592 // we just parsed a number after the exponent or exponent sign
8593 switch (get())
8594 {
8595 case '0':
8596 case '1':
8597 case '2':
8598 case '3':
8599 case '4':
8600 case '5':
8601 case '6':
8602 case '7':
8603 case '8':
8604 case '9':
8605 {
8606 add(current);
8607 goto scan_number_any2;
8608 }
4088 8609
4089 /*! 8610 default:
4090 @brief remove element from a JSON object given a key 8611 goto scan_number_done;
8612 }
8613
8614scan_number_done:
8615 // unget the character after the number (we only read it to know that
8616 // we are done scanning a number)
8617 unget();
4091 8618
4092 Removes elements from a JSON object with the key value @a key. 8619 char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
8620 errno = 0;
4093 8621
4094 @param[in] key value of the elements to remove 8622 // try to parse integers first and fall back to floats
8623 if (number_type == token_type::value_unsigned)
8624 {
8625 const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
4095 8626
4096 @return Number of elements removed. If @a ObjectType is the default 8627 // we checked the number format before
4097 `std::map` type, the return value will always be `0` (@a key was not 8628 JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
4098 found) or `1` (@a key was found).
4099 8629
4100 @post References and iterators to the erased elements are invalidated. 8630 if (errno == 0)
4101 Other references and iterators are not affected. 8631 {
8632 value_unsigned = static_cast<number_unsigned_t>(x);
8633 if (value_unsigned == x)
8634 {
8635 return token_type::value_unsigned;
8636 }
8637 }
8638 }
8639 else if (number_type == token_type::value_integer)
8640 {
8641 const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
4102 8642
4103 @throw std::domain_error when called on a type other than JSON object; 8643 // we checked the number format before
4104 example: `"cannot use erase() with null"` 8644 JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
4105 8645
4106 @complexity `log(size()) + count(key)` 8646 if (errno == 0)
8647 {
8648 value_integer = static_cast<number_integer_t>(x);
8649 if (value_integer == x)
8650 {
8651 return token_type::value_integer;
8652 }
8653 }
8654 }
4107 8655
4108 @liveexample{The example shows the effect of `erase()`.,erase__key_type} 8656 // this code is reached if we parse a floating-point number or if an
8657 // integer conversion above failed
8658 strtof(value_float, token_buffer.data(), &endptr);
4109 8659
4110 @sa @ref erase(IteratorType) -- removes the element at a given position 8660 // we checked the number format before
4111 @sa @ref erase(IteratorType, IteratorType) -- removes the elements in 8661 JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
4112 the given range
4113 @sa @ref erase(const size_type) -- removes the element from an array at
4114 the given index
4115 8662
4116 @since version 1.0.0 8663 return token_type::value_float;
8664 }
8665
8666 /*!
8667 @param[in] literal_text the literal text to expect
8668 @param[in] length the length of the passed literal text
8669 @param[in] return_type the token type to return on success
4117 */ 8670 */
4118 size_type erase(const typename object_t::key_type& key) 8671 JSON_HEDLEY_NON_NULL(2)
8672 token_type scan_literal(const char_type* literal_text, const std::size_t length,
8673 token_type return_type)
4119 { 8674 {
4120 // this erase only works for objects 8675 JSON_ASSERT(char_traits<char_type>::to_char_type(current) == literal_text[0]);
4121 if (is_object()) 8676 for (std::size_t i = 1; i < length; ++i)
4122 { 8677 {
4123 return m_value.object->erase(key); 8678 if (JSON_HEDLEY_UNLIKELY(char_traits<char_type>::to_char_type(get()) != literal_text[i]))
4124 } 8679 {
4125 else 8680 error_message = "invalid literal";
4126 { 8681 return token_type::parse_error;
4127 throw std::domain_error("cannot use erase() with " + type_name()); 8682 }
4128 } 8683 }
8684 return return_type;
4129 } 8685 }
4130 8686
4131 /*! 8687 /////////////////////
4132 @brief remove element from a JSON array given an index 8688 // input management
8689 /////////////////////
8690
8691 /// reset token_buffer; current character is beginning of token
8692 void reset() noexcept
8693 {
8694 token_buffer.clear();
8695 token_string.clear();
8696 token_string.push_back(char_traits<char_type>::to_char_type(current));
8697 }
8698
8699 /*
8700 @brief get next character from the input
4133 8701
4134 Removes element from a JSON array at the index @a idx. 8702 This function provides the interface to the used input adapter. It does
8703 not throw in case the input reached EOF, but returns a
8704 `char_traits<char>::eof()` in that case. Stores the scanned characters
8705 for use in error messages.
8706
8707 @return character read from the input
8708 */
8709 char_int_type get()
8710 {
8711 ++position.chars_read_total;
8712 ++position.chars_read_current_line;
4135 8713
4136 @param[in] idx index of the element to remove 8714 if (next_unget)
8715 {
8716 // just reset the next_unget variable and work with current
8717 next_unget = false;
8718 }
8719 else
8720 {
8721 current = ia.get_character();
8722 }
4137 8723
4138 @throw std::domain_error when called on a type other than JSON array; 8724 if (JSON_HEDLEY_LIKELY(current != char_traits<char_type>::eof()))
4139 example: `"cannot use erase() with null"` 8725 {
4140 @throw std::out_of_range when `idx >= size()`; example: `"array index 17 8726 token_string.push_back(char_traits<char_type>::to_char_type(current));
4141 is out of range"` 8727 }
4142 8728
4143 @complexity Linear in distance between @a idx and the end of the container. 8729 if (current == '\n')
8730 {
8731 ++position.lines_read;
8732 position.chars_read_current_line = 0;
8733 }
4144 8734
4145 @liveexample{The example shows the effect of `erase()`.,erase__size_type} 8735 return current;
8736 }
4146 8737
4147 @sa @ref erase(IteratorType) -- removes the element at a given position 8738 /*!
4148 @sa @ref erase(IteratorType, IteratorType) -- removes the elements in 8739 @brief unget current character (read it again on next get)
4149 the given range
4150 @sa @ref erase(const typename object_t::key_type&) -- removes the element
4151 from an object at the given key
4152 8740
4153 @since version 1.0.0 8741 We implement unget by setting variable next_unget to true. The input is not
8742 changed - we just simulate ungetting by modifying chars_read_total,
8743 chars_read_current_line, and token_string. The next call to get() will
8744 behave as if the unget character is read again.
4154 */ 8745 */
4155 void erase(const size_type idx) 8746 void unget()
4156 { 8747 {
4157 // this erase only works for arrays 8748 next_unget = true;
4158 if (is_array()) 8749
8750 --position.chars_read_total;
8751
8752 // in case we "unget" a newline, we have to also decrement the lines_read
8753 if (position.chars_read_current_line == 0)
4159 { 8754 {
4160 if (idx >= size()) 8755 if (position.lines_read > 0)
4161 { 8756 {
4162 throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); 8757 --position.lines_read;
4163 } 8758 }
4164
4165 m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
4166 } 8759 }
4167 else 8760 else
4168 { 8761 {
4169 throw std::domain_error("cannot use erase() with " + type_name()); 8762 --position.chars_read_current_line;
4170 } 8763 }
4171 }
4172
4173 /// @}
4174
4175 8764
4176 //////////// 8765 if (JSON_HEDLEY_LIKELY(current != char_traits<char_type>::eof()))
4177 // lookup // 8766 {
4178 //////////// 8767 JSON_ASSERT(!token_string.empty());
8768 token_string.pop_back();
8769 }
8770 }
4179 8771
4180 /// @name lookup 8772 /// add a character to token_buffer
4181 /// @{ 8773 void add(char_int_type c)
8774 {
8775 token_buffer.push_back(static_cast<typename string_t::value_type>(c));
8776 }
4182 8777
4183 /*! 8778 public:
4184 @brief find an element in a JSON object 8779 /////////////////////
8780 // value getters
8781 /////////////////////
4185 8782
4186 Finds an element in a JSON object with key equivalent to @a key. If the 8783 /// return integer value
4187 element is not found or the JSON value is not an object, end() is 8784 constexpr number_integer_t get_number_integer() const noexcept
4188 returned. 8785 {
8786 return value_integer;
8787 }
4189 8788
4190 @param[in] key key value of the element to search for 8789 /// return unsigned integer value
8790 constexpr number_unsigned_t get_number_unsigned() const noexcept
8791 {
8792 return value_unsigned;
8793 }
4191 8794
4192 @return Iterator to an element with key equivalent to @a key. If no such 8795 /// return floating-point value
4193 element is found, past-the-end (see end()) iterator is returned. 8796 constexpr number_float_t get_number_float() const noexcept
8797 {
8798 return value_float;
8799 }
4194 8800
4195 @complexity Logarithmic in the size of the JSON object. 8801 /// return current string value (implicitly resets the token; useful only once)
8802 string_t& get_string()
8803 {
8804 return token_buffer;
8805 }
4196 8806
4197 @liveexample{The example shows how `find()` is used.,find__key_type} 8807 /////////////////////
8808 // diagnostics
8809 /////////////////////
4198 8810
4199 @since version 1.0.0 8811 /// return position of last read token
4200 */ 8812 constexpr position_t get_position() const noexcept
4201 iterator find(typename object_t::key_type key)
4202 { 8813 {
4203 auto result = end(); 8814 return position;
8815 }
4204 8816
4205 if (is_object()) 8817 /// return the last read token (for errors only). Will never contain EOF
8818 /// (an arbitrary value that is not a valid char value, often -1), because
8819 /// 255 may legitimately occur. May contain NUL, which should be escaped.
8820 std::string get_token_string() const
8821 {
8822 // escape control characters
8823 std::string result;
8824 for (const auto c : token_string)
4206 { 8825 {
4207 result.m_it.object_iterator = m_value.object->find(key); 8826 if (static_cast<unsigned char>(c) <= '\x1F')
8827 {
8828 // escape control characters
8829 std::array<char, 9> cs{{}};
8830 static_cast<void>((std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
8831 result += cs.data();
8832 }
8833 else
8834 {
8835 // add character as is
8836 result.push_back(static_cast<std::string::value_type>(c));
8837 }
4208 } 8838 }
4209 8839
4210 return result; 8840 return result;
4211 } 8841 }
4212 8842
8843 /// return syntax error message
8844 JSON_HEDLEY_RETURNS_NON_NULL
8845 constexpr const char* get_error_message() const noexcept
8846 {
8847 return error_message;
8848 }
8849
8850 /////////////////////
8851 // actual scanner
8852 /////////////////////
8853
4213 /*! 8854 /*!
4214 @brief find an element in a JSON object 8855 @brief skip the UTF-8 byte order mark
4215 @copydoc find(typename object_t::key_type) 8856 @return true iff there is no BOM or the correct BOM has been skipped
4216 */ 8857 */
4217 const_iterator find(typename object_t::key_type key) const 8858 bool skip_bom()
4218 { 8859 {
4219 auto result = cend(); 8860 if (get() == 0xEF)
4220
4221 if (is_object())
4222 { 8861 {
4223 result.m_it.object_iterator = m_value.object->find(key); 8862 // check if we completely parse the BOM
8863 return get() == 0xBB && get() == 0xBF;
4224 } 8864 }
4225 8865
4226 return result; 8866 // the first character is not the beginning of the BOM; unget it to
8867 // process is later
8868 unget();
8869 return true;
4227 } 8870 }
4228 8871
4229 /*! 8872 void skip_whitespace()
4230 @brief returns the number of occurrences of a key in a JSON object 8873 {
8874 do
8875 {
8876 get();
8877 }
8878 while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
8879 }
4231 8880
4232 Returns the number of elements with key @a key. If ObjectType is the 8881 token_type scan()
4233 default `std::map` type, the return value will always be `0` (@a key was 8882 {
4234 not found) or `1` (@a key was found). 8883 // initially, skip the BOM
8884 if (position.chars_read_total == 0 && !skip_bom())
8885 {
8886 error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
8887 return token_type::parse_error;
8888 }
4235 8889
4236 @param[in] key key value of the element to count 8890 // read next character and ignore whitespace
8891 skip_whitespace();
4237 8892
4238 @return Number of elements with key @a key. If the JSON value is not an 8893 // ignore comments
4239 object, the return value will be `0`. 8894 while (ignore_comments && current == '/')
8895 {
8896 if (!scan_comment())
8897 {
8898 return token_type::parse_error;
8899 }
4240 8900
4241 @complexity Logarithmic in the size of the JSON object. 8901 // skip following whitespace
8902 skip_whitespace();
8903 }
4242 8904
4243 @liveexample{The example shows how `count()` is used.,count} 8905 switch (current)
8906 {
8907 // structural characters
8908 case '[':
8909 return token_type::begin_array;
8910 case ']':
8911 return token_type::end_array;
8912 case '{':
8913 return token_type::begin_object;
8914 case '}':
8915 return token_type::end_object;
8916 case ':':
8917 return token_type::name_separator;
8918 case ',':
8919 return token_type::value_separator;
8920
8921 // literals
8922 case 't':
8923 {
8924 std::array<char_type, 4> true_literal = {{static_cast<char_type>('t'), static_cast<char_type>('r'), static_cast<char_type>('u'), static_cast<char_type>('e')}};
8925 return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true);
8926 }
8927 case 'f':
8928 {
8929 std::array<char_type, 5> false_literal = {{static_cast<char_type>('f'), static_cast<char_type>('a'), static_cast<char_type>('l'), static_cast<char_type>('s'), static_cast<char_type>('e')}};
8930 return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false);
8931 }
8932 case 'n':
8933 {
8934 std::array<char_type, 4> null_literal = {{static_cast<char_type>('n'), static_cast<char_type>('u'), static_cast<char_type>('l'), static_cast<char_type>('l')}};
8935 return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null);
8936 }
4244 8937
4245 @since version 1.0.0 8938 // string
4246 */ 8939 case '\"':
4247 size_type count(typename object_t::key_type key) const 8940 return scan_string();
4248 { 8941
4249 // return 0 for all nonobject types 8942 // number
4250 return is_object() ? m_value.object->count(key) : 0; 8943 case '-':
8944 case '0':
8945 case '1':
8946 case '2':
8947 case '3':
8948 case '4':
8949 case '5':
8950 case '6':
8951 case '7':
8952 case '8':
8953 case '9':
8954 return scan_number();
8955
8956 // end of input (the null byte is needed when parsing from
8957 // string literals)
8958 case '\0':
8959 case char_traits<char_type>::eof():
8960 return token_type::end_of_input;
8961
8962 // error
8963 default:
8964 error_message = "invalid literal";
8965 return token_type::parse_error;
8966 }
4251 } 8967 }
4252 8968
4253 /// @} 8969 private:
8970 /// input adapter
8971 InputAdapterType ia;
4254 8972
8973 /// whether comments should be ignored (true) or signaled as errors (false)
8974 const bool ignore_comments = false;
4255 8975
4256 /////////////// 8976 /// the current character
4257 // iterators // 8977 char_int_type current = char_traits<char_type>::eof();
4258 ///////////////
4259 8978
4260 /// @name iterators 8979 /// whether the next get() call should just return current
4261 /// @{ 8980 bool next_unget = false;
4262 8981
4263 /*! 8982 /// the start position of the current token
4264 @brief returns an iterator to the first element 8983 position_t position {};
4265 8984
4266 Returns an iterator to the first element. 8985 /// raw input token string (for error messages)
8986 std::vector<char_type> token_string {};
4267 8987
4268 @image html range-begin-end.svg "Illustration from cppreference.com" 8988 /// buffer for variable-length tokens (numbers, strings)
8989 string_t token_buffer {};
4269 8990
4270 @return iterator to the first element 8991 /// a description of occurred lexer errors
8992 const char* error_message = "";
4271 8993
4272 @complexity Constant. 8994 // number values
8995 number_integer_t value_integer = 0;
8996 number_unsigned_t value_unsigned = 0;
8997 number_float_t value_float = 0;
4273 8998
4274 @requirement This function helps `basic_json` satisfying the 8999 /// the decimal point
4275 [Container](http://en.cppreference.com/w/cpp/concept/Container) 9000 const char_int_type decimal_point_char = '.';
4276 requirements: 9001};
4277 - The complexity is constant.
4278 9002
4279 @liveexample{The following code shows an example for `begin()`.,begin} 9003} // namespace detail
9004NLOHMANN_JSON_NAMESPACE_END
4280 9005
4281 @sa @ref cbegin() -- returns a const iterator to the beginning 9006// #include <nlohmann/detail/macro_scope.hpp>
4282 @sa @ref end() -- returns an iterator to the end
4283 @sa @ref cend() -- returns a const iterator to the end
4284 9007
4285 @since version 1.0.0 9008// #include <nlohmann/detail/meta/is_sax.hpp>
4286 */ 9009// __ _____ _____ _____
4287 iterator begin() noexcept 9010// __| | __| | | | JSON for Modern C++
4288 { 9011// | | |__ | | | | | | version 3.11.3
4289 iterator result(this); 9012// |_____|_____|_____|_|___| https://github.com/nlohmann/json
4290 result.set_begin(); 9013//
4291 return result; 9014// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
4292 } 9015// SPDX-License-Identifier: MIT
4293 9016
4294 /*!
4295 @copydoc basic_json::cbegin()
4296 */
4297 const_iterator begin() const noexcept
4298 {
4299 return cbegin();
4300 }
4301 9017
4302 /*!
4303 @brief returns a const iterator to the first element
4304 9018
4305 Returns a const iterator to the first element. 9019#include <cstdint> // size_t
9020#include <utility> // declval
9021#include <string> // string
4306 9022
4307 @image html range-begin-end.svg "Illustration from cppreference.com" 9023// #include <nlohmann/detail/abi_macros.hpp>
4308 9024
4309 @return const iterator to the first element 9025// #include <nlohmann/detail/meta/detected.hpp>
4310 9026
4311 @complexity Constant. 9027// #include <nlohmann/detail/meta/type_traits.hpp>
4312 9028
4313 @requirement This function helps `basic_json` satisfying the
4314 [Container](http://en.cppreference.com/w/cpp/concept/Container)
4315 requirements:
4316 - The complexity is constant.
4317 - Has the semantics of `const_cast<const basic_json&>(*this).begin()`.
4318 9029
4319 @liveexample{The following code shows an example for `cbegin()`.,cbegin} 9030NLOHMANN_JSON_NAMESPACE_BEGIN
9031namespace detail
9032{
4320 9033
4321 @sa @ref begin() -- returns an iterator to the beginning 9034template<typename T>
4322 @sa @ref end() -- returns an iterator to the end 9035using null_function_t = decltype(std::declval<T&>().null());
4323 @sa @ref cend() -- returns a const iterator to the end
4324 9036
4325 @since version 1.0.0 9037template<typename T>
4326 */ 9038using boolean_function_t =
4327 const_iterator cbegin() const noexcept 9039 decltype(std::declval<T&>().boolean(std::declval<bool>()));
4328 {
4329 const_iterator result(this);
4330 result.set_begin();
4331 return result;
4332 }
4333 9040
4334 /*! 9041template<typename T, typename Integer>
4335 @brief returns an iterator to one past the last element 9042using number_integer_function_t =
9043 decltype(std::declval<T&>().number_integer(std::declval<Integer>()));
4336 9044
4337 Returns an iterator to one past the last element. 9045template<typename T, typename Unsigned>
9046using number_unsigned_function_t =
9047 decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));
4338 9048
4339 @image html range-begin-end.svg "Illustration from cppreference.com" 9049template<typename T, typename Float, typename String>
9050using number_float_function_t = decltype(std::declval<T&>().number_float(
9051 std::declval<Float>(), std::declval<const String&>()));
4340 9052
4341 @return iterator one past the last element 9053template<typename T, typename String>
9054using string_function_t =
9055 decltype(std::declval<T&>().string(std::declval<String&>()));
4342 9056
4343 @complexity Constant. 9057template<typename T, typename Binary>
9058using binary_function_t =
9059 decltype(std::declval<T&>().binary(std::declval<Binary&>()));
4344 9060
4345 @requirement This function helps `basic_json` satisfying the 9061template<typename T>
4346 [Container](http://en.cppreference.com/w/cpp/concept/Container) 9062using start_object_function_t =
4347 requirements: 9063 decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));
4348 - The complexity is constant.
4349 9064
4350 @liveexample{The following code shows an example for `end()`.,end} 9065template<typename T, typename String>
9066using key_function_t =
9067 decltype(std::declval<T&>().key(std::declval<String&>()));
4351 9068
4352 @sa @ref cend() -- returns a const iterator to the end 9069template<typename T>
4353 @sa @ref begin() -- returns an iterator to the beginning 9070using end_object_function_t = decltype(std::declval<T&>().end_object());
4354 @sa @ref cbegin() -- returns a const iterator to the beginning
4355 9071
4356 @since version 1.0.0 9072template<typename T>
4357 */ 9073using start_array_function_t =
4358 iterator end() noexcept 9074 decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));
4359 {
4360 iterator result(this);
4361 result.set_end();
4362 return result;
4363 }
4364 9075
4365 /*! 9076template<typename T>
4366 @copydoc basic_json::cend() 9077using end_array_function_t = decltype(std::declval<T&>().end_array());
4367 */
4368 const_iterator end() const noexcept
4369 {
4370 return cend();
4371 }
4372 9078
4373 /*! 9079template<typename T, typename Exception>
4374 @brief returns a const iterator to one past the last element 9080using parse_error_function_t = decltype(std::declval<T&>().parse_error(
9081 std::declval<std::size_t>(), std::declval<const std::string&>(),
9082 std::declval<const Exception&>()));
4375 9083
4376 Returns a const iterator to one past the last element. 9084template<typename SAX, typename BasicJsonType>
9085struct is_sax
9086{
9087 private:
9088 static_assert(is_basic_json<BasicJsonType>::value,
9089 "BasicJsonType must be of type basic_json<...>");
9090
9091 using number_integer_t = typename BasicJsonType::number_integer_t;
9092 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
9093 using number_float_t = typename BasicJsonType::number_float_t;
9094 using string_t = typename BasicJsonType::string_t;
9095 using binary_t = typename BasicJsonType::binary_t;
9096 using exception_t = typename BasicJsonType::exception;
9097
9098 public:
9099 static constexpr bool value =
9100 is_detected_exact<bool, null_function_t, SAX>::value &&
9101 is_detected_exact<bool, boolean_function_t, SAX>::value &&
9102 is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&
9103 is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&
9104 is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&
9105 is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
9106 is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&
9107 is_detected_exact<bool, start_object_function_t, SAX>::value &&
9108 is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
9109 is_detected_exact<bool, end_object_function_t, SAX>::value &&
9110 is_detected_exact<bool, start_array_function_t, SAX>::value &&
9111 is_detected_exact<bool, end_array_function_t, SAX>::value &&
9112 is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
9113};
4377 9114
4378 @image html range-begin-end.svg "Illustration from cppreference.com" 9115template<typename SAX, typename BasicJsonType>
9116struct is_sax_static_asserts
9117{
9118 private:
9119 static_assert(is_basic_json<BasicJsonType>::value,
9120 "BasicJsonType must be of type basic_json<...>");
4379 9121
4380 @return const iterator one past the last element 9122 using number_integer_t = typename BasicJsonType::number_integer_t;
9123 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
9124 using number_float_t = typename BasicJsonType::number_float_t;
9125 using string_t = typename BasicJsonType::string_t;
9126 using binary_t = typename BasicJsonType::binary_t;
9127 using exception_t = typename BasicJsonType::exception;
4381 9128
4382 @complexity Constant. 9129 public:
9130 static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
9131 "Missing/invalid function: bool null()");
9132 static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
9133 "Missing/invalid function: bool boolean(bool)");
9134 static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
9135 "Missing/invalid function: bool boolean(bool)");
9136 static_assert(
9137 is_detected_exact<bool, number_integer_function_t, SAX,
9138 number_integer_t>::value,
9139 "Missing/invalid function: bool number_integer(number_integer_t)");
9140 static_assert(
9141 is_detected_exact<bool, number_unsigned_function_t, SAX,
9142 number_unsigned_t>::value,
9143 "Missing/invalid function: bool number_unsigned(number_unsigned_t)");
9144 static_assert(is_detected_exact<bool, number_float_function_t, SAX,
9145 number_float_t, string_t>::value,
9146 "Missing/invalid function: bool number_float(number_float_t, const string_t&)");
9147 static_assert(
9148 is_detected_exact<bool, string_function_t, SAX, string_t>::value,
9149 "Missing/invalid function: bool string(string_t&)");
9150 static_assert(
9151 is_detected_exact<bool, binary_function_t, SAX, binary_t>::value,
9152 "Missing/invalid function: bool binary(binary_t&)");
9153 static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
9154 "Missing/invalid function: bool start_object(std::size_t)");
9155 static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,
9156 "Missing/invalid function: bool key(string_t&)");
9157 static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
9158 "Missing/invalid function: bool end_object()");
9159 static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
9160 "Missing/invalid function: bool start_array(std::size_t)");
9161 static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
9162 "Missing/invalid function: bool end_array()");
9163 static_assert(
9164 is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
9165 "Missing/invalid function: bool parse_error(std::size_t, const "
9166 "std::string&, const exception&)");
9167};
4383 9168
4384 @requirement This function helps `basic_json` satisfying the 9169} // namespace detail
4385 [Container](http://en.cppreference.com/w/cpp/concept/Container) 9170NLOHMANN_JSON_NAMESPACE_END
4386 requirements:
4387 - The complexity is constant.
4388 - Has the semantics of `const_cast<const basic_json&>(*this).end()`.
4389 9171
4390 @liveexample{The following code shows an example for `cend()`.,cend} 9172// #include <nlohmann/detail/meta/type_traits.hpp>
4391 9173
4392 @sa @ref end() -- returns an iterator to the end 9174// #include <nlohmann/detail/string_concat.hpp>
4393 @sa @ref begin() -- returns an iterator to the beginning
4394 @sa @ref cbegin() -- returns a const iterator to the beginning
4395 9175
4396 @since version 1.0.0 9176// #include <nlohmann/detail/value_t.hpp>
4397 */
4398 const_iterator cend() const noexcept
4399 {
4400 const_iterator result(this);
4401 result.set_end();
4402 return result;
4403 }
4404 9177
4405 /*!
4406 @brief returns an iterator to the reverse-beginning
4407 9178
4408 Returns an iterator to the reverse-beginning; that is, the last element. 9179NLOHMANN_JSON_NAMESPACE_BEGIN
9180namespace detail
9181{
4409 9182
4410 @image html range-rbegin-rend.svg "Illustration from cppreference.com" 9183/// how to treat CBOR tags
9184enum class cbor_tag_handler_t
9185{
9186 error, ///< throw a parse_error exception in case of a tag
9187 ignore, ///< ignore tags
9188 store ///< store tags as binary type
9189};
4411 9190
4412 @complexity Constant. 9191/*!
9192@brief determine system byte order
4413 9193
4414 @requirement This function helps `basic_json` satisfying the 9194@return true if and only if system's byte order is little endian
4415 [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
4416 requirements:
4417 - The complexity is constant.
4418 - Has the semantics of `reverse_iterator(end())`.
4419 9195
4420 @liveexample{The following code shows an example for `rbegin()`.,rbegin} 9196@note from https://stackoverflow.com/a/1001328/266378
9197*/
9198static inline bool little_endianness(int num = 1) noexcept
9199{
9200 return *reinterpret_cast<char*>(&num) == 1;
9201}
4421 9202
4422 @sa @ref crbegin() -- returns a const reverse iterator to the beginning 9203///////////////////
4423 @sa @ref rend() -- returns a reverse iterator to the end 9204// binary reader //
4424 @sa @ref crend() -- returns a const reverse iterator to the end 9205///////////////////
4425 9206
4426 @since version 1.0.0 9207/*!
9208@brief deserialization of CBOR, MessagePack, and UBJSON values
9209*/
9210template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType>>
9211class binary_reader
9212{
9213 using number_integer_t = typename BasicJsonType::number_integer_t;
9214 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
9215 using number_float_t = typename BasicJsonType::number_float_t;
9216 using string_t = typename BasicJsonType::string_t;
9217 using binary_t = typename BasicJsonType::binary_t;
9218 using json_sax_t = SAX;
9219 using char_type = typename InputAdapterType::char_type;
9220 using char_int_type = typename char_traits<char_type>::int_type;
9221
9222 public:
9223 /*!
9224 @brief create a binary reader
9225
9226 @param[in] adapter input adapter to read from
4427 */ 9227 */
4428 reverse_iterator rbegin() noexcept 9228 explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json) noexcept : ia(std::move(adapter)), input_format(format)
4429 { 9229 {
4430 return reverse_iterator(end()); 9230 (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
4431 } 9231 }
4432 9232
9233 // make class move-only
9234 binary_reader(const binary_reader&) = delete;
9235 binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
9236 binary_reader& operator=(const binary_reader&) = delete;
9237 binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
9238 ~binary_reader() = default;
9239
4433 /*! 9240 /*!
4434 @copydoc basic_json::crbegin() 9241 @param[in] format the binary format to parse
9242 @param[in] sax_ a SAX event processor
9243 @param[in] strict whether to expect the input to be consumed completed
9244 @param[in] tag_handler how to treat CBOR tags
9245
9246 @return whether parsing was successful
4435 */ 9247 */
4436 const_reverse_iterator rbegin() const noexcept 9248 JSON_HEDLEY_NON_NULL(3)
9249 bool sax_parse(const input_format_t format,
9250 json_sax_t* sax_,
9251 const bool strict = true,
9252 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
4437 { 9253 {
4438 return crbegin(); 9254 sax = sax_;
4439 } 9255 bool result = false;
4440 9256
4441 /*! 9257 switch (format)
4442 @brief returns an iterator to the reverse-end 9258 {
9259 case input_format_t::bson:
9260 result = parse_bson_internal();
9261 break;
4443 9262
4444 Returns an iterator to the reverse-end; that is, one before the first 9263 case input_format_t::cbor:
4445 element. 9264 result = parse_cbor_internal(true, tag_handler);
9265 break;
4446 9266
4447 @image html range-rbegin-rend.svg "Illustration from cppreference.com" 9267 case input_format_t::msgpack:
9268 result = parse_msgpack_internal();
9269 break;
4448 9270
4449 @complexity Constant. 9271 case input_format_t::ubjson:
9272 case input_format_t::bjdata:
9273 result = parse_ubjson_internal();
9274 break;
9275
9276 case input_format_t::json: // LCOV_EXCL_LINE
9277 default: // LCOV_EXCL_LINE
9278 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
9279 }
9280
9281 // strict mode: next byte must be EOF
9282 if (result && strict)
9283 {
9284 if (input_format == input_format_t::ubjson || input_format == input_format_t::bjdata)
9285 {
9286 get_ignore_noop();
9287 }
9288 else
9289 {
9290 get();
9291 }
4450 9292
4451 @requirement This function helps `basic_json` satisfying the 9293 if (JSON_HEDLEY_UNLIKELY(current != char_traits<char_type>::eof()))
4452 [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) 9294 {
4453 requirements: 9295 return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read,
4454 - The complexity is constant. 9296 exception_message(input_format, concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr));
4455 - Has the semantics of `reverse_iterator(begin())`. 9297 }
9298 }
4456 9299
4457 @liveexample{The following code shows an example for `rend()`.,rend} 9300 return result;
9301 }
4458 9302
4459 @sa @ref crend() -- returns a const reverse iterator to the end 9303 private:
4460 @sa @ref rbegin() -- returns a reverse iterator to the beginning 9304 //////////
4461 @sa @ref crbegin() -- returns a const reverse iterator to the beginning 9305 // BSON //
9306 //////////
4462 9307
4463 @since version 1.0.0 9308 /*!
9309 @brief Reads in a BSON-object and passes it to the SAX-parser.
9310 @return whether a valid BSON-value was passed to the SAX parser
4464 */ 9311 */
4465 reverse_iterator rend() noexcept 9312 bool parse_bson_internal()
4466 { 9313 {
4467 return reverse_iterator(begin()); 9314 std::int32_t document_size{};
9315 get_number<std::int32_t, true>(input_format_t::bson, document_size);
9316
9317 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
9318 {
9319 return false;
9320 }
9321
9322 if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false)))
9323 {
9324 return false;
9325 }
9326
9327 return sax->end_object();
4468 } 9328 }
4469 9329
4470 /*! 9330 /*!
4471 @copydoc basic_json::crend() 9331 @brief Parses a C-style string from the BSON input.
9332 @param[in,out] result A reference to the string variable where the read
9333 string is to be stored.
9334 @return `true` if the \x00-byte indicating the end of the string was
9335 encountered before the EOF; false` indicates an unexpected EOF.
4472 */ 9336 */
4473 const_reverse_iterator rend() const noexcept 9337 bool get_bson_cstr(string_t& result)
4474 { 9338 {
4475 return crend(); 9339 auto out = std::back_inserter(result);
9340 while (true)
9341 {
9342 get();
9343 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring")))
9344 {
9345 return false;
9346 }
9347 if (current == 0x00)
9348 {
9349 return true;
9350 }
9351 *out++ = static_cast<typename string_t::value_type>(current);
9352 }
4476 } 9353 }
4477 9354
4478 /*! 9355 /*!
4479 @brief returns a const reverse iterator to the last element 9356 @brief Parses a zero-terminated string of length @a len from the BSON
4480 9357 input.
4481 Returns a const iterator to the reverse-beginning; that is, the last 9358 @param[in] len The length (including the zero-byte at the end) of the
4482 element. 9359 string to be read.
4483 9360 @param[in,out] result A reference to the string variable where the read
4484 @image html range-rbegin-rend.svg "Illustration from cppreference.com" 9361 string is to be stored.
9362 @tparam NumberType The type of the length @a len
9363 @pre len >= 1
9364 @return `true` if the string was successfully parsed
9365 */
9366 template<typename NumberType>
9367 bool get_bson_string(const NumberType len, string_t& result)
9368 {
9369 if (JSON_HEDLEY_UNLIKELY(len < 1))
9370 {
9371 auto last_token = get_token_string();
9372 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
9373 exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr));
9374 }
4485 9375
4486 @complexity Constant. 9376 return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != char_traits<char_type>::eof();
9377 }
4487 9378
4488 @requirement This function helps `basic_json` satisfying the 9379 /*!
4489 [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) 9380 @brief Parses a byte array input of length @a len from the BSON input.
4490 requirements: 9381 @param[in] len The length of the byte array to be read.
4491 - The complexity is constant. 9382 @param[in,out] result A reference to the binary variable where the read
4492 - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`. 9383 array is to be stored.
9384 @tparam NumberType The type of the length @a len
9385 @pre len >= 0
9386 @return `true` if the byte array was successfully parsed
9387 */
9388 template<typename NumberType>
9389 bool get_bson_binary(const NumberType len, binary_t& result)
9390 {
9391 if (JSON_HEDLEY_UNLIKELY(len < 0))
9392 {
9393 auto last_token = get_token_string();
9394 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
9395 exception_message(input_format_t::bson, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr));
9396 }
4493 9397
4494 @liveexample{The following code shows an example for `crbegin()`.,crbegin} 9398 // All BSON binary values have a subtype
9399 std::uint8_t subtype{};
9400 get_number<std::uint8_t>(input_format_t::bson, subtype);
9401 result.set_subtype(subtype);
4495 9402
4496 @sa @ref rbegin() -- returns a reverse iterator to the beginning 9403 return get_binary(input_format_t::bson, len, result);
4497 @sa @ref rend() -- returns a reverse iterator to the end 9404 }
4498 @sa @ref crend() -- returns a const reverse iterator to the end
4499 9405
4500 @since version 1.0.0 9406 /*!
9407 @brief Read a BSON document element of the given @a element_type.
9408 @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html
9409 @param[in] element_type_parse_position The position in the input stream,
9410 where the `element_type` was read.
9411 @warning Not all BSON element types are supported yet. An unsupported
9412 @a element_type will give rise to a parse_error.114:
9413 Unsupported BSON record type 0x...
9414 @return whether a valid BSON-object/array was passed to the SAX parser
4501 */ 9415 */
4502 const_reverse_iterator crbegin() const noexcept 9416 bool parse_bson_element_internal(const char_int_type element_type,
9417 const std::size_t element_type_parse_position)
4503 { 9418 {
4504 return const_reverse_iterator(cend()); 9419 switch (element_type)
4505 } 9420 {
9421 case 0x01: // double
9422 {
9423 double number{};
9424 return get_number<double, true>(input_format_t::bson, number) && sax->number_float(static_cast<number_float_t>(number), "");
9425 }
4506 9426
4507 /*! 9427 case 0x02: // string
4508 @brief returns a const reverse iterator to one before the first 9428 {
9429 std::int32_t len{};
9430 string_t value;
9431 return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value);
9432 }
4509 9433
4510 Returns a const reverse iterator to the reverse-end; that is, one before 9434 case 0x03: // object
4511 the first element. 9435 {
9436 return parse_bson_internal();
9437 }
4512 9438
4513 @image html range-rbegin-rend.svg "Illustration from cppreference.com" 9439 case 0x04: // array
9440 {
9441 return parse_bson_array();
9442 }
4514 9443
4515 @complexity Constant. 9444 case 0x05: // binary
9445 {
9446 std::int32_t len{};
9447 binary_t value;
9448 return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value);
9449 }
4516 9450
4517 @requirement This function helps `basic_json` satisfying the 9451 case 0x08: // boolean
4518 [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) 9452 {
4519 requirements: 9453 return sax->boolean(get() != 0);
4520 - The complexity is constant. 9454 }
4521 - Has the semantics of `const_cast<const basic_json&>(*this).rend()`.
4522 9455
4523 @liveexample{The following code shows an example for `crend()`.,crend} 9456 case 0x0A: // null
9457 {
9458 return sax->null();
9459 }
4524 9460
4525 @sa @ref rend() -- returns a reverse iterator to the end 9461 case 0x10: // int32
4526 @sa @ref rbegin() -- returns a reverse iterator to the beginning 9462 {
4527 @sa @ref crbegin() -- returns a const reverse iterator to the beginning 9463 std::int32_t value{};
9464 return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value);
9465 }
4528 9466
4529 @since version 1.0.0 9467 case 0x12: // int64
4530 */ 9468 {
4531 const_reverse_iterator crend() const noexcept 9469 std::int64_t value{};
4532 { 9470 return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);
4533 return const_reverse_iterator(cbegin()); 9471 }
4534 }
4535 9472
4536 private: 9473 default: // anything else not supported (yet)
4537 // forward declaration 9474 {
4538 template<typename IteratorType> class iteration_proxy; 9475 std::array<char, 3> cr{{}};
9476 static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
9477 const std::string cr_str{cr.data()};
9478 return sax->parse_error(element_type_parse_position, cr_str,
9479 parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr));
9480 }
9481 }
9482 }
4539 9483
4540 public:
4541 /*! 9484 /*!
4542 @brief wrapper to access iterator member functions in range-based for 9485 @brief Read a BSON element list (as specified in the BSON-spec)
4543 9486
4544 This function allows to access @ref iterator::key() and @ref 9487 The same binary layout is used for objects and arrays, hence it must be
4545 iterator::value() during range-based for loops. In these loops, a 9488 indicated with the argument @a is_array which one is expected
4546 reference to the JSON values is returned, so there is no access to the 9489 (true --> array, false --> object).
4547 underlying iterator.
4548 9490
4549 @note The name of this function is not yet final and may change in the 9491 @param[in] is_array Determines if the element list being read is to be
4550 future. 9492 treated as an object (@a is_array == false), or as an
9493 array (@a is_array == true).
9494 @return whether a valid BSON-object/array was passed to the SAX parser
4551 */ 9495 */
4552 static iteration_proxy<iterator> iterator_wrapper(reference cont) 9496 bool parse_bson_element_list(const bool is_array)
4553 { 9497 {
4554 return iteration_proxy<iterator>(cont); 9498 string_t key;
9499
9500 while (auto element_type = get())
9501 {
9502 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list")))
9503 {
9504 return false;
9505 }
9506
9507 const std::size_t element_type_parse_position = chars_read;
9508 if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))
9509 {
9510 return false;
9511 }
9512
9513 if (!is_array && !sax->key(key))
9514 {
9515 return false;
9516 }
9517
9518 if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position)))
9519 {
9520 return false;
9521 }
9522
9523 // get_bson_cstr only appends
9524 key.clear();
9525 }
9526
9527 return true;
4555 } 9528 }
4556 9529
4557 /*! 9530 /*!
4558 @copydoc iterator_wrapper(reference) 9531 @brief Reads an array from the BSON input and passes it to the SAX-parser.
9532 @return whether a valid BSON-array was passed to the SAX parser
4559 */ 9533 */
4560 static iteration_proxy<const_iterator> iterator_wrapper(const_reference cont) 9534 bool parse_bson_array()
4561 { 9535 {
4562 return iteration_proxy<const_iterator>(cont); 9536 std::int32_t document_size{};
4563 } 9537 get_number<std::int32_t, true>(input_format_t::bson, document_size);
4564 9538
4565 /// @} 9539 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
9540 {
9541 return false;
9542 }
4566 9543
9544 if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true)))
9545 {
9546 return false;
9547 }
4567 9548
4568 ////////////// 9549 return sax->end_array();
4569 // capacity // 9550 }
4570 //////////////
4571 9551
4572 /// @name capacity 9552 //////////
4573 /// @{ 9553 // CBOR //
9554 //////////
4574 9555
4575 /*! 9556 /*!
4576 @brief checks whether the container is empty 9557 @param[in] get_char whether a new character should be retrieved from the
9558 input (true) or whether the last read character should
9559 be considered instead (false)
9560 @param[in] tag_handler how CBOR tags should be treated
4577 9561
4578 Checks if a JSON value has no elements. 9562 @return whether a valid CBOR value was passed to the SAX parser
9563 */
9564 bool parse_cbor_internal(const bool get_char,
9565 const cbor_tag_handler_t tag_handler)
9566 {
9567 switch (get_char ? get() : current)
9568 {
9569 // EOF
9570 case char_traits<char_type>::eof():
9571 return unexpect_eof(input_format_t::cbor, "value");
4579 9572
4580 @return The return value depends on the different types and is 9573 // Integer 0x00..0x17 (0..23)
4581 defined as follows: 9574 case 0x00:
4582 Value type | return value 9575 case 0x01:
4583 ----------- | ------------- 9576 case 0x02:
4584 null | `true` 9577 case 0x03:
4585 boolean | `false` 9578 case 0x04:
4586 string | `false` 9579 case 0x05:
4587 number | `false` 9580 case 0x06:
4588 object | result of function `object_t::empty()` 9581 case 0x07:
4589 array | result of function `array_t::empty()` 9582 case 0x08:
9583 case 0x09:
9584 case 0x0A:
9585 case 0x0B:
9586 case 0x0C:
9587 case 0x0D:
9588 case 0x0E:
9589 case 0x0F:
9590 case 0x10:
9591 case 0x11:
9592 case 0x12:
9593 case 0x13:
9594 case 0x14:
9595 case 0x15:
9596 case 0x16:
9597 case 0x17:
9598 return sax->number_unsigned(static_cast<number_unsigned_t>(current));
4590 9599
4591 @note This function does not return whether a string stored as JSON value 9600 case 0x18: // Unsigned integer (one-byte uint8_t follows)
4592 is empty - it returns whether the JSON container itself is empty which is 9601 {
4593 false in the case of a string. 9602 std::uint8_t number{};
9603 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
9604 }
4594 9605
4595 @complexity Constant, as long as @ref array_t and @ref object_t satisfy 9606 case 0x19: // Unsigned integer (two-byte uint16_t follows)
4596 the Container concept; that is, their `empty()` functions have constant 9607 {
4597 complexity. 9608 std::uint16_t number{};
9609 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
9610 }
4598 9611
4599 @requirement This function helps `basic_json` satisfying the 9612 case 0x1A: // Unsigned integer (four-byte uint32_t follows)
4600 [Container](http://en.cppreference.com/w/cpp/concept/Container) 9613 {
4601 requirements: 9614 std::uint32_t number{};
4602 - The complexity is constant. 9615 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
4603 - Has the semantics of `begin() == end()`. 9616 }
4604 9617
4605 @liveexample{The following code uses `empty()` to check if a JSON 9618 case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
4606 object contains any elements.,empty} 9619 {
9620 std::uint64_t number{};
9621 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
9622 }
4607 9623
4608 @sa @ref size() -- returns the number of elements 9624 // Negative integer -1-0x00..-1-0x17 (-1..-24)
9625 case 0x20:
9626 case 0x21:
9627 case 0x22:
9628 case 0x23:
9629 case 0x24:
9630 case 0x25:
9631 case 0x26:
9632 case 0x27:
9633 case 0x28:
9634 case 0x29:
9635 case 0x2A:
9636 case 0x2B:
9637 case 0x2C:
9638 case 0x2D:
9639 case 0x2E:
9640 case 0x2F:
9641 case 0x30:
9642 case 0x31:
9643 case 0x32:
9644 case 0x33:
9645 case 0x34:
9646 case 0x35:
9647 case 0x36:
9648 case 0x37:
9649 return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));
4609 9650
4610 @since version 1.0.0 9651 case 0x38: // Negative integer (one-byte uint8_t follows)
4611 */
4612 bool empty() const noexcept
4613 {
4614 switch (m_type)
4615 {
4616 case value_t::null:
4617 { 9652 {
4618 // null values are empty 9653 std::uint8_t number{};
4619 return true; 9654 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
4620 } 9655 }
4621 9656
4622 case value_t::array: 9657 case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
4623 { 9658 {
4624 // delegate call to array_t::empty() 9659 std::uint16_t number{};
4625 return m_value.array->empty(); 9660 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
4626 } 9661 }
4627 9662
4628 case value_t::object: 9663 case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
4629 { 9664 {
4630 // delegate call to object_t::empty() 9665 std::uint32_t number{};
4631 return m_value.object->empty(); 9666 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
4632 } 9667 }
4633 9668
4634 default: 9669 case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
4635 { 9670 {
4636 // all other types are nonempty 9671 std::uint64_t number{};
4637 return false; 9672 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1)
9673 - static_cast<number_integer_t>(number));
4638 } 9674 }
4639 }
4640 }
4641 9675
4642 /*! 9676 // Binary data (0x00..0x17 bytes follow)
4643 @brief returns the number of elements 9677 case 0x40:
9678 case 0x41:
9679 case 0x42:
9680 case 0x43:
9681 case 0x44:
9682 case 0x45:
9683 case 0x46:
9684 case 0x47:
9685 case 0x48:
9686 case 0x49:
9687 case 0x4A:
9688 case 0x4B:
9689 case 0x4C:
9690 case 0x4D:
9691 case 0x4E:
9692 case 0x4F:
9693 case 0x50:
9694 case 0x51:
9695 case 0x52:
9696 case 0x53:
9697 case 0x54:
9698 case 0x55:
9699 case 0x56:
9700 case 0x57:
9701 case 0x58: // Binary data (one-byte uint8_t for n follows)
9702 case 0x59: // Binary data (two-byte uint16_t for n follow)
9703 case 0x5A: // Binary data (four-byte uint32_t for n follow)
9704 case 0x5B: // Binary data (eight-byte uint64_t for n follow)
9705 case 0x5F: // Binary data (indefinite length)
9706 {
9707 binary_t b;
9708 return get_cbor_binary(b) && sax->binary(b);
9709 }
4644 9710
4645 Returns the number of elements in a JSON value. 9711 // UTF-8 string (0x00..0x17 bytes follow)
9712 case 0x60:
9713 case 0x61:
9714 case 0x62:
9715 case 0x63:
9716 case 0x64:
9717 case 0x65:
9718 case 0x66:
9719 case 0x67:
9720 case 0x68:
9721 case 0x69:
9722 case 0x6A:
9723 case 0x6B:
9724 case 0x6C:
9725 case 0x6D:
9726 case 0x6E:
9727 case 0x6F:
9728 case 0x70:
9729 case 0x71:
9730 case 0x72:
9731 case 0x73:
9732 case 0x74:
9733 case 0x75:
9734 case 0x76:
9735 case 0x77:
9736 case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
9737 case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
9738 case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
9739 case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
9740 case 0x7F: // UTF-8 string (indefinite length)
9741 {
9742 string_t s;
9743 return get_cbor_string(s) && sax->string(s);
9744 }
4646 9745
4647 @return The return value depends on the different types and is 9746 // array (0x00..0x17 data items follow)
4648 defined as follows: 9747 case 0x80:
4649 Value type | return value 9748 case 0x81:
4650 ----------- | ------------- 9749 case 0x82:
4651 null | `0` 9750 case 0x83:
4652 boolean | `1` 9751 case 0x84:
4653 string | `1` 9752 case 0x85:
4654 number | `1` 9753 case 0x86:
4655 object | result of function object_t::size() 9754 case 0x87:
4656 array | result of function array_t::size() 9755 case 0x88:
9756 case 0x89:
9757 case 0x8A:
9758 case 0x8B:
9759 case 0x8C:
9760 case 0x8D:
9761 case 0x8E:
9762 case 0x8F:
9763 case 0x90:
9764 case 0x91:
9765 case 0x92:
9766 case 0x93:
9767 case 0x94:
9768 case 0x95:
9769 case 0x96:
9770 case 0x97:
9771 return get_cbor_array(
9772 conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
4657 9773
4658 @note This function does not return the length of a string stored as JSON 9774 case 0x98: // array (one-byte uint8_t for n follows)
4659 value - it returns the number of elements in the JSON value which is 1 in 9775 {
4660 the case of a string. 9776 std::uint8_t len{};
9777 return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
9778 }
4661 9779
4662 @complexity Constant, as long as @ref array_t and @ref object_t satisfy 9780 case 0x99: // array (two-byte uint16_t for n follow)
4663 the Container concept; that is, their size() functions have constant 9781 {
4664 complexity. 9782 std::uint16_t len{};
9783 return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
9784 }
4665 9785
4666 @requirement This function helps `basic_json` satisfying the 9786 case 0x9A: // array (four-byte uint32_t for n follow)
4667 [Container](http://en.cppreference.com/w/cpp/concept/Container) 9787 {
4668 requirements: 9788 std::uint32_t len{};
4669 - The complexity is constant. 9789 return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
4670 - Has the semantics of `std::distance(begin(), end())`. 9790 }
4671 9791
4672 @liveexample{The following code calls `size()` on the different value 9792 case 0x9B: // array (eight-byte uint64_t for n follow)
4673 types.,size} 9793 {
9794 std::uint64_t len{};
9795 return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
9796 }
4674 9797
4675 @sa @ref empty() -- checks whether the container is empty 9798 case 0x9F: // array (indefinite length)
4676 @sa @ref max_size() -- returns the maximal number of elements 9799 return get_cbor_array(static_cast<std::size_t>(-1), tag_handler);
4677 9800
4678 @since version 1.0.0 9801 // map (0x00..0x17 pairs of data items follow)
4679 */ 9802 case 0xA0:
4680 size_type size() const noexcept 9803 case 0xA1:
4681 { 9804 case 0xA2:
4682 switch (m_type) 9805 case 0xA3:
4683 { 9806 case 0xA4:
4684 case value_t::null: 9807 case 0xA5:
9808 case 0xA6:
9809 case 0xA7:
9810 case 0xA8:
9811 case 0xA9:
9812 case 0xAA:
9813 case 0xAB:
9814 case 0xAC:
9815 case 0xAD:
9816 case 0xAE:
9817 case 0xAF:
9818 case 0xB0:
9819 case 0xB1:
9820 case 0xB2:
9821 case 0xB3:
9822 case 0xB4:
9823 case 0xB5:
9824 case 0xB6:
9825 case 0xB7:
9826 return get_cbor_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
9827
9828 case 0xB8: // map (one-byte uint8_t for n follows)
4685 { 9829 {
4686 // null values are empty 9830 std::uint8_t len{};
4687 return 0; 9831 return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
4688 } 9832 }
4689 9833
4690 case value_t::array: 9834 case 0xB9: // map (two-byte uint16_t for n follow)
4691 { 9835 {
4692 // delegate call to array_t::size() 9836 std::uint16_t len{};
4693 return m_value.array->size(); 9837 return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
4694 } 9838 }
4695 9839
4696 case value_t::object: 9840 case 0xBA: // map (four-byte uint32_t for n follow)
4697 { 9841 {
4698 // delegate call to object_t::size() 9842 std::uint32_t len{};
4699 return m_value.object->size(); 9843 return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
4700 } 9844 }
4701 9845
4702 default: 9846 case 0xBB: // map (eight-byte uint64_t for n follow)
4703 { 9847 {
4704 // all other types have size 1 9848 std::uint64_t len{};
4705 return 1; 9849 return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
4706 } 9850 }
4707 }
4708 }
4709 9851
4710 /*! 9852 case 0xBF: // map (indefinite length)
4711 @brief returns the maximum possible number of elements 9853 return get_cbor_object(static_cast<std::size_t>(-1), tag_handler);
9854
9855 case 0xC6: // tagged item
9856 case 0xC7:
9857 case 0xC8:
9858 case 0xC9:
9859 case 0xCA:
9860 case 0xCB:
9861 case 0xCC:
9862 case 0xCD:
9863 case 0xCE:
9864 case 0xCF:
9865 case 0xD0:
9866 case 0xD1:
9867 case 0xD2:
9868 case 0xD3:
9869 case 0xD4:
9870 case 0xD8: // tagged item (1 bytes follow)
9871 case 0xD9: // tagged item (2 bytes follow)
9872 case 0xDA: // tagged item (4 bytes follow)
9873 case 0xDB: // tagged item (8 bytes follow)
9874 {
9875 switch (tag_handler)
9876 {
9877 case cbor_tag_handler_t::error:
9878 {
9879 auto last_token = get_token_string();
9880 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
9881 exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr));
9882 }
4712 9883
4713 Returns the maximum number of elements a JSON value is able to hold due to 9884 case cbor_tag_handler_t::ignore:
4714 system or library implementation limitations, i.e. `std::distance(begin(), 9885 {
4715 end())` for the JSON value. 9886 // ignore binary subtype
9887 switch (current)
9888 {
9889 case 0xD8:
9890 {
9891 std::uint8_t subtype_to_ignore{};
9892 get_number(input_format_t::cbor, subtype_to_ignore);
9893 break;
9894 }
9895 case 0xD9:
9896 {
9897 std::uint16_t subtype_to_ignore{};
9898 get_number(input_format_t::cbor, subtype_to_ignore);
9899 break;
9900 }
9901 case 0xDA:
9902 {
9903 std::uint32_t subtype_to_ignore{};
9904 get_number(input_format_t::cbor, subtype_to_ignore);
9905 break;
9906 }
9907 case 0xDB:
9908 {
9909 std::uint64_t subtype_to_ignore{};
9910 get_number(input_format_t::cbor, subtype_to_ignore);
9911 break;
9912 }
9913 default:
9914 break;
9915 }
9916 return parse_cbor_internal(true, tag_handler);
9917 }
4716 9918
4717 @return The return value depends on the different types and is 9919 case cbor_tag_handler_t::store:
4718 defined as follows: 9920 {
4719 Value type | return value 9921 binary_t b;
4720 ----------- | ------------- 9922 // use binary subtype and store in binary container
4721 null | `0` (same as `size()`) 9923 switch (current)
4722 boolean | `1` (same as `size()`) 9924 {
4723 string | `1` (same as `size()`) 9925 case 0xD8:
4724 number | `1` (same as `size()`) 9926 {
4725 object | result of function `object_t::max_size()` 9927 std::uint8_t subtype{};
4726 array | result of function `array_t::max_size()` 9928 get_number(input_format_t::cbor, subtype);
9929 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
9930 break;
9931 }
9932 case 0xD9:
9933 {
9934 std::uint16_t subtype{};
9935 get_number(input_format_t::cbor, subtype);
9936 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
9937 break;
9938 }
9939 case 0xDA:
9940 {
9941 std::uint32_t subtype{};
9942 get_number(input_format_t::cbor, subtype);
9943 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
9944 break;
9945 }
9946 case 0xDB:
9947 {
9948 std::uint64_t subtype{};
9949 get_number(input_format_t::cbor, subtype);
9950 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
9951 break;
9952 }
9953 default:
9954 return parse_cbor_internal(true, tag_handler);
9955 }
9956 get();
9957 return get_cbor_binary(b) && sax->binary(b);
9958 }
4727 9959
4728 @complexity Constant, as long as @ref array_t and @ref object_t satisfy 9960 default: // LCOV_EXCL_LINE
4729 the Container concept; that is, their `max_size()` functions have constant 9961 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
4730 complexity. 9962 return false; // LCOV_EXCL_LINE
9963 }
9964 }
4731 9965
4732 @requirement This function helps `basic_json` satisfying the 9966 case 0xF4: // false
4733 [Container](http://en.cppreference.com/w/cpp/concept/Container) 9967 return sax->boolean(false);
4734 requirements:
4735 - The complexity is constant.
4736 - Has the semantics of returning `b.size()` where `b` is the largest
4737 possible JSON value.
4738 9968
4739 @liveexample{The following code calls `max_size()` on the different value 9969 case 0xF5: // true
4740 types. Note the output is implementation specific.,max_size} 9970 return sax->boolean(true);
4741 9971
4742 @sa @ref size() -- returns the number of elements 9972 case 0xF6: // null
9973 return sax->null();
4743 9974
4744 @since version 1.0.0 9975 case 0xF9: // Half-Precision Float (two-byte IEEE 754)
4745 */
4746 size_type max_size() const noexcept
4747 {
4748 switch (m_type)
4749 {
4750 case value_t::array:
4751 { 9976 {
4752 // delegate call to array_t::max_size() 9977 const auto byte1_raw = get();
4753 return m_value.array->max_size(); 9978 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
9979 {
9980 return false;
9981 }
9982 const auto byte2_raw = get();
9983 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
9984 {
9985 return false;
9986 }
9987
9988 const auto byte1 = static_cast<unsigned char>(byte1_raw);
9989 const auto byte2 = static_cast<unsigned char>(byte2_raw);
9990
9991 // code from RFC 7049, Appendix D, Figure 3:
9992 // As half-precision floating-point numbers were only added
9993 // to IEEE 754 in 2008, today's programming platforms often
9994 // still only have limited support for them. It is very
9995 // easy to include at least decoding support for them even
9996 // without such support. An example of a small decoder for
9997 // half-precision floating-point numbers in the C language
9998 // is shown in Fig. 3.
9999 const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);
10000 const double val = [&half]
10001 {
10002 const int exp = (half >> 10u) & 0x1Fu;
10003 const unsigned int mant = half & 0x3FFu;
10004 JSON_ASSERT(0 <= exp&& exp <= 32);
10005 JSON_ASSERT(mant <= 1024);
10006 switch (exp)
10007 {
10008 case 0:
10009 return std::ldexp(mant, -24);
10010 case 31:
10011 return (mant == 0)
10012 ? std::numeric_limits<double>::infinity()
10013 : std::numeric_limits<double>::quiet_NaN();
10014 default:
10015 return std::ldexp(mant + 1024, exp - 25);
10016 }
10017 }();
10018 return sax->number_float((half & 0x8000u) != 0
10019 ? static_cast<number_float_t>(-val)
10020 : static_cast<number_float_t>(val), "");
4754 } 10021 }
4755 10022
4756 case value_t::object: 10023 case 0xFA: // Single-Precision Float (four-byte IEEE 754)
4757 { 10024 {
4758 // delegate call to object_t::max_size() 10025 float number{};
4759 return m_value.object->max_size(); 10026 return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
4760 } 10027 }
4761 10028
4762 default: 10029 case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
4763 { 10030 {
4764 // all other types have max_size() == size() 10031 double number{};
4765 return size(); 10032 return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
10033 }
10034
10035 default: // anything else (0xFF is handled inside the other types)
10036 {
10037 auto last_token = get_token_string();
10038 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
10039 exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr));
4766 } 10040 }
4767 } 10041 }
4768 } 10042 }
4769 10043
4770 /// @}
4771
4772
4773 ///////////////
4774 // modifiers //
4775 ///////////////
4776
4777 /// @name modifiers
4778 /// @{
4779
4780 /*! 10044 /*!
4781 @brief clears the contents 10045 @brief reads a CBOR string
4782
4783 Clears the content of a JSON value and resets it to the default value as
4784 if @ref basic_json(value_t) would have been called:
4785
4786 Value type | initial value
4787 ----------- | -------------
4788 null | `null`
4789 boolean | `false`
4790 string | `""`
4791 number | `0`
4792 object | `{}`
4793 array | `[]`
4794 10046
4795 @note Floating-point numbers are set to `0.0` which will be serialized to 10047 This function first reads starting bytes to determine the expected
4796 `0`. The vale type remains @ref number_float_t. 10048 string length and then copies this number of bytes into a string.
4797 10049 Additionally, CBOR's strings with indefinite lengths are supported.
4798 @complexity Linear in the size of the JSON value.
4799 10050
4800 @liveexample{The example below shows the effect of `clear()` to different 10051 @param[out] result created string
4801 JSON types.,clear}
4802 10052
4803 @since version 1.0.0 10053 @return whether string creation completed
4804 */ 10054 */
4805 void clear() noexcept 10055 bool get_cbor_string(string_t& result)
4806 { 10056 {
4807 switch (m_type) 10057 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string")))
4808 { 10058 {
4809 case value_t::number_integer: 10059 return false;
4810 { 10060 }
4811 m_value.number_integer = 0;
4812 break;
4813 }
4814 10061
4815 case value_t::number_unsigned: 10062 switch (current)
10063 {
10064 // UTF-8 string (0x00..0x17 bytes follow)
10065 case 0x60:
10066 case 0x61:
10067 case 0x62:
10068 case 0x63:
10069 case 0x64:
10070 case 0x65:
10071 case 0x66:
10072 case 0x67:
10073 case 0x68:
10074 case 0x69:
10075 case 0x6A:
10076 case 0x6B:
10077 case 0x6C:
10078 case 0x6D:
10079 case 0x6E:
10080 case 0x6F:
10081 case 0x70:
10082 case 0x71:
10083 case 0x72:
10084 case 0x73:
10085 case 0x74:
10086 case 0x75:
10087 case 0x76:
10088 case 0x77:
4816 { 10089 {
4817 m_value.number_unsigned = 0; 10090 return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
4818 break;
4819 } 10091 }
4820 10092
4821 case value_t::number_float: 10093 case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
4822 { 10094 {
4823 m_value.number_float = 0.0; 10095 std::uint8_t len{};
4824 break; 10096 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
4825 } 10097 }
4826 10098
4827 case value_t::boolean: 10099 case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
4828 { 10100 {
4829 m_value.boolean = false; 10101 std::uint16_t len{};
4830 break; 10102 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
4831 } 10103 }
4832 10104
4833 case value_t::string: 10105 case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
4834 { 10106 {
4835 m_value.string->clear(); 10107 std::uint32_t len{};
4836 break; 10108 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
4837 } 10109 }
4838 10110
4839 case value_t::array: 10111 case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
4840 { 10112 {
4841 m_value.array->clear(); 10113 std::uint64_t len{};
4842 break; 10114 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
4843 } 10115 }
4844 10116
4845 case value_t::object: 10117 case 0x7F: // UTF-8 string (indefinite length)
4846 { 10118 {
4847 m_value.object->clear(); 10119 while (get() != 0xFF)
4848 break; 10120 {
10121 string_t chunk;
10122 if (!get_cbor_string(chunk))
10123 {
10124 return false;
10125 }
10126 result.append(chunk);
10127 }
10128 return true;
4849 } 10129 }
4850 10130
4851 default: 10131 default:
4852 { 10132 {
4853 break; 10133 auto last_token = get_token_string();
10134 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
10135 exception_message(input_format_t::cbor, concat("expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x", last_token), "string"), nullptr));
4854 } 10136 }
4855 } 10137 }
4856 } 10138 }
4857 10139
4858 /*! 10140 /*!
4859 @brief add an object to an array 10141 @brief reads a CBOR byte array
4860
4861 Appends the given element @a val to the end of the JSON value. If the
4862 function is called on a JSON null value, an empty array is created before
4863 appending @a val.
4864
4865 @param[in] val the value to add to the JSON array
4866 10142
4867 @throw std::domain_error when called on a type other than JSON array or 10143 This function first reads starting bytes to determine the expected
4868 null; example: `"cannot use push_back() with number"` 10144 byte array length and then copies this number of bytes into the byte array.
10145 Additionally, CBOR's byte arrays with indefinite lengths are supported.
4869 10146
4870 @complexity Amortized constant. 10147 @param[out] result created byte array
4871 10148
4872 @liveexample{The example shows how `push_back()` and `+=` can be used to 10149 @return whether byte array creation completed
4873 add elements to a JSON array. Note how the `null` value was silently
4874 converted to a JSON array.,push_back}
4875
4876 @since version 1.0.0
4877 */ 10150 */
4878 void push_back(basic_json&& val) 10151 bool get_cbor_binary(binary_t& result)
4879 { 10152 {
4880 // push_back only works for null objects or arrays 10153 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary")))
4881 if (not(is_null() or is_array()))
4882 { 10154 {
4883 throw std::domain_error("cannot use push_back() with " + type_name()); 10155 return false;
4884 } 10156 }
4885 10157
4886 // transform null object into an array 10158 switch (current)
4887 if (is_null())
4888 { 10159 {
4889 m_type = value_t::array; 10160 // Binary data (0x00..0x17 bytes follow)
4890 m_value = value_t::array; 10161 case 0x40:
4891 assert_invariant(); 10162 case 0x41:
4892 } 10163 case 0x42:
10164 case 0x43:
10165 case 0x44:
10166 case 0x45:
10167 case 0x46:
10168 case 0x47:
10169 case 0x48:
10170 case 0x49:
10171 case 0x4A:
10172 case 0x4B:
10173 case 0x4C:
10174 case 0x4D:
10175 case 0x4E:
10176 case 0x4F:
10177 case 0x50:
10178 case 0x51:
10179 case 0x52:
10180 case 0x53:
10181 case 0x54:
10182 case 0x55:
10183 case 0x56:
10184 case 0x57:
10185 {
10186 return get_binary(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
10187 }
4893 10188
4894 // add element to array (move semantics) 10189 case 0x58: // Binary data (one-byte uint8_t for n follows)
4895 m_value.array->push_back(std::move(val)); 10190 {
4896 // invalidate object 10191 std::uint8_t len{};
4897 val.m_type = value_t::null; 10192 return get_number(input_format_t::cbor, len) &&
10193 get_binary(input_format_t::cbor, len, result);
10194 }
10195
10196 case 0x59: // Binary data (two-byte uint16_t for n follow)
10197 {
10198 std::uint16_t len{};
10199 return get_number(input_format_t::cbor, len) &&
10200 get_binary(input_format_t::cbor, len, result);
10201 }
10202
10203 case 0x5A: // Binary data (four-byte uint32_t for n follow)
10204 {
10205 std::uint32_t len{};
10206 return get_number(input_format_t::cbor, len) &&
10207 get_binary(input_format_t::cbor, len, result);
10208 }
10209
10210 case 0x5B: // Binary data (eight-byte uint64_t for n follow)
10211 {
10212 std::uint64_t len{};
10213 return get_number(input_format_t::cbor, len) &&
10214 get_binary(input_format_t::cbor, len, result);
10215 }
10216
10217 case 0x5F: // Binary data (indefinite length)
10218 {
10219 while (get() != 0xFF)
10220 {
10221 binary_t chunk;
10222 if (!get_cbor_binary(chunk))
10223 {
10224 return false;
10225 }
10226 result.insert(result.end(), chunk.begin(), chunk.end());
10227 }
10228 return true;
10229 }
10230
10231 default:
10232 {
10233 auto last_token = get_token_string();
10234 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
10235 exception_message(input_format_t::cbor, concat("expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x", last_token), "binary"), nullptr));
10236 }
10237 }
4898 } 10238 }
4899 10239
4900 /*! 10240 /*!
4901 @brief add an object to an array 10241 @param[in] len the length of the array or static_cast<std::size_t>(-1) for an
4902 @copydoc push_back(basic_json&&) 10242 array of indefinite size
10243 @param[in] tag_handler how CBOR tags should be treated
10244 @return whether array creation completed
4903 */ 10245 */
4904 reference operator+=(basic_json&& val) 10246 bool get_cbor_array(const std::size_t len,
10247 const cbor_tag_handler_t tag_handler)
4905 { 10248 {
4906 push_back(std::move(val)); 10249 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
4907 return *this; 10250 {
10251 return false;
10252 }
10253
10254 if (len != static_cast<std::size_t>(-1))
10255 {
10256 for (std::size_t i = 0; i < len; ++i)
10257 {
10258 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
10259 {
10260 return false;
10261 }
10262 }
10263 }
10264 else
10265 {
10266 while (get() != 0xFF)
10267 {
10268 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler)))
10269 {
10270 return false;
10271 }
10272 }
10273 }
10274
10275 return sax->end_array();
4908 } 10276 }
4909 10277
4910 /*! 10278 /*!
4911 @brief add an object to an array 10279 @param[in] len the length of the object or static_cast<std::size_t>(-1) for an
4912 @copydoc push_back(basic_json&&) 10280 object of indefinite size
10281 @param[in] tag_handler how CBOR tags should be treated
10282 @return whether object creation completed
4913 */ 10283 */
4914 void push_back(const basic_json& val) 10284 bool get_cbor_object(const std::size_t len,
10285 const cbor_tag_handler_t tag_handler)
4915 { 10286 {
4916 // push_back only works for null objects or arrays 10287 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
4917 if (not(is_null() or is_array()))
4918 { 10288 {
4919 throw std::domain_error("cannot use push_back() with " + type_name()); 10289 return false;
4920 } 10290 }
4921 10291
4922 // transform null object into an array 10292 if (len != 0)
4923 if (is_null())
4924 { 10293 {
4925 m_type = value_t::array; 10294 string_t key;
4926 m_value = value_t::array; 10295 if (len != static_cast<std::size_t>(-1))
4927 assert_invariant(); 10296 {
10297 for (std::size_t i = 0; i < len; ++i)
10298 {
10299 get();
10300 if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
10301 {
10302 return false;
10303 }
10304
10305 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
10306 {
10307 return false;
10308 }
10309 key.clear();
10310 }
10311 }
10312 else
10313 {
10314 while (get() != 0xFF)
10315 {
10316 if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
10317 {
10318 return false;
10319 }
10320
10321 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
10322 {
10323 return false;
10324 }
10325 key.clear();
10326 }
10327 }
4928 } 10328 }
4929 10329
4930 // add element to array 10330 return sax->end_object();
4931 m_value.array->push_back(val);
4932 } 10331 }
4933 10332
10333 /////////////
10334 // MsgPack //
10335 /////////////
10336
4934 /*! 10337 /*!
4935 @brief add an object to an array 10338 @return whether a valid MessagePack value was passed to the SAX parser
4936 @copydoc push_back(basic_json&&)
4937 */ 10339 */
4938 reference operator+=(const basic_json& val) 10340 bool parse_msgpack_internal()
4939 { 10341 {
4940 push_back(val); 10342 switch (get())
4941 return *this; 10343 {
4942 } 10344 // EOF
10345 case char_traits<char_type>::eof():
10346 return unexpect_eof(input_format_t::msgpack, "value");
4943 10347
4944 /*! 10348 // positive fixint
4945 @brief add an object to an object 10349 case 0x00:
10350 case 0x01:
10351 case 0x02:
10352 case 0x03:
10353 case 0x04:
10354 case 0x05:
10355 case 0x06:
10356 case 0x07:
10357 case 0x08:
10358 case 0x09:
10359 case 0x0A:
10360 case 0x0B:
10361 case 0x0C:
10362 case 0x0D:
10363 case 0x0E:
10364 case 0x0F:
10365 case 0x10:
10366 case 0x11:
10367 case 0x12:
10368 case 0x13:
10369 case 0x14:
10370 case 0x15:
10371 case 0x16:
10372 case 0x17:
10373 case 0x18:
10374 case 0x19:
10375 case 0x1A:
10376 case 0x1B:
10377 case 0x1C:
10378 case 0x1D:
10379 case 0x1E:
10380 case 0x1F:
10381 case 0x20:
10382 case 0x21:
10383 case 0x22:
10384 case 0x23:
10385 case 0x24:
10386 case 0x25:
10387 case 0x26:
10388 case 0x27:
10389 case 0x28:
10390 case 0x29:
10391 case 0x2A:
10392 case 0x2B:
10393 case 0x2C:
10394 case 0x2D:
10395 case 0x2E:
10396 case 0x2F:
10397 case 0x30:
10398 case 0x31:
10399 case 0x32:
10400 case 0x33:
10401 case 0x34:
10402 case 0x35:
10403 case 0x36:
10404 case 0x37:
10405 case 0x38:
10406 case 0x39:
10407 case 0x3A:
10408 case 0x3B:
10409 case 0x3C:
10410 case 0x3D:
10411 case 0x3E:
10412 case 0x3F:
10413 case 0x40:
10414 case 0x41:
10415 case 0x42:
10416 case 0x43:
10417 case 0x44:
10418 case 0x45:
10419 case 0x46:
10420 case 0x47:
10421 case 0x48:
10422 case 0x49:
10423 case 0x4A:
10424 case 0x4B:
10425 case 0x4C:
10426 case 0x4D:
10427 case 0x4E:
10428 case 0x4F:
10429 case 0x50:
10430 case 0x51:
10431 case 0x52:
10432 case 0x53:
10433 case 0x54:
10434 case 0x55:
10435 case 0x56:
10436 case 0x57:
10437 case 0x58:
10438 case 0x59:
10439 case 0x5A:
10440 case 0x5B:
10441 case 0x5C:
10442 case 0x5D:
10443 case 0x5E:
10444 case 0x5F:
10445 case 0x60:
10446 case 0x61:
10447 case 0x62:
10448 case 0x63:
10449 case 0x64:
10450 case 0x65:
10451 case 0x66:
10452 case 0x67:
10453 case 0x68:
10454 case 0x69:
10455 case 0x6A:
10456 case 0x6B:
10457 case 0x6C:
10458 case 0x6D:
10459 case 0x6E:
10460 case 0x6F:
10461 case 0x70:
10462 case 0x71:
10463 case 0x72:
10464 case 0x73:
10465 case 0x74:
10466 case 0x75:
10467 case 0x76:
10468 case 0x77:
10469 case 0x78:
10470 case 0x79:
10471 case 0x7A:
10472 case 0x7B:
10473 case 0x7C:
10474 case 0x7D:
10475 case 0x7E:
10476 case 0x7F:
10477 return sax->number_unsigned(static_cast<number_unsigned_t>(current));
10478
10479 // fixmap
10480 case 0x80:
10481 case 0x81:
10482 case 0x82:
10483 case 0x83:
10484 case 0x84:
10485 case 0x85:
10486 case 0x86:
10487 case 0x87:
10488 case 0x88:
10489 case 0x89:
10490 case 0x8A:
10491 case 0x8B:
10492 case 0x8C:
10493 case 0x8D:
10494 case 0x8E:
10495 case 0x8F:
10496 return get_msgpack_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
10497
10498 // fixarray
10499 case 0x90:
10500 case 0x91:
10501 case 0x92:
10502 case 0x93:
10503 case 0x94:
10504 case 0x95:
10505 case 0x96:
10506 case 0x97:
10507 case 0x98:
10508 case 0x99:
10509 case 0x9A:
10510 case 0x9B:
10511 case 0x9C:
10512 case 0x9D:
10513 case 0x9E:
10514 case 0x9F:
10515 return get_msgpack_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
10516
10517 // fixstr
10518 case 0xA0:
10519 case 0xA1:
10520 case 0xA2:
10521 case 0xA3:
10522 case 0xA4:
10523 case 0xA5:
10524 case 0xA6:
10525 case 0xA7:
10526 case 0xA8:
10527 case 0xA9:
10528 case 0xAA:
10529 case 0xAB:
10530 case 0xAC:
10531 case 0xAD:
10532 case 0xAE:
10533 case 0xAF:
10534 case 0xB0:
10535 case 0xB1:
10536 case 0xB2:
10537 case 0xB3:
10538 case 0xB4:
10539 case 0xB5:
10540 case 0xB6:
10541 case 0xB7:
10542 case 0xB8:
10543 case 0xB9:
10544 case 0xBA:
10545 case 0xBB:
10546 case 0xBC:
10547 case 0xBD:
10548 case 0xBE:
10549 case 0xBF:
10550 case 0xD9: // str 8
10551 case 0xDA: // str 16
10552 case 0xDB: // str 32
10553 {
10554 string_t s;
10555 return get_msgpack_string(s) && sax->string(s);
10556 }
10557
10558 case 0xC0: // nil
10559 return sax->null();
10560
10561 case 0xC2: // false
10562 return sax->boolean(false);
10563
10564 case 0xC3: // true
10565 return sax->boolean(true);
10566
10567 case 0xC4: // bin 8
10568 case 0xC5: // bin 16
10569 case 0xC6: // bin 32
10570 case 0xC7: // ext 8
10571 case 0xC8: // ext 16
10572 case 0xC9: // ext 32
10573 case 0xD4: // fixext 1
10574 case 0xD5: // fixext 2
10575 case 0xD6: // fixext 4
10576 case 0xD7: // fixext 8
10577 case 0xD8: // fixext 16
10578 {
10579 binary_t b;
10580 return get_msgpack_binary(b) && sax->binary(b);
10581 }
10582
10583 case 0xCA: // float 32
10584 {
10585 float number{};
10586 return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
10587 }
10588
10589 case 0xCB: // float 64
10590 {
10591 double number{};
10592 return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
10593 }
4946 10594
4947 Inserts the given element @a val to the JSON object. If the function is 10595 case 0xCC: // uint 8
4948 called on a JSON null value, an empty object is created before inserting 10596 {
4949 @a val. 10597 std::uint8_t number{};
10598 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
10599 }
10600
10601 case 0xCD: // uint 16
10602 {
10603 std::uint16_t number{};
10604 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
10605 }
4950 10606
4951 @param[in] val the value to add to the JSON object 10607 case 0xCE: // uint 32
10608 {
10609 std::uint32_t number{};
10610 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
10611 }
4952 10612
4953 @throw std::domain_error when called on a type other than JSON object or 10613 case 0xCF: // uint 64
4954 null; example: `"cannot use push_back() with number"` 10614 {
10615 std::uint64_t number{};
10616 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
10617 }
4955 10618
4956 @complexity Logarithmic in the size of the container, O(log(`size()`)). 10619 case 0xD0: // int 8
10620 {
10621 std::int8_t number{};
10622 return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
10623 }
4957 10624
4958 @liveexample{The example shows how `push_back()` and `+=` can be used to 10625 case 0xD1: // int 16
4959 add elements to a JSON object. Note how the `null` value was silently 10626 {
4960 converted to a JSON object.,push_back__object_t__value} 10627 std::int16_t number{};
10628 return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
10629 }
4961 10630
4962 @since version 1.0.0 10631 case 0xD2: // int 32
10632 {
10633 std::int32_t number{};
10634 return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
10635 }
10636
10637 case 0xD3: // int 64
10638 {
10639 std::int64_t number{};
10640 return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
10641 }
10642
10643 case 0xDC: // array 16
10644 {
10645 std::uint16_t len{};
10646 return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));
10647 }
10648
10649 case 0xDD: // array 32
10650 {
10651 std::uint32_t len{};
10652 return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast<std::size_t>(len));
10653 }
10654
10655 case 0xDE: // map 16
10656 {
10657 std::uint16_t len{};
10658 return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));
10659 }
10660
10661 case 0xDF: // map 32
10662 {
10663 std::uint32_t len{};
10664 return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast<std::size_t>(len));
10665 }
10666
10667 // negative fixint
10668 case 0xE0:
10669 case 0xE1:
10670 case 0xE2:
10671 case 0xE3:
10672 case 0xE4:
10673 case 0xE5:
10674 case 0xE6:
10675 case 0xE7:
10676 case 0xE8:
10677 case 0xE9:
10678 case 0xEA:
10679 case 0xEB:
10680 case 0xEC:
10681 case 0xED:
10682 case 0xEE:
10683 case 0xEF:
10684 case 0xF0:
10685 case 0xF1:
10686 case 0xF2:
10687 case 0xF3:
10688 case 0xF4:
10689 case 0xF5:
10690 case 0xF6:
10691 case 0xF7:
10692 case 0xF8:
10693 case 0xF9:
10694 case 0xFA:
10695 case 0xFB:
10696 case 0xFC:
10697 case 0xFD:
10698 case 0xFE:
10699 case 0xFF:
10700 return sax->number_integer(static_cast<std::int8_t>(current));
10701
10702 default: // anything else
10703 {
10704 auto last_token = get_token_string();
10705 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
10706 exception_message(input_format_t::msgpack, concat("invalid byte: 0x", last_token), "value"), nullptr));
10707 }
10708 }
10709 }
10710
10711 /*!
10712 @brief reads a MessagePack string
10713
10714 This function first reads starting bytes to determine the expected
10715 string length and then copies this number of bytes into a string.
10716
10717 @param[out] result created string
10718
10719 @return whether string creation completed
4963 */ 10720 */
4964 void push_back(const typename object_t::value_type& val) 10721 bool get_msgpack_string(string_t& result)
4965 { 10722 {
4966 // push_back only works for null objects or objects 10723 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string")))
4967 if (not(is_null() or is_object()))
4968 { 10724 {
4969 throw std::domain_error("cannot use push_back() with " + type_name()); 10725 return false;
4970 } 10726 }
4971 10727
4972 // transform null object into an object 10728 switch (current)
4973 if (is_null())
4974 { 10729 {
4975 m_type = value_t::object; 10730 // fixstr
4976 m_value = value_t::object; 10731 case 0xA0:
4977 assert_invariant(); 10732 case 0xA1:
4978 } 10733 case 0xA2:
10734 case 0xA3:
10735 case 0xA4:
10736 case 0xA5:
10737 case 0xA6:
10738 case 0xA7:
10739 case 0xA8:
10740 case 0xA9:
10741 case 0xAA:
10742 case 0xAB:
10743 case 0xAC:
10744 case 0xAD:
10745 case 0xAE:
10746 case 0xAF:
10747 case 0xB0:
10748 case 0xB1:
10749 case 0xB2:
10750 case 0xB3:
10751 case 0xB4:
10752 case 0xB5:
10753 case 0xB6:
10754 case 0xB7:
10755 case 0xB8:
10756 case 0xB9:
10757 case 0xBA:
10758 case 0xBB:
10759 case 0xBC:
10760 case 0xBD:
10761 case 0xBE:
10762 case 0xBF:
10763 {
10764 return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);
10765 }
4979 10766
4980 // add element to array 10767 case 0xD9: // str 8
4981 m_value.object->insert(val); 10768 {
10769 std::uint8_t len{};
10770 return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
10771 }
10772
10773 case 0xDA: // str 16
10774 {
10775 std::uint16_t len{};
10776 return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
10777 }
10778
10779 case 0xDB: // str 32
10780 {
10781 std::uint32_t len{};
10782 return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
10783 }
10784
10785 default:
10786 {
10787 auto last_token = get_token_string();
10788 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
10789 exception_message(input_format_t::msgpack, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr));
10790 }
10791 }
4982 } 10792 }
4983 10793
4984 /*! 10794 /*!
4985 @brief add an object to an object 10795 @brief reads a MessagePack byte array
4986 @copydoc push_back(const typename object_t::value_type&) 10796
10797 This function first reads starting bytes to determine the expected
10798 byte array length and then copies this number of bytes into a byte array.
10799
10800 @param[out] result created byte array
10801
10802 @return whether byte array creation completed
4987 */ 10803 */
4988 reference operator+=(const typename object_t::value_type& val) 10804 bool get_msgpack_binary(binary_t& result)
4989 { 10805 {
4990 push_back(val); 10806 // helper function to set the subtype
4991 return *this; 10807 auto assign_and_return_true = [&result](std::int8_t subtype)
4992 } 10808 {
10809 result.set_subtype(static_cast<std::uint8_t>(subtype));
10810 return true;
10811 };
4993 10812
4994 /*! 10813 switch (current)
4995 @brief add an object to an object 10814 {
10815 case 0xC4: // bin 8
10816 {
10817 std::uint8_t len{};
10818 return get_number(input_format_t::msgpack, len) &&
10819 get_binary(input_format_t::msgpack, len, result);
10820 }
10821
10822 case 0xC5: // bin 16
10823 {
10824 std::uint16_t len{};
10825 return get_number(input_format_t::msgpack, len) &&
10826 get_binary(input_format_t::msgpack, len, result);
10827 }
10828
10829 case 0xC6: // bin 32
10830 {
10831 std::uint32_t len{};
10832 return get_number(input_format_t::msgpack, len) &&
10833 get_binary(input_format_t::msgpack, len, result);
10834 }
10835
10836 case 0xC7: // ext 8
10837 {
10838 std::uint8_t len{};
10839 std::int8_t subtype{};
10840 return get_number(input_format_t::msgpack, len) &&
10841 get_number(input_format_t::msgpack, subtype) &&
10842 get_binary(input_format_t::msgpack, len, result) &&
10843 assign_and_return_true(subtype);
10844 }
10845
10846 case 0xC8: // ext 16
10847 {
10848 std::uint16_t len{};
10849 std::int8_t subtype{};
10850 return get_number(input_format_t::msgpack, len) &&
10851 get_number(input_format_t::msgpack, subtype) &&
10852 get_binary(input_format_t::msgpack, len, result) &&
10853 assign_and_return_true(subtype);
10854 }
10855
10856 case 0xC9: // ext 32
10857 {
10858 std::uint32_t len{};
10859 std::int8_t subtype{};
10860 return get_number(input_format_t::msgpack, len) &&
10861 get_number(input_format_t::msgpack, subtype) &&
10862 get_binary(input_format_t::msgpack, len, result) &&
10863 assign_and_return_true(subtype);
10864 }
4996 10865
4997 This function allows to use `push_back` with an initializer list. In case 10866 case 0xD4: // fixext 1
10867 {
10868 std::int8_t subtype{};
10869 return get_number(input_format_t::msgpack, subtype) &&
10870 get_binary(input_format_t::msgpack, 1, result) &&
10871 assign_and_return_true(subtype);
10872 }
4998 10873
4999 1. the current value is an object, 10874 case 0xD5: // fixext 2
5000 2. the initializer list @a init contains only two elements, and 10875 {
5001 3. the first element of @a init is a string, 10876 std::int8_t subtype{};
10877 return get_number(input_format_t::msgpack, subtype) &&
10878 get_binary(input_format_t::msgpack, 2, result) &&
10879 assign_and_return_true(subtype);
10880 }
5002 10881
5003 @a init is converted into an object element and added using 10882 case 0xD6: // fixext 4
5004 @ref push_back(const typename object_t::value_type&). Otherwise, @a init 10883 {
5005 is converted to a JSON value and added using @ref push_back(basic_json&&). 10884 std::int8_t subtype{};
10885 return get_number(input_format_t::msgpack, subtype) &&
10886 get_binary(input_format_t::msgpack, 4, result) &&
10887 assign_and_return_true(subtype);
10888 }
5006 10889
5007 @param init an initializer list 10890 case 0xD7: // fixext 8
10891 {
10892 std::int8_t subtype{};
10893 return get_number(input_format_t::msgpack, subtype) &&
10894 get_binary(input_format_t::msgpack, 8, result) &&
10895 assign_and_return_true(subtype);
10896 }
5008 10897
5009 @complexity Linear in the size of the initializer list @a init. 10898 case 0xD8: // fixext 16
10899 {
10900 std::int8_t subtype{};
10901 return get_number(input_format_t::msgpack, subtype) &&
10902 get_binary(input_format_t::msgpack, 16, result) &&
10903 assign_and_return_true(subtype);
10904 }
5010 10905
5011 @note This function is required to resolve an ambiguous overload error, 10906 default: // LCOV_EXCL_LINE
5012 because pairs like `{"key", "value"}` can be both interpreted as 10907 return false; // LCOV_EXCL_LINE
5013 `object_t::value_type` or `std::initializer_list<basic_json>`, see 10908 }
5014 https://github.com/nlohmann/json/issues/235 for more information. 10909 }
5015 10910
5016 @liveexample{The example shows how initializer lists are treated as 10911 /*!
5017 objects when possible.,push_back__initializer_list} 10912 @param[in] len the length of the array
10913 @return whether array creation completed
5018 */ 10914 */
5019 void push_back(std::initializer_list<basic_json> init) 10915 bool get_msgpack_array(const std::size_t len)
5020 { 10916 {
5021 if (is_object() and init.size() == 2 and init.begin()->is_string()) 10917 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
5022 { 10918 {
5023 const string_t key = *init.begin(); 10919 return false;
5024 push_back(typename object_t::value_type(key, *(init.begin() + 1)));
5025 } 10920 }
5026 else 10921
10922 for (std::size_t i = 0; i < len; ++i)
5027 { 10923 {
5028 push_back(basic_json(init)); 10924 if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
10925 {
10926 return false;
10927 }
5029 } 10928 }
10929
10930 return sax->end_array();
5030 } 10931 }
5031 10932
5032 /*! 10933 /*!
5033 @brief add an object to an object 10934 @param[in] len the length of the object
5034 @copydoc push_back(std::initializer_list<basic_json>) 10935 @return whether object creation completed
5035 */ 10936 */
5036 reference operator+=(std::initializer_list<basic_json> init) 10937 bool get_msgpack_object(const std::size_t len)
5037 { 10938 {
5038 push_back(init); 10939 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
5039 return *this; 10940 {
10941 return false;
10942 }
10943
10944 string_t key;
10945 for (std::size_t i = 0; i < len; ++i)
10946 {
10947 get();
10948 if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key)))
10949 {
10950 return false;
10951 }
10952
10953 if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
10954 {
10955 return false;
10956 }
10957 key.clear();
10958 }
10959
10960 return sax->end_object();
5040 } 10961 }
5041 10962
5042 /*! 10963 ////////////
5043 @brief add an object to an array 10964 // UBJSON //
10965 ////////////
5044 10966
5045 Creates a JSON value from the passed parameters @a args to the end of the 10967 /*!
5046 JSON value. If the function is called on a JSON null value, an empty array 10968 @param[in] get_char whether a new character should be retrieved from the
5047 is created before appending the value created from @a args. 10969 input (true, default) or whether the last read
10970 character should be considered instead
5048 10971
5049 @param[in] args arguments to forward to a constructor of @ref basic_json 10972 @return whether a valid UBJSON value was passed to the SAX parser
5050 @tparam Args compatible types to create a @ref basic_json object 10973 */
10974 bool parse_ubjson_internal(const bool get_char = true)
10975 {
10976 return get_ubjson_value(get_char ? get_ignore_noop() : current);
10977 }
5051 10978
5052 @throw std::domain_error when called on a type other than JSON array or 10979 /*!
5053 null; example: `"cannot use emplace_back() with number"` 10980 @brief reads a UBJSON string
5054 10981
5055 @complexity Amortized constant. 10982 This function is either called after reading the 'S' byte explicitly
10983 indicating a string, or in case of an object key where the 'S' byte can be
10984 left out.
5056 10985
5057 @liveexample{The example shows how `push_back()` can be used to add 10986 @param[out] result created string
5058 elements to a JSON array. Note how the `null` value was silently converted 10987 @param[in] get_char whether a new character should be retrieved from the
5059 to a JSON array.,emplace_back} 10988 input (true, default) or whether the last read
10989 character should be considered instead
5060 10990
5061 @since version 2.0.8 10991 @return whether string creation completed
5062 */ 10992 */
5063 template<class... Args> 10993 bool get_ubjson_string(string_t& result, const bool get_char = true)
5064 void emplace_back(Args&& ... args)
5065 { 10994 {
5066 // emplace_back only works for null objects or arrays 10995 if (get_char)
5067 if (not(is_null() or is_array()))
5068 { 10996 {
5069 throw std::domain_error("cannot use emplace_back() with " + type_name()); 10997 get(); // TODO(niels): may we ignore N here?
5070 } 10998 }
5071 10999
5072 // transform null object into an array 11000 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
5073 if (is_null())
5074 { 11001 {
5075 m_type = value_t::array; 11002 return false;
5076 m_value = value_t::array;
5077 assert_invariant();
5078 } 11003 }
5079 11004
5080 // add element to array (perfect forwarding) 11005 switch (current)
5081 m_value.array->emplace_back(std::forward<Args>(args)...); 11006 {
5082 } 11007 case 'U':
11008 {
11009 std::uint8_t len{};
11010 return get_number(input_format, len) && get_string(input_format, len, result);
11011 }
5083 11012
5084 /*! 11013 case 'i':
5085 @brief add an object to an object if key does not exist 11014 {
11015 std::int8_t len{};
11016 return get_number(input_format, len) && get_string(input_format, len, result);
11017 }
5086 11018
5087 Inserts a new element into a JSON object constructed in-place with the given 11019 case 'I':
5088 @a args if there is no element with the key in the container. If the 11020 {
5089 function is called on a JSON null value, an empty object is created before 11021 std::int16_t len{};
5090 appending the value created from @a args. 11022 return get_number(input_format, len) && get_string(input_format, len, result);
11023 }
11024
11025 case 'l':
11026 {
11027 std::int32_t len{};
11028 return get_number(input_format, len) && get_string(input_format, len, result);
11029 }
5091 11030
5092 @param[in] args arguments to forward to a constructor of @ref basic_json 11031 case 'L':
5093 @tparam Args compatible types to create a @ref basic_json object 11032 {
11033 std::int64_t len{};
11034 return get_number(input_format, len) && get_string(input_format, len, result);
11035 }
5094 11036
5095 @return a pair consisting of an iterator to the inserted element, or the 11037 case 'u':
5096 already-existing element if no insertion happened, and a bool 11038 {
5097 denoting whether the insertion took place. 11039 if (input_format != input_format_t::bjdata)
11040 {
11041 break;
11042 }
11043 std::uint16_t len{};
11044 return get_number(input_format, len) && get_string(input_format, len, result);
11045 }
5098 11046
5099 @throw std::domain_error when called on a type other than JSON object or 11047 case 'm':
5100 null; example: `"cannot use emplace() with number"` 11048 {
11049 if (input_format != input_format_t::bjdata)
11050 {
11051 break;
11052 }
11053 std::uint32_t len{};
11054 return get_number(input_format, len) && get_string(input_format, len, result);
11055 }
5101 11056
5102 @complexity Logarithmic in the size of the container, O(log(`size()`)). 11057 case 'M':
11058 {
11059 if (input_format != input_format_t::bjdata)
11060 {
11061 break;
11062 }
11063 std::uint64_t len{};
11064 return get_number(input_format, len) && get_string(input_format, len, result);
11065 }
5103 11066
5104 @liveexample{The example shows how `emplace()` can be used to add elements 11067 default:
5105 to a JSON object. Note how the `null` value was silently converted to a 11068 break;
5106 JSON object. Further note how no value is added if there was already one 11069 }
5107 value stored with the same key.,emplace} 11070 auto last_token = get_token_string();
11071 std::string message;
5108 11072
5109 @since version 2.0.8 11073 if (input_format != input_format_t::bjdata)
11074 {
11075 message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token;
11076 }
11077 else
11078 {
11079 message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token;
11080 }
11081 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr));
11082 }
11083
11084 /*!
11085 @param[out] dim an integer vector storing the ND array dimensions
11086 @return whether reading ND array size vector is successful
5110 */ 11087 */
5111 template<class... Args> 11088 bool get_ubjson_ndarray_size(std::vector<size_t>& dim)
5112 std::pair<iterator, bool> emplace(Args&& ... args)
5113 { 11089 {
5114 // emplace only works for null objects or arrays 11090 std::pair<std::size_t, char_int_type> size_and_type;
5115 if (not(is_null() or is_object())) 11091 size_t dimlen = 0;
11092 bool no_ndarray = true;
11093
11094 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, no_ndarray)))
5116 { 11095 {
5117 throw std::domain_error("cannot use emplace() with " + type_name()); 11096 return false;
5118 } 11097 }
5119 11098
5120 // transform null object into an object 11099 if (size_and_type.first != npos)
5121 if (is_null())
5122 { 11100 {
5123 m_type = value_t::object; 11101 if (size_and_type.second != 0)
5124 m_value = value_t::object; 11102 {
5125 assert_invariant(); 11103 if (size_and_type.second != 'N')
11104 {
11105 for (std::size_t i = 0; i < size_and_type.first; ++i)
11106 {
11107 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, size_and_type.second)))
11108 {
11109 return false;
11110 }
11111 dim.push_back(dimlen);
11112 }
11113 }
11114 }
11115 else
11116 {
11117 for (std::size_t i = 0; i < size_and_type.first; ++i)
11118 {
11119 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray)))
11120 {
11121 return false;
11122 }
11123 dim.push_back(dimlen);
11124 }
11125 }
5126 } 11126 }
5127 11127 else
5128 // add element to array (perfect forwarding) 11128 {
5129 auto res = m_value.object->emplace(std::forward<Args>(args)...); 11129 while (current != ']')
5130 // create result iterator and set iterator to the result of emplace 11130 {
5131 auto it = begin(); 11131 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, current)))
5132 it.m_it.object_iterator = res.first; 11132 {
5133 11133 return false;
5134 // return pair of iterator and boolean 11134 }
5135 return {it, res.second}; 11135 dim.push_back(dimlen);
11136 get_ignore_noop();
11137 }
11138 }
11139 return true;
5136 } 11140 }
5137 11141
5138 /*! 11142 /*!
5139 @brief inserts element 11143 @param[out] result determined size
11144 @param[in,out] is_ndarray for input, `true` means already inside an ndarray vector
11145 or ndarray dimension is not allowed; `false` means ndarray
11146 is allowed; for output, `true` means an ndarray is found;
11147 is_ndarray can only return `true` when its initial value
11148 is `false`
11149 @param[in] prefix type marker if already read, otherwise set to 0
11150
11151 @return whether size determination completed
11152 */
11153 bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0)
11154 {
11155 if (prefix == 0)
11156 {
11157 prefix = get_ignore_noop();
11158 }
5140 11159
5141 Inserts element @a val before iterator @a pos. 11160 switch (prefix)
11161 {
11162 case 'U':
11163 {
11164 std::uint8_t number{};
11165 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11166 {
11167 return false;
11168 }
11169 result = static_cast<std::size_t>(number);
11170 return true;
11171 }
5142 11172
5143 @param[in] pos iterator before which the content will be inserted; may be 11173 case 'i':
5144 the end() iterator 11174 {
5145 @param[in] val element to insert 11175 std::int8_t number{};
5146 @return iterator pointing to the inserted @a val. 11176 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11177 {
11178 return false;
11179 }
11180 if (number < 0)
11181 {
11182 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
11183 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
11184 }
11185 result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
11186 return true;
11187 }
5147 11188
5148 @throw std::domain_error if called on JSON values other than arrays; 11189 case 'I':
5149 example: `"cannot use insert() with string"` 11190 {
5150 @throw std::domain_error if @a pos is not an iterator of *this; example: 11191 std::int16_t number{};
5151 `"iterator does not fit current value"` 11192 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11193 {
11194 return false;
11195 }
11196 if (number < 0)
11197 {
11198 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
11199 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
11200 }
11201 result = static_cast<std::size_t>(number);
11202 return true;
11203 }
5152 11204
5153 @complexity Constant plus linear in the distance between pos and end of the 11205 case 'l':
5154 container. 11206 {
11207 std::int32_t number{};
11208 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11209 {
11210 return false;
11211 }
11212 if (number < 0)
11213 {
11214 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
11215 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
11216 }
11217 result = static_cast<std::size_t>(number);
11218 return true;
11219 }
5155 11220
5156 @liveexample{The example shows how `insert()` is used.,insert} 11221 case 'L':
11222 {
11223 std::int64_t number{};
11224 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11225 {
11226 return false;
11227 }
11228 if (number < 0)
11229 {
11230 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
11231 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
11232 }
11233 if (!value_in_range_of<std::size_t>(number))
11234 {
11235 return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
11236 exception_message(input_format, "integer value overflow", "size"), nullptr));
11237 }
11238 result = static_cast<std::size_t>(number);
11239 return true;
11240 }
5157 11241
5158 @since version 1.0.0 11242 case 'u':
5159 */ 11243 {
5160 iterator insert(const_iterator pos, const basic_json& val) 11244 if (input_format != input_format_t::bjdata)
5161 { 11245 {
5162 // insert only works for arrays 11246 break;
5163 if (is_array()) 11247 }
5164 { 11248 std::uint16_t number{};
5165 // check if iterator pos fits to this JSON value 11249 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
5166 if (pos.m_object != this) 11250 {
11251 return false;
11252 }
11253 result = static_cast<std::size_t>(number);
11254 return true;
11255 }
11256
11257 case 'm':
5167 { 11258 {
5168 throw std::domain_error("iterator does not fit current value"); 11259 if (input_format != input_format_t::bjdata)
11260 {
11261 break;
11262 }
11263 std::uint32_t number{};
11264 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11265 {
11266 return false;
11267 }
11268 result = conditional_static_cast<std::size_t>(number);
11269 return true;
5169 } 11270 }
5170 11271
5171 // insert to array and return iterator 11272 case 'M':
5172 iterator result(this); 11273 {
5173 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); 11274 if (input_format != input_format_t::bjdata)
5174 return result; 11275 {
11276 break;
11277 }
11278 std::uint64_t number{};
11279 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11280 {
11281 return false;
11282 }
11283 if (!value_in_range_of<std::size_t>(number))
11284 {
11285 return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
11286 exception_message(input_format, "integer value overflow", "size"), nullptr));
11287 }
11288 result = detail::conditional_static_cast<std::size_t>(number);
11289 return true;
11290 }
11291
11292 case '[':
11293 {
11294 if (input_format != input_format_t::bjdata)
11295 {
11296 break;
11297 }
11298 if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array
11299 {
11300 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimensional vector is not allowed", "size"), nullptr));
11301 }
11302 std::vector<size_t> dim;
11303 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim)))
11304 {
11305 return false;
11306 }
11307 if (dim.size() == 1 || (dim.size() == 2 && dim.at(0) == 1)) // return normal array size if 1D row vector
11308 {
11309 result = dim.at(dim.size() - 1);
11310 return true;
11311 }
11312 if (!dim.empty()) // if ndarray, convert to an object in JData annotated array format
11313 {
11314 for (auto i : dim) // test if any dimension in an ndarray is 0, if so, return a 1D empty container
11315 {
11316 if ( i == 0 )
11317 {
11318 result = 0;
11319 return true;
11320 }
11321 }
11322
11323 string_t key = "_ArraySize_";
11324 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size())))
11325 {
11326 return false;
11327 }
11328 result = 1;
11329 for (auto i : dim)
11330 {
11331 result *= i;
11332 if (result == 0 || result == npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be npos as it is used to initialize size in get_ubjson_size_type()
11333 {
11334 return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr));
11335 }
11336 if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast<number_unsigned_t>(i))))
11337 {
11338 return false;
11339 }
11340 }
11341 is_ndarray = true;
11342 return sax->end_array();
11343 }
11344 result = 0;
11345 return true;
11346 }
11347
11348 default:
11349 break;
11350 }
11351 auto last_token = get_token_string();
11352 std::string message;
11353
11354 if (input_format != input_format_t::bjdata)
11355 {
11356 message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token;
5175 } 11357 }
5176 else 11358 else
5177 { 11359 {
5178 throw std::domain_error("cannot use insert() with " + type_name()); 11360 message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token;
5179 } 11361 }
11362 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr));
5180 } 11363 }
5181 11364
5182 /*! 11365 /*!
5183 @brief inserts element 11366 @brief determine the type and size for a container
5184 @copydoc insert(const_iterator, const basic_json&)
5185 */
5186 iterator insert(const_iterator pos, basic_json&& val)
5187 {
5188 return insert(pos, val);
5189 }
5190 11367
5191 /*! 11368 In the optimized UBJSON format, a type and a size can be provided to allow
5192 @brief inserts elements 11369 for a more compact representation.
5193 11370
5194 Inserts @a cnt copies of @a val before iterator @a pos. 11371 @param[out] result pair of the size and the type
11372 @param[in] inside_ndarray whether the parser is parsing an ND array dimensional vector
5195 11373
5196 @param[in] pos iterator before which the content will be inserted; may be 11374 @return whether pair creation completed
5197 the end() iterator 11375 */
5198 @param[in] cnt number of copies of @a val to insert 11376 bool get_ubjson_size_type(std::pair<std::size_t, char_int_type>& result, bool inside_ndarray = false)
5199 @param[in] val element to insert 11377 {
5200 @return iterator pointing to the first element inserted, or @a pos if 11378 result.first = npos; // size
5201 `cnt==0` 11379 result.second = 0; // type
11380 bool is_ndarray = false;
5202 11381
5203 @throw std::domain_error if called on JSON values other than arrays; 11382 get_ignore_noop();
5204 example: `"cannot use insert() with string"`
5205 @throw std::domain_error if @a pos is not an iterator of *this; example:
5206 `"iterator does not fit current value"`
5207 11383
5208 @complexity Linear in @a cnt plus linear in the distance between @a pos 11384 if (current == '$')
5209 and end of the container. 11385 {
11386 result.second = get(); // must not ignore 'N', because 'N' maybe the type
11387 if (input_format == input_format_t::bjdata
11388 && JSON_HEDLEY_UNLIKELY(std::binary_search(bjd_optimized_type_markers.begin(), bjd_optimized_type_markers.end(), result.second)))
11389 {
11390 auto last_token = get_token_string();
11391 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
11392 exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr));
11393 }
5210 11394
5211 @liveexample{The example shows how `insert()` is used.,insert__count} 11395 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type")))
11396 {
11397 return false;
11398 }
5212 11399
5213 @since version 1.0.0 11400 get_ignore_noop();
5214 */ 11401 if (JSON_HEDLEY_UNLIKELY(current != '#'))
5215 iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
5216 {
5217 // insert only works for arrays
5218 if (is_array())
5219 {
5220 // check if iterator pos fits to this JSON value
5221 if (pos.m_object != this)
5222 { 11402 {
5223 throw std::domain_error("iterator does not fit current value"); 11403 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
11404 {
11405 return false;
11406 }
11407 auto last_token = get_token_string();
11408 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
11409 exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr));
5224 } 11410 }
5225 11411
5226 // insert to array and return iterator 11412 const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
5227 iterator result(this); 11413 if (input_format == input_format_t::bjdata && is_ndarray)
5228 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); 11414 {
5229 return result; 11415 if (inside_ndarray)
11416 {
11417 return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
11418 exception_message(input_format, "ndarray can not be recursive", "size"), nullptr));
11419 }
11420 result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters
11421 }
11422 return is_error;
5230 } 11423 }
5231 else 11424
11425 if (current == '#')
5232 { 11426 {
5233 throw std::domain_error("cannot use insert() with " + type_name()); 11427 const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
11428 if (input_format == input_format_t::bjdata && is_ndarray)
11429 {
11430 return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
11431 exception_message(input_format, "ndarray requires both type and size", "size"), nullptr));
11432 }
11433 return is_error;
5234 } 11434 }
11435
11436 return true;
5235 } 11437 }
5236 11438
5237 /*! 11439 /*!
5238 @brief inserts elements 11440 @param prefix the previously read or set type prefix
11441 @return whether value creation completed
11442 */
11443 bool get_ubjson_value(const char_int_type prefix)
11444 {
11445 switch (prefix)
11446 {
11447 case char_traits<char_type>::eof(): // EOF
11448 return unexpect_eof(input_format, "value");
5239 11449
5240 Inserts elements from range `[first, last)` before iterator @a pos. 11450 case 'T': // true
11451 return sax->boolean(true);
11452 case 'F': // false
11453 return sax->boolean(false);
5241 11454
5242 @param[in] pos iterator before which the content will be inserted; may be 11455 case 'Z': // null
5243 the end() iterator 11456 return sax->null();
5244 @param[in] first begin of the range of elements to insert 11457
5245 @param[in] last end of the range of elements to insert 11458 case 'U':
11459 {
11460 std::uint8_t number{};
11461 return get_number(input_format, number) && sax->number_unsigned(number);
11462 }
5246 11463
5247 @throw std::domain_error if called on JSON values other than arrays; 11464 case 'i':
5248 example: `"cannot use insert() with string"` 11465 {
5249 @throw std::domain_error if @a pos is not an iterator of *this; example: 11466 std::int8_t number{};
5250 `"iterator does not fit current value"` 11467 return get_number(input_format, number) && sax->number_integer(number);
5251 @throw std::domain_error if @a first and @a last do not belong to the same 11468 }
5252 JSON value; example: `"iterators do not fit"`
5253 @throw std::domain_error if @a first or @a last are iterators into
5254 container for which insert is called; example: `"passed iterators may not
5255 belong to container"`
5256 11469
5257 @return iterator pointing to the first element inserted, or @a pos if 11470 case 'I':
5258 `first==last` 11471 {
11472 std::int16_t number{};
11473 return get_number(input_format, number) && sax->number_integer(number);
11474 }
5259 11475
5260 @complexity Linear in `std::distance(first, last)` plus linear in the 11476 case 'l':
5261 distance between @a pos and end of the container. 11477 {
11478 std::int32_t number{};
11479 return get_number(input_format, number) && sax->number_integer(number);
11480 }
5262 11481
5263 @liveexample{The example shows how `insert()` is used.,insert__range} 11482 case 'L':
11483 {
11484 std::int64_t number{};
11485 return get_number(input_format, number) && sax->number_integer(number);
11486 }
5264 11487
5265 @since version 1.0.0 11488 case 'u':
11489 {
11490 if (input_format != input_format_t::bjdata)
11491 {
11492 break;
11493 }
11494 std::uint16_t number{};
11495 return get_number(input_format, number) && sax->number_unsigned(number);
11496 }
11497
11498 case 'm':
11499 {
11500 if (input_format != input_format_t::bjdata)
11501 {
11502 break;
11503 }
11504 std::uint32_t number{};
11505 return get_number(input_format, number) && sax->number_unsigned(number);
11506 }
11507
11508 case 'M':
11509 {
11510 if (input_format != input_format_t::bjdata)
11511 {
11512 break;
11513 }
11514 std::uint64_t number{};
11515 return get_number(input_format, number) && sax->number_unsigned(number);
11516 }
11517
11518 case 'h':
11519 {
11520 if (input_format != input_format_t::bjdata)
11521 {
11522 break;
11523 }
11524 const auto byte1_raw = get();
11525 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
11526 {
11527 return false;
11528 }
11529 const auto byte2_raw = get();
11530 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
11531 {
11532 return false;
11533 }
11534
11535 const auto byte1 = static_cast<unsigned char>(byte1_raw);
11536 const auto byte2 = static_cast<unsigned char>(byte2_raw);
11537
11538 // code from RFC 7049, Appendix D, Figure 3:
11539 // As half-precision floating-point numbers were only added
11540 // to IEEE 754 in 2008, today's programming platforms often
11541 // still only have limited support for them. It is very
11542 // easy to include at least decoding support for them even
11543 // without such support. An example of a small decoder for
11544 // half-precision floating-point numbers in the C language
11545 // is shown in Fig. 3.
11546 const auto half = static_cast<unsigned int>((byte2 << 8u) + byte1);
11547 const double val = [&half]
11548 {
11549 const int exp = (half >> 10u) & 0x1Fu;
11550 const unsigned int mant = half & 0x3FFu;
11551 JSON_ASSERT(0 <= exp&& exp <= 32);
11552 JSON_ASSERT(mant <= 1024);
11553 switch (exp)
11554 {
11555 case 0:
11556 return std::ldexp(mant, -24);
11557 case 31:
11558 return (mant == 0)
11559 ? std::numeric_limits<double>::infinity()
11560 : std::numeric_limits<double>::quiet_NaN();
11561 default:
11562 return std::ldexp(mant + 1024, exp - 25);
11563 }
11564 }();
11565 return sax->number_float((half & 0x8000u) != 0
11566 ? static_cast<number_float_t>(-val)
11567 : static_cast<number_float_t>(val), "");
11568 }
11569
11570 case 'd':
11571 {
11572 float number{};
11573 return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
11574 }
11575
11576 case 'D':
11577 {
11578 double number{};
11579 return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
11580 }
11581
11582 case 'H':
11583 {
11584 return get_ubjson_high_precision_number();
11585 }
11586
11587 case 'C': // char
11588 {
11589 get();
11590 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "char")))
11591 {
11592 return false;
11593 }
11594 if (JSON_HEDLEY_UNLIKELY(current > 127))
11595 {
11596 auto last_token = get_token_string();
11597 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
11598 exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr));
11599 }
11600 string_t s(1, static_cast<typename string_t::value_type>(current));
11601 return sax->string(s);
11602 }
11603
11604 case 'S': // string
11605 {
11606 string_t s;
11607 return get_ubjson_string(s) && sax->string(s);
11608 }
11609
11610 case '[': // array
11611 return get_ubjson_array();
11612
11613 case '{': // object
11614 return get_ubjson_object();
11615
11616 default: // anything else
11617 break;
11618 }
11619 auto last_token = get_token_string();
11620 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), nullptr));
11621 }
11622
11623 /*!
11624 @return whether array creation completed
5266 */ 11625 */
5267 iterator insert(const_iterator pos, const_iterator first, const_iterator last) 11626 bool get_ubjson_array()
5268 { 11627 {
5269 // insert only works for arrays 11628 std::pair<std::size_t, char_int_type> size_and_type;
5270 if (not is_array()) 11629 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
5271 { 11630 {
5272 throw std::domain_error("cannot use insert() with " + type_name()); 11631 return false;
5273 } 11632 }
5274 11633
5275 // check if iterator pos fits to this JSON value 11634 // if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata):
5276 if (pos.m_object != this) 11635 // {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]}
11636
11637 if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
5277 { 11638 {
5278 throw std::domain_error("iterator does not fit current value"); 11639 size_and_type.second &= ~(static_cast<char_int_type>(1) << 8); // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker
11640 auto it = std::lower_bound(bjd_types_map.begin(), bjd_types_map.end(), size_and_type.second, [](const bjd_type & p, char_int_type t)
11641 {
11642 return p.first < t;
11643 });
11644 string_t key = "_ArrayType_";
11645 if (JSON_HEDLEY_UNLIKELY(it == bjd_types_map.end() || it->first != size_and_type.second))
11646 {
11647 auto last_token = get_token_string();
11648 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
11649 exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr));
11650 }
11651
11652 string_t type = it->second; // sax->string() takes a reference
11653 if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type)))
11654 {
11655 return false;
11656 }
11657
11658 if (size_and_type.second == 'C')
11659 {
11660 size_and_type.second = 'U';
11661 }
11662
11663 key = "_ArrayData_";
11664 if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) ))
11665 {
11666 return false;
11667 }
11668
11669 for (std::size_t i = 0; i < size_and_type.first; ++i)
11670 {
11671 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
11672 {
11673 return false;
11674 }
11675 }
11676
11677 return (sax->end_array() && sax->end_object());
5279 } 11678 }
5280 11679
5281 // check if range iterators belong to the same JSON object 11680 if (size_and_type.first != npos)
5282 if (first.m_object != last.m_object)
5283 { 11681 {
5284 throw std::domain_error("iterators do not fit"); 11682 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first)))
5285 } 11683 {
11684 return false;
11685 }
5286 11686
5287 if (first.m_object == this or last.m_object == this) 11687 if (size_and_type.second != 0)
11688 {
11689 if (size_and_type.second != 'N')
11690 {
11691 for (std::size_t i = 0; i < size_and_type.first; ++i)
11692 {
11693 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
11694 {
11695 return false;
11696 }
11697 }
11698 }
11699 }
11700 else
11701 {
11702 for (std::size_t i = 0; i < size_and_type.first; ++i)
11703 {
11704 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
11705 {
11706 return false;
11707 }
11708 }
11709 }
11710 }
11711 else
5288 { 11712 {
5289 throw std::domain_error("passed iterators may not belong to container"); 11713 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
11714 {
11715 return false;
11716 }
11717
11718 while (current != ']')
11719 {
11720 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false)))
11721 {
11722 return false;
11723 }
11724 get_ignore_noop();
11725 }
5290 } 11726 }
5291 11727
5292 // insert to array and return iterator 11728 return sax->end_array();
5293 iterator result(this);
5294 result.m_it.array_iterator = m_value.array->insert(
5295 pos.m_it.array_iterator,
5296 first.m_it.array_iterator,
5297 last.m_it.array_iterator);
5298 return result;
5299 } 11729 }
5300 11730
5301 /*! 11731 /*!
5302 @brief inserts elements 11732 @return whether object creation completed
11733 */
11734 bool get_ubjson_object()
11735 {
11736 std::pair<std::size_t, char_int_type> size_and_type;
11737 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
11738 {
11739 return false;
11740 }
5303 11741
5304 Inserts elements from initializer list @a ilist before iterator @a pos. 11742 // do not accept ND-array size in objects in BJData
11743 if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
11744 {
11745 auto last_token = get_token_string();
11746 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
11747 exception_message(input_format, "BJData object does not support ND-array size in optimized format", "object"), nullptr));
11748 }
5305 11749
5306 @param[in] pos iterator before which the content will be inserted; may be 11750 string_t key;
5307 the end() iterator 11751 if (size_and_type.first != npos)
5308 @param[in] ilist initializer list to insert the values from 11752 {
11753 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first)))
11754 {
11755 return false;
11756 }
5309 11757
5310 @throw std::domain_error if called on JSON values other than arrays; 11758 if (size_and_type.second != 0)
5311 example: `"cannot use insert() with string"` 11759 {
5312 @throw std::domain_error if @a pos is not an iterator of *this; example: 11760 for (std::size_t i = 0; i < size_and_type.first; ++i)
5313 `"iterator does not fit current value"` 11761 {
11762 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
11763 {
11764 return false;
11765 }
11766 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
11767 {
11768 return false;
11769 }
11770 key.clear();
11771 }
11772 }
11773 else
11774 {
11775 for (std::size_t i = 0; i < size_and_type.first; ++i)
11776 {
11777 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
11778 {
11779 return false;
11780 }
11781 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
11782 {
11783 return false;
11784 }
11785 key.clear();
11786 }
11787 }
11788 }
11789 else
11790 {
11791 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
11792 {
11793 return false;
11794 }
5314 11795
5315 @return iterator pointing to the first element inserted, or @a pos if 11796 while (current != '}')
5316 `ilist` is empty 11797 {
11798 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key)))
11799 {
11800 return false;
11801 }
11802 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
11803 {
11804 return false;
11805 }
11806 get_ignore_noop();
11807 key.clear();
11808 }
11809 }
5317 11810
5318 @complexity Linear in `ilist.size()` plus linear in the distance between 11811 return sax->end_object();
5319 @a pos and end of the container. 11812 }
5320 11813
5321 @liveexample{The example shows how `insert()` is used.,insert__ilist} 11814 // Note, no reader for UBJSON binary types is implemented because they do
11815 // not exist
5322 11816
5323 @since version 1.0.0 11817 bool get_ubjson_high_precision_number()
5324 */
5325 iterator insert(const_iterator pos, std::initializer_list<basic_json> ilist)
5326 { 11818 {
5327 // insert only works for arrays 11819 // get size of following number string
5328 if (not is_array()) 11820 std::size_t size{};
11821 bool no_ndarray = true;
11822 auto res = get_ubjson_size_value(size, no_ndarray);
11823 if (JSON_HEDLEY_UNLIKELY(!res))
5329 { 11824 {
5330 throw std::domain_error("cannot use insert() with " + type_name()); 11825 return res;
5331 } 11826 }
5332 11827
5333 // check if iterator pos fits to this JSON value 11828 // get number string
5334 if (pos.m_object != this) 11829 std::vector<char> number_vector;
11830 for (std::size_t i = 0; i < size; ++i)
5335 { 11831 {
5336 throw std::domain_error("iterator does not fit current value"); 11832 get();
11833 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
11834 {
11835 return false;
11836 }
11837 number_vector.push_back(static_cast<char>(current));
5337 } 11838 }
5338 11839
5339 // insert to array and return iterator 11840 // parse number string
5340 iterator result(this); 11841 using ia_type = decltype(detail::input_adapter(number_vector));
5341 result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); 11842 auto number_lexer = detail::lexer<BasicJsonType, ia_type>(detail::input_adapter(number_vector), false);
5342 return result; 11843 const auto result_number = number_lexer.scan();
5343 } 11844 const auto number_string = number_lexer.get_token_string();
11845 const auto result_remainder = number_lexer.scan();
5344 11846
5345 /*! 11847 using token_type = typename detail::lexer_base<BasicJsonType>::token_type;
5346 @brief exchanges the values
5347 11848
5348 Exchanges the contents of the JSON value with those of @a other. Does not 11849 if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))
5349 invoke any move, copy, or swap operations on individual elements. All 11850 {
5350 iterators and references remain valid. The past-the-end iterator is 11851 return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,
5351 invalidated. 11852 exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
11853 }
11854
11855 switch (result_number)
11856 {
11857 case token_type::value_integer:
11858 return sax->number_integer(number_lexer.get_number_integer());
11859 case token_type::value_unsigned:
11860 return sax->number_unsigned(number_lexer.get_number_unsigned());
11861 case token_type::value_float:
11862 return sax->number_float(number_lexer.get_number_float(), std::move(number_string));
11863 case token_type::uninitialized:
11864 case token_type::literal_true:
11865 case token_type::literal_false:
11866 case token_type::literal_null:
11867 case token_type::value_string:
11868 case token_type::begin_array:
11869 case token_type::begin_object:
11870 case token_type::end_array:
11871 case token_type::end_object:
11872 case token_type::name_separator:
11873 case token_type::value_separator:
11874 case token_type::parse_error:
11875 case token_type::end_of_input:
11876 case token_type::literal_or_value:
11877 default:
11878 return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,
11879 exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
11880 }
11881 }
5352 11882
5353 @param[in,out] other JSON value to exchange the contents with 11883 ///////////////////////
11884 // Utility functions //
11885 ///////////////////////
5354 11886
5355 @complexity Constant. 11887 /*!
11888 @brief get next character from the input
5356 11889
5357 @liveexample{The example below shows how JSON values can be swapped with 11890 This function provides the interface to the used input adapter. It does
5358 `swap()`.,swap__reference} 11891 not throw in case the input reached EOF, but returns a -'ve valued
11892 `char_traits<char_type>::eof()` in that case.
5359 11893
5360 @since version 1.0.0 11894 @return character read from the input
5361 */ 11895 */
5362 void swap(reference other) noexcept ( 11896 char_int_type get()
5363 std::is_nothrow_move_constructible<value_t>::value and
5364 std::is_nothrow_move_assignable<value_t>::value and
5365 std::is_nothrow_move_constructible<json_value>::value and
5366 std::is_nothrow_move_assignable<json_value>::value
5367 )
5368 { 11897 {
5369 std::swap(m_type, other.m_type); 11898 ++chars_read;
5370 std::swap(m_value, other.m_value); 11899 return current = ia.get_character();
5371 assert_invariant();
5372 } 11900 }
5373 11901
5374 /*! 11902 /*!
5375 @brief exchanges the values 11903 @return character read from the input after ignoring all 'N' entries
5376 11904 */
5377 Exchanges the contents of a JSON array with those of @a other. Does not 11905 char_int_type get_ignore_noop()
5378 invoke any move, copy, or swap operations on individual elements. All 11906 {
5379 iterators and references remain valid. The past-the-end iterator is 11907 do
5380 invalidated. 11908 {
11909 get();
11910 }
11911 while (current == 'N');
5381 11912
5382 @param[in,out] other array to exchange the contents with 11913 return current;
11914 }
5383 11915
5384 @throw std::domain_error when JSON value is not an array; example: `"cannot 11916 /*
5385 use swap() with string"` 11917 @brief read a number from the input
5386 11918
5387 @complexity Constant. 11919 @tparam NumberType the type of the number
11920 @param[in] format the current format (for diagnostics)
11921 @param[out] result number of type @a NumberType
5388 11922
5389 @liveexample{The example below shows how arrays can be swapped with 11923 @return whether conversion completed
5390 `swap()`.,swap__array_t}
5391 11924
5392 @since version 1.0.0 11925 @note This function needs to respect the system's endianness, because
11926 bytes in CBOR, MessagePack, and UBJSON are stored in network order
11927 (big endian) and therefore need reordering on little endian systems.
11928 On the other hand, BSON and BJData use little endian and should reorder
11929 on big endian systems.
5393 */ 11930 */
5394 void swap(array_t& other) 11931 template<typename NumberType, bool InputIsLittleEndian = false>
11932 bool get_number(const input_format_t format, NumberType& result)
5395 { 11933 {
5396 // swap only works for arrays 11934 // step 1: read input into array with system's byte order
5397 if (is_array()) 11935 std::array<std::uint8_t, sizeof(NumberType)> vec{};
11936 for (std::size_t i = 0; i < sizeof(NumberType); ++i)
5398 { 11937 {
5399 std::swap(*(m_value.array), other); 11938 get();
5400 } 11939 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number")))
5401 else 11940 {
5402 { 11941 return false;
5403 throw std::domain_error("cannot use swap() with " + type_name()); 11942 }
11943
11944 // reverse byte order prior to conversion if necessary
11945 if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata))
11946 {
11947 vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);
11948 }
11949 else
11950 {
11951 vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE
11952 }
5404 } 11953 }
11954
11955 // step 2: convert array into number of type T and return
11956 std::memcpy(&result, vec.data(), sizeof(NumberType));
11957 return true;
5405 } 11958 }
5406 11959
5407 /*! 11960 /*!
5408 @brief exchanges the values 11961 @brief create a string by reading characters from the input
11962
11963 @tparam NumberType the type of the number
11964 @param[in] format the current format (for diagnostics)
11965 @param[in] len number of characters to read
11966 @param[out] result string created by reading @a len bytes
5409 11967
5410 Exchanges the contents of a JSON object with those of @a other. Does not 11968 @return whether string creation completed
5411 invoke any move, copy, or swap operations on individual elements. All
5412 iterators and references remain valid. The past-the-end iterator is
5413 invalidated.
5414 11969
5415 @param[in,out] other object to exchange the contents with 11970 @note We can not reserve @a len bytes for the result, because @a len
11971 may be too large. Usually, @ref unexpect_eof() detects the end of
11972 the input before we run out of string memory.
11973 */
11974 template<typename NumberType>
11975 bool get_string(const input_format_t format,
11976 const NumberType len,
11977 string_t& result)
11978 {
11979 bool success = true;
11980 for (NumberType i = 0; i < len; i++)
11981 {
11982 get();
11983 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string")))
11984 {
11985 success = false;
11986 break;
11987 }
11988 result.push_back(static_cast<typename string_t::value_type>(current));
11989 }
11990 return success;
11991 }
5416 11992
5417 @throw std::domain_error when JSON value is not an object; example: 11993 /*!
5418 `"cannot use swap() with string"` 11994 @brief create a byte array by reading bytes from the input
5419 11995
5420 @complexity Constant. 11996 @tparam NumberType the type of the number
11997 @param[in] format the current format (for diagnostics)
11998 @param[in] len number of bytes to read
11999 @param[out] result byte array created by reading @a len bytes
5421 12000
5422 @liveexample{The example below shows how objects can be swapped with 12001 @return whether byte array creation completed
5423 `swap()`.,swap__object_t}
5424 12002
5425 @since version 1.0.0 12003 @note We can not reserve @a len bytes for the result, because @a len
12004 may be too large. Usually, @ref unexpect_eof() detects the end of
12005 the input before we run out of memory.
5426 */ 12006 */
5427 void swap(object_t& other) 12007 template<typename NumberType>
12008 bool get_binary(const input_format_t format,
12009 const NumberType len,
12010 binary_t& result)
5428 { 12011 {
5429 // swap only works for objects 12012 bool success = true;
5430 if (is_object()) 12013 for (NumberType i = 0; i < len; i++)
5431 { 12014 {
5432 std::swap(*(m_value.object), other); 12015 get();
12016 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary")))
12017 {
12018 success = false;
12019 break;
12020 }
12021 result.push_back(static_cast<std::uint8_t>(current));
5433 } 12022 }
5434 else 12023 return success;
12024 }
12025
12026 /*!
12027 @param[in] format the current format (for diagnostics)
12028 @param[in] context further context information (for diagnostics)
12029 @return whether the last read character is not EOF
12030 */
12031 JSON_HEDLEY_NON_NULL(3)
12032 bool unexpect_eof(const input_format_t format, const char* context) const
12033 {
12034 if (JSON_HEDLEY_UNLIKELY(current == char_traits<char_type>::eof()))
5435 { 12035 {
5436 throw std::domain_error("cannot use swap() with " + type_name()); 12036 return sax->parse_error(chars_read, "<end of file>",
12037 parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr));
5437 } 12038 }
12039 return true;
12040 }
12041
12042 /*!
12043 @return a string representation of the last read byte
12044 */
12045 std::string get_token_string() const
12046 {
12047 std::array<char, 3> cr{{}};
12048 static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
12049 return std::string{cr.data()};
5438 } 12050 }
5439 12051
5440 /*! 12052 /*!
5441 @brief exchanges the values 12053 @param[in] format the current format
12054 @param[in] detail a detailed error message
12055 @param[in] context further context information
12056 @return a message string to use in the parse_error exceptions
12057 */
12058 std::string exception_message(const input_format_t format,
12059 const std::string& detail,
12060 const std::string& context) const
12061 {
12062 std::string error_msg = "syntax error while parsing ";
5442 12063
5443 Exchanges the contents of a JSON string with those of @a other. Does not 12064 switch (format)
5444 invoke any move, copy, or swap operations on individual elements. All 12065 {
5445 iterators and references remain valid. The past-the-end iterator is 12066 case input_format_t::cbor:
5446 invalidated. 12067 error_msg += "CBOR";
12068 break;
5447 12069
5448 @param[in,out] other string to exchange the contents with 12070 case input_format_t::msgpack:
12071 error_msg += "MessagePack";
12072 break;
5449 12073
5450 @throw std::domain_error when JSON value is not a string; example: `"cannot 12074 case input_format_t::ubjson:
5451 use swap() with boolean"` 12075 error_msg += "UBJSON";
12076 break;
5452 12077
5453 @complexity Constant. 12078 case input_format_t::bson:
12079 error_msg += "BSON";
12080 break;
5454 12081
5455 @liveexample{The example below shows how strings can be swapped with 12082 case input_format_t::bjdata:
5456 `swap()`.,swap__string_t} 12083 error_msg += "BJData";
12084 break;
5457 12085
5458 @since version 1.0.0 12086 case input_format_t::json: // LCOV_EXCL_LINE
5459 */ 12087 default: // LCOV_EXCL_LINE
5460 void swap(string_t& other) 12088 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
5461 {
5462 // swap only works for strings
5463 if (is_string())
5464 {
5465 std::swap(*(m_value.string), other);
5466 }
5467 else
5468 {
5469 throw std::domain_error("cannot use swap() with " + type_name());
5470 } 12089 }
12090
12091 return concat(error_msg, ' ', context, ": ", detail);
5471 } 12092 }
5472 12093
5473 /// @} 12094 private:
12095 static JSON_INLINE_VARIABLE constexpr std::size_t npos = static_cast<std::size_t>(-1);
12096
12097 /// input adapter
12098 InputAdapterType ia;
12099
12100 /// the current character
12101 char_int_type current = char_traits<char_type>::eof();
12102
12103 /// the number of characters read
12104 std::size_t chars_read = 0;
12105
12106 /// whether we can assume little endianness
12107 const bool is_little_endian = little_endianness();
12108
12109 /// input format
12110 const input_format_t input_format = input_format_t::json;
12111
12112 /// the SAX parser
12113 json_sax_t* sax = nullptr;
12114
12115 // excluded markers in bjdata optimized type
12116#define JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ \
12117 make_array<char_int_type>('F', 'H', 'N', 'S', 'T', 'Z', '[', '{')
12118
12119#define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \
12120 make_array<bjd_type>( \
12121 bjd_type{'C', "char"}, \
12122 bjd_type{'D', "double"}, \
12123 bjd_type{'I', "int16"}, \
12124 bjd_type{'L', "int64"}, \
12125 bjd_type{'M', "uint64"}, \
12126 bjd_type{'U', "uint8"}, \
12127 bjd_type{'d', "single"}, \
12128 bjd_type{'i', "int8"}, \
12129 bjd_type{'l', "int32"}, \
12130 bjd_type{'m', "uint32"}, \
12131 bjd_type{'u', "uint16"})
12132
12133 JSON_PRIVATE_UNLESS_TESTED:
12134 // lookup tables
12135 // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
12136 const decltype(JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_) bjd_optimized_type_markers =
12137 JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_;
12138
12139 using bjd_type = std::pair<char_int_type, string_t>;
12140 // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
12141 const decltype(JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_) bjd_types_map =
12142 JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_;
12143
12144#undef JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_
12145#undef JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_
12146};
5474 12147
12148#ifndef JSON_HAS_CPP_17
12149 template<typename BasicJsonType, typename InputAdapterType, typename SAX>
12150 constexpr std::size_t binary_reader<BasicJsonType, InputAdapterType, SAX>::npos;
12151#endif
5475 12152
5476 ////////////////////////////////////////// 12153} // namespace detail
5477 // lexicographical comparison operators // 12154NLOHMANN_JSON_NAMESPACE_END
5478 //////////////////////////////////////////
5479 12155
5480 /// @name lexicographical comparison operators 12156// #include <nlohmann/detail/input/input_adapters.hpp>
5481 /// @{ 12157
12158// #include <nlohmann/detail/input/lexer.hpp>
12159
12160// #include <nlohmann/detail/input/parser.hpp>
12161// __ _____ _____ _____
12162// __| | __| | | | JSON for Modern C++
12163// | | |__ | | | | | | version 3.11.3
12164// |_____|_____|_____|_|___| https://github.com/nlohmann/json
12165//
12166// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
12167// SPDX-License-Identifier: MIT
12168
12169
12170
12171#include <cmath> // isfinite
12172#include <cstdint> // uint8_t
12173#include <functional> // function
12174#include <string> // string
12175#include <utility> // move
12176#include <vector> // vector
12177
12178// #include <nlohmann/detail/exceptions.hpp>
12179
12180// #include <nlohmann/detail/input/input_adapters.hpp>
12181
12182// #include <nlohmann/detail/input/json_sax.hpp>
12183
12184// #include <nlohmann/detail/input/lexer.hpp>
12185
12186// #include <nlohmann/detail/macro_scope.hpp>
12187
12188// #include <nlohmann/detail/meta/is_sax.hpp>
12189
12190// #include <nlohmann/detail/string_concat.hpp>
12191
12192// #include <nlohmann/detail/value_t.hpp>
12193
12194
12195NLOHMANN_JSON_NAMESPACE_BEGIN
12196namespace detail
12197{
12198////////////
12199// parser //
12200////////////
12201
12202enum class parse_event_t : std::uint8_t
12203{
12204 /// the parser read `{` and started to process a JSON object
12205 object_start,
12206 /// the parser read `}` and finished processing a JSON object
12207 object_end,
12208 /// the parser read `[` and started to process a JSON array
12209 array_start,
12210 /// the parser read `]` and finished processing a JSON array
12211 array_end,
12212 /// the parser read a key of a value in an object
12213 key,
12214 /// the parser finished reading a JSON value
12215 value
12216};
12217
12218template<typename BasicJsonType>
12219using parser_callback_t =
12220 std::function<bool(int /*depth*/, parse_event_t /*event*/, BasicJsonType& /*parsed*/)>;
12221
12222/*!
12223@brief syntax analysis
12224
12225This class implements a recursive descent parser.
12226*/
12227template<typename BasicJsonType, typename InputAdapterType>
12228class parser
12229{
12230 using number_integer_t = typename BasicJsonType::number_integer_t;
12231 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
12232 using number_float_t = typename BasicJsonType::number_float_t;
12233 using string_t = typename BasicJsonType::string_t;
12234 using lexer_t = lexer<BasicJsonType, InputAdapterType>;
12235 using token_type = typename lexer_t::token_type;
12236
12237 public:
12238 /// a parser reading from an input adapter
12239 explicit parser(InputAdapterType&& adapter,
12240 const parser_callback_t<BasicJsonType> cb = nullptr,
12241 const bool allow_exceptions_ = true,
12242 const bool skip_comments = false)
12243 : callback(cb)
12244 , m_lexer(std::move(adapter), skip_comments)
12245 , allow_exceptions(allow_exceptions_)
12246 {
12247 // read first token
12248 get_token();
12249 }
5482 12250
5483 private:
5484 /*! 12251 /*!
5485 @brief comparison operator for JSON types 12252 @brief public parser interface
5486 12253
5487 Returns an ordering that is similar to Python: 12254 @param[in] strict whether to expect the last token to be EOF
5488 - order: null < boolean < number < object < array < string 12255 @param[in,out] result parsed JSON value
5489 - furthermore, each type is not smaller than itself
5490 12256
5491 @since version 1.0.0 12257 @throw parse_error.101 in case of an unexpected token
12258 @throw parse_error.102 if to_unicode fails or surrogate error
12259 @throw parse_error.103 if to_unicode fails
5492 */ 12260 */
5493 friend bool operator<(const value_t lhs, const value_t rhs) noexcept 12261 void parse(const bool strict, BasicJsonType& result)
5494 { 12262 {
5495 static constexpr std::array<uint8_t, 8> order = {{ 12263 if (callback)
5496 0, // null 12264 {
5497 3, // object 12265 json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
5498 4, // array 12266 sax_parse_internal(&sdp);
5499 5, // string 12267
5500 1, // boolean 12268 // in strict mode, input must be completely read
5501 2, // integer 12269 if (strict && (get_token() != token_type::end_of_input))
5502 2, // unsigned 12270 {
5503 2, // float 12271 sdp.parse_error(m_lexer.get_position(),
12272 m_lexer.get_token_string(),
12273 parse_error::create(101, m_lexer.get_position(),
12274 exception_message(token_type::end_of_input, "value"), nullptr));
12275 }
12276
12277 // in case of an error, return discarded value
12278 if (sdp.is_errored())
12279 {
12280 result = value_t::discarded;
12281 return;
5504 } 12282 }
5505 };
5506 12283
5507 // discarded values are not comparable 12284 // set top-level value to null if it was discarded by the callback
5508 if (lhs == value_t::discarded or rhs == value_t::discarded) 12285 // function
12286 if (result.is_discarded())
12287 {
12288 result = nullptr;
12289 }
12290 }
12291 else
5509 { 12292 {
5510 return false; 12293 json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
12294 sax_parse_internal(&sdp);
12295
12296 // in strict mode, input must be completely read
12297 if (strict && (get_token() != token_type::end_of_input))
12298 {
12299 sdp.parse_error(m_lexer.get_position(),
12300 m_lexer.get_token_string(),
12301 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));
12302 }
12303
12304 // in case of an error, return discarded value
12305 if (sdp.is_errored())
12306 {
12307 result = value_t::discarded;
12308 return;
12309 }
5511 } 12310 }
5512 12311
5513 return order[static_cast<std::size_t>(lhs)] < order[static_cast<std::size_t>(rhs)]; 12312 result.assert_invariant();
5514 } 12313 }
5515 12314
5516 public:
5517 /*! 12315 /*!
5518 @brief comparison: equal 12316 @brief public accept interface
5519 12317
5520 Compares two JSON values for equality according to the following rules: 12318 @param[in] strict whether to expect the last token to be EOF
5521 - Two JSON values are equal if (1) they are from the same type and (2) 12319 @return whether the input is a proper JSON text
5522 their stored values are the same. 12320 */
5523 - Integer and floating-point numbers are automatically converted before 12321 bool accept(const bool strict = true)
5524 comparison. Floating-point numbers are compared indirectly: two 12322 {
5525 floating-point numbers `f1` and `f2` are considered equal if neither 12323 json_sax_acceptor<BasicJsonType> sax_acceptor;
5526 `f1 > f2` nor `f2 > f1` holds. 12324 return sax_parse(&sax_acceptor, strict);
5527 - Two JSON null values are equal. 12325 }
5528 12326
5529 @param[in] lhs first JSON value to consider 12327 template<typename SAX>
5530 @param[in] rhs second JSON value to consider 12328 JSON_HEDLEY_NON_NULL(2)
5531 @return whether the values @a lhs and @a rhs are equal 12329 bool sax_parse(SAX* sax, const bool strict = true)
12330 {
12331 (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
12332 const bool result = sax_parse_internal(sax);
5532 12333
5533 @complexity Linear. 12334 // strict mode: next byte must be EOF
12335 if (result && strict && (get_token() != token_type::end_of_input))
12336 {
12337 return sax->parse_error(m_lexer.get_position(),
12338 m_lexer.get_token_string(),
12339 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));
12340 }
5534 12341
5535 @liveexample{The example demonstrates comparing several JSON 12342 return result;
5536 types.,operator__equal} 12343 }
5537 12344
5538 @since version 1.0.0 12345 private:
5539 */ 12346 template<typename SAX>
5540 friend bool operator==(const_reference lhs, const_reference rhs) noexcept 12347 JSON_HEDLEY_NON_NULL(2)
12348 bool sax_parse_internal(SAX* sax)
5541 { 12349 {
5542 const auto lhs_type = lhs.type(); 12350 // stack to remember the hierarchy of structured values we are parsing
5543 const auto rhs_type = rhs.type(); 12351 // true = array; false = object
12352 std::vector<bool> states;
12353 // value to avoid a goto (see comment where set to true)
12354 bool skip_to_state_evaluation = false;
5544 12355
5545 if (lhs_type == rhs_type) 12356 while (true)
5546 { 12357 {
5547 switch (lhs_type) 12358 if (!skip_to_state_evaluation)
5548 { 12359 {
5549 case value_t::array: 12360 // invariant: get_token() was called before each iteration
5550 { 12361 switch (last_token)
5551 return *lhs.m_value.array == *rhs.m_value.array;
5552 }
5553 case value_t::object:
5554 { 12362 {
5555 return *lhs.m_value.object == *rhs.m_value.object; 12363 case token_type::begin_object:
5556 } 12364 {
5557 case value_t::null: 12365 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
5558 { 12366 {
5559 return true; 12367 return false;
12368 }
12369
12370 // closing } -> we are done
12371 if (get_token() == token_type::end_object)
12372 {
12373 if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
12374 {
12375 return false;
12376 }
12377 break;
12378 }
12379
12380 // parse key
12381 if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
12382 {
12383 return sax->parse_error(m_lexer.get_position(),
12384 m_lexer.get_token_string(),
12385 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
12386 }
12387 if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
12388 {
12389 return false;
12390 }
12391
12392 // parse separator (:)
12393 if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
12394 {
12395 return sax->parse_error(m_lexer.get_position(),
12396 m_lexer.get_token_string(),
12397 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
12398 }
12399
12400 // remember we are now inside an object
12401 states.push_back(false);
12402
12403 // parse values
12404 get_token();
12405 continue;
12406 }
12407
12408 case token_type::begin_array:
12409 {
12410 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
12411 {
12412 return false;
12413 }
12414
12415 // closing ] -> we are done
12416 if (get_token() == token_type::end_array)
12417 {
12418 if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
12419 {
12420 return false;
12421 }
12422 break;
12423 }
12424
12425 // remember we are now inside an array
12426 states.push_back(true);
12427
12428 // parse values (no need to call get_token)
12429 continue;
12430 }
12431
12432 case token_type::value_float:
12433 {
12434 const auto res = m_lexer.get_number_float();
12435
12436 if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res)))
12437 {
12438 return sax->parse_error(m_lexer.get_position(),
12439 m_lexer.get_token_string(),
12440 out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr));
12441 }
12442
12443 if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))
12444 {
12445 return false;
12446 }
12447
12448 break;
12449 }
12450
12451 case token_type::literal_false:
12452 {
12453 if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false)))
12454 {
12455 return false;
12456 }
12457 break;
12458 }
12459
12460 case token_type::literal_null:
12461 {
12462 if (JSON_HEDLEY_UNLIKELY(!sax->null()))
12463 {
12464 return false;
12465 }
12466 break;
12467 }
12468
12469 case token_type::literal_true:
12470 {
12471 if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true)))
12472 {
12473 return false;
12474 }
12475 break;
12476 }
12477
12478 case token_type::value_integer:
12479 {
12480 if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer())))
12481 {
12482 return false;
12483 }
12484 break;
12485 }
12486
12487 case token_type::value_string:
12488 {
12489 if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string())))
12490 {
12491 return false;
12492 }
12493 break;
12494 }
12495
12496 case token_type::value_unsigned:
12497 {
12498 if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned())))
12499 {
12500 return false;
12501 }
12502 break;
12503 }
12504
12505 case token_type::parse_error:
12506 {
12507 // using "uninitialized" to avoid "expected" message
12508 return sax->parse_error(m_lexer.get_position(),
12509 m_lexer.get_token_string(),
12510 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr));
12511 }
12512 case token_type::end_of_input:
12513 {
12514 if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1))
12515 {
12516 return sax->parse_error(m_lexer.get_position(),
12517 m_lexer.get_token_string(),
12518 parse_error::create(101, m_lexer.get_position(),
12519 "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
12520 }
12521
12522 return sax->parse_error(m_lexer.get_position(),
12523 m_lexer.get_token_string(),
12524 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
12525 }
12526 case token_type::uninitialized:
12527 case token_type::end_array:
12528 case token_type::end_object:
12529 case token_type::name_separator:
12530 case token_type::value_separator:
12531 case token_type::literal_or_value:
12532 default: // the last token was unexpected
12533 {
12534 return sax->parse_error(m_lexer.get_position(),
12535 m_lexer.get_token_string(),
12536 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
12537 }
5560 } 12538 }
5561 case value_t::string: 12539 }
12540 else
12541 {
12542 skip_to_state_evaluation = false;
12543 }
12544
12545 // we reached this line after we successfully parsed a value
12546 if (states.empty())
12547 {
12548 // empty stack: we reached the end of the hierarchy: done
12549 return true;
12550 }
12551
12552 if (states.back()) // array
12553 {
12554 // comma -> next value
12555 if (get_token() == token_type::value_separator)
5562 { 12556 {
5563 return *lhs.m_value.string == *rhs.m_value.string; 12557 // parse a new value
12558 get_token();
12559 continue;
5564 } 12560 }
5565 case value_t::boolean: 12561
12562 // closing ]
12563 if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array))
5566 { 12564 {
5567 return lhs.m_value.boolean == rhs.m_value.boolean; 12565 if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
12566 {
12567 return false;
12568 }
12569
12570 // We are done with this array. Before we can parse a
12571 // new value, we need to evaluate the new state first.
12572 // By setting skip_to_state_evaluation to false, we
12573 // are effectively jumping to the beginning of this if.
12574 JSON_ASSERT(!states.empty());
12575 states.pop_back();
12576 skip_to_state_evaluation = true;
12577 continue;
5568 } 12578 }
5569 case value_t::number_integer: 12579
12580 return sax->parse_error(m_lexer.get_position(),
12581 m_lexer.get_token_string(),
12582 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr));
12583 }
12584
12585 // states.back() is false -> object
12586
12587 // comma -> next value
12588 if (get_token() == token_type::value_separator)
12589 {
12590 // parse key
12591 if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))
5570 { 12592 {
5571 return lhs.m_value.number_integer == rhs.m_value.number_integer; 12593 return sax->parse_error(m_lexer.get_position(),
12594 m_lexer.get_token_string(),
12595 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
5572 } 12596 }
5573 case value_t::number_unsigned: 12597
12598 if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
5574 { 12599 {
5575 return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; 12600 return false;
5576 } 12601 }
5577 case value_t::number_float: 12602
12603 // parse separator (:)
12604 if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
5578 { 12605 {
5579 return lhs.m_value.number_float == rhs.m_value.number_float; 12606 return sax->parse_error(m_lexer.get_position(),
12607 m_lexer.get_token_string(),
12608 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
5580 } 12609 }
5581 default: 12610
12611 // parse values
12612 get_token();
12613 continue;
12614 }
12615
12616 // closing }
12617 if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))
12618 {
12619 if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
5582 { 12620 {
5583 return false; 12621 return false;
5584 } 12622 }
12623
12624 // We are done with this object. Before we can parse a
12625 // new value, we need to evaluate the new state first.
12626 // By setting skip_to_state_evaluation to false, we
12627 // are effectively jumping to the beginning of this if.
12628 JSON_ASSERT(!states.empty());
12629 states.pop_back();
12630 skip_to_state_evaluation = true;
12631 continue;
5585 } 12632 }
12633
12634 return sax->parse_error(m_lexer.get_position(),
12635 m_lexer.get_token_string(),
12636 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr));
5586 } 12637 }
5587 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) 12638 }
5588 { 12639
5589 return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float; 12640 /// get next token from lexer
5590 } 12641 token_type get_token()
5591 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) 12642 {
5592 { 12643 return last_token = m_lexer.scan();
5593 return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer); 12644 }
5594 } 12645
5595 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) 12646 std::string exception_message(const token_type expected, const std::string& context)
12647 {
12648 std::string error_msg = "syntax error ";
12649
12650 if (!context.empty())
5596 { 12651 {
5597 return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float; 12652 error_msg += concat("while parsing ", context, ' ');
5598 } 12653 }
5599 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) 12654
12655 error_msg += "- ";
12656
12657 if (last_token == token_type::parse_error)
5600 { 12658 {
5601 return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned); 12659 error_msg += concat(m_lexer.get_error_message(), "; last read: '",
12660 m_lexer.get_token_string(), '\'');
5602 } 12661 }
5603 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) 12662 else
5604 { 12663 {
5605 return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; 12664 error_msg += concat("unexpected ", lexer_t::token_type_name(last_token));
5606 } 12665 }
5607 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) 12666
12667 if (expected != token_type::uninitialized)
5608 { 12668 {
5609 return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned); 12669 error_msg += concat("; expected ", lexer_t::token_type_name(expected));
5610 } 12670 }
5611 12671
5612 return false; 12672 return error_msg;
5613 } 12673 }
5614 12674
5615 /*! 12675 private:
5616 @brief comparison: equal 12676 /// callback function
12677 const parser_callback_t<BasicJsonType> callback = nullptr;
12678 /// the type of the last read token
12679 token_type last_token = token_type::uninitialized;
12680 /// the lexer
12681 lexer_t m_lexer;
12682 /// whether to throw exceptions in case of errors
12683 const bool allow_exceptions = true;
12684};
5617 12685
5618 The functions compares the given JSON value against a null pointer. As the 12686} // namespace detail
5619 null pointer can be used to initialize a JSON value to null, a comparison 12687NLOHMANN_JSON_NAMESPACE_END
5620 of JSON value @a v with a null pointer should be equivalent to call
5621 `v.is_null()`.
5622 12688
5623 @param[in] v JSON value to consider 12689// #include <nlohmann/detail/iterators/internal_iterator.hpp>
5624 @return whether @a v is null 12690// __ _____ _____ _____
12691// __| | __| | | | JSON for Modern C++
12692// | | |__ | | | | | | version 3.11.3
12693// |_____|_____|_____|_|___| https://github.com/nlohmann/json
12694//
12695// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
12696// SPDX-License-Identifier: MIT
5625 12697
5626 @complexity Constant.
5627 12698
5628 @liveexample{The example compares several JSON types to the null pointer.
5629 ,operator__equal__nullptr_t}
5630 12699
5631 @since version 1.0.0 12700// #include <nlohmann/detail/abi_macros.hpp>
5632 */ 12701
5633 friend bool operator==(const_reference v, std::nullptr_t) noexcept 12702// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
12703// __ _____ _____ _____
12704// __| | __| | | | JSON for Modern C++
12705// | | |__ | | | | | | version 3.11.3
12706// |_____|_____|_____|_|___| https://github.com/nlohmann/json
12707//
12708// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
12709// SPDX-License-Identifier: MIT
12710
12711
12712
12713#include <cstddef> // ptrdiff_t
12714#include <limits> // numeric_limits
12715
12716// #include <nlohmann/detail/macro_scope.hpp>
12717
12718
12719NLOHMANN_JSON_NAMESPACE_BEGIN
12720namespace detail
12721{
12722
12723/*
12724@brief an iterator for primitive JSON types
12725
12726This class models an iterator for primitive JSON types (boolean, number,
12727string). It's only purpose is to allow the iterator/const_iterator classes
12728to "iterate" over primitive values. Internally, the iterator is modeled by
12729a `difference_type` variable. Value begin_value (`0`) models the begin,
12730end_value (`1`) models past the end.
12731*/
12732class primitive_iterator_t
12733{
12734 private:
12735 using difference_type = std::ptrdiff_t;
12736 static constexpr difference_type begin_value = 0;
12737 static constexpr difference_type end_value = begin_value + 1;
12738
12739 JSON_PRIVATE_UNLESS_TESTED:
12740 /// iterator as signed integer type
12741 difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();
12742
12743 public:
12744 constexpr difference_type get_value() const noexcept
5634 { 12745 {
5635 return v.is_null(); 12746 return m_it;
5636 } 12747 }
5637 12748
5638 /*! 12749 /// set iterator to a defined beginning
5639 @brief comparison: equal 12750 void set_begin() noexcept
5640 @copydoc operator==(const_reference, std::nullptr_t)
5641 */
5642 friend bool operator==(std::nullptr_t, const_reference v) noexcept
5643 { 12751 {
5644 return v.is_null(); 12752 m_it = begin_value;
5645 } 12753 }
5646 12754
5647 /*! 12755 /// set iterator to a defined past the end
5648 @brief comparison: not equal 12756 void set_end() noexcept
12757 {
12758 m_it = end_value;
12759 }
5649 12760
5650 Compares two JSON values for inequality by calculating `not (lhs == rhs)`. 12761 /// return whether the iterator can be dereferenced
12762 constexpr bool is_begin() const noexcept
12763 {
12764 return m_it == begin_value;
12765 }
5651 12766
5652 @param[in] lhs first JSON value to consider 12767 /// return whether the iterator is at end
5653 @param[in] rhs second JSON value to consider 12768 constexpr bool is_end() const noexcept
5654 @return whether the values @a lhs and @a rhs are not equal 12769 {
12770 return m_it == end_value;
12771 }
5655 12772
5656 @complexity Linear. 12773 friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
12774 {
12775 return lhs.m_it == rhs.m_it;
12776 }
5657 12777
5658 @liveexample{The example demonstrates comparing several JSON 12778 friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
5659 types.,operator__notequal} 12779 {
12780 return lhs.m_it < rhs.m_it;
12781 }
5660 12782
5661 @since version 1.0.0 12783 primitive_iterator_t operator+(difference_type n) noexcept
5662 */ 12784 {
5663 friend bool operator!=(const_reference lhs, const_reference rhs) noexcept 12785 auto result = *this;
12786 result += n;
12787 return result;
12788 }
12789
12790 friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
12791 {
12792 return lhs.m_it - rhs.m_it;
12793 }
12794
12795 primitive_iterator_t& operator++() noexcept
12796 {
12797 ++m_it;
12798 return *this;
12799 }
12800
12801 primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp)
12802 {
12803 auto result = *this;
12804 ++m_it;
12805 return result;
12806 }
12807
12808 primitive_iterator_t& operator--() noexcept
12809 {
12810 --m_it;
12811 return *this;
12812 }
12813
12814 primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp)
5664 { 12815 {
5665 return not (lhs == rhs); 12816 auto result = *this;
12817 --m_it;
12818 return result;
12819 }
12820
12821 primitive_iterator_t& operator+=(difference_type n) noexcept
12822 {
12823 m_it += n;
12824 return *this;
5666 } 12825 }
5667 12826
12827 primitive_iterator_t& operator-=(difference_type n) noexcept
12828 {
12829 m_it -= n;
12830 return *this;
12831 }
12832};
12833
12834} // namespace detail
12835NLOHMANN_JSON_NAMESPACE_END
12836
12837
12838NLOHMANN_JSON_NAMESPACE_BEGIN
12839namespace detail
12840{
12841
12842/*!
12843@brief an iterator value
12844
12845@note This structure could easily be a union, but MSVC currently does not allow
12846unions members with complex constructors, see https://github.com/nlohmann/json/pull/105.
12847*/
12848template<typename BasicJsonType> struct internal_iterator
12849{
12850 /// iterator for JSON objects
12851 typename BasicJsonType::object_t::iterator object_iterator {};
12852 /// iterator for JSON arrays
12853 typename BasicJsonType::array_t::iterator array_iterator {};
12854 /// generic iterator for all other types
12855 primitive_iterator_t primitive_iterator {};
12856};
12857
12858} // namespace detail
12859NLOHMANN_JSON_NAMESPACE_END
12860
12861// #include <nlohmann/detail/iterators/iter_impl.hpp>
12862// __ _____ _____ _____
12863// __| | __| | | | JSON for Modern C++
12864// | | |__ | | | | | | version 3.11.3
12865// |_____|_____|_____|_|___| https://github.com/nlohmann/json
12866//
12867// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
12868// SPDX-License-Identifier: MIT
12869
12870
12871
12872#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
12873#include <type_traits> // conditional, is_const, remove_const
12874
12875// #include <nlohmann/detail/exceptions.hpp>
12876
12877// #include <nlohmann/detail/iterators/internal_iterator.hpp>
12878
12879// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
12880
12881// #include <nlohmann/detail/macro_scope.hpp>
12882
12883// #include <nlohmann/detail/meta/cpp_future.hpp>
12884
12885// #include <nlohmann/detail/meta/type_traits.hpp>
12886
12887// #include <nlohmann/detail/value_t.hpp>
12888
12889
12890NLOHMANN_JSON_NAMESPACE_BEGIN
12891namespace detail
12892{
12893
12894// forward declare, to be able to friend it later on
12895template<typename IteratorType> class iteration_proxy;
12896template<typename IteratorType> class iteration_proxy_value;
12897
12898/*!
12899@brief a template for a bidirectional iterator for the @ref basic_json class
12900This class implements a both iterators (iterator and const_iterator) for the
12901@ref basic_json class.
12902@note An iterator is called *initialized* when a pointer to a JSON value has
12903 been set (e.g., by a constructor or a copy assignment). If the iterator is
12904 default-constructed, it is *uninitialized* and most methods are undefined.
12905 **The library uses assertions to detect calls on uninitialized iterators.**
12906@requirement The class satisfies the following concept requirements:
12907-
12908[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
12909 The iterator that can be moved can be moved in both directions (i.e.
12910 incremented and decremented).
12911@since version 1.0.0, simplified in version 2.0.9, change to bidirectional
12912 iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
12913*/
12914template<typename BasicJsonType>
12915class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
12916{
12917 /// the iterator with BasicJsonType of different const-ness
12918 using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
12919 /// allow basic_json to access private members
12920 friend other_iter_impl;
12921 friend BasicJsonType;
12922 friend iteration_proxy<iter_impl>;
12923 friend iteration_proxy_value<iter_impl>;
12924
12925 using object_t = typename BasicJsonType::object_t;
12926 using array_t = typename BasicJsonType::array_t;
12927 // make sure BasicJsonType is basic_json or const basic_json
12928 static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
12929 "iter_impl only accepts (const) basic_json");
12930 // superficial check for the LegacyBidirectionalIterator named requirement
12931 static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value
12932 && std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
12933 "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement.");
12934
12935 public:
12936 /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
12937 /// The C++ Standard has never required user-defined iterators to derive from std::iterator.
12938 /// A user-defined iterator should provide publicly accessible typedefs named
12939 /// iterator_category, value_type, difference_type, pointer, and reference.
12940 /// Note that value_type is required to be non-const, even for constant iterators.
12941 using iterator_category = std::bidirectional_iterator_tag;
12942
12943 /// the type of the values when the iterator is dereferenced
12944 using value_type = typename BasicJsonType::value_type;
12945 /// a type to represent differences between iterators
12946 using difference_type = typename BasicJsonType::difference_type;
12947 /// defines a pointer to the type iterated over (value_type)
12948 using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
12949 typename BasicJsonType::const_pointer,
12950 typename BasicJsonType::pointer>::type;
12951 /// defines a reference to the type iterated over (value_type)
12952 using reference =
12953 typename std::conditional<std::is_const<BasicJsonType>::value,
12954 typename BasicJsonType::const_reference,
12955 typename BasicJsonType::reference>::type;
12956
12957 iter_impl() = default;
12958 ~iter_impl() = default;
12959 iter_impl(iter_impl&&) noexcept = default;
12960 iter_impl& operator=(iter_impl&&) noexcept = default;
12961
5668 /*! 12962 /*!
5669 @brief comparison: not equal 12963 @brief constructor for a given JSON instance
12964 @param[in] object pointer to a JSON object for this iterator
12965 @pre object != nullptr
12966 @post The iterator is initialized; i.e. `m_object != nullptr`.
12967 */
12968 explicit iter_impl(pointer object) noexcept : m_object(object)
12969 {
12970 JSON_ASSERT(m_object != nullptr);
5670 12971
5671 The functions compares the given JSON value against a null pointer. As the 12972 switch (m_object->m_data.m_type)
5672 null pointer can be used to initialize a JSON value to null, a comparison 12973 {
5673 of JSON value @a v with a null pointer should be equivalent to call 12974 case value_t::object:
5674 `not v.is_null()`. 12975 {
12976 m_it.object_iterator = typename object_t::iterator();
12977 break;
12978 }
5675 12979
5676 @param[in] v JSON value to consider 12980 case value_t::array:
5677 @return whether @a v is not null 12981 {
12982 m_it.array_iterator = typename array_t::iterator();
12983 break;
12984 }
5678 12985
5679 @complexity Constant. 12986 case value_t::null:
12987 case value_t::string:
12988 case value_t::boolean:
12989 case value_t::number_integer:
12990 case value_t::number_unsigned:
12991 case value_t::number_float:
12992 case value_t::binary:
12993 case value_t::discarded:
12994 default:
12995 {
12996 m_it.primitive_iterator = primitive_iterator_t();
12997 break;
12998 }
12999 }
13000 }
5680 13001
5681 @liveexample{The example compares several JSON types to the null pointer. 13002 /*!
5682 ,operator__notequal__nullptr_t} 13003 @note The conventional copy constructor and copy assignment are implicitly
13004 defined. Combined with the following converting constructor and
13005 assignment, they support: (1) copy from iterator to iterator, (2)
13006 copy from const iterator to const iterator, and (3) conversion from
13007 iterator to const iterator. However conversion from const iterator
13008 to iterator is not defined.
13009 */
5683 13010
5684 @since version 1.0.0 13011 /*!
13012 @brief const copy constructor
13013 @param[in] other const iterator to copy from
13014 @note This copy constructor had to be defined explicitly to circumvent a bug
13015 occurring on msvc v19.0 compiler (VS 2015) debug build. For more
13016 information refer to: https://github.com/nlohmann/json/issues/1608
13017 */
13018 iter_impl(const iter_impl<const BasicJsonType>& other) noexcept
13019 : m_object(other.m_object), m_it(other.m_it)
13020 {}
13021
13022 /*!
13023 @brief converting assignment
13024 @param[in] other const iterator to copy from
13025 @return const/non-const iterator
13026 @note It is not checked whether @a other is initialized.
5685 */ 13027 */
5686 friend bool operator!=(const_reference v, std::nullptr_t) noexcept 13028 iter_impl& operator=(const iter_impl<const BasicJsonType>& other) noexcept
5687 { 13029 {
5688 return not v.is_null(); 13030 if (&other != this)
13031 {
13032 m_object = other.m_object;
13033 m_it = other.m_it;
13034 }
13035 return *this;
5689 } 13036 }
5690 13037
5691 /*! 13038 /*!
5692 @brief comparison: not equal 13039 @brief converting constructor
5693 @copydoc operator!=(const_reference, std::nullptr_t) 13040 @param[in] other non-const iterator to copy from
13041 @note It is not checked whether @a other is initialized.
5694 */ 13042 */
5695 friend bool operator!=(std::nullptr_t, const_reference v) noexcept 13043 iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
13044 : m_object(other.m_object), m_it(other.m_it)
13045 {}
13046
13047 /*!
13048 @brief converting assignment
13049 @param[in] other non-const iterator to copy from
13050 @return const/non-const iterator
13051 @note It is not checked whether @a other is initialized.
13052 */
13053 iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept // NOLINT(cert-oop54-cpp)
5696 { 13054 {
5697 return not v.is_null(); 13055 m_object = other.m_object;
13056 m_it = other.m_it;
13057 return *this;
5698 } 13058 }
5699 13059
13060 JSON_PRIVATE_UNLESS_TESTED:
5700 /*! 13061 /*!
5701 @brief comparison: less than 13062 @brief set the iterator to the first value
13063 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13064 */
13065 void set_begin() noexcept
13066 {
13067 JSON_ASSERT(m_object != nullptr);
5702 13068
5703 Compares whether one JSON value @a lhs is less than another JSON value @a 13069 switch (m_object->m_data.m_type)
5704 rhs according to the following rules: 13070 {
5705 - If @a lhs and @a rhs have the same type, the values are compared using 13071 case value_t::object:
5706 the default `<` operator. 13072 {
5707 - Integer and floating-point numbers are automatically converted before 13073 m_it.object_iterator = m_object->m_data.m_value.object->begin();
5708 comparison 13074 break;
5709 - In case @a lhs and @a rhs have different types, the values are ignored 13075 }
5710 and the order of the types is considered, see
5711 @ref operator<(const value_t, const value_t).
5712 13076
5713 @param[in] lhs first JSON value to consider 13077 case value_t::array:
5714 @param[in] rhs second JSON value to consider 13078 {
5715 @return whether @a lhs is less than @a rhs 13079 m_it.array_iterator = m_object->m_data.m_value.array->begin();
13080 break;
13081 }
5716 13082
5717 @complexity Linear. 13083 case value_t::null:
13084 {
13085 // set to end so begin()==end() is true: null is empty
13086 m_it.primitive_iterator.set_end();
13087 break;
13088 }
5718 13089
5719 @liveexample{The example demonstrates comparing several JSON 13090 case value_t::string:
5720 types.,operator__less} 13091 case value_t::boolean:
13092 case value_t::number_integer:
13093 case value_t::number_unsigned:
13094 case value_t::number_float:
13095 case value_t::binary:
13096 case value_t::discarded:
13097 default:
13098 {
13099 m_it.primitive_iterator.set_begin();
13100 break;
13101 }
13102 }
13103 }
5721 13104
5722 @since version 1.0.0 13105 /*!
13106 @brief set the iterator past the last value
13107 @pre The iterator is initialized; i.e. `m_object != nullptr`.
5723 */ 13108 */
5724 friend bool operator<(const_reference lhs, const_reference rhs) noexcept 13109 void set_end() noexcept
5725 { 13110 {
5726 const auto lhs_type = lhs.type(); 13111 JSON_ASSERT(m_object != nullptr);
5727 const auto rhs_type = rhs.type();
5728 13112
5729 if (lhs_type == rhs_type) 13113 switch (m_object->m_data.m_type)
5730 { 13114 {
5731 switch (lhs_type) 13115 case value_t::object:
5732 { 13116 {
5733 case value_t::array: 13117 m_it.object_iterator = m_object->m_data.m_value.object->end();
5734 { 13118 break;
5735 return *lhs.m_value.array < *rhs.m_value.array; 13119 }
5736 } 13120
5737 case value_t::object: 13121 case value_t::array:
5738 { 13122 {
5739 return *lhs.m_value.object < *rhs.m_value.object; 13123 m_it.array_iterator = m_object->m_data.m_value.array->end();
5740 } 13124 break;
5741 case value_t::null: 13125 }
5742 { 13126
5743 return false; 13127 case value_t::null:
5744 } 13128 case value_t::string:
5745 case value_t::string: 13129 case value_t::boolean:
5746 { 13130 case value_t::number_integer:
5747 return *lhs.m_value.string < *rhs.m_value.string; 13131 case value_t::number_unsigned:
5748 } 13132 case value_t::number_float:
5749 case value_t::boolean: 13133 case value_t::binary:
5750 { 13134 case value_t::discarded:
5751 return lhs.m_value.boolean < rhs.m_value.boolean; 13135 default:
5752 } 13136 {
5753 case value_t::number_integer: 13137 m_it.primitive_iterator.set_end();
5754 { 13138 break;
5755 return lhs.m_value.number_integer < rhs.m_value.number_integer; 13139 }
5756 } 13140 }
5757 case value_t::number_unsigned: 13141 }
5758 { 13142
5759 return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; 13143 public:
5760 } 13144 /*!
5761 case value_t::number_float: 13145 @brief return a reference to the value pointed to by the iterator
13146 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13147 */
13148 reference operator*() const
13149 {
13150 JSON_ASSERT(m_object != nullptr);
13151
13152 switch (m_object->m_data.m_type)
13153 {
13154 case value_t::object:
13155 {
13156 JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());
13157 return m_it.object_iterator->second;
13158 }
13159
13160 case value_t::array:
13161 {
13162 JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
13163 return *m_it.array_iterator;
13164 }
13165
13166 case value_t::null:
13167 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
13168
13169 case value_t::string:
13170 case value_t::boolean:
13171 case value_t::number_integer:
13172 case value_t::number_unsigned:
13173 case value_t::number_float:
13174 case value_t::binary:
13175 case value_t::discarded:
13176 default:
13177 {
13178 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
5762 { 13179 {
5763 return lhs.m_value.number_float < rhs.m_value.number_float; 13180 return *m_object;
5764 } 13181 }
5765 default: 13182
13183 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
13184 }
13185 }
13186 }
13187
13188 /*!
13189 @brief dereference the iterator
13190 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13191 */
13192 pointer operator->() const
13193 {
13194 JSON_ASSERT(m_object != nullptr);
13195
13196 switch (m_object->m_data.m_type)
13197 {
13198 case value_t::object:
13199 {
13200 JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());
13201 return &(m_it.object_iterator->second);
13202 }
13203
13204 case value_t::array:
13205 {
13206 JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
13207 return &*m_it.array_iterator;
13208 }
13209
13210 case value_t::null:
13211 case value_t::string:
13212 case value_t::boolean:
13213 case value_t::number_integer:
13214 case value_t::number_unsigned:
13215 case value_t::number_float:
13216 case value_t::binary:
13217 case value_t::discarded:
13218 default:
13219 {
13220 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
5766 { 13221 {
5767 return false; 13222 return m_object;
5768 } 13223 }
13224
13225 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
5769 } 13226 }
5770 } 13227 }
5771 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) 13228 }
13229
13230 /*!
13231 @brief post-increment (it++)
13232 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13233 */
13234 iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp)
13235 {
13236 auto result = *this;
13237 ++(*this);
13238 return result;
13239 }
13240
13241 /*!
13242 @brief pre-increment (++it)
13243 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13244 */
13245 iter_impl& operator++()
13246 {
13247 JSON_ASSERT(m_object != nullptr);
13248
13249 switch (m_object->m_data.m_type)
5772 { 13250 {
5773 return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float; 13251 case value_t::object:
13252 {
13253 std::advance(m_it.object_iterator, 1);
13254 break;
13255 }
13256
13257 case value_t::array:
13258 {
13259 std::advance(m_it.array_iterator, 1);
13260 break;
13261 }
13262
13263 case value_t::null:
13264 case value_t::string:
13265 case value_t::boolean:
13266 case value_t::number_integer:
13267 case value_t::number_unsigned:
13268 case value_t::number_float:
13269 case value_t::binary:
13270 case value_t::discarded:
13271 default:
13272 {
13273 ++m_it.primitive_iterator;
13274 break;
13275 }
5774 } 13276 }
5775 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) 13277
13278 return *this;
13279 }
13280
13281 /*!
13282 @brief post-decrement (it--)
13283 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13284 */
13285 iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp)
13286 {
13287 auto result = *this;
13288 --(*this);
13289 return result;
13290 }
13291
13292 /*!
13293 @brief pre-decrement (--it)
13294 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13295 */
13296 iter_impl& operator--()
13297 {
13298 JSON_ASSERT(m_object != nullptr);
13299
13300 switch (m_object->m_data.m_type)
5776 { 13301 {
5777 return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer); 13302 case value_t::object:
13303 {
13304 std::advance(m_it.object_iterator, -1);
13305 break;
13306 }
13307
13308 case value_t::array:
13309 {
13310 std::advance(m_it.array_iterator, -1);
13311 break;
13312 }
13313
13314 case value_t::null:
13315 case value_t::string:
13316 case value_t::boolean:
13317 case value_t::number_integer:
13318 case value_t::number_unsigned:
13319 case value_t::number_float:
13320 case value_t::binary:
13321 case value_t::discarded:
13322 default:
13323 {
13324 --m_it.primitive_iterator;
13325 break;
13326 }
5778 } 13327 }
5779 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) 13328
13329 return *this;
13330 }
13331
13332 /*!
13333 @brief comparison: equal
13334 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13335 */
13336 template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
13337 bool operator==(const IterImpl& other) const
13338 {
13339 // if objects are not the same, the comparison is undefined
13340 if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
5780 { 13341 {
5781 return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float; 13342 JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
5782 } 13343 }
5783 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) 13344
13345 JSON_ASSERT(m_object != nullptr);
13346
13347 switch (m_object->m_data.m_type)
5784 { 13348 {
5785 return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned); 13349 case value_t::object:
13350 return (m_it.object_iterator == other.m_it.object_iterator);
13351
13352 case value_t::array:
13353 return (m_it.array_iterator == other.m_it.array_iterator);
13354
13355 case value_t::null:
13356 case value_t::string:
13357 case value_t::boolean:
13358 case value_t::number_integer:
13359 case value_t::number_unsigned:
13360 case value_t::number_float:
13361 case value_t::binary:
13362 case value_t::discarded:
13363 default:
13364 return (m_it.primitive_iterator == other.m_it.primitive_iterator);
5786 } 13365 }
5787 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) 13366 }
13367
13368 /*!
13369 @brief comparison: not equal
13370 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13371 */
13372 template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
13373 bool operator!=(const IterImpl& other) const
13374 {
13375 return !operator==(other);
13376 }
13377
13378 /*!
13379 @brief comparison: smaller
13380 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13381 */
13382 bool operator<(const iter_impl& other) const
13383 {
13384 // if objects are not the same, the comparison is undefined
13385 if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
5788 { 13386 {
5789 return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned); 13387 JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
5790 } 13388 }
5791 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) 13389
13390 JSON_ASSERT(m_object != nullptr);
13391
13392 switch (m_object->m_data.m_type)
5792 { 13393 {
5793 return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; 13394 case value_t::object:
5794 } 13395 JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object));
5795 13396
5796 // We only reach this line if we cannot compare values. In that case, 13397 case value_t::array:
5797 // we compare types. Note we have to call the operator explicitly, 13398 return (m_it.array_iterator < other.m_it.array_iterator);
5798 // because MSVC has problems otherwise. 13399
5799 return operator<(lhs_type, rhs_type); 13400 case value_t::null:
13401 case value_t::string:
13402 case value_t::boolean:
13403 case value_t::number_integer:
13404 case value_t::number_unsigned:
13405 case value_t::number_float:
13406 case value_t::binary:
13407 case value_t::discarded:
13408 default:
13409 return (m_it.primitive_iterator < other.m_it.primitive_iterator);
13410 }
5800 } 13411 }
5801 13412
5802 /*! 13413 /*!
5803 @brief comparison: less than or equal 13414 @brief comparison: less than or equal
13415 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13416 */
13417 bool operator<=(const iter_impl& other) const
13418 {
13419 return !other.operator < (*this);
13420 }
13421
13422 /*!
13423 @brief comparison: greater than
13424 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13425 */
13426 bool operator>(const iter_impl& other) const
13427 {
13428 return !operator<=(other);
13429 }
13430
13431 /*!
13432 @brief comparison: greater than or equal
13433 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13434 */
13435 bool operator>=(const iter_impl& other) const
13436 {
13437 return !operator<(other);
13438 }
13439
13440 /*!
13441 @brief add to iterator
13442 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13443 */
13444 iter_impl& operator+=(difference_type i)
13445 {
13446 JSON_ASSERT(m_object != nullptr);
5804 13447
5805 Compares whether one JSON value @a lhs is less than or equal to another 13448 switch (m_object->m_data.m_type)
5806 JSON value by calculating `not (rhs < lhs)`. 13449 {
13450 case value_t::object:
13451 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
5807 13452
5808 @param[in] lhs first JSON value to consider 13453 case value_t::array:
5809 @param[in] rhs second JSON value to consider 13454 {
5810 @return whether @a lhs is less than or equal to @a rhs 13455 std::advance(m_it.array_iterator, i);
13456 break;
13457 }
5811 13458
5812 @complexity Linear. 13459 case value_t::null:
13460 case value_t::string:
13461 case value_t::boolean:
13462 case value_t::number_integer:
13463 case value_t::number_unsigned:
13464 case value_t::number_float:
13465 case value_t::binary:
13466 case value_t::discarded:
13467 default:
13468 {
13469 m_it.primitive_iterator += i;
13470 break;
13471 }
13472 }
5813 13473
5814 @liveexample{The example demonstrates comparing several JSON 13474 return *this;
5815 types.,operator__greater} 13475 }
5816 13476
5817 @since version 1.0.0 13477 /*!
13478 @brief subtract from iterator
13479 @pre The iterator is initialized; i.e. `m_object != nullptr`.
5818 */ 13480 */
5819 friend bool operator<=(const_reference lhs, const_reference rhs) noexcept 13481 iter_impl& operator-=(difference_type i)
5820 { 13482 {
5821 return not (rhs < lhs); 13483 return operator+=(-i);
5822 } 13484 }
5823 13485
5824 /*! 13486 /*!
5825 @brief comparison: greater than 13487 @brief add to iterator
5826 13488 @pre The iterator is initialized; i.e. `m_object != nullptr`.
5827 Compares whether one JSON value @a lhs is greater than another 13489 */
5828 JSON value by calculating `not (lhs <= rhs)`. 13490 iter_impl operator+(difference_type i) const
5829 13491 {
5830 @param[in] lhs first JSON value to consider 13492 auto result = *this;
5831 @param[in] rhs second JSON value to consider 13493 result += i;
5832 @return whether @a lhs is greater than to @a rhs 13494 return result;
13495 }
5833 13496
5834 @complexity Linear. 13497 /*!
13498 @brief addition of distance and iterator
13499 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13500 */
13501 friend iter_impl operator+(difference_type i, const iter_impl& it)
13502 {
13503 auto result = it;
13504 result += i;
13505 return result;
13506 }
5835 13507
5836 @liveexample{The example demonstrates comparing several JSON 13508 /*!
5837 types.,operator__lessequal} 13509 @brief subtract from iterator
13510 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13511 */
13512 iter_impl operator-(difference_type i) const
13513 {
13514 auto result = *this;
13515 result -= i;
13516 return result;
13517 }
5838 13518
5839 @since version 1.0.0 13519 /*!
13520 @brief return difference
13521 @pre The iterator is initialized; i.e. `m_object != nullptr`.
5840 */ 13522 */
5841 friend bool operator>(const_reference lhs, const_reference rhs) noexcept 13523 difference_type operator-(const iter_impl& other) const
5842 { 13524 {
5843 return not (lhs <= rhs); 13525 JSON_ASSERT(m_object != nullptr);
13526
13527 switch (m_object->m_data.m_type)
13528 {
13529 case value_t::object:
13530 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
13531
13532 case value_t::array:
13533 return m_it.array_iterator - other.m_it.array_iterator;
13534
13535 case value_t::null:
13536 case value_t::string:
13537 case value_t::boolean:
13538 case value_t::number_integer:
13539 case value_t::number_unsigned:
13540 case value_t::number_float:
13541 case value_t::binary:
13542 case value_t::discarded:
13543 default:
13544 return m_it.primitive_iterator - other.m_it.primitive_iterator;
13545 }
5844 } 13546 }
5845 13547
5846 /*! 13548 /*!
5847 @brief comparison: greater than or equal 13549 @brief access to successor
13550 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13551 */
13552 reference operator[](difference_type n) const
13553 {
13554 JSON_ASSERT(m_object != nullptr);
5848 13555
5849 Compares whether one JSON value @a lhs is greater than or equal to another 13556 switch (m_object->m_data.m_type)
5850 JSON value by calculating `not (lhs < rhs)`. 13557 {
13558 case value_t::object:
13559 JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object));
5851 13560
5852 @param[in] lhs first JSON value to consider 13561 case value_t::array:
5853 @param[in] rhs second JSON value to consider 13562 return *std::next(m_it.array_iterator, n);
5854 @return whether @a lhs is greater than or equal to @a rhs
5855 13563
5856 @complexity Linear. 13564 case value_t::null:
13565 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
5857 13566
5858 @liveexample{The example demonstrates comparing several JSON 13567 case value_t::string:
5859 types.,operator__greaterequal} 13568 case value_t::boolean:
13569 case value_t::number_integer:
13570 case value_t::number_unsigned:
13571 case value_t::number_float:
13572 case value_t::binary:
13573 case value_t::discarded:
13574 default:
13575 {
13576 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n))
13577 {
13578 return *m_object;
13579 }
5860 13580
5861 @since version 1.0.0 13581 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
13582 }
13583 }
13584 }
13585
13586 /*!
13587 @brief return the key of an object iterator
13588 @pre The iterator is initialized; i.e. `m_object != nullptr`.
5862 */ 13589 */
5863 friend bool operator>=(const_reference lhs, const_reference rhs) noexcept 13590 const typename object_t::key_type& key() const
5864 { 13591 {
5865 return not (lhs < rhs); 13592 JSON_ASSERT(m_object != nullptr);
13593
13594 if (JSON_HEDLEY_LIKELY(m_object->is_object()))
13595 {
13596 return m_it.object_iterator->first;
13597 }
13598
13599 JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object));
5866 } 13600 }
5867 13601
5868 /// @} 13602 /*!
13603 @brief return the value of an iterator
13604 @pre The iterator is initialized; i.e. `m_object != nullptr`.
13605 */
13606 reference value() const
13607 {
13608 return operator*();
13609 }
5869 13610
13611 JSON_PRIVATE_UNLESS_TESTED:
13612 /// associated JSON instance
13613 pointer m_object = nullptr;
13614 /// the actual iterator of the associated instance
13615 internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {};
13616};
5870 13617
5871 /////////////////// 13618} // namespace detail
5872 // serialization // 13619NLOHMANN_JSON_NAMESPACE_END
5873 ///////////////////
5874 13620
5875 /// @name serialization 13621// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
5876 /// @{
5877 13622
5878 /*! 13623// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
5879 @brief serialize to stream 13624// __ _____ _____ _____
13625// __| | __| | | | JSON for Modern C++
13626// | | |__ | | | | | | version 3.11.3
13627// |_____|_____|_____|_|___| https://github.com/nlohmann/json
13628//
13629// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
13630// SPDX-License-Identifier: MIT
5880 13631
5881 Serialize the given JSON value @a j to the output stream @a o. The JSON
5882 value will be serialized using the @ref dump member function. The
5883 indentation of the output can be controlled with the member variable
5884 `width` of the output stream @a o. For instance, using the manipulator
5885 `std::setw(4)` on @a o sets the indentation level to `4` and the
5886 serialization result is the same as calling `dump(4)`.
5887 13632
5888 @note During serializaion, the locale and the precision of the output
5889 stream @a o are changed. The original values are restored when the
5890 function returns.
5891 13633
5892 @param[in,out] o stream to serialize to 13634#include <cstddef> // ptrdiff_t
5893 @param[in] j JSON value to serialize 13635#include <iterator> // reverse_iterator
13636#include <utility> // declval
5894 13637
5895 @return the stream @a o 13638// #include <nlohmann/detail/abi_macros.hpp>
5896 13639
5897 @complexity Linear.
5898 13640
5899 @liveexample{The example below shows the serialization with different 13641NLOHMANN_JSON_NAMESPACE_BEGIN
5900 parameters to `width` to adjust the indentation level.,operator_serialize} 13642namespace detail
13643{
5901 13644
5902 @since version 1.0.0 13645//////////////////////
5903 */ 13646// reverse_iterator //
5904 friend std::ostream& operator<<(std::ostream& o, const basic_json& j) 13647//////////////////////
13648
13649/*!
13650@brief a template for a reverse iterator class
13651
13652@tparam Base the base iterator type to reverse. Valid types are @ref
13653iterator (to create @ref reverse_iterator) and @ref const_iterator (to
13654create @ref const_reverse_iterator).
13655
13656@requirement The class satisfies the following concept requirements:
13657-
13658[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
13659 The iterator that can be moved can be moved in both directions (i.e.
13660 incremented and decremented).
13661- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):
13662 It is possible to write to the pointed-to element (only if @a Base is
13663 @ref iterator).
13664
13665@since version 1.0.0
13666*/
13667template<typename Base>
13668class json_reverse_iterator : public std::reverse_iterator<Base>
13669{
13670 public:
13671 using difference_type = std::ptrdiff_t;
13672 /// shortcut to the reverse iterator adapter
13673 using base_iterator = std::reverse_iterator<Base>;
13674 /// the reference type for the pointed-to element
13675 using reference = typename Base::reference;
13676
13677 /// create reverse iterator from iterator
13678 explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
13679 : base_iterator(it) {}
13680
13681 /// create reverse iterator from base class
13682 explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}
13683
13684 /// post-increment (it++)
13685 json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp)
5905 { 13686 {
5906 // read width member and use it as indentation parameter if nonzero 13687 return static_cast<json_reverse_iterator>(base_iterator::operator++(1));
5907 const bool pretty_print = (o.width() > 0); 13688 }
5908 const auto indentation = (pretty_print ? o.width() : 0);
5909 13689
5910 // reset width to 0 for subsequent calls to this stream 13690 /// pre-increment (++it)
5911 o.width(0); 13691 json_reverse_iterator& operator++()
13692 {
13693 return static_cast<json_reverse_iterator&>(base_iterator::operator++());
13694 }
5912 13695
5913 // fix locale problems 13696 /// post-decrement (it--)
5914 const auto old_locale = o.imbue(std::locale::classic()); 13697 json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp)
5915 // set precision 13698 {
13699 return static_cast<json_reverse_iterator>(base_iterator::operator--(1));
13700 }
5916 13701
5917 // 6, 15 or 16 digits of precision allows round-trip IEEE 754 13702 /// pre-decrement (--it)
5918 // string->float->string, string->double->string or string->long 13703 json_reverse_iterator& operator--()
5919 // double->string; to be safe, we read this value from 13704 {
5920 // std::numeric_limits<number_float_t>::digits10 13705 return static_cast<json_reverse_iterator&>(base_iterator::operator--());
5921 const auto old_precision = o.precision(std::numeric_limits<double>::digits10); 13706 }
5922 13707
5923 // do the actual serialization 13708 /// add to iterator
5924 j.dump(o, pretty_print, static_cast<unsigned int>(indentation)); 13709 json_reverse_iterator& operator+=(difference_type i)
13710 {
13711 return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));
13712 }
5925 13713
5926 // reset locale and precision 13714 /// add to iterator
5927 o.imbue(old_locale); 13715 json_reverse_iterator operator+(difference_type i) const
5928 o.precision(old_precision); 13716 {
5929 return o; 13717 return static_cast<json_reverse_iterator>(base_iterator::operator+(i));
5930 } 13718 }
5931 13719
5932 /*! 13720 /// subtract from iterator
5933 @brief serialize to stream 13721 json_reverse_iterator operator-(difference_type i) const
5934 @copydoc operator<<(std::ostream&, const basic_json&)
5935 */
5936 friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
5937 { 13722 {
5938 return o << j; 13723 return static_cast<json_reverse_iterator>(base_iterator::operator-(i));
5939 } 13724 }
5940 13725
5941 /// @} 13726 /// return difference
13727 difference_type operator-(const json_reverse_iterator& other) const
13728 {
13729 return base_iterator(*this) - base_iterator(other);
13730 }
5942 13731
13732 /// access to successor
13733 reference operator[](difference_type n) const
13734 {
13735 return *(this->operator+(n));
13736 }
5943 13737
5944 ///////////////////// 13738 /// return the key of an object iterator
5945 // deserialization // 13739 auto key() const -> decltype(std::declval<Base>().key())
5946 ///////////////////// 13740 {
13741 auto it = --this->base();
13742 return it.key();
13743 }
5947 13744
5948 /// @name deserialization 13745 /// return the value of an iterator
5949 /// @{ 13746 reference value() const
13747 {
13748 auto it = --this->base();
13749 return it.operator * ();
13750 }
13751};
5950 13752
5951 /*! 13753} // namespace detail
5952 @brief deserialize from an array 13754NLOHMANN_JSON_NAMESPACE_END
5953 13755
5954 This function reads from an array of 1-byte values. 13756// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
5955 13757
5956 @pre Each element of the container has a size of 1 byte. Violating this 13758// #include <nlohmann/detail/json_custom_base_class.hpp>
5957 precondition yields undefined behavior. **This precondition is enforced 13759// __ _____ _____ _____
5958 with a static assertion.** 13760// __| | __| | | | JSON for Modern C++
13761// | | |__ | | | | | | version 3.11.3
13762// |_____|_____|_____|_|___| https://github.com/nlohmann/json
13763//
13764// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
13765// SPDX-License-Identifier: MIT
5959 13766
5960 @param[in] array array to read from
5961 @param[in] cb a parser callback function of type @ref parser_callback_t
5962 which is used to control the deserialization by filtering unwanted values
5963 (optional)
5964 13767
5965 @return result of the deserialization
5966 13768
5967 @complexity Linear in the length of the input. The parser is a predictive 13769#include <type_traits> // conditional, is_same
5968 LL(1) parser. The complexity can be higher if the parser callback function
5969 @a cb has a super-linear complexity.
5970 13770
5971 @note A UTF-8 byte order mark is silently ignored. 13771// #include <nlohmann/detail/abi_macros.hpp>
5972 13772
5973 @liveexample{The example below demonstrates the `parse()` function reading
5974 from an array.,parse__array__parser_callback_t}
5975 13773
5976 @since version 2.0.3 13774NLOHMANN_JSON_NAMESPACE_BEGIN
5977 */ 13775namespace detail
5978 template<class T, std::size_t N> 13776{
5979 static basic_json parse(T (&array)[N], 13777
5980 const parser_callback_t cb = nullptr) 13778/*!
13779@brief Default base class of the @ref basic_json class.
13780
13781So that the correct implementations of the copy / move ctors / assign operators
13782of @ref basic_json do not require complex case distinctions
13783(no base class / custom base class used as customization point),
13784@ref basic_json always has a base class.
13785By default, this class is used because it is empty and thus has no effect
13786on the behavior of @ref basic_json.
13787*/
13788struct json_default_base {};
13789
13790template<class T>
13791using json_base_class = typename std::conditional <
13792 std::is_same<T, void>::value,
13793 json_default_base,
13794 T
13795 >::type;
13796
13797} // namespace detail
13798NLOHMANN_JSON_NAMESPACE_END
13799
13800// #include <nlohmann/detail/json_pointer.hpp>
13801// __ _____ _____ _____
13802// __| | __| | | | JSON for Modern C++
13803// | | |__ | | | | | | version 3.11.3
13804// |_____|_____|_____|_|___| https://github.com/nlohmann/json
13805//
13806// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
13807// SPDX-License-Identifier: MIT
13808
13809
13810
13811#include <algorithm> // all_of
13812#include <cctype> // isdigit
13813#include <cerrno> // errno, ERANGE
13814#include <cstdlib> // strtoull
13815#ifndef JSON_NO_IO
13816 #include <iosfwd> // ostream
13817#endif // JSON_NO_IO
13818#include <limits> // max
13819#include <numeric> // accumulate
13820#include <string> // string
13821#include <utility> // move
13822#include <vector> // vector
13823
13824// #include <nlohmann/detail/exceptions.hpp>
13825
13826// #include <nlohmann/detail/macro_scope.hpp>
13827
13828// #include <nlohmann/detail/string_concat.hpp>
13829
13830// #include <nlohmann/detail/string_escape.hpp>
13831
13832// #include <nlohmann/detail/value_t.hpp>
13833
13834
13835NLOHMANN_JSON_NAMESPACE_BEGIN
13836
13837/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
13838/// @sa https://json.nlohmann.me/api/json_pointer/
13839template<typename RefStringType>
13840class json_pointer
13841{
13842 // allow basic_json to access private members
13843 NLOHMANN_BASIC_JSON_TPL_DECLARATION
13844 friend class basic_json;
13845
13846 template<typename>
13847 friend class json_pointer;
13848
13849 template<typename T>
13850 struct string_t_helper
13851 {
13852 using type = T;
13853 };
13854
13855 NLOHMANN_BASIC_JSON_TPL_DECLARATION
13856 struct string_t_helper<NLOHMANN_BASIC_JSON_TPL>
13857 {
13858 using type = StringType;
13859 };
13860
13861 public:
13862 // for backwards compatibility accept BasicJsonType
13863 using string_t = typename string_t_helper<RefStringType>::type;
13864
13865 /// @brief create JSON pointer
13866 /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/
13867 explicit json_pointer(const string_t& s = "")
13868 : reference_tokens(split(s))
13869 {}
13870
13871 /// @brief return a string representation of the JSON pointer
13872 /// @sa https://json.nlohmann.me/api/json_pointer/to_string/
13873 string_t to_string() const
5981 { 13874 {
5982 // delegate the call to the iterator-range parse overload 13875 return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
5983 return parse(std::begin(array), std::end(array), cb); 13876 string_t{},
13877 [](const string_t& a, const string_t& b)
13878 {
13879 return detail::concat(a, '/', detail::escape(b));
13880 });
5984 } 13881 }
5985 13882
5986 /*! 13883 /// @brief return a string representation of the JSON pointer
5987 @brief deserialize from string literal 13884 /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/
13885 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string())
13886 operator string_t() const
13887 {
13888 return to_string();
13889 }
5988 13890
5989 @tparam CharT character/literal type with size of 1 byte 13891#ifndef JSON_NO_IO
5990 @param[in] s string literal to read a serialized JSON value from 13892 /// @brief write string representation of the JSON pointer to stream
5991 @param[in] cb a parser callback function of type @ref parser_callback_t 13893 /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
5992 which is used to control the deserialization by filtering unwanted values 13894 friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr)
5993 (optional) 13895 {
13896 o << ptr.to_string();
13897 return o;
13898 }
13899#endif
5994 13900
5995 @return result of the deserialization 13901 /// @brief append another JSON pointer at the end of this JSON pointer
13902 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
13903 json_pointer& operator/=(const json_pointer& ptr)
13904 {
13905 reference_tokens.insert(reference_tokens.end(),
13906 ptr.reference_tokens.begin(),
13907 ptr.reference_tokens.end());
13908 return *this;
13909 }
5996 13910
5997 @complexity Linear in the length of the input. The parser is a predictive 13911 /// @brief append an unescaped reference token at the end of this JSON pointer
5998 LL(1) parser. The complexity can be higher if the parser callback function 13912 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
5999 @a cb has a super-linear complexity. 13913 json_pointer& operator/=(string_t token)
13914 {
13915 push_back(std::move(token));
13916 return *this;
13917 }
6000 13918
6001 @note A UTF-8 byte order mark is silently ignored. 13919 /// @brief append an array index at the end of this JSON pointer
6002 @note String containers like `std::string` or @ref string_t can be parsed 13920 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/
6003 with @ref parse(const ContiguousContainer&, const parser_callback_t) 13921 json_pointer& operator/=(std::size_t array_idx)
13922 {
13923 return *this /= std::to_string(array_idx);
13924 }
6004 13925
6005 @liveexample{The example below demonstrates the `parse()` function with 13926 /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
6006 and without callback function.,parse__string__parser_callback_t} 13927 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
13928 friend json_pointer operator/(const json_pointer& lhs,
13929 const json_pointer& rhs)
13930 {
13931 return json_pointer(lhs) /= rhs;
13932 }
6007 13933
6008 @sa @ref parse(std::istream&, const parser_callback_t) for a version that 13934 /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
6009 reads from an input stream 13935 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
13936 friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param)
13937 {
13938 return json_pointer(lhs) /= std::move(token);
13939 }
6010 13940
6011 @since version 1.0.0 (originally for @ref string_t) 13941 /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
6012 */ 13942 /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
6013 template<typename CharT, typename std::enable_if< 13943 friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx)
6014 std::is_pointer<CharT>::value and
6015 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
6016 sizeof(typename std::remove_pointer<CharT>::type) == 1, int>::type = 0>
6017 static basic_json parse(const CharT s,
6018 const parser_callback_t cb = nullptr)
6019 { 13944 {
6020 return parser(reinterpret_cast<const char*>(s), cb).parse(); 13945 return json_pointer(lhs) /= array_idx;
6021 } 13946 }
6022 13947
6023 /*! 13948 /// @brief returns the parent of this JSON pointer
6024 @brief deserialize from stream 13949 /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/
13950 json_pointer parent_pointer() const
13951 {
13952 if (empty())
13953 {
13954 return *this;
13955 }
6025 13956
6026 @param[in,out] i stream to read a serialized JSON value from 13957 json_pointer res = *this;
6027 @param[in] cb a parser callback function of type @ref parser_callback_t 13958 res.pop_back();
6028 which is used to control the deserialization by filtering unwanted values 13959 return res;
6029 (optional) 13960 }
6030 13961
6031 @return result of the deserialization 13962 /// @brief remove last reference token
13963 /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/
13964 void pop_back()
13965 {
13966 if (JSON_HEDLEY_UNLIKELY(empty()))
13967 {
13968 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
13969 }
6032 13970
6033 @complexity Linear in the length of the input. The parser is a predictive 13971 reference_tokens.pop_back();
6034 LL(1) parser. The complexity can be higher if the parser callback function 13972 }
6035 @a cb has a super-linear complexity.
6036 13973
6037 @note A UTF-8 byte order mark is silently ignored. 13974 /// @brief return last reference token
13975 /// @sa https://json.nlohmann.me/api/json_pointer/back/
13976 const string_t& back() const
13977 {
13978 if (JSON_HEDLEY_UNLIKELY(empty()))
13979 {
13980 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
13981 }
6038 13982
6039 @liveexample{The example below demonstrates the `parse()` function with 13983 return reference_tokens.back();
6040 and without callback function.,parse__istream__parser_callback_t} 13984 }
6041 13985
6042 @sa @ref parse(const CharT, const parser_callback_t) for a version 13986 /// @brief append an unescaped token at the end of the reference pointer
6043 that reads from a string 13987 /// @sa https://json.nlohmann.me/api/json_pointer/push_back/
13988 void push_back(const string_t& token)
13989 {
13990 reference_tokens.push_back(token);
13991 }
6044 13992
6045 @since version 1.0.0 13993 /// @brief append an unescaped token at the end of the reference pointer
6046 */ 13994 /// @sa https://json.nlohmann.me/api/json_pointer/push_back/
6047 static basic_json parse(std::istream& i, 13995 void push_back(string_t&& token)
6048 const parser_callback_t cb = nullptr)
6049 { 13996 {
6050 return parser(i, cb).parse(); 13997 reference_tokens.push_back(std::move(token));
6051 } 13998 }
6052 13999
6053 /*! 14000 /// @brief return whether pointer points to the root document
6054 @copydoc parse(std::istream&, const parser_callback_t) 14001 /// @sa https://json.nlohmann.me/api/json_pointer/empty/
6055 */ 14002 bool empty() const noexcept
6056 static basic_json parse(std::istream&& i,
6057 const parser_callback_t cb = nullptr)
6058 { 14003 {
6059 return parser(i, cb).parse(); 14004 return reference_tokens.empty();
6060 } 14005 }
6061 14006
14007 private:
6062 /*! 14008 /*!
6063 @brief deserialize from an iterator range with contiguous storage 14009 @param[in] s reference token to be converted into an array index
6064 14010
6065 This function reads from an iterator range of a container with contiguous 14011 @return integer representation of @a s
6066 storage of 1-byte values. Compatible container types include
6067 `std::vector`, `std::string`, `std::array`, `std::valarray`, and
6068 `std::initializer_list`. Furthermore, C-style arrays can be used with
6069 `std::begin()`/`std::end()`. User-defined containers can be used as long
6070 as they implement random-access iterators and a contiguous storage.
6071 14012
6072 @pre The iterator range is contiguous. Violating this precondition yields 14013 @throw parse_error.106 if an array index begins with '0'
6073 undefined behavior. **This precondition is enforced with an assertion.** 14014 @throw parse_error.109 if an array index begins not with a digit
6074 @pre Each element in the range has a size of 1 byte. Violating this 14015 @throw out_of_range.404 if string @a s could not be converted to an integer
6075 precondition yields undefined behavior. **This precondition is enforced 14016 @throw out_of_range.410 if an array index exceeds size_type
6076 with a static assertion.** 14017 */
14018 template<typename BasicJsonType>
14019 static typename BasicJsonType::size_type array_index(const string_t& s)
14020 {
14021 using size_type = typename BasicJsonType::size_type;
6077 14022
6078 @warning There is no way to enforce all preconditions at compile-time. If 14023 // error condition (cf. RFC 6901, Sect. 4)
6079 the function is called with noncompliant iterators and with 14024 if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))
6080 assertions switched off, the behavior is undefined and will most 14025 {
6081 likely yield segmentation violation. 14026 JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
14027 }
6082 14028
6083 @tparam IteratorType iterator of container with contiguous storage 14029 // error condition (cf. RFC 6901, Sect. 4)
6084 @param[in] first begin of the range to parse (included) 14030 if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
6085 @param[in] last end of the range to parse (excluded) 14031 {
6086 @param[in] cb a parser callback function of type @ref parser_callback_t 14032 JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
6087 which is used to control the deserialization by filtering unwanted values 14033 }
6088 (optional)
6089 14034
6090 @return result of the deserialization 14035 const char* p = s.c_str();
14036 char* p_end = nullptr;
14037 errno = 0; // strtoull doesn't reset errno
14038 const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
14039 if (p == p_end // invalid input or empty string
14040 || errno == ERANGE // out of range
14041 || JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read
14042 {
14043 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr));
14044 }
6091 14045
6092 @complexity Linear in the length of the input. The parser is a predictive 14046 // only triggered on special platforms (like 32bit), see also
6093 LL(1) parser. The complexity can be higher if the parser callback function 14047 // https://github.com/nlohmann/json/pull/2203
6094 @a cb has a super-linear complexity. 14048 if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)())) // NOLINT(runtime/int)
14049 {
14050 JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE
14051 }
6095 14052
6096 @note A UTF-8 byte order mark is silently ignored. 14053 return static_cast<size_type>(res);
14054 }
14055
14056 JSON_PRIVATE_UNLESS_TESTED:
14057 json_pointer top() const
14058 {
14059 if (JSON_HEDLEY_UNLIKELY(empty()))
14060 {
14061 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
14062 }
14063
14064 json_pointer result = *this;
14065 result.reference_tokens = {reference_tokens[0]};
14066 return result;
14067 }
14068
14069 private:
14070 /*!
14071 @brief create and return a reference to the pointed to value
6097 14072
6098 @liveexample{The example below demonstrates the `parse()` function reading 14073 @complexity Linear in the number of reference tokens.
6099 from an iterator range.,parse__iteratortype__parser_callback_t}
6100 14074
6101 @since version 2.0.3 14075 @throw parse_error.109 if array index is not a number
14076 @throw type_error.313 if value cannot be unflattened
6102 */ 14077 */
6103 template<class IteratorType, typename std::enable_if< 14078 template<typename BasicJsonType>
6104 std::is_base_of< 14079 BasicJsonType& get_and_create(BasicJsonType& j) const
6105 std::random_access_iterator_tag,
6106 typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
6107 static basic_json parse(IteratorType first, IteratorType last,
6108 const parser_callback_t cb = nullptr)
6109 { 14080 {
6110 // assertion to check that the iterator range is indeed contiguous, 14081 auto* result = &j;
6111 // see http://stackoverflow.com/a/35008842/266378 for more discussion 14082
6112 assert(std::accumulate(first, last, std::make_pair<bool, int>(true, 0), 14083 // in case no reference tokens exist, return a reference to the JSON value
6113 [&first](std::pair<bool, int> res, decltype(*first) val) 14084 // j which will be overwritten by a primitive value
14085 for (const auto& reference_token : reference_tokens)
6114 { 14086 {
6115 res.first &= (val == *(std::next(std::addressof(*first), res.second++))); 14087 switch (result->type())
6116 return res; 14088 {
6117 }).first); 14089 case detail::value_t::null:
14090 {
14091 if (reference_token == "0")
14092 {
14093 // start a new array if reference token is 0
14094 result = &result->operator[](0);
14095 }
14096 else
14097 {
14098 // start a new object otherwise
14099 result = &result->operator[](reference_token);
14100 }
14101 break;
14102 }
6118 14103
6119 // assertion to check that each element is 1 byte long 14104 case detail::value_t::object:
6120 static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1, 14105 {
6121 "each element in the iterator range must have the size of 1 byte"); 14106 // create an entry in the object
14107 result = &result->operator[](reference_token);
14108 break;
14109 }
6122 14110
6123 // if iterator range is empty, create a parser with an empty string 14111 case detail::value_t::array:
6124 // to generate "unexpected EOF" error message 14112 {
6125 if (std::distance(first, last) <= 0) 14113 // create an entry in the array
6126 { 14114 result = &result->operator[](array_index<BasicJsonType>(reference_token));
6127 return parser("").parse(); 14115 break;
14116 }
14117
14118 /*
14119 The following code is only reached if there exists a reference
14120 token _and_ the current value is primitive. In this case, we have
14121 an error situation, because primitive values may only occur as
14122 single value; that is, with an empty list of reference tokens.
14123 */
14124 case detail::value_t::string:
14125 case detail::value_t::boolean:
14126 case detail::value_t::number_integer:
14127 case detail::value_t::number_unsigned:
14128 case detail::value_t::number_float:
14129 case detail::value_t::binary:
14130 case detail::value_t::discarded:
14131 default:
14132 JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
14133 }
6128 } 14134 }
6129 14135
6130 return parser(first, last, cb).parse(); 14136 return *result;
6131 } 14137 }
6132 14138
6133 /*! 14139 /*!
6134 @brief deserialize from a container with contiguous storage 14140 @brief return a reference to the pointed to value
14141
14142 @note This version does not throw if a value is not present, but tries to
14143 create nested values instead. For instance, calling this function
14144 with pointer `"/this/that"` on a null value is equivalent to calling
14145 `operator[]("this").operator[]("that")` on that value, effectively
14146 changing the null value to an object.
14147
14148 @param[in] ptr a JSON value
6135 14149
6136 This function reads from a container with contiguous storage of 1-byte 14150 @return reference to the JSON value pointed to by the JSON pointer
6137 values. Compatible container types include `std::vector`, `std::string`,
6138 `std::array`, and `std::initializer_list`. User-defined containers can be
6139 used as long as they implement random-access iterators and a contiguous
6140 storage.
6141 14151
6142 @pre The container storage is contiguous. Violating this precondition 14152 @complexity Linear in the length of the JSON pointer.
6143 yields undefined behavior. **This precondition is enforced with an
6144 assertion.**
6145 @pre Each element of the container has a size of 1 byte. Violating this
6146 precondition yields undefined behavior. **This precondition is enforced
6147 with a static assertion.**
6148 14153
6149 @warning There is no way to enforce all preconditions at compile-time. If 14154 @throw parse_error.106 if an array index begins with '0'
6150 the function is called with a noncompliant container and with 14155 @throw parse_error.109 if an array index was not a number
6151 assertions switched off, the behavior is undefined and will most 14156 @throw out_of_range.404 if the JSON pointer can not be resolved
6152 likely yield segmentation violation. 14157 */
14158 template<typename BasicJsonType>
14159 BasicJsonType& get_unchecked(BasicJsonType* ptr) const
14160 {
14161 for (const auto& reference_token : reference_tokens)
14162 {
14163 // convert null values to arrays or objects before continuing
14164 if (ptr->is_null())
14165 {
14166 // check if reference token is a number
14167 const bool nums =
14168 std::all_of(reference_token.begin(), reference_token.end(),
14169 [](const unsigned char x)
14170 {
14171 return std::isdigit(x);
14172 });
6153 14173
6154 @tparam ContiguousContainer container type with contiguous storage 14174 // change value to array for numbers or "-" or to object otherwise
6155 @param[in] c container to read from 14175 *ptr = (nums || reference_token == "-")
6156 @param[in] cb a parser callback function of type @ref parser_callback_t 14176 ? detail::value_t::array
6157 which is used to control the deserialization by filtering unwanted values 14177 : detail::value_t::object;
6158 (optional) 14178 }
6159 14179
6160 @return result of the deserialization 14180 switch (ptr->type())
14181 {
14182 case detail::value_t::object:
14183 {
14184 // use unchecked object access
14185 ptr = &ptr->operator[](reference_token);
14186 break;
14187 }
6161 14188
6162 @complexity Linear in the length of the input. The parser is a predictive 14189 case detail::value_t::array:
6163 LL(1) parser. The complexity can be higher if the parser callback function 14190 {
6164 @a cb has a super-linear complexity. 14191 if (reference_token == "-")
14192 {
14193 // explicitly treat "-" as index beyond the end
14194 ptr = &ptr->operator[](ptr->m_data.m_value.array->size());
14195 }
14196 else
14197 {
14198 // convert array index to number; unchecked access
14199 ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
14200 }
14201 break;
14202 }
6165 14203
6166 @note A UTF-8 byte order mark is silently ignored. 14204 case detail::value_t::null:
14205 case detail::value_t::string:
14206 case detail::value_t::boolean:
14207 case detail::value_t::number_integer:
14208 case detail::value_t::number_unsigned:
14209 case detail::value_t::number_float:
14210 case detail::value_t::binary:
14211 case detail::value_t::discarded:
14212 default:
14213 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
14214 }
14215 }
6167 14216
6168 @liveexample{The example below demonstrates the `parse()` function reading 14217 return *ptr;
6169 from a contiguous container.,parse__contiguouscontainer__parser_callback_t} 14218 }
6170 14219
6171 @since version 2.0.3 14220 /*!
14221 @throw parse_error.106 if an array index begins with '0'
14222 @throw parse_error.109 if an array index was not a number
14223 @throw out_of_range.402 if the array index '-' is used
14224 @throw out_of_range.404 if the JSON pointer can not be resolved
6172 */ 14225 */
6173 template<class ContiguousContainer, typename std::enable_if< 14226 template<typename BasicJsonType>
6174 not std::is_pointer<ContiguousContainer>::value and 14227 BasicJsonType& get_checked(BasicJsonType* ptr) const
6175 std::is_base_of<
6176 std::random_access_iterator_tag,
6177 typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value
6178 , int>::type = 0>
6179 static basic_json parse(const ContiguousContainer& c,
6180 const parser_callback_t cb = nullptr)
6181 { 14228 {
6182 // delegate the call to the iterator-range parse overload 14229 for (const auto& reference_token : reference_tokens)
6183 return parse(std::begin(c), std::end(c), cb); 14230 {
14231 switch (ptr->type())
14232 {
14233 case detail::value_t::object:
14234 {
14235 // note: at performs range check
14236 ptr = &ptr->at(reference_token);
14237 break;
14238 }
14239
14240 case detail::value_t::array:
14241 {
14242 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
14243 {
14244 // "-" always fails the range check
14245 JSON_THROW(detail::out_of_range::create(402, detail::concat(
14246 "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
14247 ") is out of range"), ptr));
14248 }
14249
14250 // note: at performs range check
14251 ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
14252 break;
14253 }
14254
14255 case detail::value_t::null:
14256 case detail::value_t::string:
14257 case detail::value_t::boolean:
14258 case detail::value_t::number_integer:
14259 case detail::value_t::number_unsigned:
14260 case detail::value_t::number_float:
14261 case detail::value_t::binary:
14262 case detail::value_t::discarded:
14263 default:
14264 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
14265 }
14266 }
14267
14268 return *ptr;
6184 } 14269 }
6185 14270
6186 /*! 14271 /*!
6187 @brief deserialize from stream 14272 @brief return a const reference to the pointed to value
6188 14273
6189 Deserializes an input stream to a JSON value. 14274 @param[in] ptr a JSON value
6190 14275
6191 @param[in,out] i input stream to read a serialized JSON value from 14276 @return const reference to the JSON value pointed to by the JSON
6192 @param[in,out] j JSON value to write the deserialized input to 14277 pointer
6193 14278
6194 @throw std::invalid_argument in case of parse errors 14279 @throw parse_error.106 if an array index begins with '0'
14280 @throw parse_error.109 if an array index was not a number
14281 @throw out_of_range.402 if the array index '-' is used
14282 @throw out_of_range.404 if the JSON pointer can not be resolved
14283 */
14284 template<typename BasicJsonType>
14285 const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
14286 {
14287 for (const auto& reference_token : reference_tokens)
14288 {
14289 switch (ptr->type())
14290 {
14291 case detail::value_t::object:
14292 {
14293 // use unchecked object access
14294 ptr = &ptr->operator[](reference_token);
14295 break;
14296 }
6195 14297
6196 @complexity Linear in the length of the input. The parser is a predictive 14298 case detail::value_t::array:
6197 LL(1) parser. 14299 {
14300 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
14301 {
14302 // "-" cannot be used for const access
14303 JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr));
14304 }
6198 14305
6199 @note A UTF-8 byte order mark is silently ignored. 14306 // use unchecked array access
14307 ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
14308 break;
14309 }
6200 14310
6201 @liveexample{The example below shows how a JSON value is constructed by 14311 case detail::value_t::null:
6202 reading a serialization from a stream.,operator_deserialize} 14312 case detail::value_t::string:
14313 case detail::value_t::boolean:
14314 case detail::value_t::number_integer:
14315 case detail::value_t::number_unsigned:
14316 case detail::value_t::number_float:
14317 case detail::value_t::binary:
14318 case detail::value_t::discarded:
14319 default:
14320 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
14321 }
14322 }
6203 14323
6204 @sa parse(std::istream&, const parser_callback_t) for a variant with a 14324 return *ptr;
6205 parser callback function to filter values while parsing 14325 }
6206 14326
6207 @since version 1.0.0 14327 /*!
14328 @throw parse_error.106 if an array index begins with '0'
14329 @throw parse_error.109 if an array index was not a number
14330 @throw out_of_range.402 if the array index '-' is used
14331 @throw out_of_range.404 if the JSON pointer can not be resolved
6208 */ 14332 */
6209 friend std::istream& operator<<(basic_json& j, std::istream& i) 14333 template<typename BasicJsonType>
14334 const BasicJsonType& get_checked(const BasicJsonType* ptr) const
6210 { 14335 {
6211 j = parser(i).parse(); 14336 for (const auto& reference_token : reference_tokens)
6212 return i; 14337 {
14338 switch (ptr->type())
14339 {
14340 case detail::value_t::object:
14341 {
14342 // note: at performs range check
14343 ptr = &ptr->at(reference_token);
14344 break;
14345 }
14346
14347 case detail::value_t::array:
14348 {
14349 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
14350 {
14351 // "-" always fails the range check
14352 JSON_THROW(detail::out_of_range::create(402, detail::concat(
14353 "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
14354 ") is out of range"), ptr));
14355 }
14356
14357 // note: at performs range check
14358 ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
14359 break;
14360 }
14361
14362 case detail::value_t::null:
14363 case detail::value_t::string:
14364 case detail::value_t::boolean:
14365 case detail::value_t::number_integer:
14366 case detail::value_t::number_unsigned:
14367 case detail::value_t::number_float:
14368 case detail::value_t::binary:
14369 case detail::value_t::discarded:
14370 default:
14371 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
14372 }
14373 }
14374
14375 return *ptr;
6213 } 14376 }
6214 14377
6215 /*! 14378 /*!
6216 @brief deserialize from stream 14379 @throw parse_error.106 if an array index begins with '0'
6217 @copydoc operator<<(basic_json&, std::istream&) 14380 @throw parse_error.109 if an array index was not a number
6218 */ 14381 */
6219 friend std::istream& operator>>(std::istream& i, basic_json& j) 14382 template<typename BasicJsonType>
14383 bool contains(const BasicJsonType* ptr) const
6220 { 14384 {
6221 j = parser(i).parse(); 14385 for (const auto& reference_token : reference_tokens)
6222 return i; 14386 {
6223 } 14387 switch (ptr->type())
14388 {
14389 case detail::value_t::object:
14390 {
14391 if (!ptr->contains(reference_token))
14392 {
14393 // we did not find the key in the object
14394 return false;
14395 }
6224 14396
6225 /// @} 14397 ptr = &ptr->operator[](reference_token);
14398 break;
14399 }
6226 14400
6227 ////////////////////////////////////////// 14401 case detail::value_t::array:
6228 // binary serialization/deserialization // 14402 {
6229 ////////////////////////////////////////// 14403 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
14404 {
14405 // "-" always fails the range check
14406 return false;
14407 }
14408 if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
14409 {
14410 // invalid char
14411 return false;
14412 }
14413 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))
14414 {
14415 if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))
14416 {
14417 // first char should be between '1' and '9'
14418 return false;
14419 }
14420 for (std::size_t i = 1; i < reference_token.size(); i++)
14421 {
14422 if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))
14423 {
14424 // other char should be between '0' and '9'
14425 return false;
14426 }
14427 }
14428 }
6230 14429
6231 /// @name binary serialization/deserialization support 14430 const auto idx = array_index<BasicJsonType>(reference_token);
6232 /// @{ 14431 if (idx >= ptr->size())
14432 {
14433 // index out of range
14434 return false;
14435 }
6233 14436
6234 private: 14437 ptr = &ptr->operator[](idx);
6235 template<typename T> 14438 break;
6236 static void add_to_vector(std::vector<uint8_t>& vec, size_t bytes, const T number) 14439 }
14440
14441 case detail::value_t::null:
14442 case detail::value_t::string:
14443 case detail::value_t::boolean:
14444 case detail::value_t::number_integer:
14445 case detail::value_t::number_unsigned:
14446 case detail::value_t::number_float:
14447 case detail::value_t::binary:
14448 case detail::value_t::discarded:
14449 default:
14450 {
14451 // we do not expect primitive values if there is still a
14452 // reference token to process
14453 return false;
14454 }
14455 }
14456 }
14457
14458 // no reference token left means we found a primitive value
14459 return true;
14460 }
14461
14462 /*!
14463 @brief split the string input to reference tokens
14464
14465 @note This function is only called by the json_pointer constructor.
14466 All exceptions below are documented there.
14467
14468 @throw parse_error.107 if the pointer is not empty or begins with '/'
14469 @throw parse_error.108 if character '~' is not followed by '0' or '1'
14470 */
14471 static std::vector<string_t> split(const string_t& reference_string)
6237 { 14472 {
6238 assert(bytes == 1 or bytes == 2 or bytes == 4 or bytes == 8); 14473 std::vector<string_t> result;
14474
14475 // special case: empty reference string -> no reference tokens
14476 if (reference_string.empty())
14477 {
14478 return result;
14479 }
6239 14480
6240 switch (bytes) 14481 // check if nonempty reference string begins with slash
14482 if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
6241 { 14483 {
6242 case 8: 14484 JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr));
14485 }
14486
14487 // extract the reference tokens:
14488 // - slash: position of the last read slash (or end of string)
14489 // - start: position after the previous slash
14490 for (
14491 // search for the first slash after the first character
14492 std::size_t slash = reference_string.find_first_of('/', 1),
14493 // set the beginning of the first reference token
14494 start = 1;
14495 // we can stop if start == 0 (if slash == string_t::npos)
14496 start != 0;
14497 // set the beginning of the next reference token
14498 // (will eventually be 0 if slash == string_t::npos)
14499 start = (slash == string_t::npos) ? 0 : slash + 1,
14500 // find next slash
14501 slash = reference_string.find_first_of('/', start))
14502 {
14503 // use the text between the beginning of the reference token
14504 // (start) and the last slash (slash).
14505 auto reference_token = reference_string.substr(start, slash - start);
14506
14507 // check reference tokens are properly escaped
14508 for (std::size_t pos = reference_token.find_first_of('~');
14509 pos != string_t::npos;
14510 pos = reference_token.find_first_of('~', pos + 1))
6243 { 14511 {
6244 vec.push_back(static_cast<uint8_t>((number >> 070) & 0xff)); 14512 JSON_ASSERT(reference_token[pos] == '~');
6245 vec.push_back(static_cast<uint8_t>((number >> 060) & 0xff)); 14513
6246 vec.push_back(static_cast<uint8_t>((number >> 050) & 0xff)); 14514 // ~ must be followed by 0 or 1
6247 vec.push_back(static_cast<uint8_t>((number >> 040) & 0xff)); 14515 if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
6248 // intentional fall-through 14516 (reference_token[pos + 1] != '0' &&
14517 reference_token[pos + 1] != '1')))
14518 {
14519 JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr));
14520 }
6249 } 14521 }
6250 14522
6251 case 4: 14523 // finally, store the reference token
14524 detail::unescape(reference_token);
14525 result.push_back(reference_token);
14526 }
14527
14528 return result;
14529 }
14530
14531 private:
14532 /*!
14533 @param[in] reference_string the reference string to the current value
14534 @param[in] value the value to consider
14535 @param[in,out] result the result object to insert values to
14536
14537 @note Empty objects or arrays are flattened to `null`.
14538 */
14539 template<typename BasicJsonType>
14540 static void flatten(const string_t& reference_string,
14541 const BasicJsonType& value,
14542 BasicJsonType& result)
14543 {
14544 switch (value.type())
14545 {
14546 case detail::value_t::array:
6252 { 14547 {
6253 vec.push_back(static_cast<uint8_t>((number >> 030) & 0xff)); 14548 if (value.m_data.m_value.array->empty())
6254 vec.push_back(static_cast<uint8_t>((number >> 020) & 0xff)); 14549 {
6255 // intentional fall-through 14550 // flatten empty array as null
14551 result[reference_string] = nullptr;
14552 }
14553 else
14554 {
14555 // iterate array and use index as reference string
14556 for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i)
14557 {
14558 flatten(detail::concat(reference_string, '/', std::to_string(i)),
14559 value.m_data.m_value.array->operator[](i), result);
14560 }
14561 }
14562 break;
6256 } 14563 }
6257 14564
6258 case 2: 14565 case detail::value_t::object:
6259 { 14566 {
6260 vec.push_back(static_cast<uint8_t>((number >> 010) & 0xff)); 14567 if (value.m_data.m_value.object->empty())
6261 // intentional fall-through 14568 {
14569 // flatten empty object as null
14570 result[reference_string] = nullptr;
14571 }
14572 else
14573 {
14574 // iterate object and use keys as reference string
14575 for (const auto& element : *value.m_data.m_value.object)
14576 {
14577 flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result);
14578 }
14579 }
14580 break;
6262 } 14581 }
6263 14582
6264 case 1: 14583 case detail::value_t::null:
14584 case detail::value_t::string:
14585 case detail::value_t::boolean:
14586 case detail::value_t::number_integer:
14587 case detail::value_t::number_unsigned:
14588 case detail::value_t::number_float:
14589 case detail::value_t::binary:
14590 case detail::value_t::discarded:
14591 default:
6265 { 14592 {
6266 vec.push_back(static_cast<uint8_t>(number & 0xff)); 14593 // add primitive value with its reference string
14594 result[reference_string] = value;
6267 break; 14595 break;
6268 } 14596 }
6269 } 14597 }
6270 } 14598 }
6271 14599
6272 /*! 14600 /*!
6273 @brief take sufficient bytes from a vector to fill an integer variable 14601 @param[in] value flattened JSON
6274 14602
6275 In the context of binary serialization formats, we need to read several 14603 @return unflattened JSON
6276 bytes from a byte vector and combine them to multi-byte integral data
6277 types.
6278 14604
6279 @param[in] vec byte vector to read from 14605 @throw parse_error.109 if array index is not a number
6280 @param[in] current_index the position in the vector after which to read 14606 @throw type_error.314 if value is not an object
14607 @throw type_error.315 if object values are not primitive
14608 @throw type_error.313 if value cannot be unflattened
14609 */
14610 template<typename BasicJsonType>
14611 static BasicJsonType
14612 unflatten(const BasicJsonType& value)
14613 {
14614 if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
14615 {
14616 JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value));
14617 }
6281 14618
6282 @return the next sizeof(T) bytes from @a vec, in reverse order as T 14619 BasicJsonType result;
6283 14620
6284 @tparam T the integral return type 14621 // iterate the JSON object values
14622 for (const auto& element : *value.m_data.m_value.object)
14623 {
14624 if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
14625 {
14626 JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second));
14627 }
6285 14628
6286 @throw std::out_of_range if there are less than sizeof(T)+1 bytes in the 14629 // assign value to reference pointed to by JSON pointer; Note that if
6287 vector @a vec to read 14630 // the JSON pointer is "" (i.e., points to the whole value), function
14631 // get_and_create returns a reference to result itself. An assignment
14632 // will then create a primitive value.
14633 json_pointer(element.first).get_and_create(result) = element.second;
14634 }
6288 14635
6289 In the for loop, the bytes from the vector are copied in reverse order into 14636 return result;
6290 the return value. In the figures below, let sizeof(T)=4 and `i` be the loop 14637 }
6291 variable.
6292 14638
6293 Precondition: 14639 // can't use conversion operator because of ambiguity
14640 json_pointer<string_t> convert() const&
14641 {
14642 json_pointer<string_t> result;
14643 result.reference_tokens = reference_tokens;
14644 return result;
14645 }
6294 14646
6295 vec: | | | a | b | c | d | T: | | | | | 14647 json_pointer<string_t> convert()&&
6296 ^ ^ ^ ^ 14648 {
6297 current_index i ptr sizeof(T) 14649 json_pointer<string_t> result;
14650 result.reference_tokens = std::move(reference_tokens);
14651 return result;
14652 }
6298 14653
6299 Postcondition: 14654 public:
14655#if JSON_HAS_THREE_WAY_COMPARISON
14656 /// @brief compares two JSON pointers for equality
14657 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
14658 template<typename RefStringTypeRhs>
14659 bool operator==(const json_pointer<RefStringTypeRhs>& rhs) const noexcept
14660 {
14661 return reference_tokens == rhs.reference_tokens;
14662 }
6300 14663
6301 vec: | | | a | b | c | d | T: | d | c | b | a | 14664 /// @brief compares JSON pointer and string for equality
6302 ^ ^ ^ 14665 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
6303 | i ptr 14666 JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer))
6304 current_index 14667 bool operator==(const string_t& rhs) const
14668 {
14669 return *this == json_pointer(rhs);
14670 }
6305 14671
6306 @sa Code adapted from <http://stackoverflow.com/a/41031865/266378>. 14672 /// @brief 3-way compares two JSON pointers
6307 */ 14673 template<typename RefStringTypeRhs>
6308 template<typename T> 14674 std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD*
6309 static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_index)
6310 { 14675 {
6311 if (current_index + sizeof(T) + 1 > vec.size()) 14676 return reference_tokens <=> rhs.reference_tokens; // *NOPAD*
6312 { 14677 }
6313 throw std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector"); 14678#else
6314 } 14679 /// @brief compares two JSON pointers for equality
14680 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
14681 template<typename RefStringTypeLhs, typename RefStringTypeRhs>
14682 // NOLINTNEXTLINE(readability-redundant-declaration)
14683 friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
14684 const json_pointer<RefStringTypeRhs>& rhs) noexcept;
14685
14686 /// @brief compares JSON pointer and string for equality
14687 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
14688 template<typename RefStringTypeLhs, typename StringType>
14689 // NOLINTNEXTLINE(readability-redundant-declaration)
14690 friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
14691 const StringType& rhs);
14692
14693 /// @brief compares string and JSON pointer for equality
14694 /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/
14695 template<typename RefStringTypeRhs, typename StringType>
14696 // NOLINTNEXTLINE(readability-redundant-declaration)
14697 friend bool operator==(const StringType& lhs,
14698 const json_pointer<RefStringTypeRhs>& rhs);
14699
14700 /// @brief compares two JSON pointers for inequality
14701 /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
14702 template<typename RefStringTypeLhs, typename RefStringTypeRhs>
14703 // NOLINTNEXTLINE(readability-redundant-declaration)
14704 friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
14705 const json_pointer<RefStringTypeRhs>& rhs) noexcept;
14706
14707 /// @brief compares JSON pointer and string for inequality
14708 /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
14709 template<typename RefStringTypeLhs, typename StringType>
14710 // NOLINTNEXTLINE(readability-redundant-declaration)
14711 friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
14712 const StringType& rhs);
14713
14714 /// @brief compares string and JSON pointer for inequality
14715 /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/
14716 template<typename RefStringTypeRhs, typename StringType>
14717 // NOLINTNEXTLINE(readability-redundant-declaration)
14718 friend bool operator!=(const StringType& lhs,
14719 const json_pointer<RefStringTypeRhs>& rhs);
14720
14721 /// @brief compares two JSON pointer for less-than
14722 template<typename RefStringTypeLhs, typename RefStringTypeRhs>
14723 // NOLINTNEXTLINE(readability-redundant-declaration)
14724 friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
14725 const json_pointer<RefStringTypeRhs>& rhs) noexcept;
14726#endif
14727
14728 private:
14729 /// the reference tokens
14730 std::vector<string_t> reference_tokens;
14731};
14732
14733#if !JSON_HAS_THREE_WAY_COMPARISON
14734// functions cannot be defined inside class due to ODR violations
14735template<typename RefStringTypeLhs, typename RefStringTypeRhs>
14736inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
14737 const json_pointer<RefStringTypeRhs>& rhs) noexcept
14738{
14739 return lhs.reference_tokens == rhs.reference_tokens;
14740}
14741
14742template<typename RefStringTypeLhs,
14743 typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
14744JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
14745inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
14746 const StringType& rhs)
14747{
14748 return lhs == json_pointer<RefStringTypeLhs>(rhs);
14749}
6315 14750
6316 T result; 14751template<typename RefStringTypeRhs,
6317 uint8_t* ptr = reinterpret_cast<uint8_t*>(&result); 14752 typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
6318 for (size_t i = 0; i < sizeof(T); ++i) 14753JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
14754inline bool operator==(const StringType& lhs,
14755 const json_pointer<RefStringTypeRhs>& rhs)
14756{
14757 return json_pointer<RefStringTypeRhs>(lhs) == rhs;
14758}
14759
14760template<typename RefStringTypeLhs, typename RefStringTypeRhs>
14761inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
14762 const json_pointer<RefStringTypeRhs>& rhs) noexcept
14763{
14764 return !(lhs == rhs);
14765}
14766
14767template<typename RefStringTypeLhs,
14768 typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
14769JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
14770inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
14771 const StringType& rhs)
14772{
14773 return !(lhs == rhs);
14774}
14775
14776template<typename RefStringTypeRhs,
14777 typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
14778JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
14779inline bool operator!=(const StringType& lhs,
14780 const json_pointer<RefStringTypeRhs>& rhs)
14781{
14782 return !(lhs == rhs);
14783}
14784
14785template<typename RefStringTypeLhs, typename RefStringTypeRhs>
14786inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
14787 const json_pointer<RefStringTypeRhs>& rhs) noexcept
14788{
14789 return lhs.reference_tokens < rhs.reference_tokens;
14790}
14791#endif
14792
14793NLOHMANN_JSON_NAMESPACE_END
14794
14795// #include <nlohmann/detail/json_ref.hpp>
14796// __ _____ _____ _____
14797// __| | __| | | | JSON for Modern C++
14798// | | |__ | | | | | | version 3.11.3
14799// |_____|_____|_____|_|___| https://github.com/nlohmann/json
14800//
14801// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
14802// SPDX-License-Identifier: MIT
14803
14804
14805
14806#include <initializer_list>
14807#include <utility>
14808
14809// #include <nlohmann/detail/abi_macros.hpp>
14810
14811// #include <nlohmann/detail/meta/type_traits.hpp>
14812
14813
14814NLOHMANN_JSON_NAMESPACE_BEGIN
14815namespace detail
14816{
14817
14818template<typename BasicJsonType>
14819class json_ref
14820{
14821 public:
14822 using value_type = BasicJsonType;
14823
14824 json_ref(value_type&& value)
14825 : owned_value(std::move(value))
14826 {}
14827
14828 json_ref(const value_type& value)
14829 : value_ref(&value)
14830 {}
14831
14832 json_ref(std::initializer_list<json_ref> init)
14833 : owned_value(init)
14834 {}
14835
14836 template <
14837 class... Args,
14838 enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >
14839 json_ref(Args && ... args)
14840 : owned_value(std::forward<Args>(args)...)
14841 {}
14842
14843 // class should be movable only
14844 json_ref(json_ref&&) noexcept = default;
14845 json_ref(const json_ref&) = delete;
14846 json_ref& operator=(const json_ref&) = delete;
14847 json_ref& operator=(json_ref&&) = delete;
14848 ~json_ref() = default;
14849
14850 value_type moved_or_copied() const
14851 {
14852 if (value_ref == nullptr)
6319 { 14853 {
6320 *ptr++ = vec[current_index + sizeof(T) - i]; 14854 return std::move(owned_value);
6321 } 14855 }
6322 return result; 14856 return *value_ref;
14857 }
14858
14859 value_type const& operator*() const
14860 {
14861 return value_ref ? *value_ref : owned_value;
14862 }
14863
14864 value_type const* operator->() const
14865 {
14866 return &** this;
14867 }
14868
14869 private:
14870 mutable value_type owned_value = nullptr;
14871 value_type const* value_ref = nullptr;
14872};
14873
14874} // namespace detail
14875NLOHMANN_JSON_NAMESPACE_END
14876
14877// #include <nlohmann/detail/macro_scope.hpp>
14878
14879// #include <nlohmann/detail/string_concat.hpp>
14880
14881// #include <nlohmann/detail/string_escape.hpp>
14882
14883// #include <nlohmann/detail/meta/cpp_future.hpp>
14884
14885// #include <nlohmann/detail/meta/type_traits.hpp>
14886
14887// #include <nlohmann/detail/output/binary_writer.hpp>
14888// __ _____ _____ _____
14889// __| | __| | | | JSON for Modern C++
14890// | | |__ | | | | | | version 3.11.3
14891// |_____|_____|_____|_|___| https://github.com/nlohmann/json
14892//
14893// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
14894// SPDX-License-Identifier: MIT
14895
14896
14897
14898#include <algorithm> // reverse
14899#include <array> // array
14900#include <map> // map
14901#include <cmath> // isnan, isinf
14902#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
14903#include <cstring> // memcpy
14904#include <limits> // numeric_limits
14905#include <string> // string
14906#include <utility> // move
14907#include <vector> // vector
14908
14909// #include <nlohmann/detail/input/binary_reader.hpp>
14910
14911// #include <nlohmann/detail/macro_scope.hpp>
14912
14913// #include <nlohmann/detail/output/output_adapters.hpp>
14914// __ _____ _____ _____
14915// __| | __| | | | JSON for Modern C++
14916// | | |__ | | | | | | version 3.11.3
14917// |_____|_____|_____|_|___| https://github.com/nlohmann/json
14918//
14919// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
14920// SPDX-License-Identifier: MIT
14921
14922
14923
14924#include <algorithm> // copy
14925#include <cstddef> // size_t
14926#include <iterator> // back_inserter
14927#include <memory> // shared_ptr, make_shared
14928#include <string> // basic_string
14929#include <vector> // vector
14930
14931#ifndef JSON_NO_IO
14932 #include <ios> // streamsize
14933 #include <ostream> // basic_ostream
14934#endif // JSON_NO_IO
14935
14936// #include <nlohmann/detail/macro_scope.hpp>
14937
14938
14939NLOHMANN_JSON_NAMESPACE_BEGIN
14940namespace detail
14941{
14942
14943/// abstract output adapter interface
14944template<typename CharType> struct output_adapter_protocol
14945{
14946 virtual void write_character(CharType c) = 0;
14947 virtual void write_characters(const CharType* s, std::size_t length) = 0;
14948 virtual ~output_adapter_protocol() = default;
14949
14950 output_adapter_protocol() = default;
14951 output_adapter_protocol(const output_adapter_protocol&) = default;
14952 output_adapter_protocol(output_adapter_protocol&&) noexcept = default;
14953 output_adapter_protocol& operator=(const output_adapter_protocol&) = default;
14954 output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default;
14955};
14956
14957/// a type to simplify interfaces
14958template<typename CharType>
14959using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;
14960
14961/// output adapter for byte vectors
14962template<typename CharType, typename AllocatorType = std::allocator<CharType>>
14963class output_vector_adapter : public output_adapter_protocol<CharType>
14964{
14965 public:
14966 explicit output_vector_adapter(std::vector<CharType, AllocatorType>& vec) noexcept
14967 : v(vec)
14968 {}
14969
14970 void write_character(CharType c) override
14971 {
14972 v.push_back(c);
6323 } 14973 }
6324 14974
14975 JSON_HEDLEY_NON_NULL(2)
14976 void write_characters(const CharType* s, std::size_t length) override
14977 {
14978 v.insert(v.end(), s, s + length);
14979 }
14980
14981 private:
14982 std::vector<CharType, AllocatorType>& v;
14983};
14984
14985#ifndef JSON_NO_IO
14986/// output adapter for output streams
14987template<typename CharType>
14988class output_stream_adapter : public output_adapter_protocol<CharType>
14989{
14990 public:
14991 explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept
14992 : stream(s)
14993 {}
14994
14995 void write_character(CharType c) override
14996 {
14997 stream.put(c);
14998 }
14999
15000 JSON_HEDLEY_NON_NULL(2)
15001 void write_characters(const CharType* s, std::size_t length) override
15002 {
15003 stream.write(s, static_cast<std::streamsize>(length));
15004 }
15005
15006 private:
15007 std::basic_ostream<CharType>& stream;
15008};
15009#endif // JSON_NO_IO
15010
15011/// output adapter for basic_string
15012template<typename CharType, typename StringType = std::basic_string<CharType>>
15013class output_string_adapter : public output_adapter_protocol<CharType>
15014{
15015 public:
15016 explicit output_string_adapter(StringType& s) noexcept
15017 : str(s)
15018 {}
15019
15020 void write_character(CharType c) override
15021 {
15022 str.push_back(c);
15023 }
15024
15025 JSON_HEDLEY_NON_NULL(2)
15026 void write_characters(const CharType* s, std::size_t length) override
15027 {
15028 str.append(s, length);
15029 }
15030
15031 private:
15032 StringType& str;
15033};
15034
15035template<typename CharType, typename StringType = std::basic_string<CharType>>
15036class output_adapter
15037{
15038 public:
15039 template<typename AllocatorType = std::allocator<CharType>>
15040 output_adapter(std::vector<CharType, AllocatorType>& vec)
15041 : oa(std::make_shared<output_vector_adapter<CharType, AllocatorType>>(vec)) {}
15042
15043#ifndef JSON_NO_IO
15044 output_adapter(std::basic_ostream<CharType>& s)
15045 : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
15046#endif // JSON_NO_IO
15047
15048 output_adapter(StringType& s)
15049 : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}
15050
15051 operator output_adapter_t<CharType>()
15052 {
15053 return oa;
15054 }
15055
15056 private:
15057 output_adapter_t<CharType> oa = nullptr;
15058};
15059
15060} // namespace detail
15061NLOHMANN_JSON_NAMESPACE_END
15062
15063// #include <nlohmann/detail/string_concat.hpp>
15064
15065
15066NLOHMANN_JSON_NAMESPACE_BEGIN
15067namespace detail
15068{
15069
15070///////////////////
15071// binary writer //
15072///////////////////
15073
15074/*!
15075@brief serialization to CBOR and MessagePack values
15076*/
15077template<typename BasicJsonType, typename CharType>
15078class binary_writer
15079{
15080 using string_t = typename BasicJsonType::string_t;
15081 using binary_t = typename BasicJsonType::binary_t;
15082 using number_float_t = typename BasicJsonType::number_float_t;
15083
15084 public:
6325 /*! 15085 /*!
6326 @brief create a MessagePack serialization of a given JSON value 15086 @brief create a binary writer
6327 15087
6328 This is a straightforward implementation of the MessagePack specification. 15088 @param[in] adapter output adapter to write to
15089 */
15090 explicit binary_writer(output_adapter_t<CharType> adapter) : oa(std::move(adapter))
15091 {
15092 JSON_ASSERT(oa);
15093 }
6329 15094
15095 /*!
6330 @param[in] j JSON value to serialize 15096 @param[in] j JSON value to serialize
6331 @param[in,out] v byte vector to write the serialization to 15097 @pre j.type() == value_t::object
15098 */
15099 void write_bson(const BasicJsonType& j)
15100 {
15101 switch (j.type())
15102 {
15103 case value_t::object:
15104 {
15105 write_bson_object(*j.m_data.m_value.object);
15106 break;
15107 }
15108
15109 case value_t::null:
15110 case value_t::array:
15111 case value_t::string:
15112 case value_t::boolean:
15113 case value_t::number_integer:
15114 case value_t::number_unsigned:
15115 case value_t::number_float:
15116 case value_t::binary:
15117 case value_t::discarded:
15118 default:
15119 {
15120 JSON_THROW(type_error::create(317, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j));
15121 }
15122 }
15123 }
6332 15124
6333 @sa https://github.com/msgpack/msgpack/blob/master/spec.md 15125 /*!
15126 @param[in] j JSON value to serialize
6334 */ 15127 */
6335 static void to_msgpack_internal(const basic_json& j, std::vector<uint8_t>& v) 15128 void write_cbor(const BasicJsonType& j)
6336 { 15129 {
6337 switch (j.type()) 15130 switch (j.type())
6338 { 15131 {
6339 case value_t::null: 15132 case value_t::null:
6340 { 15133 {
6341 // nil 15134 oa->write_character(to_char_type(0xF6));
6342 v.push_back(0xc0);
6343 break; 15135 break;
6344 } 15136 }
6345 15137
6346 case value_t::boolean: 15138 case value_t::boolean:
6347 { 15139 {
6348 // true and false 15140 oa->write_character(j.m_data.m_value.boolean
6349 v.push_back(j.m_value.boolean ? 0xc3 : 0xc2); 15141 ? to_char_type(0xF5)
15142 : to_char_type(0xF4));
6350 break; 15143 break;
6351 } 15144 }
6352 15145
6353 case value_t::number_integer: 15146 case value_t::number_integer:
6354 { 15147 {
6355 if (j.m_value.number_integer >= 0) 15148 if (j.m_data.m_value.number_integer >= 0)
6356 { 15149 {
6357 // MessagePack does not differentiate between positive 15150 // CBOR does not differentiate between positive signed
6358 // signed integers and unsigned integers. Therefore, we used 15151 // integers and unsigned integers. Therefore, we used the
6359 // the code from the value_t::number_unsigned case here. 15152 // code from the value_t::number_unsigned case here.
6360 if (j.m_value.number_unsigned < 128) 15153 if (j.m_data.m_value.number_integer <= 0x17)
6361 { 15154 {
6362 // positive fixnum 15155 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
6363 add_to_vector(v, 1, j.m_value.number_unsigned);
6364 } 15156 }
6365 else if (j.m_value.number_unsigned <= UINT8_MAX) 15157 else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
6366 { 15158 {
6367 // uint 8 15159 oa->write_character(to_char_type(0x18));
6368 v.push_back(0xcc); 15160 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
6369 add_to_vector(v, 1, j.m_value.number_unsigned);
6370 } 15161 }
6371 else if (j.m_value.number_unsigned <= UINT16_MAX) 15162 else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
6372 { 15163 {
6373 // uint 16 15164 oa->write_character(to_char_type(0x19));
6374 v.push_back(0xcd); 15165 write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
6375 add_to_vector(v, 2, j.m_value.number_unsigned);
6376 } 15166 }
6377 else if (j.m_value.number_unsigned <= UINT32_MAX) 15167 else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
6378 { 15168 {
6379 // uint 32 15169 oa->write_character(to_char_type(0x1A));
6380 v.push_back(0xce); 15170 write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
6381 add_to_vector(v, 4, j.m_value.number_unsigned);
6382 } 15171 }
6383 else if (j.m_value.number_unsigned <= UINT64_MAX) 15172 else
6384 { 15173 {
6385 // uint 64 15174 oa->write_character(to_char_type(0x1B));
6386 v.push_back(0xcf); 15175 write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
6387 add_to_vector(v, 8, j.m_value.number_unsigned);
6388 } 15176 }
6389 } 15177 }
6390 else 15178 else
6391 { 15179 {
6392 if (j.m_value.number_integer >= -32) 15180 // The conversions below encode the sign in the first
15181 // byte, and the value is converted to a positive number.
15182 const auto positive_number = -1 - j.m_data.m_value.number_integer;
15183 if (j.m_data.m_value.number_integer >= -24)
6393 { 15184 {
6394 // negative fixnum 15185 write_number(static_cast<std::uint8_t>(0x20 + positive_number));
6395 add_to_vector(v, 1, j.m_value.number_integer);
6396 } 15186 }
6397 else if (j.m_value.number_integer >= INT8_MIN and j.m_value.number_integer <= INT8_MAX) 15187 else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())
6398 { 15188 {
6399 // int 8 15189 oa->write_character(to_char_type(0x38));
6400 v.push_back(0xd0); 15190 write_number(static_cast<std::uint8_t>(positive_number));
6401 add_to_vector(v, 1, j.m_value.number_integer);
6402 } 15191 }
6403 else if (j.m_value.number_integer >= INT16_MIN and j.m_value.number_integer <= INT16_MAX) 15192 else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())
6404 { 15193 {
6405 // int 16 15194 oa->write_character(to_char_type(0x39));
6406 v.push_back(0xd1); 15195 write_number(static_cast<std::uint16_t>(positive_number));
6407 add_to_vector(v, 2, j.m_value.number_integer);
6408 } 15196 }
6409 else if (j.m_value.number_integer >= INT32_MIN and j.m_value.number_integer <= INT32_MAX) 15197 else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())
6410 { 15198 {
6411 // int 32 15199 oa->write_character(to_char_type(0x3A));
6412 v.push_back(0xd2); 15200 write_number(static_cast<std::uint32_t>(positive_number));
6413 add_to_vector(v, 4, j.m_value.number_integer);
6414 } 15201 }
6415 else if (j.m_value.number_integer >= INT64_MIN and j.m_value.number_integer <= INT64_MAX) 15202 else
6416 { 15203 {
6417 // int 64 15204 oa->write_character(to_char_type(0x3B));
6418 v.push_back(0xd3); 15205 write_number(static_cast<std::uint64_t>(positive_number));
6419 add_to_vector(v, 8, j.m_value.number_integer);
6420 } 15206 }
6421 } 15207 }
6422 break; 15208 break;
@@ -6424,243 +15210,334 @@ class basic_json
6424 15210
6425 case value_t::number_unsigned: 15211 case value_t::number_unsigned:
6426 { 15212 {
6427 if (j.m_value.number_unsigned < 128) 15213 if (j.m_data.m_value.number_unsigned <= 0x17)
6428 { 15214 {
6429 // positive fixnum 15215 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));
6430 add_to_vector(v, 1, j.m_value.number_unsigned);
6431 } 15216 }
6432 else if (j.m_value.number_unsigned <= UINT8_MAX) 15217 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
6433 { 15218 {
6434 // uint 8 15219 oa->write_character(to_char_type(0x18));
6435 v.push_back(0xcc); 15220 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));
6436 add_to_vector(v, 1, j.m_value.number_unsigned);
6437 } 15221 }
6438 else if (j.m_value.number_unsigned <= UINT16_MAX) 15222 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
6439 { 15223 {
6440 // uint 16 15224 oa->write_character(to_char_type(0x19));
6441 v.push_back(0xcd); 15225 write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_unsigned));
6442 add_to_vector(v, 2, j.m_value.number_unsigned);
6443 } 15226 }
6444 else if (j.m_value.number_unsigned <= UINT32_MAX) 15227 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
6445 { 15228 {
6446 // uint 32 15229 oa->write_character(to_char_type(0x1A));
6447 v.push_back(0xce); 15230 write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_unsigned));
6448 add_to_vector(v, 4, j.m_value.number_unsigned);
6449 } 15231 }
6450 else if (j.m_value.number_unsigned <= UINT64_MAX) 15232 else
6451 { 15233 {
6452 // uint 64 15234 oa->write_character(to_char_type(0x1B));
6453 v.push_back(0xcf); 15235 write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned));
6454 add_to_vector(v, 8, j.m_value.number_unsigned);
6455 } 15236 }
6456 break; 15237 break;
6457 } 15238 }
6458 15239
6459 case value_t::number_float: 15240 case value_t::number_float:
6460 { 15241 {
6461 // float 64 15242 if (std::isnan(j.m_data.m_value.number_float))
6462 v.push_back(0xcb); 15243 {
6463 const uint8_t* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float)); 15244 // NaN is 0xf97e00 in CBOR
6464 for (size_t i = 0; i < 8; ++i) 15245 oa->write_character(to_char_type(0xF9));
15246 oa->write_character(to_char_type(0x7E));
15247 oa->write_character(to_char_type(0x00));
15248 }
15249 else if (std::isinf(j.m_data.m_value.number_float))
6465 { 15250 {
6466 v.push_back(helper[7 - i]); 15251 // Infinity is 0xf97c00, -Infinity is 0xf9fc00
15252 oa->write_character(to_char_type(0xf9));
15253 oa->write_character(j.m_data.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));
15254 oa->write_character(to_char_type(0x00));
15255 }
15256 else
15257 {
15258 write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::cbor);
6467 } 15259 }
6468 break; 15260 break;
6469 } 15261 }
6470 15262
6471 case value_t::string: 15263 case value_t::string:
6472 { 15264 {
6473 const auto N = j.m_value.string->size(); 15265 // step 1: write control byte and the string length
6474 if (N <= 31) 15266 const auto N = j.m_data.m_value.string->size();
15267 if (N <= 0x17)
6475 { 15268 {
6476 // fixstr 15269 write_number(static_cast<std::uint8_t>(0x60 + N));
6477 v.push_back(static_cast<uint8_t>(0xa0 | N));
6478 } 15270 }
6479 else if (N <= 255) 15271 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
6480 { 15272 {
6481 // str 8 15273 oa->write_character(to_char_type(0x78));
6482 v.push_back(0xd9); 15274 write_number(static_cast<std::uint8_t>(N));
6483 add_to_vector(v, 1, N);
6484 } 15275 }
6485 else if (N <= 65535) 15276 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
6486 { 15277 {
6487 // str 16 15278 oa->write_character(to_char_type(0x79));
6488 v.push_back(0xda); 15279 write_number(static_cast<std::uint16_t>(N));
6489 add_to_vector(v, 2, N);
6490 } 15280 }
6491 else if (N <= 4294967295) 15281 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
6492 { 15282 {
6493 // str 32 15283 oa->write_character(to_char_type(0x7A));
6494 v.push_back(0xdb); 15284 write_number(static_cast<std::uint32_t>(N));
6495 add_to_vector(v, 4, N);
6496 } 15285 }
15286 // LCOV_EXCL_START
15287 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
15288 {
15289 oa->write_character(to_char_type(0x7B));
15290 write_number(static_cast<std::uint64_t>(N));
15291 }
15292 // LCOV_EXCL_STOP
6497 15293
6498 // append string 15294 // step 2: write the string
6499 std::copy(j.m_value.string->begin(), j.m_value.string->end(), 15295 oa->write_characters(
6500 std::back_inserter(v)); 15296 reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
15297 j.m_data.m_value.string->size());
6501 break; 15298 break;
6502 } 15299 }
6503 15300
6504 case value_t::array: 15301 case value_t::array:
6505 { 15302 {
6506 const auto N = j.m_value.array->size(); 15303 // step 1: write control byte and the array size
6507 if (N <= 15) 15304 const auto N = j.m_data.m_value.array->size();
15305 if (N <= 0x17)
6508 { 15306 {
6509 // fixarray 15307 write_number(static_cast<std::uint8_t>(0x80 + N));
6510 v.push_back(static_cast<uint8_t>(0x90 | N));
6511 } 15308 }
6512 else if (N <= 0xffff) 15309 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
6513 { 15310 {
6514 // array 16 15311 oa->write_character(to_char_type(0x98));
6515 v.push_back(0xdc); 15312 write_number(static_cast<std::uint8_t>(N));
6516 add_to_vector(v, 2, N);
6517 } 15313 }
6518 else if (N <= 0xffffffff) 15314 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
6519 { 15315 {
6520 // array 32 15316 oa->write_character(to_char_type(0x99));
6521 v.push_back(0xdd); 15317 write_number(static_cast<std::uint16_t>(N));
6522 add_to_vector(v, 4, N); 15318 }
15319 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
15320 {
15321 oa->write_character(to_char_type(0x9A));
15322 write_number(static_cast<std::uint32_t>(N));
15323 }
15324 // LCOV_EXCL_START
15325 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
15326 {
15327 oa->write_character(to_char_type(0x9B));
15328 write_number(static_cast<std::uint64_t>(N));
15329 }
15330 // LCOV_EXCL_STOP
15331
15332 // step 2: write each element
15333 for (const auto& el : *j.m_data.m_value.array)
15334 {
15335 write_cbor(el);
15336 }
15337 break;
15338 }
15339
15340 case value_t::binary:
15341 {
15342 if (j.m_data.m_value.binary->has_subtype())
15343 {
15344 if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint8_t>::max)())
15345 {
15346 write_number(static_cast<std::uint8_t>(0xd8));
15347 write_number(static_cast<std::uint8_t>(j.m_data.m_value.binary->subtype()));
15348 }
15349 else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint16_t>::max)())
15350 {
15351 write_number(static_cast<std::uint8_t>(0xd9));
15352 write_number(static_cast<std::uint16_t>(j.m_data.m_value.binary->subtype()));
15353 }
15354 else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint32_t>::max)())
15355 {
15356 write_number(static_cast<std::uint8_t>(0xda));
15357 write_number(static_cast<std::uint32_t>(j.m_data.m_value.binary->subtype()));
15358 }
15359 else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)())
15360 {
15361 write_number(static_cast<std::uint8_t>(0xdb));
15362 write_number(static_cast<std::uint64_t>(j.m_data.m_value.binary->subtype()));
15363 }
6523 } 15364 }
6524 15365
6525 // append each element 15366 // step 1: write control byte and the binary array size
6526 for (const auto& el : *j.m_value.array) 15367 const auto N = j.m_data.m_value.binary->size();
15368 if (N <= 0x17)
15369 {
15370 write_number(static_cast<std::uint8_t>(0x40 + N));
15371 }
15372 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
6527 { 15373 {
6528 to_msgpack_internal(el, v); 15374 oa->write_character(to_char_type(0x58));
15375 write_number(static_cast<std::uint8_t>(N));
6529 } 15376 }
15377 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
15378 {
15379 oa->write_character(to_char_type(0x59));
15380 write_number(static_cast<std::uint16_t>(N));
15381 }
15382 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
15383 {
15384 oa->write_character(to_char_type(0x5A));
15385 write_number(static_cast<std::uint32_t>(N));
15386 }
15387 // LCOV_EXCL_START
15388 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
15389 {
15390 oa->write_character(to_char_type(0x5B));
15391 write_number(static_cast<std::uint64_t>(N));
15392 }
15393 // LCOV_EXCL_STOP
15394
15395 // step 2: write each element
15396 oa->write_characters(
15397 reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
15398 N);
15399
6530 break; 15400 break;
6531 } 15401 }
6532 15402
6533 case value_t::object: 15403 case value_t::object:
6534 { 15404 {
6535 const auto N = j.m_value.object->size(); 15405 // step 1: write control byte and the object size
6536 if (N <= 15) 15406 const auto N = j.m_data.m_value.object->size();
15407 if (N <= 0x17)
6537 { 15408 {
6538 // fixmap 15409 write_number(static_cast<std::uint8_t>(0xA0 + N));
6539 v.push_back(static_cast<uint8_t>(0x80 | (N & 0xf)));
6540 } 15410 }
6541 else if (N <= 65535) 15411 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
6542 { 15412 {
6543 // map 16 15413 oa->write_character(to_char_type(0xB8));
6544 v.push_back(0xde); 15414 write_number(static_cast<std::uint8_t>(N));
6545 add_to_vector(v, 2, N);
6546 } 15415 }
6547 else if (N <= 4294967295) 15416 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
6548 { 15417 {
6549 // map 32 15418 oa->write_character(to_char_type(0xB9));
6550 v.push_back(0xdf); 15419 write_number(static_cast<std::uint16_t>(N));
6551 add_to_vector(v, 4, N); 15420 }
15421 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
15422 {
15423 oa->write_character(to_char_type(0xBA));
15424 write_number(static_cast<std::uint32_t>(N));
15425 }
15426 // LCOV_EXCL_START
15427 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
15428 {
15429 oa->write_character(to_char_type(0xBB));
15430 write_number(static_cast<std::uint64_t>(N));
6552 } 15431 }
15432 // LCOV_EXCL_STOP
6553 15433
6554 // append each element 15434 // step 2: write each element
6555 for (const auto& el : *j.m_value.object) 15435 for (const auto& el : *j.m_data.m_value.object)
6556 { 15436 {
6557 to_msgpack_internal(el.first, v); 15437 write_cbor(el.first);
6558 to_msgpack_internal(el.second, v); 15438 write_cbor(el.second);
6559 } 15439 }
6560 break; 15440 break;
6561 } 15441 }
6562 15442
15443 case value_t::discarded:
6563 default: 15444 default:
6564 {
6565 break; 15445 break;
6566 }
6567 } 15446 }
6568 } 15447 }
6569 15448
6570 /*! 15449 /*!
6571 @brief create a CBOR serialization of a given JSON value
6572
6573 This is a straightforward implementation of the CBOR specification.
6574
6575 @param[in] j JSON value to serialize 15450 @param[in] j JSON value to serialize
6576 @param[in,out] v byte vector to write the serialization to
6577
6578 @sa https://tools.ietf.org/html/rfc7049
6579 */ 15451 */
6580 static void to_cbor_internal(const basic_json& j, std::vector<uint8_t>& v) 15452 void write_msgpack(const BasicJsonType& j)
6581 { 15453 {
6582 switch (j.type()) 15454 switch (j.type())
6583 { 15455 {
6584 case value_t::null: 15456 case value_t::null: // nil
6585 { 15457 {
6586 v.push_back(0xf6); 15458 oa->write_character(to_char_type(0xC0));
6587 break; 15459 break;
6588 } 15460 }
6589 15461
6590 case value_t::boolean: 15462 case value_t::boolean: // true and false
6591 { 15463 {
6592 v.push_back(j.m_value.boolean ? 0xf5 : 0xf4); 15464 oa->write_character(j.m_data.m_value.boolean
15465 ? to_char_type(0xC3)
15466 : to_char_type(0xC2));
6593 break; 15467 break;
6594 } 15468 }
6595 15469
6596 case value_t::number_integer: 15470 case value_t::number_integer:
6597 { 15471 {
6598 if (j.m_value.number_integer >= 0) 15472 if (j.m_data.m_value.number_integer >= 0)
6599 { 15473 {
6600 // CBOR does not differentiate between positive signed 15474 // MessagePack does not differentiate between positive
6601 // integers and unsigned integers. Therefore, we used the 15475 // signed integers and unsigned integers. Therefore, we used
6602 // code from the value_t::number_unsigned case here. 15476 // the code from the value_t::number_unsigned case here.
6603 if (j.m_value.number_integer <= 0x17) 15477 if (j.m_data.m_value.number_unsigned < 128)
6604 { 15478 {
6605 add_to_vector(v, 1, j.m_value.number_integer); 15479 // positive fixnum
15480 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
6606 } 15481 }
6607 else if (j.m_value.number_integer <= UINT8_MAX) 15482 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
6608 { 15483 {
6609 v.push_back(0x18); 15484 // uint 8
6610 // one-byte uint8_t 15485 oa->write_character(to_char_type(0xCC));
6611 add_to_vector(v, 1, j.m_value.number_integer); 15486 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
6612 } 15487 }
6613 else if (j.m_value.number_integer <= UINT16_MAX) 15488 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
6614 { 15489 {
6615 v.push_back(0x19); 15490 // uint 16
6616 // two-byte uint16_t 15491 oa->write_character(to_char_type(0xCD));
6617 add_to_vector(v, 2, j.m_value.number_integer); 15492 write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
6618 } 15493 }
6619 else if (j.m_value.number_integer <= UINT32_MAX) 15494 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
6620 { 15495 {
6621 v.push_back(0x1a); 15496 // uint 32
6622 // four-byte uint32_t 15497 oa->write_character(to_char_type(0xCE));
6623 add_to_vector(v, 4, j.m_value.number_integer); 15498 write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
6624 } 15499 }
6625 else 15500 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
6626 { 15501 {
6627 v.push_back(0x1b); 15502 // uint 64
6628 // eight-byte uint64_t 15503 oa->write_character(to_char_type(0xCF));
6629 add_to_vector(v, 8, j.m_value.number_integer); 15504 write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
6630 } 15505 }
6631 } 15506 }
6632 else 15507 else
6633 { 15508 {
6634 // The conversions below encode the sign in the first byte, 15509 if (j.m_data.m_value.number_integer >= -32)
6635 // and the value is converted to a positive number.
6636 const auto positive_number = -1 - j.m_value.number_integer;
6637 if (j.m_value.number_integer >= -24)
6638 { 15510 {
6639 v.push_back(static_cast<uint8_t>(0x20 + positive_number)); 15511 // negative fixnum
15512 write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
6640 } 15513 }
6641 else if (positive_number <= UINT8_MAX) 15514 else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&
15515 j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
6642 { 15516 {
6643 // int 8 15517 // int 8
6644 v.push_back(0x38); 15518 oa->write_character(to_char_type(0xD0));
6645 add_to_vector(v, 1, positive_number); 15519 write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
6646 } 15520 }
6647 else if (positive_number <= UINT16_MAX) 15521 else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
15522 j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
6648 { 15523 {
6649 // int 16 15524 // int 16
6650 v.push_back(0x39); 15525 oa->write_character(to_char_type(0xD1));
6651 add_to_vector(v, 2, positive_number); 15526 write_number(static_cast<std::int16_t>(j.m_data.m_value.number_integer));
6652 } 15527 }
6653 else if (positive_number <= UINT32_MAX) 15528 else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
15529 j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
6654 { 15530 {
6655 // int 32 15531 // int 32
6656 v.push_back(0x3a); 15532 oa->write_character(to_char_type(0xD2));
6657 add_to_vector(v, 4, positive_number); 15533 write_number(static_cast<std::int32_t>(j.m_data.m_value.number_integer));
6658 } 15534 }
6659 else 15535 else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
15536 j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
6660 { 15537 {
6661 // int 64 15538 // int 64
6662 v.push_back(0x3b); 15539 oa->write_character(to_char_type(0xD3));
6663 add_to_vector(v, 8, positive_number); 15540 write_number(static_cast<std::int64_t>(j.m_data.m_value.number_integer));
6664 } 15541 }
6665 } 15542 }
6666 break; 15543 break;
@@ -6668,1192 +15545,2550 @@ class basic_json
6668 15545
6669 case value_t::number_unsigned: 15546 case value_t::number_unsigned:
6670 { 15547 {
6671 if (j.m_value.number_unsigned <= 0x17) 15548 if (j.m_data.m_value.number_unsigned < 128)
6672 { 15549 {
6673 v.push_back(static_cast<uint8_t>(j.m_value.number_unsigned)); 15550 // positive fixnum
15551 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
6674 } 15552 }
6675 else if (j.m_value.number_unsigned <= 0xff) 15553 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
6676 { 15554 {
6677 v.push_back(0x18); 15555 // uint 8
6678 // one-byte uint8_t 15556 oa->write_character(to_char_type(0xCC));
6679 add_to_vector(v, 1, j.m_value.number_unsigned); 15557 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
6680 } 15558 }
6681 else if (j.m_value.number_unsigned <= 0xffff) 15559 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
6682 { 15560 {
6683 v.push_back(0x19); 15561 // uint 16
6684 // two-byte uint16_t 15562 oa->write_character(to_char_type(0xCD));
6685 add_to_vector(v, 2, j.m_value.number_unsigned); 15563 write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
6686 } 15564 }
6687 else if (j.m_value.number_unsigned <= 0xffffffff) 15565 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
6688 { 15566 {
6689 v.push_back(0x1a); 15567 // uint 32
6690 // four-byte uint32_t 15568 oa->write_character(to_char_type(0xCE));
6691 add_to_vector(v, 4, j.m_value.number_unsigned); 15569 write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
6692 } 15570 }
6693 else if (j.m_value.number_unsigned <= 0xffffffffffffffff) 15571 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
6694 { 15572 {
6695 v.push_back(0x1b); 15573 // uint 64
6696 // eight-byte uint64_t 15574 oa->write_character(to_char_type(0xCF));
6697 add_to_vector(v, 8, j.m_value.number_unsigned); 15575 write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
6698 } 15576 }
6699 break; 15577 break;
6700 } 15578 }
6701 15579
6702 case value_t::number_float: 15580 case value_t::number_float:
6703 { 15581 {
6704 // Double-Precision Float 15582 write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::msgpack);
6705 v.push_back(0xfb);
6706 const uint8_t* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
6707 for (size_t i = 0; i < 8; ++i)
6708 {
6709 v.push_back(helper[7 - i]);
6710 }
6711 break; 15583 break;
6712 } 15584 }
6713 15585
6714 case value_t::string: 15586 case value_t::string:
6715 { 15587 {
6716 const auto N = j.m_value.string->size(); 15588 // step 1: write control byte and the string length
6717 if (N <= 0x17) 15589 const auto N = j.m_data.m_value.string->size();
6718 { 15590 if (N <= 31)
6719 v.push_back(0x60 + N); // 1 byte for string + size
6720 }
6721 else if (N <= 0xff)
6722 { 15591 {
6723 v.push_back(0x78); // one-byte uint8_t for N 15592 // fixstr
6724 add_to_vector(v, 1, N); 15593 write_number(static_cast<std::uint8_t>(0xA0 | N));
6725 } 15594 }
6726 else if (N <= 0xffff) 15595 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
6727 { 15596 {
6728 v.push_back(0x79); // two-byte uint16_t for N 15597 // str 8
6729 add_to_vector(v, 2, N); 15598 oa->write_character(to_char_type(0xD9));
15599 write_number(static_cast<std::uint8_t>(N));
6730 } 15600 }
6731 else if (N <= 0xffffffff) 15601 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
6732 { 15602 {
6733 v.push_back(0x7a); // four-byte uint32_t for N 15603 // str 16
6734 add_to_vector(v, 4, N); 15604 oa->write_character(to_char_type(0xDA));
15605 write_number(static_cast<std::uint16_t>(N));
6735 } 15606 }
6736 // LCOV_EXCL_START 15607 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
6737 else if (N <= 0xffffffffffffffff)
6738 { 15608 {
6739 v.push_back(0x7b); // eight-byte uint64_t for N 15609 // str 32
6740 add_to_vector(v, 8, N); 15610 oa->write_character(to_char_type(0xDB));
15611 write_number(static_cast<std::uint32_t>(N));
6741 } 15612 }
6742 // LCOV_EXCL_STOP
6743 15613
6744 // append string 15614 // step 2: write the string
6745 std::copy(j.m_value.string->begin(), j.m_value.string->end(), 15615 oa->write_characters(
6746 std::back_inserter(v)); 15616 reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
15617 j.m_data.m_value.string->size());
6747 break; 15618 break;
6748 } 15619 }
6749 15620
6750 case value_t::array: 15621 case value_t::array:
6751 { 15622 {
6752 const auto N = j.m_value.array->size(); 15623 // step 1: write control byte and the array size
6753 if (N <= 0x17) 15624 const auto N = j.m_data.m_value.array->size();
15625 if (N <= 15)
6754 { 15626 {
6755 v.push_back(0x80 + N); // 1 byte for array + size 15627 // fixarray
15628 write_number(static_cast<std::uint8_t>(0x90 | N));
6756 } 15629 }
6757 else if (N <= 0xff) 15630 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
6758 { 15631 {
6759 v.push_back(0x98); // one-byte uint8_t for N 15632 // array 16
6760 add_to_vector(v, 1, N); 15633 oa->write_character(to_char_type(0xDC));
15634 write_number(static_cast<std::uint16_t>(N));
6761 } 15635 }
6762 else if (N <= 0xffff) 15636 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
6763 { 15637 {
6764 v.push_back(0x99); // two-byte uint16_t for N 15638 // array 32
6765 add_to_vector(v, 2, N); 15639 oa->write_character(to_char_type(0xDD));
15640 write_number(static_cast<std::uint32_t>(N));
6766 } 15641 }
6767 else if (N <= 0xffffffff) 15642
15643 // step 2: write each element
15644 for (const auto& el : *j.m_data.m_value.array)
6768 { 15645 {
6769 v.push_back(0x9a); // four-byte uint32_t for N 15646 write_msgpack(el);
6770 add_to_vector(v, 4, N);
6771 } 15647 }
6772 // LCOV_EXCL_START 15648 break;
6773 else if (N <= 0xffffffffffffffff) 15649 }
15650
15651 case value_t::binary:
15652 {
15653 // step 0: determine if the binary type has a set subtype to
15654 // determine whether or not to use the ext or fixext types
15655 const bool use_ext = j.m_data.m_value.binary->has_subtype();
15656
15657 // step 1: write control byte and the byte string length
15658 const auto N = j.m_data.m_value.binary->size();
15659 if (N <= (std::numeric_limits<std::uint8_t>::max)())
15660 {
15661 std::uint8_t output_type{};
15662 bool fixed = true;
15663 if (use_ext)
15664 {
15665 switch (N)
15666 {
15667 case 1:
15668 output_type = 0xD4; // fixext 1
15669 break;
15670 case 2:
15671 output_type = 0xD5; // fixext 2
15672 break;
15673 case 4:
15674 output_type = 0xD6; // fixext 4
15675 break;
15676 case 8:
15677 output_type = 0xD7; // fixext 8
15678 break;
15679 case 16:
15680 output_type = 0xD8; // fixext 16
15681 break;
15682 default:
15683 output_type = 0xC7; // ext 8
15684 fixed = false;
15685 break;
15686 }
15687
15688 }
15689 else
15690 {
15691 output_type = 0xC4; // bin 8
15692 fixed = false;
15693 }
15694
15695 oa->write_character(to_char_type(output_type));
15696 if (!fixed)
15697 {
15698 write_number(static_cast<std::uint8_t>(N));
15699 }
15700 }
15701 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
15702 {
15703 const std::uint8_t output_type = use_ext
15704 ? 0xC8 // ext 16
15705 : 0xC5; // bin 16
15706
15707 oa->write_character(to_char_type(output_type));
15708 write_number(static_cast<std::uint16_t>(N));
15709 }
15710 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
6774 { 15711 {
6775 v.push_back(0x9b); // eight-byte uint64_t for N 15712 const std::uint8_t output_type = use_ext
6776 add_to_vector(v, 8, N); 15713 ? 0xC9 // ext 32
15714 : 0xC6; // bin 32
15715
15716 oa->write_character(to_char_type(output_type));
15717 write_number(static_cast<std::uint32_t>(N));
6777 } 15718 }
6778 // LCOV_EXCL_STOP
6779 15719
6780 // append each element 15720 // step 1.5: if this is an ext type, write the subtype
6781 for (const auto& el : *j.m_value.array) 15721 if (use_ext)
6782 { 15722 {
6783 to_cbor_internal(el, v); 15723 write_number(static_cast<std::int8_t>(j.m_data.m_value.binary->subtype()));
6784 } 15724 }
15725
15726 // step 2: write the byte string
15727 oa->write_characters(
15728 reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
15729 N);
15730
6785 break; 15731 break;
6786 } 15732 }
6787 15733
6788 case value_t::object: 15734 case value_t::object:
6789 { 15735 {
6790 const auto N = j.m_value.object->size(); 15736 // step 1: write control byte and the object size
6791 if (N <= 0x17) 15737 const auto N = j.m_data.m_value.object->size();
6792 { 15738 if (N <= 15)
6793 v.push_back(0xa0 + N); // 1 byte for object + size
6794 }
6795 else if (N <= 0xff)
6796 {
6797 v.push_back(0xb8);
6798 add_to_vector(v, 1, N); // one-byte uint8_t for N
6799 }
6800 else if (N <= 0xffff)
6801 { 15739 {
6802 v.push_back(0xb9); 15740 // fixmap
6803 add_to_vector(v, 2, N); // two-byte uint16_t for N 15741 write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));
6804 } 15742 }
6805 else if (N <= 0xffffffff) 15743 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
6806 { 15744 {
6807 v.push_back(0xba); 15745 // map 16
6808 add_to_vector(v, 4, N); // four-byte uint32_t for N 15746 oa->write_character(to_char_type(0xDE));
15747 write_number(static_cast<std::uint16_t>(N));
6809 } 15748 }
6810 // LCOV_EXCL_START 15749 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
6811 else if (N <= 0xffffffffffffffff)
6812 { 15750 {
6813 v.push_back(0xbb); 15751 // map 32
6814 add_to_vector(v, 8, N); // eight-byte uint64_t for N 15752 oa->write_character(to_char_type(0xDF));
15753 write_number(static_cast<std::uint32_t>(N));
6815 } 15754 }
6816 // LCOV_EXCL_STOP
6817 15755
6818 // append each element 15756 // step 2: write each element
6819 for (const auto& el : *j.m_value.object) 15757 for (const auto& el : *j.m_data.m_value.object)
6820 { 15758 {
6821 to_cbor_internal(el.first, v); 15759 write_msgpack(el.first);
6822 to_cbor_internal(el.second, v); 15760 write_msgpack(el.second);
6823 } 15761 }
6824 break; 15762 break;
6825 } 15763 }
6826 15764
15765 case value_t::discarded:
6827 default: 15766 default:
6828 {
6829 break; 15767 break;
6830 }
6831 } 15768 }
6832 } 15769 }
6833 15770
6834 /*! 15771 /*!
6835 @brief create a JSON value from a given MessagePack vector 15772 @param[in] j JSON value to serialize
6836 15773 @param[in] use_count whether to use '#' prefixes (optimized format)
6837 @param[in] v MessagePack serialization 15774 @param[in] use_type whether to use '$' prefixes (optimized format)
6838 @param[in] idx byte index to start reading from @a v 15775 @param[in] add_prefix whether prefixes need to be used for this value
6839 15776 @param[in] use_bjdata whether write in BJData format, default is false
6840 @return deserialized JSON value
6841
6842 @throw std::invalid_argument if unsupported features from MessagePack were
6843 used in the given vector @a v or if the input is not valid MessagePack
6844 @throw std::out_of_range if the given vector ends prematurely
6845
6846 @sa https://github.com/msgpack/msgpack/blob/master/spec.md
6847 */ 15777 */
6848 static basic_json from_msgpack_internal(const std::vector<uint8_t>& v, size_t& idx) 15778 void write_ubjson(const BasicJsonType& j, const bool use_count,
15779 const bool use_type, const bool add_prefix = true,
15780 const bool use_bjdata = false)
6849 { 15781 {
6850 // store and increment index 15782 switch (j.type())
6851 const size_t current_idx = idx++;
6852
6853 if (v[current_idx] <= 0xbf)
6854 { 15783 {
6855 if (v[current_idx] <= 0x7f) // positive fixint 15784 case value_t::null:
6856 {
6857 return v[current_idx];
6858 }
6859 else if (v[current_idx] <= 0x8f) // fixmap
6860 { 15785 {
6861 basic_json result = value_t::object; 15786 if (add_prefix)
6862 const size_t len = v[current_idx] & 0x0f;
6863 for (size_t i = 0; i < len; ++i)
6864 { 15787 {
6865 std::string key = from_msgpack_internal(v, idx); 15788 oa->write_character(to_char_type('Z'));
6866 result[key] = from_msgpack_internal(v, idx);
6867 } 15789 }
6868 return result; 15790 break;
6869 } 15791 }
6870 else if (v[current_idx] <= 0x9f) // fixarray 15792
15793 case value_t::boolean:
6871 { 15794 {
6872 basic_json result = value_t::array; 15795 if (add_prefix)
6873 const size_t len = v[current_idx] & 0x0f;
6874 for (size_t i = 0; i < len; ++i)
6875 { 15796 {
6876 result.push_back(from_msgpack_internal(v, idx)); 15797 oa->write_character(j.m_data.m_value.boolean
15798 ? to_char_type('T')
15799 : to_char_type('F'));
6877 } 15800 }
6878 return result; 15801 break;
15802 }
15803
15804 case value_t::number_integer:
15805 {
15806 write_number_with_ubjson_prefix(j.m_data.m_value.number_integer, add_prefix, use_bjdata);
15807 break;
6879 } 15808 }
6880 else // fixstr 15809
15810 case value_t::number_unsigned:
6881 { 15811 {
6882 const size_t len = v[current_idx] & 0x1f; 15812 write_number_with_ubjson_prefix(j.m_data.m_value.number_unsigned, add_prefix, use_bjdata);
6883 const size_t offset = current_idx + 1; 15813 break;
6884 idx += len; // skip content bytes
6885 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
6886 } 15814 }
6887 } 15815
6888 else if (v[current_idx] >= 0xe0) // negative fixint 15816 case value_t::number_float:
6889 {
6890 return static_cast<int8_t>(v[current_idx]);
6891 }
6892 else
6893 {
6894 switch (v[current_idx])
6895 { 15817 {
6896 case 0xc0: // nil 15818 write_number_with_ubjson_prefix(j.m_data.m_value.number_float, add_prefix, use_bjdata);
6897 { 15819 break;
6898 return value_t::null; 15820 }
6899 }
6900 15821
6901 case 0xc2: // false 15822 case value_t::string:
15823 {
15824 if (add_prefix)
6902 { 15825 {
6903 return false; 15826 oa->write_character(to_char_type('S'));
6904 } 15827 }
15828 write_number_with_ubjson_prefix(j.m_data.m_value.string->size(), true, use_bjdata);
15829 oa->write_characters(
15830 reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
15831 j.m_data.m_value.string->size());
15832 break;
15833 }
6905 15834
6906 case 0xc3: // true 15835 case value_t::array:
15836 {
15837 if (add_prefix)
6907 { 15838 {
6908 return true; 15839 oa->write_character(to_char_type('['));
6909 } 15840 }
6910 15841
6911 case 0xca: // float 32 15842 bool prefix_required = true;
15843 if (use_type && !j.m_data.m_value.array->empty())
6912 { 15844 {
6913 // copy bytes in reverse order into the double variable 15845 JSON_ASSERT(use_count);
6914 float res; 15846 const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
6915 for (size_t byte = 0; byte < sizeof(float); ++byte) 15847 const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
15848 [this, first_prefix, use_bjdata](const BasicJsonType & v)
6916 { 15849 {
6917 reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte]; 15850 return ubjson_prefix(v, use_bjdata) == first_prefix;
6918 } 15851 });
6919 idx += sizeof(float); // skip content bytes
6920 return res;
6921 }
6922 15852
6923 case 0xcb: // float 64 15853 std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type
6924 { 15854
6925 // copy bytes in reverse order into the double variable 15855 if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
6926 double res;
6927 for (size_t byte = 0; byte < sizeof(double); ++byte)
6928 { 15856 {
6929 reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte]; 15857 prefix_required = false;
15858 oa->write_character(to_char_type('$'));
15859 oa->write_character(first_prefix);
6930 } 15860 }
6931 idx += sizeof(double); // skip content bytes
6932 return res;
6933 } 15861 }
6934 15862
6935 case 0xcc: // uint 8 15863 if (use_count)
6936 { 15864 {
6937 idx += 1; // skip content byte 15865 oa->write_character(to_char_type('#'));
6938 return get_from_vector<uint8_t>(v, current_idx); 15866 write_number_with_ubjson_prefix(j.m_data.m_value.array->size(), true, use_bjdata);
6939 } 15867 }
6940 15868
6941 case 0xcd: // uint 16 15869 for (const auto& el : *j.m_data.m_value.array)
6942 { 15870 {
6943 idx += 2; // skip 2 content bytes 15871 write_ubjson(el, use_count, use_type, prefix_required, use_bjdata);
6944 return get_from_vector<uint16_t>(v, current_idx);
6945 } 15872 }
6946 15873
6947 case 0xce: // uint 32 15874 if (!use_count)
6948 { 15875 {
6949 idx += 4; // skip 4 content bytes 15876 oa->write_character(to_char_type(']'));
6950 return get_from_vector<uint32_t>(v, current_idx);
6951 } 15877 }
6952 15878
6953 case 0xcf: // uint 64 15879 break;
15880 }
15881
15882 case value_t::binary:
15883 {
15884 if (add_prefix)
6954 { 15885 {
6955 idx += 8; // skip 8 content bytes 15886 oa->write_character(to_char_type('['));
6956 return get_from_vector<uint64_t>(v, current_idx);
6957 } 15887 }
6958 15888
6959 case 0xd0: // int 8 15889 if (use_type && !j.m_data.m_value.binary->empty())
6960 { 15890 {
6961 idx += 1; // skip content byte 15891 JSON_ASSERT(use_count);
6962 return get_from_vector<int8_t>(v, current_idx); 15892 oa->write_character(to_char_type('$'));
15893 oa->write_character('U');
6963 } 15894 }
6964 15895
6965 case 0xd1: // int 16 15896 if (use_count)
6966 { 15897 {
6967 idx += 2; // skip 2 content bytes 15898 oa->write_character(to_char_type('#'));
6968 return get_from_vector<int16_t>(v, current_idx); 15899 write_number_with_ubjson_prefix(j.m_data.m_value.binary->size(), true, use_bjdata);
6969 } 15900 }
6970 15901
6971 case 0xd2: // int 32 15902 if (use_type)
6972 { 15903 {
6973 idx += 4; // skip 4 content bytes 15904 oa->write_characters(
6974 return get_from_vector<int32_t>(v, current_idx); 15905 reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
15906 j.m_data.m_value.binary->size());
6975 } 15907 }
6976 15908 else
6977 case 0xd3: // int 64
6978 { 15909 {
6979 idx += 8; // skip 8 content bytes 15910 for (size_t i = 0; i < j.m_data.m_value.binary->size(); ++i)
6980 return get_from_vector<int64_t>(v, current_idx); 15911 {
15912 oa->write_character(to_char_type('U'));
15913 oa->write_character(j.m_data.m_value.binary->data()[i]);
15914 }
6981 } 15915 }
6982 15916
6983 case 0xd9: // str 8 15917 if (!use_count)
6984 { 15918 {
6985 const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx)); 15919 oa->write_character(to_char_type(']'));
6986 const size_t offset = current_idx + 2;
6987 idx += len + 1; // skip size byte + content bytes
6988 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
6989 } 15920 }
6990 15921
6991 case 0xda: // str 16 15922 break;
15923 }
15924
15925 case value_t::object:
15926 {
15927 if (use_bjdata && j.m_data.m_value.object->size() == 3 && j.m_data.m_value.object->find("_ArrayType_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArraySize_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArrayData_") != j.m_data.m_value.object->end())
6992 { 15928 {
6993 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); 15929 if (!write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata)
6994 const size_t offset = current_idx + 3; 15930 {
6995 idx += len + 2; // skip 2 size bytes + content bytes 15931 break;
6996 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); 15932 }
6997 } 15933 }
6998 15934
6999 case 0xdb: // str 32 15935 if (add_prefix)
7000 { 15936 {
7001 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); 15937 oa->write_character(to_char_type('{'));
7002 const size_t offset = current_idx + 5;
7003 idx += len + 4; // skip 4 size bytes + content bytes
7004 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
7005 } 15938 }
7006 15939
7007 case 0xdc: // array 16 15940 bool prefix_required = true;
15941 if (use_type && !j.m_data.m_value.object->empty())
7008 { 15942 {
7009 basic_json result = value_t::array; 15943 JSON_ASSERT(use_count);
7010 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); 15944 const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
7011 idx += 2; // skip 2 size bytes 15945 const bool same_prefix = std::all_of(j.begin(), j.end(),
7012 for (size_t i = 0; i < len; ++i) 15946 [this, first_prefix, use_bjdata](const BasicJsonType & v)
7013 { 15947 {
7014 result.push_back(from_msgpack_internal(v, idx)); 15948 return ubjson_prefix(v, use_bjdata) == first_prefix;
7015 } 15949 });
7016 return result;
7017 }
7018 15950
7019 case 0xdd: // array 32 15951 std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type
7020 { 15952
7021 basic_json result = value_t::array; 15953 if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
7022 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
7023 idx += 4; // skip 4 size bytes
7024 for (size_t i = 0; i < len; ++i)
7025 { 15954 {
7026 result.push_back(from_msgpack_internal(v, idx)); 15955 prefix_required = false;
15956 oa->write_character(to_char_type('$'));
15957 oa->write_character(first_prefix);
7027 } 15958 }
7028 return result;
7029 } 15959 }
7030 15960
7031 case 0xde: // map 16 15961 if (use_count)
7032 { 15962 {
7033 basic_json result = value_t::object; 15963 oa->write_character(to_char_type('#'));
7034 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); 15964 write_number_with_ubjson_prefix(j.m_data.m_value.object->size(), true, use_bjdata);
7035 idx += 2; // skip 2 size bytes
7036 for (size_t i = 0; i < len; ++i)
7037 {
7038 std::string key = from_msgpack_internal(v, idx);
7039 result[key] = from_msgpack_internal(v, idx);
7040 }
7041 return result;
7042 } 15965 }
7043 15966
7044 case 0xdf: // map 32 15967 for (const auto& el : *j.m_data.m_value.object)
7045 { 15968 {
7046 basic_json result = value_t::object; 15969 write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata);
7047 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); 15970 oa->write_characters(
7048 idx += 4; // skip 4 size bytes 15971 reinterpret_cast<const CharType*>(el.first.c_str()),
7049 for (size_t i = 0; i < len; ++i) 15972 el.first.size());
7050 { 15973 write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata);
7051 std::string key = from_msgpack_internal(v, idx);
7052 result[key] = from_msgpack_internal(v, idx);
7053 }
7054 return result;
7055 } 15974 }
7056 15975
7057 default: 15976 if (!use_count)
7058 { 15977 {
7059 throw std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx]))); 15978 oa->write_character(to_char_type('}'));
7060 } 15979 }
15980
15981 break;
7061 } 15982 }
15983
15984 case value_t::discarded:
15985 default:
15986 break;
15987 }
15988 }
15989
15990 private:
15991 //////////
15992 // BSON //
15993 //////////
15994
15995 /*!
15996 @return The size of a BSON document entry header, including the id marker
15997 and the entry name size (and its null-terminator).
15998 */
15999 static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j)
16000 {
16001 const auto it = name.find(static_cast<typename string_t::value_type>(0));
16002 if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))
16003 {
16004 JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j));
16005 static_cast<void>(j);
7062 } 16006 }
16007
16008 return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;
16009 }
16010
16011 /*!
16012 @brief Writes the given @a element_type and @a name to the output adapter
16013 */
16014 void write_bson_entry_header(const string_t& name,
16015 const std::uint8_t element_type)
16016 {
16017 oa->write_character(to_char_type(element_type)); // boolean
16018 oa->write_characters(
16019 reinterpret_cast<const CharType*>(name.c_str()),
16020 name.size() + 1u);
16021 }
16022
16023 /*!
16024 @brief Writes a BSON element with key @a name and boolean value @a value
16025 */
16026 void write_bson_boolean(const string_t& name,
16027 const bool value)
16028 {
16029 write_bson_entry_header(name, 0x08);
16030 oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));
16031 }
16032
16033 /*!
16034 @brief Writes a BSON element with key @a name and double value @a value
16035 */
16036 void write_bson_double(const string_t& name,
16037 const double value)
16038 {
16039 write_bson_entry_header(name, 0x01);
16040 write_number<double>(value, true);
16041 }
16042
16043 /*!
16044 @return The size of the BSON-encoded string in @a value
16045 */
16046 static std::size_t calc_bson_string_size(const string_t& value)
16047 {
16048 return sizeof(std::int32_t) + value.size() + 1ul;
7063 } 16049 }
7064 16050
7065 /*! 16051 /*!
7066 @brief create a JSON value from a given CBOR vector 16052 @brief Writes a BSON element with key @a name and string value @a value
16053 */
16054 void write_bson_string(const string_t& name,
16055 const string_t& value)
16056 {
16057 write_bson_entry_header(name, 0x02);
7067 16058
7068 @param[in] v CBOR serialization 16059 write_number<std::int32_t>(static_cast<std::int32_t>(value.size() + 1ul), true);
7069 @param[in] idx byte index to start reading from @a v 16060 oa->write_characters(
16061 reinterpret_cast<const CharType*>(value.c_str()),
16062 value.size() + 1);
16063 }
16064
16065 /*!
16066 @brief Writes a BSON element with key @a name and null value
16067 */
16068 void write_bson_null(const string_t& name)
16069 {
16070 write_bson_entry_header(name, 0x0A);
16071 }
7070 16072
7071 @return deserialized JSON value 16073 /*!
16074 @return The size of the BSON-encoded integer @a value
16075 */
16076 static std::size_t calc_bson_integer_size(const std::int64_t value)
16077 {
16078 return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()
16079 ? sizeof(std::int32_t)
16080 : sizeof(std::int64_t);
16081 }
7072 16082
7073 @throw std::invalid_argument if unsupported features from CBOR were used in 16083 /*!
7074 the given vector @a v or if the input is not valid CBOR 16084 @brief Writes a BSON element with key @a name and integer @a value
7075 @throw std::out_of_range if the given vector ends prematurely 16085 */
16086 void write_bson_integer(const string_t& name,
16087 const std::int64_t value)
16088 {
16089 if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)())
16090 {
16091 write_bson_entry_header(name, 0x10); // int32
16092 write_number<std::int32_t>(static_cast<std::int32_t>(value), true);
16093 }
16094 else
16095 {
16096 write_bson_entry_header(name, 0x12); // int64
16097 write_number<std::int64_t>(static_cast<std::int64_t>(value), true);
16098 }
16099 }
7076 16100
7077 @sa https://tools.ietf.org/html/rfc7049 16101 /*!
16102 @return The size of the BSON-encoded unsigned integer in @a j
7078 */ 16103 */
7079 static basic_json from_cbor_internal(const std::vector<uint8_t>& v, size_t& idx) 16104 static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept
7080 { 16105 {
7081 // store and increment index 16106 return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
7082 const size_t current_idx = idx++; 16107 ? sizeof(std::int32_t)
16108 : sizeof(std::int64_t);
16109 }
7083 16110
7084 switch (v[current_idx]) 16111 /*!
16112 @brief Writes a BSON element with key @a name and unsigned @a value
16113 */
16114 void write_bson_unsigned(const string_t& name,
16115 const BasicJsonType& j)
16116 {
16117 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
7085 { 16118 {
7086 // Integer 0x00..0x17 (0..23) 16119 write_bson_entry_header(name, 0x10 /* int32 */);
7087 case 0x00: 16120 write_number<std::int32_t>(static_cast<std::int32_t>(j.m_data.m_value.number_unsigned), true);
7088 case 0x01: 16121 }
7089 case 0x02: 16122 else if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
7090 case 0x03: 16123 {
7091 case 0x04: 16124 write_bson_entry_header(name, 0x12 /* int64 */);
7092 case 0x05: 16125 write_number<std::int64_t>(static_cast<std::int64_t>(j.m_data.m_value.number_unsigned), true);
7093 case 0x06: 16126 }
7094 case 0x07: 16127 else
7095 case 0x08: 16128 {
7096 case 0x09: 16129 JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j));
7097 case 0x0a: 16130 }
7098 case 0x0b: 16131 }
7099 case 0x0c: 16132
7100 case 0x0d: 16133 /*!
7101 case 0x0e: 16134 @brief Writes a BSON element with key @a name and object @a value
7102 case 0x0f: 16135 */
7103 case 0x10: 16136 void write_bson_object_entry(const string_t& name,
7104 case 0x11: 16137 const typename BasicJsonType::object_t& value)
7105 case 0x12: 16138 {
7106 case 0x13: 16139 write_bson_entry_header(name, 0x03); // object
7107 case 0x14: 16140 write_bson_object(value);
7108 case 0x15: 16141 }
7109 case 0x16: 16142
7110 case 0x17: 16143 /*!
16144 @return The size of the BSON-encoded array @a value
16145 */
16146 static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)
16147 {
16148 std::size_t array_index = 0ul;
16149
16150 const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast<std::size_t>(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el)
16151 {
16152 return result + calc_bson_element_size(std::to_string(array_index++), el);
16153 });
16154
16155 return sizeof(std::int32_t) + embedded_document_size + 1ul;
16156 }
16157
16158 /*!
16159 @return The size of the BSON-encoded binary array @a value
16160 */
16161 static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value)
16162 {
16163 return sizeof(std::int32_t) + value.size() + 1ul;
16164 }
16165
16166 /*!
16167 @brief Writes a BSON element with key @a name and array @a value
16168 */
16169 void write_bson_array(const string_t& name,
16170 const typename BasicJsonType::array_t& value)
16171 {
16172 write_bson_entry_header(name, 0x04); // array
16173 write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_array_size(value)), true);
16174
16175 std::size_t array_index = 0ul;
16176
16177 for (const auto& el : value)
16178 {
16179 write_bson_element(std::to_string(array_index++), el);
16180 }
16181
16182 oa->write_character(to_char_type(0x00));
16183 }
16184
16185 /*!
16186 @brief Writes a BSON element with key @a name and binary value @a value
16187 */
16188 void write_bson_binary(const string_t& name,
16189 const binary_t& value)
16190 {
16191 write_bson_entry_header(name, 0x05);
16192
16193 write_number<std::int32_t>(static_cast<std::int32_t>(value.size()), true);
16194 write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : static_cast<std::uint8_t>(0x00));
16195
16196 oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());
16197 }
16198
16199 /*!
16200 @brief Calculates the size necessary to serialize the JSON value @a j with its @a name
16201 @return The calculated size for the BSON document entry for @a j with the given @a name.
16202 */
16203 static std::size_t calc_bson_element_size(const string_t& name,
16204 const BasicJsonType& j)
16205 {
16206 const auto header_size = calc_bson_entry_header_size(name, j);
16207 switch (j.type())
16208 {
16209 case value_t::object:
16210 return header_size + calc_bson_object_size(*j.m_data.m_value.object);
16211
16212 case value_t::array:
16213 return header_size + calc_bson_array_size(*j.m_data.m_value.array);
16214
16215 case value_t::binary:
16216 return header_size + calc_bson_binary_size(*j.m_data.m_value.binary);
16217
16218 case value_t::boolean:
16219 return header_size + 1ul;
16220
16221 case value_t::number_float:
16222 return header_size + 8ul;
16223
16224 case value_t::number_integer:
16225 return header_size + calc_bson_integer_size(j.m_data.m_value.number_integer);
16226
16227 case value_t::number_unsigned:
16228 return header_size + calc_bson_unsigned_size(j.m_data.m_value.number_unsigned);
16229
16230 case value_t::string:
16231 return header_size + calc_bson_string_size(*j.m_data.m_value.string);
16232
16233 case value_t::null:
16234 return header_size + 0ul;
16235
16236 // LCOV_EXCL_START
16237 case value_t::discarded:
16238 default:
16239 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
16240 return 0ul;
16241 // LCOV_EXCL_STOP
16242 }
16243 }
16244
16245 /*!
16246 @brief Serializes the JSON value @a j to BSON and associates it with the
16247 key @a name.
16248 @param name The name to associate with the JSON entity @a j within the
16249 current BSON document
16250 */
16251 void write_bson_element(const string_t& name,
16252 const BasicJsonType& j)
16253 {
16254 switch (j.type())
16255 {
16256 case value_t::object:
16257 return write_bson_object_entry(name, *j.m_data.m_value.object);
16258
16259 case value_t::array:
16260 return write_bson_array(name, *j.m_data.m_value.array);
16261
16262 case value_t::binary:
16263 return write_bson_binary(name, *j.m_data.m_value.binary);
16264
16265 case value_t::boolean:
16266 return write_bson_boolean(name, j.m_data.m_value.boolean);
16267
16268 case value_t::number_float:
16269 return write_bson_double(name, j.m_data.m_value.number_float);
16270
16271 case value_t::number_integer:
16272 return write_bson_integer(name, j.m_data.m_value.number_integer);
16273
16274 case value_t::number_unsigned:
16275 return write_bson_unsigned(name, j);
16276
16277 case value_t::string:
16278 return write_bson_string(name, *j.m_data.m_value.string);
16279
16280 case value_t::null:
16281 return write_bson_null(name);
16282
16283 // LCOV_EXCL_START
16284 case value_t::discarded:
16285 default:
16286 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
16287 return;
16288 // LCOV_EXCL_STOP
16289 }
16290 }
16291
16292 /*!
16293 @brief Calculates the size of the BSON serialization of the given
16294 JSON-object @a j.
16295 @param[in] value JSON value to serialize
16296 @pre value.type() == value_t::object
16297 */
16298 static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
16299 {
16300 const std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast<std::size_t>(0),
16301 [](size_t result, const typename BasicJsonType::object_t::value_type & el)
16302 {
16303 return result += calc_bson_element_size(el.first, el.second);
16304 });
16305
16306 return sizeof(std::int32_t) + document_size + 1ul;
16307 }
16308
16309 /*!
16310 @param[in] value JSON value to serialize
16311 @pre value.type() == value_t::object
16312 */
16313 void write_bson_object(const typename BasicJsonType::object_t& value)
16314 {
16315 write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_object_size(value)), true);
16316
16317 for (const auto& el : value)
16318 {
16319 write_bson_element(el.first, el.second);
16320 }
16321
16322 oa->write_character(to_char_type(0x00));
16323 }
16324
16325 //////////
16326 // CBOR //
16327 //////////
16328
16329 static constexpr CharType get_cbor_float_prefix(float /*unused*/)
16330 {
16331 return to_char_type(0xFA); // Single-Precision Float
16332 }
16333
16334 static constexpr CharType get_cbor_float_prefix(double /*unused*/)
16335 {
16336 return to_char_type(0xFB); // Double-Precision Float
16337 }
16338
16339 /////////////
16340 // MsgPack //
16341 /////////////
16342
16343 static constexpr CharType get_msgpack_float_prefix(float /*unused*/)
16344 {
16345 return to_char_type(0xCA); // float 32
16346 }
16347
16348 static constexpr CharType get_msgpack_float_prefix(double /*unused*/)
16349 {
16350 return to_char_type(0xCB); // float 64
16351 }
16352
16353 ////////////
16354 // UBJSON //
16355 ////////////
16356
16357 // UBJSON: write number (floating point)
16358 template<typename NumberType, typename std::enable_if<
16359 std::is_floating_point<NumberType>::value, int>::type = 0>
16360 void write_number_with_ubjson_prefix(const NumberType n,
16361 const bool add_prefix,
16362 const bool use_bjdata)
16363 {
16364 if (add_prefix)
16365 {
16366 oa->write_character(get_ubjson_float_prefix(n));
16367 }
16368 write_number(n, use_bjdata);
16369 }
16370
16371 // UBJSON: write number (unsigned integer)
16372 template<typename NumberType, typename std::enable_if<
16373 std::is_unsigned<NumberType>::value, int>::type = 0>
16374 void write_number_with_ubjson_prefix(const NumberType n,
16375 const bool add_prefix,
16376 const bool use_bjdata)
16377 {
16378 if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
16379 {
16380 if (add_prefix)
7111 { 16381 {
7112 return v[current_idx]; 16382 oa->write_character(to_char_type('i')); // int8
7113 } 16383 }
7114 16384 write_number(static_cast<std::uint8_t>(n), use_bjdata);
7115 case 0x18: // Unsigned integer (one-byte uint8_t follows) 16385 }
16386 else if (n <= (std::numeric_limits<std::uint8_t>::max)())
16387 {
16388 if (add_prefix)
7116 { 16389 {
7117 idx += 1; // skip content byte 16390 oa->write_character(to_char_type('U')); // uint8
7118 return get_from_vector<uint8_t>(v, current_idx);
7119 } 16391 }
7120 16392 write_number(static_cast<std::uint8_t>(n), use_bjdata);
7121 case 0x19: // Unsigned integer (two-byte uint16_t follows) 16393 }
16394 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
16395 {
16396 if (add_prefix)
7122 { 16397 {
7123 idx += 2; // skip 2 content bytes 16398 oa->write_character(to_char_type('I')); // int16
7124 return get_from_vector<uint16_t>(v, current_idx);
7125 } 16399 }
7126 16400 write_number(static_cast<std::int16_t>(n), use_bjdata);
7127 case 0x1a: // Unsigned integer (four-byte uint32_t follows) 16401 }
16402 else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint16_t>::max)()))
16403 {
16404 if (add_prefix)
7128 { 16405 {
7129 idx += 4; // skip 4 content bytes 16406 oa->write_character(to_char_type('u')); // uint16 - bjdata only
7130 return get_from_vector<uint32_t>(v, current_idx);
7131 } 16407 }
7132 16408 write_number(static_cast<std::uint16_t>(n), use_bjdata);
7133 case 0x1b: // Unsigned integer (eight-byte uint64_t follows) 16409 }
16410 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
16411 {
16412 if (add_prefix)
7134 { 16413 {
7135 idx += 8; // skip 8 content bytes 16414 oa->write_character(to_char_type('l')); // int32
7136 return get_from_vector<uint64_t>(v, current_idx);
7137 } 16415 }
7138 16416 write_number(static_cast<std::int32_t>(n), use_bjdata);
7139 // Negative integer -1-0x00..-1-0x17 (-1..-24) 16417 }
7140 case 0x20: 16418 else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint32_t>::max)()))
7141 case 0x21: 16419 {
7142 case 0x22: 16420 if (add_prefix)
7143 case 0x23:
7144 case 0x24:
7145 case 0x25:
7146 case 0x26:
7147 case 0x27:
7148 case 0x28:
7149 case 0x29:
7150 case 0x2a:
7151 case 0x2b:
7152 case 0x2c:
7153 case 0x2d:
7154 case 0x2e:
7155 case 0x2f:
7156 case 0x30:
7157 case 0x31:
7158 case 0x32:
7159 case 0x33:
7160 case 0x34:
7161 case 0x35:
7162 case 0x36:
7163 case 0x37:
7164 { 16421 {
7165 return static_cast<int8_t>(0x20 - 1 - v[current_idx]); 16422 oa->write_character(to_char_type('m')); // uint32 - bjdata only
7166 } 16423 }
7167 16424 write_number(static_cast<std::uint32_t>(n), use_bjdata);
7168 case 0x38: // Negative integer (one-byte uint8_t follows) 16425 }
16426 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
16427 {
16428 if (add_prefix)
7169 { 16429 {
7170 idx += 1; // skip content byte 16430 oa->write_character(to_char_type('L')); // int64
7171 // must be uint8_t !
7172 return static_cast<number_integer_t>(-1) - get_from_vector<uint8_t>(v, current_idx);
7173 } 16431 }
7174 16432 write_number(static_cast<std::int64_t>(n), use_bjdata);
7175 case 0x39: // Negative integer -1-n (two-byte uint16_t follows) 16433 }
16434 else if (use_bjdata && n <= (std::numeric_limits<uint64_t>::max)())
16435 {
16436 if (add_prefix)
7176 { 16437 {
7177 idx += 2; // skip 2 content bytes 16438 oa->write_character(to_char_type('M')); // uint64 - bjdata only
7178 return static_cast<number_integer_t>(-1) - get_from_vector<uint16_t>(v, current_idx);
7179 } 16439 }
7180 16440 write_number(static_cast<std::uint64_t>(n), use_bjdata);
7181 case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) 16441 }
16442 else
16443 {
16444 if (add_prefix)
7182 { 16445 {
7183 idx += 4; // skip 4 content bytes 16446 oa->write_character(to_char_type('H')); // high-precision number
7184 return static_cast<number_integer_t>(-1) - get_from_vector<uint32_t>(v, current_idx);
7185 } 16447 }
7186 16448
7187 case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) 16449 const auto number = BasicJsonType(n).dump();
16450 write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
16451 for (std::size_t i = 0; i < number.size(); ++i)
7188 { 16452 {
7189 idx += 8; // skip 8 content bytes 16453 oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
7190 return static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(get_from_vector<uint64_t>(v, current_idx));
7191 } 16454 }
16455 }
16456 }
7192 16457
7193 // UTF-8 string (0x00..0x17 bytes follow) 16458 // UBJSON: write number (signed integer)
7194 case 0x60: 16459 template < typename NumberType, typename std::enable_if <
7195 case 0x61: 16460 std::is_signed<NumberType>::value&&
7196 case 0x62: 16461 !std::is_floating_point<NumberType>::value, int >::type = 0 >
7197 case 0x63: 16462 void write_number_with_ubjson_prefix(const NumberType n,
7198 case 0x64: 16463 const bool add_prefix,
7199 case 0x65: 16464 const bool use_bjdata)
7200 case 0x66: 16465 {
7201 case 0x67: 16466 if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)())
7202 case 0x68: 16467 {
7203 case 0x69: 16468 if (add_prefix)
7204 case 0x6a:
7205 case 0x6b:
7206 case 0x6c:
7207 case 0x6d:
7208 case 0x6e:
7209 case 0x6f:
7210 case 0x70:
7211 case 0x71:
7212 case 0x72:
7213 case 0x73:
7214 case 0x74:
7215 case 0x75:
7216 case 0x76:
7217 case 0x77:
7218 { 16469 {
7219 const auto len = static_cast<size_t>(v[current_idx] - 0x60); 16470 oa->write_character(to_char_type('i')); // int8
7220 const size_t offset = current_idx + 1;
7221 idx += len; // skip content bytes
7222 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
7223 } 16471 }
7224 16472 write_number(static_cast<std::int8_t>(n), use_bjdata);
7225 case 0x78: // UTF-8 string (one-byte uint8_t for n follows) 16473 }
16474 else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))
16475 {
16476 if (add_prefix)
7226 { 16477 {
7227 const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx)); 16478 oa->write_character(to_char_type('U')); // uint8
7228 const size_t offset = current_idx + 2;
7229 idx += len + 1; // skip size byte + content bytes
7230 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
7231 } 16479 }
7232 16480 write_number(static_cast<std::uint8_t>(n), use_bjdata);
7233 case 0x79: // UTF-8 string (two-byte uint16_t for n follow) 16481 }
16482 else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)())
16483 {
16484 if (add_prefix)
7234 { 16485 {
7235 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); 16486 oa->write_character(to_char_type('I')); // int16
7236 const size_t offset = current_idx + 3;
7237 idx += len + 2; // skip 2 size bytes + content bytes
7238 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
7239 } 16487 }
7240 16488 write_number(static_cast<std::int16_t>(n), use_bjdata);
7241 case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) 16489 }
16490 else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::max)())))
16491 {
16492 if (add_prefix)
7242 { 16493 {
7243 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); 16494 oa->write_character(to_char_type('u')); // uint16 - bjdata only
7244 const size_t offset = current_idx + 5;
7245 idx += len + 4; // skip 4 size bytes + content bytes
7246 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
7247 } 16495 }
7248 16496 write_number(static_cast<uint16_t>(n), use_bjdata);
7249 case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) 16497 }
16498 else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)())
16499 {
16500 if (add_prefix)
7250 { 16501 {
7251 const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx)); 16502 oa->write_character(to_char_type('l')); // int32
7252 const size_t offset = current_idx + 9;
7253 idx += len + 8; // skip 8 size bytes + content bytes
7254 return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
7255 } 16503 }
7256 16504 write_number(static_cast<std::int32_t>(n), use_bjdata);
7257 case 0x7f: // UTF-8 string (indefinite length) 16505 }
16506 else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::max)())))
16507 {
16508 if (add_prefix)
7258 { 16509 {
7259 std::string result; 16510 oa->write_character(to_char_type('m')); // uint32 - bjdata only
7260 while (v[idx] != 0xff)
7261 {
7262 string_t s = from_cbor_internal(v, idx);
7263 result += s;
7264 }
7265 // skip break byte (0xFF)
7266 idx += 1;
7267 return result;
7268 } 16511 }
7269 16512 write_number(static_cast<uint32_t>(n), use_bjdata);
7270 // array (0x00..0x17 data items follow) 16513 }
7271 case 0x80: 16514 else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())
7272 case 0x81: 16515 {
7273 case 0x82: 16516 if (add_prefix)
7274 case 0x83:
7275 case 0x84:
7276 case 0x85:
7277 case 0x86:
7278 case 0x87:
7279 case 0x88:
7280 case 0x89:
7281 case 0x8a:
7282 case 0x8b:
7283 case 0x8c:
7284 case 0x8d:
7285 case 0x8e:
7286 case 0x8f:
7287 case 0x90:
7288 case 0x91:
7289 case 0x92:
7290 case 0x93:
7291 case 0x94:
7292 case 0x95:
7293 case 0x96:
7294 case 0x97:
7295 { 16517 {
7296 basic_json result = value_t::array; 16518 oa->write_character(to_char_type('L')); // int64
7297 const auto len = static_cast<size_t>(v[current_idx] - 0x80);
7298 for (size_t i = 0; i < len; ++i)
7299 {
7300 result.push_back(from_cbor_internal(v, idx));
7301 }
7302 return result;
7303 } 16519 }
7304 16520 write_number(static_cast<std::int64_t>(n), use_bjdata);
7305 case 0x98: // array (one-byte uint8_t for n follows) 16521 }
16522 // LCOV_EXCL_START
16523 else
16524 {
16525 if (add_prefix)
7306 { 16526 {
7307 basic_json result = value_t::array; 16527 oa->write_character(to_char_type('H')); // high-precision number
7308 const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
7309 idx += 1; // skip 1 size byte
7310 for (size_t i = 0; i < len; ++i)
7311 {
7312 result.push_back(from_cbor_internal(v, idx));
7313 }
7314 return result;
7315 } 16528 }
7316 16529
7317 case 0x99: // array (two-byte uint16_t for n follow) 16530 const auto number = BasicJsonType(n).dump();
16531 write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
16532 for (std::size_t i = 0; i < number.size(); ++i)
7318 { 16533 {
7319 basic_json result = value_t::array; 16534 oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
7320 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
7321 idx += 2; // skip 4 size bytes
7322 for (size_t i = 0; i < len; ++i)
7323 {
7324 result.push_back(from_cbor_internal(v, idx));
7325 }
7326 return result;
7327 } 16535 }
16536 }
16537 // LCOV_EXCL_STOP
16538 }
16539
16540 /*!
16541 @brief determine the type prefix of container values
16542 */
16543 CharType ubjson_prefix(const BasicJsonType& j, const bool use_bjdata) const noexcept
16544 {
16545 switch (j.type())
16546 {
16547 case value_t::null:
16548 return 'Z';
16549
16550 case value_t::boolean:
16551 return j.m_data.m_value.boolean ? 'T' : 'F';
7328 16552
7329 case 0x9a: // array (four-byte uint32_t for n follow) 16553 case value_t::number_integer:
7330 { 16554 {
7331 basic_json result = value_t::array; 16555 if ((std::numeric_limits<std::int8_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
7332 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
7333 idx += 4; // skip 4 size bytes
7334 for (size_t i = 0; i < len; ++i)
7335 { 16556 {
7336 result.push_back(from_cbor_internal(v, idx)); 16557 return 'i';
7337 } 16558 }
7338 return result; 16559 if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
7339 }
7340
7341 case 0x9b: // array (eight-byte uint64_t for n follow)
7342 {
7343 basic_json result = value_t::array;
7344 const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
7345 idx += 8; // skip 8 size bytes
7346 for (size_t i = 0; i < len; ++i)
7347 { 16560 {
7348 result.push_back(from_cbor_internal(v, idx)); 16561 return 'U';
7349 } 16562 }
7350 return result; 16563 if ((std::numeric_limits<std::int16_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
7351 }
7352
7353 case 0x9f: // array (indefinite length)
7354 {
7355 basic_json result = value_t::array;
7356 while (v[idx] != 0xff)
7357 { 16564 {
7358 result.push_back(from_cbor_internal(v, idx)); 16565 return 'I';
7359 } 16566 }
7360 // skip break byte (0xFF) 16567 if (use_bjdata && ((std::numeric_limits<std::uint16_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)()))
7361 idx += 1;
7362 return result;
7363 }
7364
7365 // map (0x00..0x17 pairs of data items follow)
7366 case 0xa0:
7367 case 0xa1:
7368 case 0xa2:
7369 case 0xa3:
7370 case 0xa4:
7371 case 0xa5:
7372 case 0xa6:
7373 case 0xa7:
7374 case 0xa8:
7375 case 0xa9:
7376 case 0xaa:
7377 case 0xab:
7378 case 0xac:
7379 case 0xad:
7380 case 0xae:
7381 case 0xaf:
7382 case 0xb0:
7383 case 0xb1:
7384 case 0xb2:
7385 case 0xb3:
7386 case 0xb4:
7387 case 0xb5:
7388 case 0xb6:
7389 case 0xb7:
7390 {
7391 basic_json result = value_t::object;
7392 const auto len = static_cast<size_t>(v[current_idx] - 0xa0);
7393 for (size_t i = 0; i < len; ++i)
7394 { 16568 {
7395 std::string key = from_cbor_internal(v, idx); 16569 return 'u';
7396 result[key] = from_cbor_internal(v, idx);
7397 } 16570 }
7398 return result; 16571 if ((std::numeric_limits<std::int32_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
7399 }
7400
7401 case 0xb8: // map (one-byte uint8_t for n follows)
7402 {
7403 basic_json result = value_t::object;
7404 const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
7405 idx += 1; // skip 1 size byte
7406 for (size_t i = 0; i < len; ++i)
7407 { 16572 {
7408 std::string key = from_cbor_internal(v, idx); 16573 return 'l';
7409 result[key] = from_cbor_internal(v, idx);
7410 } 16574 }
7411 return result; 16575 if (use_bjdata && ((std::numeric_limits<std::uint32_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)()))
7412 }
7413
7414 case 0xb9: // map (two-byte uint16_t for n follow)
7415 {
7416 basic_json result = value_t::object;
7417 const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
7418 idx += 2; // skip 2 size bytes
7419 for (size_t i = 0; i < len; ++i)
7420 { 16576 {
7421 std::string key = from_cbor_internal(v, idx); 16577 return 'm';
7422 result[key] = from_cbor_internal(v, idx);
7423 } 16578 }
7424 return result; 16579 if ((std::numeric_limits<std::int64_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
7425 }
7426
7427 case 0xba: // map (four-byte uint32_t for n follow)
7428 {
7429 basic_json result = value_t::object;
7430 const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
7431 idx += 4; // skip 4 size bytes
7432 for (size_t i = 0; i < len; ++i)
7433 { 16580 {
7434 std::string key = from_cbor_internal(v, idx); 16581 return 'L';
7435 result[key] = from_cbor_internal(v, idx);
7436 } 16582 }
7437 return result; 16583 // anything else is treated as high-precision number
16584 return 'H'; // LCOV_EXCL_LINE
7438 } 16585 }
7439 16586
7440 case 0xbb: // map (eight-byte uint64_t for n follow) 16587 case value_t::number_unsigned:
7441 { 16588 {
7442 basic_json result = value_t::object; 16589 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
7443 const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
7444 idx += 8; // skip 8 size bytes
7445 for (size_t i = 0; i < len; ++i)
7446 { 16590 {
7447 std::string key = from_cbor_internal(v, idx); 16591 return 'i';
7448 result[key] = from_cbor_internal(v, idx);
7449 } 16592 }
7450 return result; 16593 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))
7451 } 16594 {
7452 16595 return 'U';
7453 case 0xbf: // map (indefinite length) 16596 }
7454 { 16597 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
7455 basic_json result = value_t::object; 16598 {
7456 while (v[idx] != 0xff) 16599 return 'I';
16600 }
16601 if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint16_t>::max)()))
16602 {
16603 return 'u';
16604 }
16605 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
16606 {
16607 return 'l';
16608 }
16609 if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint32_t>::max)()))
16610 {
16611 return 'm';
16612 }
16613 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
16614 {
16615 return 'L';
16616 }
16617 if (use_bjdata && j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
7457 { 16618 {
7458 std::string key = from_cbor_internal(v, idx); 16619 return 'M';
7459 result[key] = from_cbor_internal(v, idx);
7460 } 16620 }
7461 // skip break byte (0xFF) 16621 // anything else is treated as high-precision number
7462 idx += 1; 16622 return 'H'; // LCOV_EXCL_LINE
7463 return result;
7464 } 16623 }
7465 16624
7466 case 0xf4: // false 16625 case value_t::number_float:
16626 return get_ubjson_float_prefix(j.m_data.m_value.number_float);
16627
16628 case value_t::string:
16629 return 'S';
16630
16631 case value_t::array: // fallthrough
16632 case value_t::binary:
16633 return '[';
16634
16635 case value_t::object:
16636 return '{';
16637
16638 case value_t::discarded:
16639 default: // discarded values
16640 return 'N';
16641 }
16642 }
16643
16644 static constexpr CharType get_ubjson_float_prefix(float /*unused*/)
16645 {
16646 return 'd'; // float 32
16647 }
16648
16649 static constexpr CharType get_ubjson_float_prefix(double /*unused*/)
16650 {
16651 return 'D'; // float 64
16652 }
16653
16654 /*!
16655 @return false if the object is successfully converted to a bjdata ndarray, true if the type or size is invalid
16656 */
16657 bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type)
16658 {
16659 std::map<string_t, CharType> bjdtype = {{"uint8", 'U'}, {"int8", 'i'}, {"uint16", 'u'}, {"int16", 'I'},
16660 {"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'}, {"char", 'C'}
16661 };
16662
16663 string_t key = "_ArrayType_";
16664 auto it = bjdtype.find(static_cast<string_t>(value.at(key)));
16665 if (it == bjdtype.end())
16666 {
16667 return true;
16668 }
16669 CharType dtype = it->second;
16670
16671 key = "_ArraySize_";
16672 std::size_t len = (value.at(key).empty() ? 0 : 1);
16673 for (const auto& el : value.at(key))
16674 {
16675 len *= static_cast<std::size_t>(el.m_data.m_value.number_unsigned);
16676 }
16677
16678 key = "_ArrayData_";
16679 if (value.at(key).size() != len)
16680 {
16681 return true;
16682 }
16683
16684 oa->write_character('[');
16685 oa->write_character('$');
16686 oa->write_character(dtype);
16687 oa->write_character('#');
16688
16689 key = "_ArraySize_";
16690 write_ubjson(value.at(key), use_count, use_type, true, true);
16691
16692 key = "_ArrayData_";
16693 if (dtype == 'U' || dtype == 'C')
16694 {
16695 for (const auto& el : value.at(key))
7467 { 16696 {
7468 return false; 16697 write_number(static_cast<std::uint8_t>(el.m_data.m_value.number_unsigned), true);
7469 } 16698 }
7470 16699 }
7471 case 0xf5: // true 16700 else if (dtype == 'i')
16701 {
16702 for (const auto& el : value.at(key))
7472 { 16703 {
7473 return true; 16704 write_number(static_cast<std::int8_t>(el.m_data.m_value.number_integer), true);
7474 } 16705 }
7475 16706 }
7476 case 0xf6: // null 16707 else if (dtype == 'u')
16708 {
16709 for (const auto& el : value.at(key))
7477 { 16710 {
7478 return value_t::null; 16711 write_number(static_cast<std::uint16_t>(el.m_data.m_value.number_unsigned), true);
7479 } 16712 }
7480 16713 }
7481 case 0xf9: // Half-Precision Float (two-byte IEEE 754) 16714 else if (dtype == 'I')
16715 {
16716 for (const auto& el : value.at(key))
7482 { 16717 {
7483 idx += 2; // skip two content bytes 16718 write_number(static_cast<std::int16_t>(el.m_data.m_value.number_integer), true);
7484
7485 // code from RFC 7049, Appendix D, Figure 3:
7486 // As half-precision floating-point numbers were only added to
7487 // IEEE 754 in 2008, today's programming platforms often still
7488 // only have limited support for them. It is very easy to
7489 // include at least decoding support for them even without such
7490 // support. An example of a small decoder for half-precision
7491 // floating-point numbers in the C language is shown in Fig. 3.
7492 const int half = (v[current_idx + 1] << 8) + v[current_idx + 2];
7493 const int exp = (half >> 10) & 0x1f;
7494 const int mant = half & 0x3ff;
7495 double val;
7496 if (exp == 0)
7497 {
7498 val = std::ldexp(mant, -24);
7499 }
7500 else if (exp != 31)
7501 {
7502 val = std::ldexp(mant + 1024, exp - 25);
7503 }
7504 else
7505 {
7506 val = mant == 0 ? INFINITY : NAN;
7507 }
7508 return half & 0x8000 ? -val : val;
7509 } 16719 }
7510 16720 }
7511 case 0xfa: // Single-Precision Float (four-byte IEEE 754) 16721 else if (dtype == 'm')
16722 {
16723 for (const auto& el : value.at(key))
7512 { 16724 {
7513 // copy bytes in reverse order into the float variable 16725 write_number(static_cast<std::uint32_t>(el.m_data.m_value.number_unsigned), true);
7514 float res;
7515 for (size_t byte = 0; byte < sizeof(float); ++byte)
7516 {
7517 reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte];
7518 }
7519 idx += sizeof(float); // skip content bytes
7520 return res;
7521 } 16726 }
7522 16727 }
7523 case 0xfb: // Double-Precision Float (eight-byte IEEE 754) 16728 else if (dtype == 'l')
16729 {
16730 for (const auto& el : value.at(key))
7524 { 16731 {
7525 // copy bytes in reverse order into the double variable 16732 write_number(static_cast<std::int32_t>(el.m_data.m_value.number_integer), true);
7526 double res;
7527 for (size_t byte = 0; byte < sizeof(double); ++byte)
7528 {
7529 reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte];
7530 }
7531 idx += sizeof(double); // skip content bytes
7532 return res;
7533 } 16733 }
7534 16734 }
7535 default: // anything else (0xFF is handled inside the other types) 16735 else if (dtype == 'M')
16736 {
16737 for (const auto& el : value.at(key))
16738 {
16739 write_number(static_cast<std::uint64_t>(el.m_data.m_value.number_unsigned), true);
16740 }
16741 }
16742 else if (dtype == 'L')
16743 {
16744 for (const auto& el : value.at(key))
16745 {
16746 write_number(static_cast<std::int64_t>(el.m_data.m_value.number_integer), true);
16747 }
16748 }
16749 else if (dtype == 'd')
16750 {
16751 for (const auto& el : value.at(key))
16752 {
16753 write_number(static_cast<float>(el.m_data.m_value.number_float), true);
16754 }
16755 }
16756 else if (dtype == 'D')
16757 {
16758 for (const auto& el : value.at(key))
7536 { 16759 {
7537 throw std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx]))); 16760 write_number(static_cast<double>(el.m_data.m_value.number_float), true);
7538 } 16761 }
7539 } 16762 }
16763 return false;
7540 } 16764 }
7541 16765
7542 public: 16766 ///////////////////////
7543 /*! 16767 // Utility functions //
7544 @brief create a MessagePack serialization of a given JSON value 16768 ///////////////////////
7545 16769
7546 Serializes a given JSON value @a j to a byte vector using the MessagePack 16770 /*
7547 serialization format. MessagePack is a binary serialization format which 16771 @brief write a number to output input
7548 aims to be more compact than JSON itself, yet more efficient to parse. 16772 @param[in] n number of type @a NumberType
16773 @param[in] OutputIsLittleEndian Set to true if output data is
16774 required to be little endian
16775 @tparam NumberType the type of the number
16776
16777 @note This function needs to respect the system's endianness, because bytes
16778 in CBOR, MessagePack, and UBJSON are stored in network order (big
16779 endian) and therefore need reordering on little endian systems.
16780 On the other hand, BSON and BJData use little endian and should reorder
16781 on big endian systems.
16782 */
16783 template<typename NumberType>
16784 void write_number(const NumberType n, const bool OutputIsLittleEndian = false)
16785 {
16786 // step 1: write number to array of length NumberType
16787 std::array<CharType, sizeof(NumberType)> vec{};
16788 std::memcpy(vec.data(), &n, sizeof(NumberType));
7549 16789
7550 @param[in] j JSON value to serialize 16790 // step 2: write array to output (with possible reordering)
7551 @return MessagePack serialization as byte vector 16791 if (is_little_endian != OutputIsLittleEndian)
16792 {
16793 // reverse byte order prior to conversion if necessary
16794 std::reverse(vec.begin(), vec.end());
16795 }
7552 16796
7553 @complexity Linear in the size of the JSON value @a j. 16797 oa->write_characters(vec.data(), sizeof(NumberType));
16798 }
7554 16799
7555 @liveexample{The example shows the serialization of a JSON value to a byte 16800 void write_compact_float(const number_float_t n, detail::input_format_t format)
7556 vector in MessagePack format.,to_msgpack} 16801 {
16802#ifdef __GNUC__
16803#pragma GCC diagnostic push
16804#pragma GCC diagnostic ignored "-Wfloat-equal"
16805#endif
16806 if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
16807 static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
16808 static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))
16809 {
16810 oa->write_character(format == detail::input_format_t::cbor
16811 ? get_cbor_float_prefix(static_cast<float>(n))
16812 : get_msgpack_float_prefix(static_cast<float>(n)));
16813 write_number(static_cast<float>(n));
16814 }
16815 else
16816 {
16817 oa->write_character(format == detail::input_format_t::cbor
16818 ? get_cbor_float_prefix(n)
16819 : get_msgpack_float_prefix(n));
16820 write_number(n);
16821 }
16822#ifdef __GNUC__
16823#pragma GCC diagnostic pop
16824#endif
16825 }
7557 16826
7558 @sa http://msgpack.org 16827 public:
7559 @sa @ref from_msgpack(const std::vector<uint8_t>&) for the analogous 16828 // The following to_char_type functions are implement the conversion
7560 deserialization 16829 // between uint8_t and CharType. In case CharType is not unsigned,
7561 @sa @ref to_cbor(const basic_json& for the related CBOR format 16830 // such a conversion is required to allow values greater than 128.
7562 */ 16831 // See <https://github.com/nlohmann/json/issues/1286> for a discussion.
7563 static std::vector<uint8_t> to_msgpack(const basic_json& j) 16832 template < typename C = CharType,
16833 enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr >
16834 static constexpr CharType to_char_type(std::uint8_t x) noexcept
16835 {
16836 return *reinterpret_cast<char*>(&x);
16837 }
16838
16839 template < typename C = CharType,
16840 enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr >
16841 static CharType to_char_type(std::uint8_t x) noexcept
7564 { 16842 {
7565 std::vector<uint8_t> result; 16843 static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
7566 to_msgpack_internal(j, result); 16844 static_assert(std::is_trivial<CharType>::value, "CharType must be trivial");
16845 CharType result;
16846 std::memcpy(&result, &x, sizeof(x));
7567 return result; 16847 return result;
7568 } 16848 }
7569 16849
7570 /*! 16850 template<typename C = CharType,
7571 @brief create a JSON value from a byte vector in MessagePack format 16851 enable_if_t<std::is_unsigned<C>::value>* = nullptr>
16852 static constexpr CharType to_char_type(std::uint8_t x) noexcept
16853 {
16854 return x;
16855 }
7572 16856
7573 Deserializes a given byte vector @a v to a JSON value using the MessagePack 16857 template < typename InputCharType, typename C = CharType,
7574 serialization format. 16858 enable_if_t <
16859 std::is_signed<C>::value &&
16860 std::is_signed<char>::value &&
16861 std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
16862 > * = nullptr >
16863 static constexpr CharType to_char_type(InputCharType x) noexcept
16864 {
16865 return x;
16866 }
7575 16867
7576 @param[in] v a byte vector in MessagePack format 16868 private:
7577 @return deserialized JSON value 16869 /// whether we can assume little endianness
16870 const bool is_little_endian = little_endianness();
16871
16872 /// the output
16873 output_adapter_t<CharType> oa = nullptr;
16874};
16875
16876} // namespace detail
16877NLOHMANN_JSON_NAMESPACE_END
16878
16879// #include <nlohmann/detail/output/output_adapters.hpp>
16880
16881// #include <nlohmann/detail/output/serializer.hpp>
16882// __ _____ _____ _____
16883// __| | __| | | | JSON for Modern C++
16884// | | |__ | | | | | | version 3.11.3
16885// |_____|_____|_____|_|___| https://github.com/nlohmann/json
16886//
16887// SPDX-FileCopyrightText: 2008-2009 Björn Hoehrmann <bjoern@hoehrmann.de>
16888// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
16889// SPDX-License-Identifier: MIT
16890
16891
16892
16893#include <algorithm> // reverse, remove, fill, find, none_of
16894#include <array> // array
16895#include <clocale> // localeconv, lconv
16896#include <cmath> // labs, isfinite, isnan, signbit
16897#include <cstddef> // size_t, ptrdiff_t
16898#include <cstdint> // uint8_t
16899#include <cstdio> // snprintf
16900#include <limits> // numeric_limits
16901#include <string> // string, char_traits
16902#include <iomanip> // setfill, setw
16903#include <type_traits> // is_same
16904#include <utility> // move
16905
16906// #include <nlohmann/detail/conversions/to_chars.hpp>
16907// __ _____ _____ _____
16908// __| | __| | | | JSON for Modern C++
16909// | | |__ | | | | | | version 3.11.3
16910// |_____|_____|_____|_|___| https://github.com/nlohmann/json
16911//
16912// SPDX-FileCopyrightText: 2009 Florian Loitsch <https://florian.loitsch.com/>
16913// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
16914// SPDX-License-Identifier: MIT
16915
16916
16917
16918#include <array> // array
16919#include <cmath> // signbit, isfinite
16920#include <cstdint> // intN_t, uintN_t
16921#include <cstring> // memcpy, memmove
16922#include <limits> // numeric_limits
16923#include <type_traits> // conditional
7578 16924
7579 @throw std::invalid_argument if unsupported features from MessagePack were 16925// #include <nlohmann/detail/macro_scope.hpp>
7580 used in the given vector @a v or if the input is not valid MessagePack
7581 @throw std::out_of_range if the given vector ends prematurely
7582 16926
7583 @complexity Linear in the size of the byte vector @a v.
7584 16927
7585 @liveexample{The example shows the deserialization of a byte vector in 16928NLOHMANN_JSON_NAMESPACE_BEGIN
7586 MessagePack format to a JSON value.,from_msgpack} 16929namespace detail
16930{
16931
16932/*!
16933@brief implements the Grisu2 algorithm for binary to decimal floating-point
16934conversion.
7587 16935
7588 @sa http://msgpack.org 16936This implementation is a slightly modified version of the reference
7589 @sa @ref to_msgpack(const basic_json&) for the analogous serialization 16937implementation which may be obtained from
7590 @sa @ref from_cbor(const std::vector<uint8_t>&) for the related CBOR format 16938http://florian.loitsch.com/publications (bench.tar.gz).
16939
16940The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.
16941
16942For a detailed description of the algorithm see:
16943
16944[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with
16945 Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming
16946 Language Design and Implementation, PLDI 2010
16947[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately",
16948 Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language
16949 Design and Implementation, PLDI 1996
16950*/
16951namespace dtoa_impl
16952{
16953
16954template<typename Target, typename Source>
16955Target reinterpret_bits(const Source source)
16956{
16957 static_assert(sizeof(Target) == sizeof(Source), "size mismatch");
16958
16959 Target target;
16960 std::memcpy(&target, &source, sizeof(Source));
16961 return target;
16962}
16963
16964struct diyfp // f * 2^e
16965{
16966 static constexpr int kPrecision = 64; // = q
16967
16968 std::uint64_t f = 0;
16969 int e = 0;
16970
16971 constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {}
16972
16973 /*!
16974 @brief returns x - y
16975 @pre x.e == y.e and x.f >= y.f
7591 */ 16976 */
7592 static basic_json from_msgpack(const std::vector<uint8_t>& v) 16977 static diyfp sub(const diyfp& x, const diyfp& y) noexcept
7593 { 16978 {
7594 size_t i = 0; 16979 JSON_ASSERT(x.e == y.e);
7595 return from_msgpack_internal(v, i); 16980 JSON_ASSERT(x.f >= y.f);
16981
16982 return {x.f - y.f, x.e};
7596 } 16983 }
7597 16984
7598 /*! 16985 /*!
7599 @brief create a MessagePack serialization of a given JSON value 16986 @brief returns x * y
7600 16987 @note The result is rounded. (Only the upper q bits are returned.)
7601 Serializes a given JSON value @a j to a byte vector using the CBOR (Concise 16988 */
7602 Binary Object Representation) serialization format. CBOR is a binary 16989 static diyfp mul(const diyfp& x, const diyfp& y) noexcept
7603 serialization format which aims to be more compact than JSON itself, yet 16990 {
7604 more efficient to parse. 16991 static_assert(kPrecision == 64, "internal error");
16992
16993 // Computes:
16994 // f = round((x.f * y.f) / 2^q)
16995 // e = x.e + y.e + q
16996
16997 // Emulate the 64-bit * 64-bit multiplication:
16998 //
16999 // p = u * v
17000 // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)
17001 // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi )
17002 // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 )
17003 // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 )
17004 // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3)
17005 // = (p0_lo ) + 2^32 (Q ) + 2^64 (H )
17006 // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H )
17007 //
17008 // (Since Q might be larger than 2^32 - 1)
17009 //
17010 // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)
17011 //
17012 // (Q_hi + H does not overflow a 64-bit int)
17013 //
17014 // = p_lo + 2^64 p_hi
17015
17016 const std::uint64_t u_lo = x.f & 0xFFFFFFFFu;
17017 const std::uint64_t u_hi = x.f >> 32u;
17018 const std::uint64_t v_lo = y.f & 0xFFFFFFFFu;
17019 const std::uint64_t v_hi = y.f >> 32u;
17020
17021 const std::uint64_t p0 = u_lo * v_lo;
17022 const std::uint64_t p1 = u_lo * v_hi;
17023 const std::uint64_t p2 = u_hi * v_lo;
17024 const std::uint64_t p3 = u_hi * v_hi;
17025
17026 const std::uint64_t p0_hi = p0 >> 32u;
17027 const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu;
17028 const std::uint64_t p1_hi = p1 >> 32u;
17029 const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu;
17030 const std::uint64_t p2_hi = p2 >> 32u;
17031
17032 std::uint64_t Q = p0_hi + p1_lo + p2_lo;
17033
17034 // The full product might now be computed as
17035 //
17036 // p_hi = p3 + p2_hi + p1_hi + (Q >> 32)
17037 // p_lo = p0_lo + (Q << 32)
17038 //
17039 // But in this particular case here, the full p_lo is not required.
17040 // Effectively we only need to add the highest bit in p_lo to p_hi (and
17041 // Q_hi + 1 does not overflow).
17042
17043 Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up
17044
17045 const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u);
17046
17047 return {h, x.e + y.e + 64};
17048 }
7605 17049
7606 @param[in] j JSON value to serialize 17050 /*!
7607 @return MessagePack serialization as byte vector 17051 @brief normalize x such that the significand is >= 2^(q-1)
17052 @pre x.f != 0
17053 */
17054 static diyfp normalize(diyfp x) noexcept
17055 {
17056 JSON_ASSERT(x.f != 0);
7608 17057
7609 @complexity Linear in the size of the JSON value @a j. 17058 while ((x.f >> 63u) == 0)
17059 {
17060 x.f <<= 1u;
17061 x.e--;
17062 }
7610 17063
7611 @liveexample{The example shows the serialization of a JSON value to a byte 17064 return x;
7612 vector in CBOR format.,to_cbor} 17065 }
7613 17066
7614 @sa http://cbor.io 17067 /*!
7615 @sa @ref from_cbor(const std::vector<uint8_t>&) for the analogous 17068 @brief normalize x such that the result has the exponent E
7616 deserialization 17069 @pre e >= x.e and the upper e - x.e bits of x.f must be zero.
7617 @sa @ref to_msgpack(const basic_json& for the related MessagePack format
7618 */ 17070 */
7619 static std::vector<uint8_t> to_cbor(const basic_json& j) 17071 static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept
7620 { 17072 {
7621 std::vector<uint8_t> result; 17073 const int delta = x.e - target_exponent;
7622 to_cbor_internal(j, result);
7623 return result;
7624 }
7625 17074
7626 /*! 17075 JSON_ASSERT(delta >= 0);
7627 @brief create a JSON value from a byte vector in CBOR format 17076 JSON_ASSERT(((x.f << delta) >> delta) == x.f);
7628 17077
7629 Deserializes a given byte vector @a v to a JSON value using the CBOR 17078 return {x.f << delta, target_exponent};
7630 (Concise Binary Object Representation) serialization format. 17079 }
17080};
7631 17081
7632 @param[in] v a byte vector in CBOR format 17082struct boundaries
7633 @return deserialized JSON value 17083{
17084 diyfp w;
17085 diyfp minus;
17086 diyfp plus;
17087};
7634 17088
7635 @throw std::invalid_argument if unsupported features from CBOR were used in 17089/*!
7636 the given vector @a v or if the input is not valid MessagePack 17090Compute the (normalized) diyfp representing the input number 'value' and its
7637 @throw std::out_of_range if the given vector ends prematurely 17091boundaries.
7638 17092
7639 @complexity Linear in the size of the byte vector @a v. 17093@pre value must be finite and positive
17094*/
17095template<typename FloatType>
17096boundaries compute_boundaries(FloatType value)
17097{
17098 JSON_ASSERT(std::isfinite(value));
17099 JSON_ASSERT(value > 0);
17100
17101 // Convert the IEEE representation into a diyfp.
17102 //
17103 // If v is denormal:
17104 // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1))
17105 // If v is normalized:
17106 // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))
17107
17108 static_assert(std::numeric_limits<FloatType>::is_iec559,
17109 "internal error: dtoa_short requires an IEEE-754 floating-point implementation");
17110
17111 constexpr int kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)
17112 constexpr int kBias = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);
17113 constexpr int kMinExp = 1 - kBias;
17114 constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1)
17115
17116 using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type;
17117
17118 const auto bits = static_cast<std::uint64_t>(reinterpret_bits<bits_type>(value));
17119 const std::uint64_t E = bits >> (kPrecision - 1);
17120 const std::uint64_t F = bits & (kHiddenBit - 1);
17121
17122 const bool is_denormal = E == 0;
17123 const diyfp v = is_denormal
17124 ? diyfp(F, kMinExp)
17125 : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
17126
17127 // Compute the boundaries m- and m+ of the floating-point value
17128 // v = f * 2^e.
17129 //
17130 // Determine v- and v+, the floating-point predecessor and successor if v,
17131 // respectively.
17132 //
17133 // v- = v - 2^e if f != 2^(p-1) or e == e_min (A)
17134 // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B)
17135 //
17136 // v+ = v + 2^e
17137 //
17138 // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_
17139 // between m- and m+ round to v, regardless of how the input rounding
17140 // algorithm breaks ties.
17141 //
17142 // ---+-------------+-------------+-------------+-------------+--- (A)
17143 // v- m- v m+ v+
17144 //
17145 // -----------------+------+------+-------------+-------------+--- (B)
17146 // v- m- v m+ v+
17147
17148 const bool lower_boundary_is_closer = F == 0 && E > 1;
17149 const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
17150 const diyfp m_minus = lower_boundary_is_closer
17151 ? diyfp(4 * v.f - 1, v.e - 2) // (B)
17152 : diyfp(2 * v.f - 1, v.e - 1); // (A)
17153
17154 // Determine the normalized w+ = m+.
17155 const diyfp w_plus = diyfp::normalize(m_plus);
17156
17157 // Determine w- = m- such that e_(w-) = e_(w+).
17158 const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);
17159
17160 return {diyfp::normalize(v), w_minus, w_plus};
17161}
7640 17162
7641 @liveexample{The example shows the deserialization of a byte vector in CBOR 17163// Given normalized diyfp w, Grisu needs to find a (normalized) cached
7642 format to a JSON value.,from_cbor} 17164// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies
17165// within a certain range [alpha, gamma] (Definition 3.2 from [1])
17166//
17167// alpha <= e = e_c + e_w + q <= gamma
17168//
17169// or
17170//
17171// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q
17172// <= f_c * f_w * 2^gamma
17173//
17174// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies
17175//
17176// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma
17177//
17178// or
17179//
17180// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma)
17181//
17182// The choice of (alpha,gamma) determines the size of the table and the form of
17183// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well
17184// in practice:
17185//
17186// The idea is to cut the number c * w = f * 2^e into two parts, which can be
17187// processed independently: An integral part p1, and a fractional part p2:
17188//
17189// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e
17190// = (f div 2^-e) + (f mod 2^-e) * 2^e
17191// = p1 + p2 * 2^e
17192//
17193// The conversion of p1 into decimal form requires a series of divisions and
17194// modulos by (a power of) 10. These operations are faster for 32-bit than for
17195// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be
17196// achieved by choosing
17197//
17198// -e >= 32 or e <= -32 := gamma
17199//
17200// In order to convert the fractional part
17201//
17202// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...
17203//
17204// into decimal form, the fraction is repeatedly multiplied by 10 and the digits
17205// d[-i] are extracted in order:
17206//
17207// (10 * p2) div 2^-e = d[-1]
17208// (10 * p2) mod 2^-e = d[-2] / 10^1 + ...
17209//
17210// The multiplication by 10 must not overflow. It is sufficient to choose
17211//
17212// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.
17213//
17214// Since p2 = f mod 2^-e < 2^-e,
17215//
17216// -e <= 60 or e >= -60 := alpha
17217
17218constexpr int kAlpha = -60;
17219constexpr int kGamma = -32;
17220
17221struct cached_power // c = f * 2^e ~= 10^k
17222{
17223 std::uint64_t f;
17224 int e;
17225 int k;
17226};
7643 17227
7644 @sa http://cbor.io 17228/*!
7645 @sa @ref to_cbor(const basic_json&) for the analogous serialization 17229For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached
7646 @sa @ref from_msgpack(const std::vector<uint8_t>&) for the related 17230power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c
7647 MessagePack format 17231satisfies (Definition 3.2 from [1])
7648 */ 17232
7649 static basic_json from_cbor(const std::vector<uint8_t>& v) 17233 alpha <= e_c + e + q <= gamma.
17234*/
17235inline cached_power get_cached_power_for_binary_exponent(int e)
17236{
17237 // Now
17238 //
17239 // alpha <= e_c + e + q <= gamma (1)
17240 // ==> f_c * 2^alpha <= c * 2^e * 2^q
17241 //
17242 // and since the c's are normalized, 2^(q-1) <= f_c,
17243 //
17244 // ==> 2^(q - 1 + alpha) <= c * 2^(e + q)
17245 // ==> 2^(alpha - e - 1) <= c
17246 //
17247 // If c were an exact power of ten, i.e. c = 10^k, one may determine k as
17248 //
17249 // k = ceil( log_10( 2^(alpha - e - 1) ) )
17250 // = ceil( (alpha - e - 1) * log_10(2) )
17251 //
17252 // From the paper:
17253 // "In theory the result of the procedure could be wrong since c is rounded,
17254 // and the computation itself is approximated [...]. In practice, however,
17255 // this simple function is sufficient."
17256 //
17257 // For IEEE double precision floating-point numbers converted into
17258 // normalized diyfp's w = f * 2^e, with q = 64,
17259 //
17260 // e >= -1022 (min IEEE exponent)
17261 // -52 (p - 1)
17262 // -52 (p - 1, possibly normalize denormal IEEE numbers)
17263 // -11 (normalize the diyfp)
17264 // = -1137
17265 //
17266 // and
17267 //
17268 // e <= +1023 (max IEEE exponent)
17269 // -52 (p - 1)
17270 // -11 (normalize the diyfp)
17271 // = 960
17272 //
17273 // This binary exponent range [-1137,960] results in a decimal exponent
17274 // range [-307,324]. One does not need to store a cached power for each
17275 // k in this range. For each such k it suffices to find a cached power
17276 // such that the exponent of the product lies in [alpha,gamma].
17277 // This implies that the difference of the decimal exponents of adjacent
17278 // table entries must be less than or equal to
17279 //
17280 // floor( (gamma - alpha) * log_10(2) ) = 8.
17281 //
17282 // (A smaller distance gamma-alpha would require a larger table.)
17283
17284 // NB:
17285 // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.
17286
17287 constexpr int kCachedPowersMinDecExp = -300;
17288 constexpr int kCachedPowersDecStep = 8;
17289
17290 static constexpr std::array<cached_power, 79> kCachedPowers =
7650 { 17291 {
7651 size_t i = 0; 17292 {
7652 return from_cbor_internal(v, i); 17293 { 0xAB70FE17C79AC6CA, -1060, -300 },
7653 } 17294 { 0xFF77B1FCBEBCDC4F, -1034, -292 },
17295 { 0xBE5691EF416BD60C, -1007, -284 },
17296 { 0x8DD01FAD907FFC3C, -980, -276 },
17297 { 0xD3515C2831559A83, -954, -268 },
17298 { 0x9D71AC8FADA6C9B5, -927, -260 },
17299 { 0xEA9C227723EE8BCB, -901, -252 },
17300 { 0xAECC49914078536D, -874, -244 },
17301 { 0x823C12795DB6CE57, -847, -236 },
17302 { 0xC21094364DFB5637, -821, -228 },
17303 { 0x9096EA6F3848984F, -794, -220 },
17304 { 0xD77485CB25823AC7, -768, -212 },
17305 { 0xA086CFCD97BF97F4, -741, -204 },
17306 { 0xEF340A98172AACE5, -715, -196 },
17307 { 0xB23867FB2A35B28E, -688, -188 },
17308 { 0x84C8D4DFD2C63F3B, -661, -180 },
17309 { 0xC5DD44271AD3CDBA, -635, -172 },
17310 { 0x936B9FCEBB25C996, -608, -164 },
17311 { 0xDBAC6C247D62A584, -582, -156 },
17312 { 0xA3AB66580D5FDAF6, -555, -148 },
17313 { 0xF3E2F893DEC3F126, -529, -140 },
17314 { 0xB5B5ADA8AAFF80B8, -502, -132 },
17315 { 0x87625F056C7C4A8B, -475, -124 },
17316 { 0xC9BCFF6034C13053, -449, -116 },
17317 { 0x964E858C91BA2655, -422, -108 },
17318 { 0xDFF9772470297EBD, -396, -100 },
17319 { 0xA6DFBD9FB8E5B88F, -369, -92 },
17320 { 0xF8A95FCF88747D94, -343, -84 },
17321 { 0xB94470938FA89BCF, -316, -76 },
17322 { 0x8A08F0F8BF0F156B, -289, -68 },
17323 { 0xCDB02555653131B6, -263, -60 },
17324 { 0x993FE2C6D07B7FAC, -236, -52 },
17325 { 0xE45C10C42A2B3B06, -210, -44 },
17326 { 0xAA242499697392D3, -183, -36 },
17327 { 0xFD87B5F28300CA0E, -157, -28 },
17328 { 0xBCE5086492111AEB, -130, -20 },
17329 { 0x8CBCCC096F5088CC, -103, -12 },
17330 { 0xD1B71758E219652C, -77, -4 },
17331 { 0x9C40000000000000, -50, 4 },
17332 { 0xE8D4A51000000000, -24, 12 },
17333 { 0xAD78EBC5AC620000, 3, 20 },
17334 { 0x813F3978F8940984, 30, 28 },
17335 { 0xC097CE7BC90715B3, 56, 36 },
17336 { 0x8F7E32CE7BEA5C70, 83, 44 },
17337 { 0xD5D238A4ABE98068, 109, 52 },
17338 { 0x9F4F2726179A2245, 136, 60 },
17339 { 0xED63A231D4C4FB27, 162, 68 },
17340 { 0xB0DE65388CC8ADA8, 189, 76 },
17341 { 0x83C7088E1AAB65DB, 216, 84 },
17342 { 0xC45D1DF942711D9A, 242, 92 },
17343 { 0x924D692CA61BE758, 269, 100 },
17344 { 0xDA01EE641A708DEA, 295, 108 },
17345 { 0xA26DA3999AEF774A, 322, 116 },
17346 { 0xF209787BB47D6B85, 348, 124 },
17347 { 0xB454E4A179DD1877, 375, 132 },
17348 { 0x865B86925B9BC5C2, 402, 140 },
17349 { 0xC83553C5C8965D3D, 428, 148 },
17350 { 0x952AB45CFA97A0B3, 455, 156 },
17351 { 0xDE469FBD99A05FE3, 481, 164 },
17352 { 0xA59BC234DB398C25, 508, 172 },
17353 { 0xF6C69A72A3989F5C, 534, 180 },
17354 { 0xB7DCBF5354E9BECE, 561, 188 },
17355 { 0x88FCF317F22241E2, 588, 196 },
17356 { 0xCC20CE9BD35C78A5, 614, 204 },
17357 { 0x98165AF37B2153DF, 641, 212 },
17358 { 0xE2A0B5DC971F303A, 667, 220 },
17359 { 0xA8D9D1535CE3B396, 694, 228 },
17360 { 0xFB9B7CD9A4A7443C, 720, 236 },
17361 { 0xBB764C4CA7A44410, 747, 244 },
17362 { 0x8BAB8EEFB6409C1A, 774, 252 },
17363 { 0xD01FEF10A657842C, 800, 260 },
17364 { 0x9B10A4E5E9913129, 827, 268 },
17365 { 0xE7109BFBA19C0C9D, 853, 276 },
17366 { 0xAC2820D9623BF429, 880, 284 },
17367 { 0x80444B5E7AA7CF85, 907, 292 },
17368 { 0xBF21E44003ACDD2D, 933, 300 },
17369 { 0x8E679C2F5E44FF8F, 960, 308 },
17370 { 0xD433179D9C8CB841, 986, 316 },
17371 { 0x9E19DB92B4E31BA9, 1013, 324 },
17372 }
17373 };
7654 17374
7655 /// @} 17375 // This computation gives exactly the same results for k as
17376 // k = ceil((kAlpha - e - 1) * 0.30102999566398114)
17377 // for |e| <= 1500, but doesn't require floating-point operations.
17378 // NB: log_10(2) ~= 78913 / 2^18
17379 JSON_ASSERT(e >= -1500);
17380 JSON_ASSERT(e <= 1500);
17381 const int f = kAlpha - e - 1;
17382 const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);
7656 17383
7657 private: 17384 const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
7658 /////////////////////////// 17385 JSON_ASSERT(index >= 0);
7659 // convenience functions // 17386 JSON_ASSERT(static_cast<std::size_t>(index) < kCachedPowers.size());
7660 ///////////////////////////
7661 17387
7662 /*! 17388 const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];
7663 @brief return the type as string 17389 JSON_ASSERT(kAlpha <= cached.e + e + 64);
17390 JSON_ASSERT(kGamma >= cached.e + e + 64);
7664 17391
7665 Returns the type name as string to be used in error messages - usually to 17392 return cached;
7666 indicate that a function was called on a wrong JSON type. 17393}
7667 17394
7668 @return basically a string representation of a the @a m_type member 17395/*!
17396For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.
17397For n == 0, returns 1 and sets pow10 := 1.
17398*/
17399inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)
17400{
17401 // LCOV_EXCL_START
17402 if (n >= 1000000000)
17403 {
17404 pow10 = 1000000000;
17405 return 10;
17406 }
17407 // LCOV_EXCL_STOP
17408 if (n >= 100000000)
17409 {
17410 pow10 = 100000000;
17411 return 9;
17412 }
17413 if (n >= 10000000)
17414 {
17415 pow10 = 10000000;
17416 return 8;
17417 }
17418 if (n >= 1000000)
17419 {
17420 pow10 = 1000000;
17421 return 7;
17422 }
17423 if (n >= 100000)
17424 {
17425 pow10 = 100000;
17426 return 6;
17427 }
17428 if (n >= 10000)
17429 {
17430 pow10 = 10000;
17431 return 5;
17432 }
17433 if (n >= 1000)
17434 {
17435 pow10 = 1000;
17436 return 4;
17437 }
17438 if (n >= 100)
17439 {
17440 pow10 = 100;
17441 return 3;
17442 }
17443 if (n >= 10)
17444 {
17445 pow10 = 10;
17446 return 2;
17447 }
7669 17448
7670 @complexity Constant. 17449 pow10 = 1;
17450 return 1;
17451}
7671 17452
7672 @since version 1.0.0 17453inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,
7673 */ 17454 std::uint64_t rest, std::uint64_t ten_k)
7674 std::string type_name() const 17455{
17456 JSON_ASSERT(len >= 1);
17457 JSON_ASSERT(dist <= delta);
17458 JSON_ASSERT(rest <= delta);
17459 JSON_ASSERT(ten_k > 0);
17460
17461 // <--------------------------- delta ---->
17462 // <---- dist --------->
17463 // --------------[------------------+-------------------]--------------
17464 // M- w M+
17465 //
17466 // ten_k
17467 // <------>
17468 // <---- rest ---->
17469 // --------------[------------------+----+--------------]--------------
17470 // w V
17471 // = buf * 10^k
17472 //
17473 // ten_k represents a unit-in-the-last-place in the decimal representation
17474 // stored in buf.
17475 // Decrement buf by ten_k while this takes buf closer to w.
17476
17477 // The tests are written in this order to avoid overflow in unsigned
17478 // integer arithmetic.
17479
17480 while (rest < dist
17481 && delta - rest >= ten_k
17482 && (rest + ten_k < dist || dist - rest > rest + ten_k - dist))
17483 {
17484 JSON_ASSERT(buf[len - 1] != '0');
17485 buf[len - 1]--;
17486 rest += ten_k;
17487 }
17488}
17489
17490/*!
17491Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.
17492M- and M+ must be normalized and share the same exponent -60 <= e <= -32.
17493*/
17494inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
17495 diyfp M_minus, diyfp w, diyfp M_plus)
17496{
17497 static_assert(kAlpha >= -60, "internal error");
17498 static_assert(kGamma <= -32, "internal error");
17499
17500 // Generates the digits (and the exponent) of a decimal floating-point
17501 // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's
17502 // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.
17503 //
17504 // <--------------------------- delta ---->
17505 // <---- dist --------->
17506 // --------------[------------------+-------------------]--------------
17507 // M- w M+
17508 //
17509 // Grisu2 generates the digits of M+ from left to right and stops as soon as
17510 // V is in [M-,M+].
17511
17512 JSON_ASSERT(M_plus.e >= kAlpha);
17513 JSON_ASSERT(M_plus.e <= kGamma);
17514
17515 std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)
17516 std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e)
17517
17518 // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):
17519 //
17520 // M+ = f * 2^e
17521 // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e
17522 // = ((p1 ) * 2^-e + (p2 )) * 2^e
17523 // = p1 + p2 * 2^e
17524
17525 const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e);
17526
17527 auto p1 = static_cast<std::uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)
17528 std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e
17529
17530 // 1)
17531 //
17532 // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]
17533
17534 JSON_ASSERT(p1 > 0);
17535
17536 std::uint32_t pow10{};
17537 const int k = find_largest_pow10(p1, pow10);
17538
17539 // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)
17540 //
17541 // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))
17542 // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1))
17543 //
17544 // M+ = p1 + p2 * 2^e
17545 // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e
17546 // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e
17547 // = d[k-1] * 10^(k-1) + ( rest) * 2^e
17548 //
17549 // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)
17550 //
17551 // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]
17552 //
17553 // but stop as soon as
17554 //
17555 // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e
17556
17557 int n = k;
17558 while (n > 0)
7675 { 17559 {
7676 switch (m_type) 17560 // Invariants:
17561 // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k)
17562 // pow10 = 10^(n-1) <= p1 < 10^n
17563 //
17564 const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1)
17565 const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1)
17566 //
17567 // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
17568 // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
17569 //
17570 JSON_ASSERT(d <= 9);
17571 buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
17572 //
17573 // M+ = buffer * 10^(n-1) + (r + p2 * 2^e)
17574 //
17575 p1 = r;
17576 n--;
17577 //
17578 // M+ = buffer * 10^n + (p1 + p2 * 2^e)
17579 // pow10 = 10^n
17580 //
17581
17582 // Now check if enough digits have been generated.
17583 // Compute
17584 //
17585 // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e
17586 //
17587 // Note:
17588 // Since rest and delta share the same exponent e, it suffices to
17589 // compare the significands.
17590 const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2;
17591 if (rest <= delta)
7677 { 17592 {
7678 case value_t::null: 17593 // V = buffer * 10^n, with M- <= V <= M+.
7679 return "null"; 17594
7680 case value_t::object: 17595 decimal_exponent += n;
7681 return "object"; 17596
7682 case value_t::array: 17597 // We may now just stop. But instead look if the buffer could be
7683 return "array"; 17598 // decremented to bring V closer to w.
7684 case value_t::string: 17599 //
7685 return "string"; 17600 // pow10 = 10^n is now 1 ulp in the decimal representation V.
7686 case value_t::boolean: 17601 // The rounding procedure works with diyfp's with an implicit
7687 return "boolean"; 17602 // exponent of e.
7688 case value_t::discarded: 17603 //
7689 return "discarded"; 17604 // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e
7690 default: 17605 //
7691 return "number"; 17606 const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e;
17607 grisu2_round(buffer, length, dist, delta, rest, ten_n);
17608
17609 return;
7692 } 17610 }
17611
17612 pow10 /= 10;
17613 //
17614 // pow10 = 10^(n-1) <= p1 < 10^n
17615 // Invariants restored.
7693 } 17616 }
7694 17617
7695 /*! 17618 // 2)
7696 @brief calculates the extra space to escape a JSON string 17619 //
17620 // The digits of the integral part have been generated:
17621 //
17622 // M+ = d[k-1]...d[1]d[0] + p2 * 2^e
17623 // = buffer + p2 * 2^e
17624 //
17625 // Now generate the digits of the fractional part p2 * 2^e.
17626 //
17627 // Note:
17628 // No decimal point is generated: the exponent is adjusted instead.
17629 //
17630 // p2 actually represents the fraction
17631 //
17632 // p2 * 2^e
17633 // = p2 / 2^-e
17634 // = d[-1] / 10^1 + d[-2] / 10^2 + ...
17635 //
17636 // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)
17637 //
17638 // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m
17639 // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)
17640 //
17641 // using
17642 //
17643 // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)
17644 // = ( d) * 2^-e + ( r)
17645 //
17646 // or
17647 // 10^m * p2 * 2^e = d + r * 2^e
17648 //
17649 // i.e.
17650 //
17651 // M+ = buffer + p2 * 2^e
17652 // = buffer + 10^-m * (d + r * 2^e)
17653 // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e
17654 //
17655 // and stop as soon as 10^-m * r * 2^e <= delta * 2^e
17656
17657 JSON_ASSERT(p2 > delta);
17658
17659 int m = 0;
17660 for (;;)
17661 {
17662 // Invariant:
17663 // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e
17664 // = buffer * 10^-m + 10^-m * (p2 ) * 2^e
17665 // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e
17666 // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e
17667 //
17668 JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);
17669 p2 *= 10;
17670 const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e
17671 const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e
17672 //
17673 // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e
17674 // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
17675 // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e
17676 //
17677 JSON_ASSERT(d <= 9);
17678 buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
17679 //
17680 // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e
17681 //
17682 p2 = r;
17683 m++;
17684 //
17685 // M+ = buffer * 10^-m + 10^-m * p2 * 2^e
17686 // Invariant restored.
17687
17688 // Check if enough digits have been generated.
17689 //
17690 // 10^-m * p2 * 2^e <= delta * 2^e
17691 // p2 * 2^e <= 10^m * delta * 2^e
17692 // p2 <= 10^m * delta
17693 delta *= 10;
17694 dist *= 10;
17695 if (p2 <= delta)
17696 {
17697 break;
17698 }
17699 }
7697 17700
7698 @param[in] s the string to escape 17701 // V = buffer * 10^-m, with M- <= V <= M+.
7699 @return the number of characters required to escape string @a s 17702
17703 decimal_exponent -= m;
17704
17705 // 1 ulp in the decimal representation is now 10^-m.
17706 // Since delta and dist are now scaled by 10^m, we need to do the
17707 // same with ulp in order to keep the units in sync.
17708 //
17709 // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e
17710 //
17711 const std::uint64_t ten_m = one.f;
17712 grisu2_round(buffer, length, dist, delta, p2, ten_m);
17713
17714 // By construction this algorithm generates the shortest possible decimal
17715 // number (Loitsch, Theorem 6.2) which rounds back to w.
17716 // For an input number of precision p, at least
17717 //
17718 // N = 1 + ceil(p * log_10(2))
17719 //
17720 // decimal digits are sufficient to identify all binary floating-point
17721 // numbers (Matula, "In-and-Out conversions").
17722 // This implies that the algorithm does not produce more than N decimal
17723 // digits.
17724 //
17725 // N = 17 for p = 53 (IEEE double precision)
17726 // N = 9 for p = 24 (IEEE single precision)
17727}
7700 17728
7701 @complexity Linear in the length of string @a s. 17729/*!
7702 */ 17730v = buf * 10^decimal_exponent
7703 static std::size_t extra_space(const string_t& s) noexcept 17731len is the length of the buffer (number of decimal digits)
17732The buffer must be large enough, i.e. >= max_digits10.
17733*/
17734JSON_HEDLEY_NON_NULL(1)
17735inline void grisu2(char* buf, int& len, int& decimal_exponent,
17736 diyfp m_minus, diyfp v, diyfp m_plus)
17737{
17738 JSON_ASSERT(m_plus.e == m_minus.e);
17739 JSON_ASSERT(m_plus.e == v.e);
17740
17741 // --------(-----------------------+-----------------------)-------- (A)
17742 // m- v m+
17743 //
17744 // --------------------(-----------+-----------------------)-------- (B)
17745 // m- v m+
17746 //
17747 // First scale v (and m- and m+) such that the exponent is in the range
17748 // [alpha, gamma].
17749
17750 const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);
17751
17752 const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k
17753
17754 // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]
17755 const diyfp w = diyfp::mul(v, c_minus_k);
17756 const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);
17757 const diyfp w_plus = diyfp::mul(m_plus, c_minus_k);
17758
17759 // ----(---+---)---------------(---+---)---------------(---+---)----
17760 // w- w w+
17761 // = c*m- = c*v = c*m+
17762 //
17763 // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and
17764 // w+ are now off by a small amount.
17765 // In fact:
17766 //
17767 // w - v * 10^k < 1 ulp
17768 //
17769 // To account for this inaccuracy, add resp. subtract 1 ulp.
17770 //
17771 // --------+---[---------------(---+---)---------------]---+--------
17772 // w- M- w M+ w+
17773 //
17774 // Now any number in [M-, M+] (bounds included) will round to w when input,
17775 // regardless of how the input rounding algorithm breaks ties.
17776 //
17777 // And digit_gen generates the shortest possible such number in [M-, M+].
17778 // Note that this does not mean that Grisu2 always generates the shortest
17779 // possible number in the interval (m-, m+).
17780 const diyfp M_minus(w_minus.f + 1, w_minus.e);
17781 const diyfp M_plus (w_plus.f - 1, w_plus.e );
17782
17783 decimal_exponent = -cached.k; // = -(-k) = k
17784
17785 grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);
17786}
17787
17788/*!
17789v = buf * 10^decimal_exponent
17790len is the length of the buffer (number of decimal digits)
17791The buffer must be large enough, i.e. >= max_digits10.
17792*/
17793template<typename FloatType>
17794JSON_HEDLEY_NON_NULL(1)
17795void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
17796{
17797 static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,
17798 "internal error: not enough precision");
17799
17800 JSON_ASSERT(std::isfinite(value));
17801 JSON_ASSERT(value > 0);
17802
17803 // If the neighbors (and boundaries) of 'value' are always computed for double-precision
17804 // numbers, all float's can be recovered using strtod (and strtof). However, the resulting
17805 // decimal representations are not exactly "short".
17806 //
17807 // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)
17808 // says "value is converted to a string as if by std::sprintf in the default ("C") locale"
17809 // and since sprintf promotes floats to doubles, I think this is exactly what 'std::to_chars'
17810 // does.
17811 // On the other hand, the documentation for 'std::to_chars' requires that "parsing the
17812 // representation using the corresponding std::from_chars function recovers value exactly". That
17813 // indicates that single precision floating-point numbers should be recovered using
17814 // 'std::strtof'.
17815 //
17816 // NB: If the neighbors are computed for single-precision numbers, there is a single float
17817 // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision
17818 // value is off by 1 ulp.
17819#if 0 // NOLINT(readability-avoid-unconditional-preprocessor-if)
17820 const boundaries w = compute_boundaries(static_cast<double>(value));
17821#else
17822 const boundaries w = compute_boundaries(value);
17823#endif
17824
17825 grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);
17826}
17827
17828/*!
17829@brief appends a decimal representation of e to buf
17830@return a pointer to the element following the exponent.
17831@pre -1000 < e < 1000
17832*/
17833JSON_HEDLEY_NON_NULL(1)
17834JSON_HEDLEY_RETURNS_NON_NULL
17835inline char* append_exponent(char* buf, int e)
17836{
17837 JSON_ASSERT(e > -1000);
17838 JSON_ASSERT(e < 1000);
17839
17840 if (e < 0)
7704 { 17841 {
7705 return std::accumulate(s.begin(), s.end(), size_t{}, 17842 e = -e;
7706 [](size_t res, typename string_t::value_type c) 17843 *buf++ = '-';
7707 { 17844 }
7708 switch (c) 17845 else
7709 { 17846 {
7710 case '"': 17847 *buf++ = '+';
7711 case '\\': 17848 }
7712 case '\b':
7713 case '\f':
7714 case '\n':
7715 case '\r':
7716 case '\t':
7717 {
7718 // from c (1 byte) to \x (2 bytes)
7719 return res + 1;
7720 }
7721 17849
7722 default: 17850 auto k = static_cast<std::uint32_t>(e);
7723 { 17851 if (k < 10)
7724 if (c >= 0x00 and c <= 0x1f) 17852 {
7725 { 17853 // Always print at least two digits in the exponent.
7726 // from c (1 byte) to \uxxxx (6 bytes) 17854 // This is for compatibility with printf("%g").
7727 return res + 5; 17855 *buf++ = '0';
7728 } 17856 *buf++ = static_cast<char>('0' + k);
7729 else 17857 }
7730 { 17858 else if (k < 100)
7731 return res; 17859 {
7732 } 17860 *buf++ = static_cast<char>('0' + k / 10);
7733 } 17861 k %= 10;
7734 } 17862 *buf++ = static_cast<char>('0' + k);
7735 }); 17863 }
17864 else
17865 {
17866 *buf++ = static_cast<char>('0' + k / 100);
17867 k %= 100;
17868 *buf++ = static_cast<char>('0' + k / 10);
17869 k %= 10;
17870 *buf++ = static_cast<char>('0' + k);
7736 } 17871 }
7737 17872
7738 /*! 17873 return buf;
7739 @brief escape a string 17874}
7740 17875
7741 Escape a string by replacing certain special characters by a sequence of 17876/*!
7742 an escape character (backslash) and another character and other control 17877@brief prettify v = buf * 10^decimal_exponent
7743 characters by a sequence of "\u" followed by a four-digit hex
7744 representation.
7745 17878
7746 @param[in] s the string to escape 17879If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point
7747 @return the escaped string 17880notation. Otherwise it will be printed in exponential notation.
7748 17881
7749 @complexity Linear in the length of string @a s. 17882@pre min_exp < 0
7750 */ 17883@pre max_exp > 0
7751 static string_t escape_string(const string_t& s) 17884*/
17885JSON_HEDLEY_NON_NULL(1)
17886JSON_HEDLEY_RETURNS_NON_NULL
17887inline char* format_buffer(char* buf, int len, int decimal_exponent,
17888 int min_exp, int max_exp)
17889{
17890 JSON_ASSERT(min_exp < 0);
17891 JSON_ASSERT(max_exp > 0);
17892
17893 const int k = len;
17894 const int n = len + decimal_exponent;
17895
17896 // v = buf * 10^(n-k)
17897 // k is the length of the buffer (number of decimal digits)
17898 // n is the position of the decimal point relative to the start of the buffer.
17899
17900 if (k <= n && n <= max_exp)
7752 { 17901 {
7753 const auto space = extra_space(s); 17902 // digits[000]
7754 if (space == 0) 17903 // len <= max_exp + 2
7755 { 17904
7756 return s; 17905 std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k));
7757 } 17906 // Make it look like a floating-point number (#362, #378)
17907 buf[n + 0] = '.';
17908 buf[n + 1] = '0';
17909 return buf + (static_cast<size_t>(n) + 2);
17910 }
7758 17911
7759 // create a result string of necessary size 17912 if (0 < n && n <= max_exp)
7760 string_t result(s.size() + space, '\\'); 17913 {
7761 std::size_t pos = 0; 17914 // dig.its
17915 // len <= max_digits10 + 1
7762 17916
7763 for (const auto& c : s) 17917 JSON_ASSERT(k > n);
7764 {
7765 switch (c)
7766 {
7767 // quotation mark (0x22)
7768 case '"':
7769 {
7770 result[pos + 1] = '"';
7771 pos += 2;
7772 break;
7773 }
7774 17918
7775 // reverse solidus (0x5c) 17919 std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n));
7776 case '\\': 17920 buf[n] = '.';
7777 { 17921 return buf + (static_cast<size_t>(k) + 1U);
7778 // nothing to change 17922 }
7779 pos += 2;
7780 break;
7781 }
7782 17923
7783 // backspace (0x08) 17924 if (min_exp < n && n <= 0)
7784 case '\b': 17925 {
7785 { 17926 // 0.[000]digits
7786 result[pos + 1] = 'b'; 17927 // len <= 2 + (-min_exp - 1) + max_digits10
7787 pos += 2; 17928
7788 break; 17929 std::memmove(buf + (2 + static_cast<size_t>(-n)), buf, static_cast<size_t>(k));
7789 } 17930 buf[0] = '0';
17931 buf[1] = '.';
17932 std::memset(buf + 2, '0', static_cast<size_t>(-n));
17933 return buf + (2U + static_cast<size_t>(-n) + static_cast<size_t>(k));
17934 }
7790 17935
7791 // formfeed (0x0c) 17936 if (k == 1)
7792 case '\f': 17937 {
7793 { 17938 // dE+123
7794 result[pos + 1] = 'f'; 17939 // len <= 1 + 5
7795 pos += 2;
7796 break;
7797 }
7798 17940
7799 // newline (0x0a) 17941 buf += 1;
7800 case '\n': 17942 }
7801 { 17943 else
7802 result[pos + 1] = 'n'; 17944 {
7803 pos += 2; 17945 // d.igitsE+123
7804 break; 17946 // len <= max_digits10 + 1 + 5
7805 }
7806 17947
7807 // carriage return (0x0d) 17948 std::memmove(buf + 2, buf + 1, static_cast<size_t>(k) - 1);
7808 case '\r': 17949 buf[1] = '.';
7809 { 17950 buf += 1 + static_cast<size_t>(k);
7810 result[pos + 1] = 'r'; 17951 }
7811 pos += 2;
7812 break;
7813 }
7814 17952
7815 // horizontal tab (0x09) 17953 *buf++ = 'e';
7816 case '\t': 17954 return append_exponent(buf, n - 1);
7817 { 17955}
7818 result[pos + 1] = 't';
7819 pos += 2;
7820 break;
7821 }
7822 17956
7823 default: 17957} // namespace dtoa_impl
7824 {
7825 if (c >= 0x00 and c <= 0x1f)
7826 {
7827 // convert a number 0..15 to its hex representation
7828 // (0..f)
7829 static const char hexify[16] =
7830 {
7831 '0', '1', '2', '3', '4', '5', '6', '7',
7832 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
7833 };
7834
7835 // print character c as \uxxxx
7836 for (const char m :
7837 { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f]
7838 })
7839 {
7840 result[++pos] = m;
7841 }
7842 17958
7843 ++pos; 17959/*!
7844 } 17960@brief generates a decimal representation of the floating-point number value in [first, last).
7845 else
7846 {
7847 // all other characters are added as-is
7848 result[pos++] = c;
7849 }
7850 break;
7851 }
7852 }
7853 }
7854 17961
7855 return result; 17962The format of the resulting decimal representation is similar to printf's %g
17963format. Returns an iterator pointing past-the-end of the decimal representation.
17964
17965@note The input number must be finite, i.e. NaN's and Inf's are not supported.
17966@note The buffer must be large enough.
17967@note The result is NOT null-terminated.
17968*/
17969template<typename FloatType>
17970JSON_HEDLEY_NON_NULL(1, 2)
17971JSON_HEDLEY_RETURNS_NON_NULL
17972char* to_chars(char* first, const char* last, FloatType value)
17973{
17974 static_cast<void>(last); // maybe unused - fix warning
17975 JSON_ASSERT(std::isfinite(value));
17976
17977 // Use signbit(value) instead of (value < 0) since signbit works for -0.
17978 if (std::signbit(value))
17979 {
17980 value = -value;
17981 *first++ = '-';
17982 }
17983
17984#ifdef __GNUC__
17985#pragma GCC diagnostic push
17986#pragma GCC diagnostic ignored "-Wfloat-equal"
17987#endif
17988 if (value == 0) // +-0
17989 {
17990 *first++ = '0';
17991 // Make it look like a floating-point number (#362, #378)
17992 *first++ = '.';
17993 *first++ = '0';
17994 return first;
7856 } 17995 }
17996#ifdef __GNUC__
17997#pragma GCC diagnostic pop
17998#endif
17999
18000 JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);
18001
18002 // Compute v = buffer * 10^decimal_exponent.
18003 // The decimal digits are stored in the buffer, which needs to be interpreted
18004 // as an unsigned decimal integer.
18005 // len is the length of the buffer, i.e. the number of decimal digits.
18006 int len = 0;
18007 int decimal_exponent = 0;
18008 dtoa_impl::grisu2(first, len, decimal_exponent, value);
18009
18010 JSON_ASSERT(len <= std::numeric_limits<FloatType>::max_digits10);
18011
18012 // Format the buffer like printf("%.*g", prec, value)
18013 constexpr int kMinExp = -4;
18014 // Use digits10 here to increase compatibility with version 2.
18015 constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;
18016
18017 JSON_ASSERT(last - first >= kMaxExp + 2);
18018 JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
18019 JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
18020
18021 return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
18022}
18023
18024} // namespace detail
18025NLOHMANN_JSON_NAMESPACE_END
18026
18027// #include <nlohmann/detail/exceptions.hpp>
18028
18029// #include <nlohmann/detail/macro_scope.hpp>
18030
18031// #include <nlohmann/detail/meta/cpp_future.hpp>
18032
18033// #include <nlohmann/detail/output/binary_writer.hpp>
18034
18035// #include <nlohmann/detail/output/output_adapters.hpp>
18036
18037// #include <nlohmann/detail/string_concat.hpp>
18038
18039// #include <nlohmann/detail/value_t.hpp>
18040
18041
18042NLOHMANN_JSON_NAMESPACE_BEGIN
18043namespace detail
18044{
18045
18046///////////////////
18047// serialization //
18048///////////////////
18049
18050/// how to treat decoding errors
18051enum class error_handler_t
18052{
18053 strict, ///< throw a type_error exception in case of invalid UTF-8
18054 replace, ///< replace invalid UTF-8 sequences with U+FFFD
18055 ignore ///< ignore invalid UTF-8 sequences
18056};
18057
18058template<typename BasicJsonType>
18059class serializer
18060{
18061 using string_t = typename BasicJsonType::string_t;
18062 using number_float_t = typename BasicJsonType::number_float_t;
18063 using number_integer_t = typename BasicJsonType::number_integer_t;
18064 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
18065 using binary_char_t = typename BasicJsonType::binary_t::value_type;
18066 static constexpr std::uint8_t UTF8_ACCEPT = 0;
18067 static constexpr std::uint8_t UTF8_REJECT = 1;
18068
18069 public:
18070 /*!
18071 @param[in] s output stream to serialize to
18072 @param[in] ichar indentation character to use
18073 @param[in] error_handler_ how to react on decoding errors
18074 */
18075 serializer(output_adapter_t<char> s, const char ichar,
18076 error_handler_t error_handler_ = error_handler_t::strict)
18077 : o(std::move(s))
18078 , loc(std::localeconv())
18079 , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
18080 , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
18081 , indent_char(ichar)
18082 , indent_string(512, indent_char)
18083 , error_handler(error_handler_)
18084 {}
18085
18086 // delete because of pointer members
18087 serializer(const serializer&) = delete;
18088 serializer& operator=(const serializer&) = delete;
18089 serializer(serializer&&) = delete;
18090 serializer& operator=(serializer&&) = delete;
18091 ~serializer() = default;
7857 18092
7858 /*! 18093 /*!
7859 @brief internal implementation of the serialization function 18094 @brief internal implementation of the serialization function
@@ -7861,3733 +18096,5883 @@ class basic_json
7861 This function is called by the public member function dump and organizes 18096 This function is called by the public member function dump and organizes
7862 the serialization internally. The indentation level is propagated as 18097 the serialization internally. The indentation level is propagated as
7863 additional parameter. In case of arrays and objects, the function is 18098 additional parameter. In case of arrays and objects, the function is
7864 called recursively. Note that 18099 called recursively.
7865 18100
7866 - strings and object keys are escaped using `escape_string()` 18101 - strings and object keys are escaped using `escape_string()`
7867 - integer numbers are converted implicitly via `operator<<` 18102 - integer numbers are converted implicitly via `operator<<`
7868 - floating-point numbers are converted to a string using `"%g"` format 18103 - floating-point numbers are converted to a string using `"%g"` format
7869 18104 - binary values are serialized as objects containing the subtype and the
7870 @param[out] o stream to write to 18105 byte array
7871 @param[in] pretty_print whether the output shall be pretty-printed 18106
7872 @param[in] indent_step the indent level 18107 @param[in] val value to serialize
7873 @param[in] current_indent the current indent level (only used internally) 18108 @param[in] pretty_print whether the output shall be pretty-printed
18109 @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters
18110 in the output are escaped with `\uXXXX` sequences, and the result consists
18111 of ASCII characters only.
18112 @param[in] indent_step the indent level
18113 @param[in] current_indent the current indent level (only used internally)
7874 */ 18114 */
7875 void dump(std::ostream& o, 18115 void dump(const BasicJsonType& val,
7876 const bool pretty_print, 18116 const bool pretty_print,
18117 const bool ensure_ascii,
7877 const unsigned int indent_step, 18118 const unsigned int indent_step,
7878 const unsigned int current_indent = 0) const 18119 const unsigned int current_indent = 0)
7879 { 18120 {
7880 // variable to hold indentation for recursive calls 18121 switch (val.m_data.m_type)
7881 unsigned int new_indent = current_indent;
7882
7883 switch (m_type)
7884 { 18122 {
7885 case value_t::object: 18123 case value_t::object:
7886 { 18124 {
7887 if (m_value.object->empty()) 18125 if (val.m_data.m_value.object->empty())
7888 { 18126 {
7889 o << "{}"; 18127 o->write_characters("{}", 2);
7890 return; 18128 return;
7891 } 18129 }
7892 18130
7893 o << "{";
7894
7895 // increase indentation
7896 if (pretty_print) 18131 if (pretty_print)
7897 { 18132 {
7898 new_indent += indent_step; 18133 o->write_characters("{\n", 2);
7899 o << "\n";
7900 }
7901 18134
7902 for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i) 18135 // variable to hold indentation for recursive calls
7903 { 18136 const auto new_indent = current_indent + indent_step;
7904 if (i != m_value.object->cbegin()) 18137 if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
7905 { 18138 {
7906 o << (pretty_print ? ",\n" : ","); 18139 indent_string.resize(indent_string.size() * 2, ' ');
7907 } 18140 }
7908 o << string_t(new_indent, ' ') << "\""
7909 << escape_string(i->first) << "\":"
7910 << (pretty_print ? " " : "");
7911 i->second.dump(o, pretty_print, indent_step, new_indent);
7912 }
7913 18141
7914 // decrease indentation 18142 // first n-1 elements
7915 if (pretty_print) 18143 auto i = val.m_data.m_value.object->cbegin();
18144 for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)
18145 {
18146 o->write_characters(indent_string.c_str(), new_indent);
18147 o->write_character('\"');
18148 dump_escaped(i->first, ensure_ascii);
18149 o->write_characters("\": ", 3);
18150 dump(i->second, true, ensure_ascii, indent_step, new_indent);
18151 o->write_characters(",\n", 2);
18152 }
18153
18154 // last element
18155 JSON_ASSERT(i != val.m_data.m_value.object->cend());
18156 JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());
18157 o->write_characters(indent_string.c_str(), new_indent);
18158 o->write_character('\"');
18159 dump_escaped(i->first, ensure_ascii);
18160 o->write_characters("\": ", 3);
18161 dump(i->second, true, ensure_ascii, indent_step, new_indent);
18162
18163 o->write_character('\n');
18164 o->write_characters(indent_string.c_str(), current_indent);
18165 o->write_character('}');
18166 }
18167 else
7916 { 18168 {
7917 new_indent -= indent_step; 18169 o->write_character('{');
7918 o << "\n"; 18170
18171 // first n-1 elements
18172 auto i = val.m_data.m_value.object->cbegin();
18173 for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)
18174 {
18175 o->write_character('\"');
18176 dump_escaped(i->first, ensure_ascii);
18177 o->write_characters("\":", 2);
18178 dump(i->second, false, ensure_ascii, indent_step, current_indent);
18179 o->write_character(',');
18180 }
18181
18182 // last element
18183 JSON_ASSERT(i != val.m_data.m_value.object->cend());
18184 JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());
18185 o->write_character('\"');
18186 dump_escaped(i->first, ensure_ascii);
18187 o->write_characters("\":", 2);
18188 dump(i->second, false, ensure_ascii, indent_step, current_indent);
18189
18190 o->write_character('}');
7919 } 18191 }
7920 18192
7921 o << string_t(new_indent, ' ') + "}";
7922 return; 18193 return;
7923 } 18194 }
7924 18195
7925 case value_t::array: 18196 case value_t::array:
7926 { 18197 {
7927 if (m_value.array->empty()) 18198 if (val.m_data.m_value.array->empty())
7928 { 18199 {
7929 o << "[]"; 18200 o->write_characters("[]", 2);
7930 return; 18201 return;
7931 } 18202 }
7932 18203
7933 o << "[";
7934
7935 // increase indentation
7936 if (pretty_print) 18204 if (pretty_print)
7937 { 18205 {
7938 new_indent += indent_step; 18206 o->write_characters("[\n", 2);
7939 o << "\n";
7940 }
7941 18207
7942 for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i) 18208 // variable to hold indentation for recursive calls
7943 { 18209 const auto new_indent = current_indent + indent_step;
7944 if (i != m_value.array->cbegin()) 18210 if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
7945 { 18211 {
7946 o << (pretty_print ? ",\n" : ","); 18212 indent_string.resize(indent_string.size() * 2, ' ');
7947 } 18213 }
7948 o << string_t(new_indent, ' ');
7949 i->dump(o, pretty_print, indent_step, new_indent);
7950 }
7951 18214
7952 // decrease indentation 18215 // first n-1 elements
7953 if (pretty_print) 18216 for (auto i = val.m_data.m_value.array->cbegin();
18217 i != val.m_data.m_value.array->cend() - 1; ++i)
18218 {
18219 o->write_characters(indent_string.c_str(), new_indent);
18220 dump(*i, true, ensure_ascii, indent_step, new_indent);
18221 o->write_characters(",\n", 2);
18222 }
18223
18224 // last element
18225 JSON_ASSERT(!val.m_data.m_value.array->empty());
18226 o->write_characters(indent_string.c_str(), new_indent);
18227 dump(val.m_data.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
18228
18229 o->write_character('\n');
18230 o->write_characters(indent_string.c_str(), current_indent);
18231 o->write_character(']');
18232 }
18233 else
7954 { 18234 {
7955 new_indent -= indent_step; 18235 o->write_character('[');
7956 o << "\n"; 18236
18237 // first n-1 elements
18238 for (auto i = val.m_data.m_value.array->cbegin();
18239 i != val.m_data.m_value.array->cend() - 1; ++i)
18240 {
18241 dump(*i, false, ensure_ascii, indent_step, current_indent);
18242 o->write_character(',');
18243 }
18244
18245 // last element
18246 JSON_ASSERT(!val.m_data.m_value.array->empty());
18247 dump(val.m_data.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
18248
18249 o->write_character(']');
7957 } 18250 }
7958 18251
7959 o << string_t(new_indent, ' ') << "]";
7960 return; 18252 return;
7961 } 18253 }
7962 18254
7963 case value_t::string: 18255 case value_t::string:
7964 { 18256 {
7965 o << string_t("\"") << escape_string(*m_value.string) << "\""; 18257 o->write_character('\"');
18258 dump_escaped(*val.m_data.m_value.string, ensure_ascii);
18259 o->write_character('\"');
18260 return;
18261 }
18262
18263 case value_t::binary:
18264 {
18265 if (pretty_print)
18266 {
18267 o->write_characters("{\n", 2);
18268
18269 // variable to hold indentation for recursive calls
18270 const auto new_indent = current_indent + indent_step;
18271 if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
18272 {
18273 indent_string.resize(indent_string.size() * 2, ' ');
18274 }
18275
18276 o->write_characters(indent_string.c_str(), new_indent);
18277
18278 o->write_characters("\"bytes\": [", 10);
18279
18280 if (!val.m_data.m_value.binary->empty())
18281 {
18282 for (auto i = val.m_data.m_value.binary->cbegin();
18283 i != val.m_data.m_value.binary->cend() - 1; ++i)
18284 {
18285 dump_integer(*i);
18286 o->write_characters(", ", 2);
18287 }
18288 dump_integer(val.m_data.m_value.binary->back());
18289 }
18290
18291 o->write_characters("],\n", 3);
18292 o->write_characters(indent_string.c_str(), new_indent);
18293
18294 o->write_characters("\"subtype\": ", 11);
18295 if (val.m_data.m_value.binary->has_subtype())
18296 {
18297 dump_integer(val.m_data.m_value.binary->subtype());
18298 }
18299 else
18300 {
18301 o->write_characters("null", 4);
18302 }
18303 o->write_character('\n');
18304 o->write_characters(indent_string.c_str(), current_indent);
18305 o->write_character('}');
18306 }
18307 else
18308 {
18309 o->write_characters("{\"bytes\":[", 10);
18310
18311 if (!val.m_data.m_value.binary->empty())
18312 {
18313 for (auto i = val.m_data.m_value.binary->cbegin();
18314 i != val.m_data.m_value.binary->cend() - 1; ++i)
18315 {
18316 dump_integer(*i);
18317 o->write_character(',');
18318 }
18319 dump_integer(val.m_data.m_value.binary->back());
18320 }
18321
18322 o->write_characters("],\"subtype\":", 12);
18323 if (val.m_data.m_value.binary->has_subtype())
18324 {
18325 dump_integer(val.m_data.m_value.binary->subtype());
18326 o->write_character('}');
18327 }
18328 else
18329 {
18330 o->write_characters("null}", 5);
18331 }
18332 }
7966 return; 18333 return;
7967 } 18334 }
7968 18335
7969 case value_t::boolean: 18336 case value_t::boolean:
7970 { 18337 {
7971 o << (m_value.boolean ? "true" : "false"); 18338 if (val.m_data.m_value.boolean)
18339 {
18340 o->write_characters("true", 4);
18341 }
18342 else
18343 {
18344 o->write_characters("false", 5);
18345 }
7972 return; 18346 return;
7973 } 18347 }
7974 18348
7975 case value_t::number_integer: 18349 case value_t::number_integer:
7976 { 18350 {
7977 o << m_value.number_integer; 18351 dump_integer(val.m_data.m_value.number_integer);
7978 return; 18352 return;
7979 } 18353 }
7980 18354
7981 case value_t::number_unsigned: 18355 case value_t::number_unsigned:
7982 { 18356 {
7983 o << m_value.number_unsigned; 18357 dump_integer(val.m_data.m_value.number_unsigned);
7984 return; 18358 return;
7985 } 18359 }
7986 18360
7987 case value_t::number_float: 18361 case value_t::number_float:
7988 { 18362 {
7989 if (m_value.number_float == 0) 18363 dump_float(val.m_data.m_value.number_float);
7990 {
7991 // special case for zero to get "0.0"/"-0.0"
7992 o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0");
7993 }
7994 else
7995 {
7996 o << m_value.number_float;
7997 }
7998 return; 18364 return;
7999 } 18365 }
8000 18366
8001 case value_t::discarded: 18367 case value_t::discarded:
8002 { 18368 {
8003 o << "<discarded>"; 18369 o->write_characters("<discarded>", 11);
8004 return; 18370 return;
8005 } 18371 }
8006 18372
8007 case value_t::null: 18373 case value_t::null:
8008 { 18374 {
8009 o << "null"; 18375 o->write_characters("null", 4);
8010 return; 18376 return;
8011 } 18377 }
18378
18379 default: // LCOV_EXCL_LINE
18380 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
8012 } 18381 }
8013 } 18382 }
8014 18383
8015 private: 18384 JSON_PRIVATE_UNLESS_TESTED:
8016 ////////////////////// 18385 /*!
8017 // member variables // 18386 @brief dump escaped string
8018 ////////////////////// 18387
18388 Escape a string by replacing certain special characters by a sequence of an
18389 escape character (backslash) and another character and other control
18390 characters by a sequence of "\u" followed by a four-digit hex
18391 representation. The escaped string is written to output stream @a o.
18392
18393 @param[in] s the string to escape
18394 @param[in] ensure_ascii whether to escape non-ASCII characters with
18395 \uXXXX sequences
18396
18397 @complexity Linear in the length of string @a s.
18398 */
18399 void dump_escaped(const string_t& s, const bool ensure_ascii)
18400 {
18401 std::uint32_t codepoint{};
18402 std::uint8_t state = UTF8_ACCEPT;
18403 std::size_t bytes = 0; // number of bytes written to string_buffer
18404
18405 // number of bytes written at the point of the last valid byte
18406 std::size_t bytes_after_last_accept = 0;
18407 std::size_t undumped_chars = 0;
18408
18409 for (std::size_t i = 0; i < s.size(); ++i)
18410 {
18411 const auto byte = static_cast<std::uint8_t>(s[i]);
18412
18413 switch (decode(state, codepoint, byte))
18414 {
18415 case UTF8_ACCEPT: // decode found a new code point
18416 {
18417 switch (codepoint)
18418 {
18419 case 0x08: // backspace
18420 {
18421 string_buffer[bytes++] = '\\';
18422 string_buffer[bytes++] = 'b';
18423 break;
18424 }
18425
18426 case 0x09: // horizontal tab
18427 {
18428 string_buffer[bytes++] = '\\';
18429 string_buffer[bytes++] = 't';
18430 break;
18431 }
18432
18433 case 0x0A: // newline
18434 {
18435 string_buffer[bytes++] = '\\';
18436 string_buffer[bytes++] = 'n';
18437 break;
18438 }
18439
18440 case 0x0C: // formfeed
18441 {
18442 string_buffer[bytes++] = '\\';
18443 string_buffer[bytes++] = 'f';
18444 break;
18445 }
18446
18447 case 0x0D: // carriage return
18448 {
18449 string_buffer[bytes++] = '\\';
18450 string_buffer[bytes++] = 'r';
18451 break;
18452 }
18453
18454 case 0x22: // quotation mark
18455 {
18456 string_buffer[bytes++] = '\\';
18457 string_buffer[bytes++] = '\"';
18458 break;
18459 }
18460
18461 case 0x5C: // reverse solidus
18462 {
18463 string_buffer[bytes++] = '\\';
18464 string_buffer[bytes++] = '\\';
18465 break;
18466 }
18467
18468 default:
18469 {
18470 // escape control characters (0x00..0x1F) or, if
18471 // ensure_ascii parameter is used, non-ASCII characters
18472 if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))
18473 {
18474 if (codepoint <= 0xFFFF)
18475 {
18476 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
18477 static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
18478 static_cast<std::uint16_t>(codepoint)));
18479 bytes += 6;
18480 }
18481 else
18482 {
18483 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
18484 static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
18485 static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
18486 static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
18487 bytes += 12;
18488 }
18489 }
18490 else
18491 {
18492 // copy byte to buffer (all previous bytes
18493 // been copied have in default case above)
18494 string_buffer[bytes++] = s[i];
18495 }
18496 break;
18497 }
18498 }
18499
18500 // write buffer and reset index; there must be 13 bytes
18501 // left, as this is the maximal number of bytes to be
18502 // written ("\uxxxx\uxxxx\0") for one code point
18503 if (string_buffer.size() - bytes < 13)
18504 {
18505 o->write_characters(string_buffer.data(), bytes);
18506 bytes = 0;
18507 }
18508
18509 // remember the byte position of this accept
18510 bytes_after_last_accept = bytes;
18511 undumped_chars = 0;
18512 break;
18513 }
18514
18515 case UTF8_REJECT: // decode found invalid UTF-8 byte
18516 {
18517 switch (error_handler)
18518 {
18519 case error_handler_t::strict:
18520 {
18521 JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", hex_bytes(byte | 0)), nullptr));
18522 }
18523
18524 case error_handler_t::ignore:
18525 case error_handler_t::replace:
18526 {
18527 // in case we saw this character the first time, we
18528 // would like to read it again, because the byte
18529 // may be OK for itself, but just not OK for the
18530 // previous sequence
18531 if (undumped_chars > 0)
18532 {
18533 --i;
18534 }
18535
18536 // reset length buffer to the last accepted index;
18537 // thus removing/ignoring the invalid characters
18538 bytes = bytes_after_last_accept;
18539
18540 if (error_handler == error_handler_t::replace)
18541 {
18542 // add a replacement character
18543 if (ensure_ascii)
18544 {
18545 string_buffer[bytes++] = '\\';
18546 string_buffer[bytes++] = 'u';
18547 string_buffer[bytes++] = 'f';
18548 string_buffer[bytes++] = 'f';
18549 string_buffer[bytes++] = 'f';
18550 string_buffer[bytes++] = 'd';
18551 }
18552 else
18553 {
18554 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xEF');
18555 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF');
18556 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD');
18557 }
18558
18559 // write buffer and reset index; there must be 13 bytes
18560 // left, as this is the maximal number of bytes to be
18561 // written ("\uxxxx\uxxxx\0") for one code point
18562 if (string_buffer.size() - bytes < 13)
18563 {
18564 o->write_characters(string_buffer.data(), bytes);
18565 bytes = 0;
18566 }
18567
18568 bytes_after_last_accept = bytes;
18569 }
18570
18571 undumped_chars = 0;
18572
18573 // continue processing the string
18574 state = UTF8_ACCEPT;
18575 break;
18576 }
18577
18578 default: // LCOV_EXCL_LINE
18579 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
18580 }
18581 break;
18582 }
18583
18584 default: // decode found yet incomplete multi-byte code point
18585 {
18586 if (!ensure_ascii)
18587 {
18588 // code point will not be escaped - copy byte to buffer
18589 string_buffer[bytes++] = s[i];
18590 }
18591 ++undumped_chars;
18592 break;
18593 }
18594 }
18595 }
18596
18597 // we finished processing the string
18598 if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT))
18599 {
18600 // write buffer
18601 if (bytes > 0)
18602 {
18603 o->write_characters(string_buffer.data(), bytes);
18604 }
18605 }
18606 else
18607 {
18608 // we finish reading, but do not accept: string was incomplete
18609 switch (error_handler)
18610 {
18611 case error_handler_t::strict:
18612 {
18613 JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", hex_bytes(static_cast<std::uint8_t>(s.back() | 0))), nullptr));
18614 }
8019 18615
8020 /// the type of the current element 18616 case error_handler_t::ignore:
8021 value_t m_type = value_t::null; 18617 {
18618 // write all accepted bytes
18619 o->write_characters(string_buffer.data(), bytes_after_last_accept);
18620 break;
18621 }
8022 18622
8023 /// the value of the current element 18623 case error_handler_t::replace:
8024 json_value m_value = {}; 18624 {
18625 // write all accepted bytes
18626 o->write_characters(string_buffer.data(), bytes_after_last_accept);
18627 // add a replacement character
18628 if (ensure_ascii)
18629 {
18630 o->write_characters("\\ufffd", 6);
18631 }
18632 else
18633 {
18634 o->write_characters("\xEF\xBF\xBD", 3);
18635 }
18636 break;
18637 }
8025 18638
18639 default: // LCOV_EXCL_LINE
18640 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
18641 }
18642 }
18643 }
8026 18644
8027 private: 18645 private:
8028 /////////////// 18646 /*!
8029 // iterators // 18647 @brief count digits
8030 /////////////// 18648
18649 Count the number of decimal (base 10) digits for an input unsigned integer.
18650
18651 @param[in] x unsigned integer number to count its digits
18652 @return number of decimal digits
18653 */
18654 inline unsigned int count_digits(number_unsigned_t x) noexcept
18655 {
18656 unsigned int n_digits = 1;
18657 for (;;)
18658 {
18659 if (x < 10)
18660 {
18661 return n_digits;
18662 }
18663 if (x < 100)
18664 {
18665 return n_digits + 1;
18666 }
18667 if (x < 1000)
18668 {
18669 return n_digits + 2;
18670 }
18671 if (x < 10000)
18672 {
18673 return n_digits + 3;
18674 }
18675 x = x / 10000u;
18676 n_digits += 4;
18677 }
18678 }
18679
18680 /*!
18681 * @brief convert a byte to a uppercase hex representation
18682 * @param[in] byte byte to represent
18683 * @return representation ("00".."FF")
18684 */
18685 static std::string hex_bytes(std::uint8_t byte)
18686 {
18687 std::string result = "FF";
18688 constexpr const char* nibble_to_hex = "0123456789ABCDEF";
18689 result[0] = nibble_to_hex[byte / 16];
18690 result[1] = nibble_to_hex[byte % 16];
18691 return result;
18692 }
18693
18694 // templates to avoid warnings about useless casts
18695 template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
18696 bool is_negative_number(NumberType x)
18697 {
18698 return x < 0;
18699 }
18700
18701 template < typename NumberType, enable_if_t <std::is_unsigned<NumberType>::value, int > = 0 >
18702 bool is_negative_number(NumberType /*unused*/)
18703 {
18704 return false;
18705 }
8031 18706
8032 /*! 18707 /*!
8033 @brief an iterator for primitive JSON types 18708 @brief dump an integer
18709
18710 Dump a given integer to output stream @a o. Works internally with
18711 @a number_buffer.
8034 18712
8035 This class models an iterator for primitive JSON types (boolean, number, 18713 @param[in] x integer number (signed or unsigned) to dump
8036 string). It's only purpose is to allow the iterator/const_iterator classes 18714 @tparam NumberType either @a number_integer_t or @a number_unsigned_t
8037 to "iterate" over primitive values. Internally, the iterator is modeled by
8038 a `difference_type` variable. Value begin_value (`0`) models the begin,
8039 end_value (`1`) models past the end.
8040 */ 18715 */
8041 class primitive_iterator_t 18716 template < typename NumberType, detail::enable_if_t <
18717 std::is_integral<NumberType>::value ||
18718 std::is_same<NumberType, number_unsigned_t>::value ||
18719 std::is_same<NumberType, number_integer_t>::value ||
18720 std::is_same<NumberType, binary_char_t>::value,
18721 int > = 0 >
18722 void dump_integer(NumberType x)
8042 { 18723 {
8043 public: 18724 static constexpr std::array<std::array<char, 2>, 100> digits_to_99
8044 /// set iterator to a defined beginning 18725 {
8045 void set_begin() noexcept 18726 {
18727 {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},
18728 {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}},
18729 {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}},
18730 {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}},
18731 {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}},
18732 {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}},
18733 {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}},
18734 {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}},
18735 {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}},
18736 {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},
18737 }
18738 };
18739
18740 // special case for "0"
18741 if (x == 0)
18742 {
18743 o->write_character('0');
18744 return;
18745 }
18746
18747 // use a pointer to fill the buffer
18748 auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
18749
18750 number_unsigned_t abs_value;
18751
18752 unsigned int n_chars{};
18753
18754 if (is_negative_number(x))
18755 {
18756 *buffer_ptr = '-';
18757 abs_value = remove_sign(static_cast<number_integer_t>(x));
18758
18759 // account one more byte for the minus sign
18760 n_chars = 1 + count_digits(abs_value);
18761 }
18762 else
8046 { 18763 {
8047 m_it = begin_value; 18764 abs_value = static_cast<number_unsigned_t>(x);
18765 n_chars = count_digits(abs_value);
8048 } 18766 }
8049 18767
8050 /// set iterator to a defined past the end 18768 // spare 1 byte for '\0'
8051 void set_end() noexcept 18769 JSON_ASSERT(n_chars < number_buffer.size() - 1);
18770
18771 // jump to the end to generate the string from backward,
18772 // so we later avoid reversing the result
18773 buffer_ptr += n_chars;
18774
18775 // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu
18776 // See: https://www.youtube.com/watch?v=o4-CwDo2zpg
18777 while (abs_value >= 100)
8052 { 18778 {
8053 m_it = end_value; 18779 const auto digits_index = static_cast<unsigned>((abs_value % 100));
18780 abs_value /= 100;
18781 *(--buffer_ptr) = digits_to_99[digits_index][1];
18782 *(--buffer_ptr) = digits_to_99[digits_index][0];
8054 } 18783 }
8055 18784
8056 /// return whether the iterator can be dereferenced 18785 if (abs_value >= 10)
8057 constexpr bool is_begin() const noexcept
8058 { 18786 {
8059 return (m_it == begin_value); 18787 const auto digits_index = static_cast<unsigned>(abs_value);
18788 *(--buffer_ptr) = digits_to_99[digits_index][1];
18789 *(--buffer_ptr) = digits_to_99[digits_index][0];
8060 } 18790 }
18791 else
18792 {
18793 *(--buffer_ptr) = static_cast<char>('0' + abs_value);
18794 }
18795
18796 o->write_characters(number_buffer.data(), n_chars);
18797 }
8061 18798
8062 /// return whether the iterator is at end 18799 /*!
8063 constexpr bool is_end() const noexcept 18800 @brief dump a floating-point number
18801
18802 Dump a given floating-point number to output stream @a o. Works internally
18803 with @a number_buffer.
18804
18805 @param[in] x floating-point number to dump
18806 */
18807 void dump_float(number_float_t x)
18808 {
18809 // NaN / inf
18810 if (!std::isfinite(x))
8064 { 18811 {
8065 return (m_it == end_value); 18812 o->write_characters("null", 4);
18813 return;
8066 } 18814 }
8067 18815
8068 /// return reference to the value to change and compare 18816 // If number_float_t is an IEEE-754 single or double precision number,
8069 operator difference_type& () noexcept 18817 // use the Grisu2 algorithm to produce short numbers which are
18818 // guaranteed to round-trip, using strtof and strtod, resp.
18819 //
18820 // NB: The test below works if <long double> == <double>.
18821 static constexpr bool is_ieee_single_or_double
18822 = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) ||
18823 (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);
18824
18825 dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
18826 }
18827
18828 void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
18829 {
18830 auto* begin = number_buffer.data();
18831 auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
18832
18833 o->write_characters(begin, static_cast<size_t>(end - begin));
18834 }
18835
18836 void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
18837 {
18838 // get number of digits for a float -> text -> float round-trip
18839 static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;
18840
18841 // the actual conversion
18842 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
18843 std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
18844
18845 // negative value indicates an error
18846 JSON_ASSERT(len > 0);
18847 // check if buffer was large enough
18848 JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
18849
18850 // erase thousands separator
18851 if (thousands_sep != '\0')
8070 { 18852 {
8071 return m_it; 18853 // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081
18854 const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep);
18855 std::fill(end, number_buffer.end(), '\0');
18856 JSON_ASSERT((end - number_buffer.begin()) <= len);
18857 len = (end - number_buffer.begin());
8072 } 18858 }
8073 18859
8074 /// return value to compare 18860 // convert decimal point to '.'
8075 constexpr operator difference_type () const noexcept 18861 if (decimal_point != '\0' && decimal_point != '.')
8076 { 18862 {
8077 return m_it; 18863 // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081
18864 const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
18865 if (dec_pos != number_buffer.end())
18866 {
18867 *dec_pos = '.';
18868 }
8078 } 18869 }
8079 18870
8080 private: 18871 o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));
8081 static constexpr difference_type begin_value = 0;
8082 static constexpr difference_type end_value = begin_value + 1;
8083 18872
8084 /// iterator as signed integer type 18873 // determine if we need to append ".0"
8085 difference_type m_it = std::numeric_limits<std::ptrdiff_t>::denorm_min(); 18874 const bool value_is_int_like =
8086 }; 18875 std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
18876 [](char c)
18877 {
18878 return c == '.' || c == 'e';
18879 });
18880
18881 if (value_is_int_like)
18882 {
18883 o->write_characters(".0", 2);
18884 }
18885 }
8087 18886
8088 /*! 18887 /*!
8089 @brief an iterator value 18888 @brief check whether a string is UTF-8 encoded
8090 18889
8091 @note This structure could easily be a union, but MSVC currently does not 18890 The function checks each byte of a string whether it is UTF-8 encoded. The
8092 allow unions members with complex constructors, see 18891 result of the check is stored in the @a state parameter. The function must
8093 https://github.com/nlohmann/json/pull/105. 18892 be called initially with state 0 (accept). State 1 means the string must
18893 be rejected, because the current byte is not allowed. If the string is
18894 completely processed, but the state is non-zero, the string ended
18895 prematurely; that is, the last byte indicated more bytes should have
18896 followed.
18897
18898 @param[in,out] state the state of the decoding
18899 @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT)
18900 @param[in] byte next byte to decode
18901 @return new state
18902
18903 @note The function has been edited: a std::array is used.
18904
18905 @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
18906 @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
8094 */ 18907 */
8095 struct internal_iterator 18908 static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept
8096 { 18909 {
8097 /// iterator for JSON objects 18910 static const std::array<std::uint8_t, 400> utf8d =
8098 typename object_t::iterator object_iterator; 18911 {
8099 /// iterator for JSON arrays 18912 {
8100 typename array_t::iterator array_iterator; 18913 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F
8101 /// generic iterator for all other types 18914 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F
8102 primitive_iterator_t primitive_iterator; 18915 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F
18916 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F
18917 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F
18918 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF
18919 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF
18920 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF
18921 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF
18922 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
18923 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
18924 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
18925 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
18926 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8
18927 }
18928 };
8103 18929
8104 /// create an uninitialized internal_iterator 18930 JSON_ASSERT(byte < utf8d.size());
8105 internal_iterator() noexcept 18931 const std::uint8_t type = utf8d[byte];
8106 : object_iterator(), array_iterator(), primitive_iterator()
8107 {}
8108 };
8109 18932
8110 /// proxy class for the iterator_wrapper functions 18933 codep = (state != UTF8_ACCEPT)
8111 template<typename IteratorType> 18934 ? (byte & 0x3fu) | (codep << 6u)
8112 class iteration_proxy 18935 : (0xFFu >> type) & (byte);
18936
18937 const std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
18938 JSON_ASSERT(index < utf8d.size());
18939 state = utf8d[index];
18940 return state;
18941 }
18942
18943 /*
18944 * Overload to make the compiler happy while it is instantiating
18945 * dump_integer for number_unsigned_t.
18946 * Must never be called.
18947 */
18948 number_unsigned_t remove_sign(number_unsigned_t x)
8113 { 18949 {
8114 private: 18950 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
8115 /// helper class for iteration 18951 return x; // LCOV_EXCL_LINE
8116 class iteration_proxy_internal 18952 }
8117 { 18953
8118 private: 18954 /*
8119 /// the iterator 18955 * Helper function for dump_integer
8120 IteratorType anchor; 18956 *
8121 /// an index for arrays (used to create key names) 18957 * This function takes a negative signed integer and returns its absolute
8122 size_t array_index = 0; 18958 * value as unsigned integer. The plus/minus shuffling is necessary as we can
18959 * not directly remove the sign of an arbitrary signed integer as the
18960 * absolute values of INT_MIN and INT_MAX are usually not the same. See
18961 * #1708 for details.
18962 */
18963 inline number_unsigned_t remove_sign(number_integer_t x) noexcept
18964 {
18965 JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)()); // NOLINT(misc-redundant-expression)
18966 return static_cast<number_unsigned_t>(-(x + 1)) + 1;
18967 }
18968
18969 private:
18970 /// the output of the serializer
18971 output_adapter_t<char> o = nullptr;
18972
18973 /// a (hopefully) large enough character buffer
18974 std::array<char, 64> number_buffer{{}};
18975
18976 /// the locale
18977 const std::lconv* loc = nullptr;
18978 /// the locale's thousand separator character
18979 const char thousands_sep = '\0';
18980 /// the locale's decimal point character
18981 const char decimal_point = '\0';
18982
18983 /// string buffer
18984 std::array<char, 512> string_buffer{{}};
18985
18986 /// the indentation character
18987 const char indent_char;
18988 /// the indentation string
18989 string_t indent_string;
18990
18991 /// error_handler how to react on decoding errors
18992 const error_handler_t error_handler;
18993};
18994
18995} // namespace detail
18996NLOHMANN_JSON_NAMESPACE_END
18997
18998// #include <nlohmann/detail/value_t.hpp>
18999
19000// #include <nlohmann/json_fwd.hpp>
19001
19002// #include <nlohmann/ordered_map.hpp>
19003// __ _____ _____ _____
19004// __| | __| | | | JSON for Modern C++
19005// | | |__ | | | | | | version 3.11.3
19006// |_____|_____|_____|_|___| https://github.com/nlohmann/json
19007//
19008// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
19009// SPDX-License-Identifier: MIT
19010
19011
19012
19013#include <functional> // equal_to, less
19014#include <initializer_list> // initializer_list
19015#include <iterator> // input_iterator_tag, iterator_traits
19016#include <memory> // allocator
19017#include <stdexcept> // for out_of_range
19018#include <type_traits> // enable_if, is_convertible
19019#include <utility> // pair
19020#include <vector> // vector
19021
19022// #include <nlohmann/detail/macro_scope.hpp>
8123 19023
8124 public: 19024// #include <nlohmann/detail/meta/type_traits.hpp>
8125 explicit iteration_proxy_internal(IteratorType it) noexcept
8126 : anchor(it)
8127 {}
8128 19025
8129 /// dereference operator (needed for range-based for) 19026
8130 iteration_proxy_internal& operator*() 19027NLOHMANN_JSON_NAMESPACE_BEGIN
19028
19029/// ordered_map: a minimal map-like container that preserves insertion order
19030/// for use within nlohmann::basic_json<ordered_map>
19031template <class Key, class T, class IgnoredLess = std::less<Key>,
19032 class Allocator = std::allocator<std::pair<const Key, T>>>
19033 struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>
19034{
19035 using key_type = Key;
19036 using mapped_type = T;
19037 using Container = std::vector<std::pair<const Key, T>, Allocator>;
19038 using iterator = typename Container::iterator;
19039 using const_iterator = typename Container::const_iterator;
19040 using size_type = typename Container::size_type;
19041 using value_type = typename Container::value_type;
19042#ifdef JSON_HAS_CPP_14
19043 using key_compare = std::equal_to<>;
19044#else
19045 using key_compare = std::equal_to<Key>;
19046#endif
19047
19048 // Explicit constructors instead of `using Container::Container`
19049 // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
19050 ordered_map() noexcept(noexcept(Container())) : Container{} {}
19051 explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {}
19052 template <class It>
19053 ordered_map(It first, It last, const Allocator& alloc = Allocator())
19054 : Container{first, last, alloc} {}
19055 ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() )
19056 : Container{init, alloc} {}
19057
19058 std::pair<iterator, bool> emplace(const key_type& key, T&& t)
19059 {
19060 for (auto it = this->begin(); it != this->end(); ++it)
19061 {
19062 if (m_compare(it->first, key))
8131 { 19063 {
8132 return *this; 19064 return {it, false};
8133 } 19065 }
19066 }
19067 Container::emplace_back(key, std::forward<T>(t));
19068 return {std::prev(this->end()), true};
19069 }
8134 19070
8135 /// increment operator (needed for range-based for) 19071 template<class KeyType, detail::enable_if_t<
8136 iteration_proxy_internal& operator++() 19072 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19073 std::pair<iterator, bool> emplace(KeyType && key, T && t)
19074 {
19075 for (auto it = this->begin(); it != this->end(); ++it)
19076 {
19077 if (m_compare(it->first, key))
8137 { 19078 {
8138 ++anchor; 19079 return {it, false};
8139 ++array_index; 19080 }
19081 }
19082 Container::emplace_back(std::forward<KeyType>(key), std::forward<T>(t));
19083 return {std::prev(this->end()), true};
19084 }
19085
19086 T& operator[](const key_type& key)
19087 {
19088 return emplace(key, T{}).first->second;
19089 }
19090
19091 template<class KeyType, detail::enable_if_t<
19092 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19093 T & operator[](KeyType && key)
19094 {
19095 return emplace(std::forward<KeyType>(key), T{}).first->second;
19096 }
19097
19098 const T& operator[](const key_type& key) const
19099 {
19100 return at(key);
19101 }
8140 19102
8141 return *this; 19103 template<class KeyType, detail::enable_if_t<
19104 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19105 const T & operator[](KeyType && key) const
19106 {
19107 return at(std::forward<KeyType>(key));
19108 }
19109
19110 T& at(const key_type& key)
19111 {
19112 for (auto it = this->begin(); it != this->end(); ++it)
19113 {
19114 if (m_compare(it->first, key))
19115 {
19116 return it->second;
8142 } 19117 }
19118 }
8143 19119
8144 /// inequality operator (needed for range-based for) 19120 JSON_THROW(std::out_of_range("key not found"));
8145 bool operator!= (const iteration_proxy_internal& o) const 19121 }
19122
19123 template<class KeyType, detail::enable_if_t<
19124 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19125 T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
19126 {
19127 for (auto it = this->begin(); it != this->end(); ++it)
19128 {
19129 if (m_compare(it->first, key))
8146 { 19130 {
8147 return anchor != o.anchor; 19131 return it->second;
8148 } 19132 }
19133 }
19134
19135 JSON_THROW(std::out_of_range("key not found"));
19136 }
8149 19137
8150 /// return key of the iterator 19138 const T& at(const key_type& key) const
8151 typename basic_json::string_t key() const 19139 {
19140 for (auto it = this->begin(); it != this->end(); ++it)
19141 {
19142 if (m_compare(it->first, key))
8152 { 19143 {
8153 assert(anchor.m_object != nullptr); 19144 return it->second;
19145 }
19146 }
8154 19147
8155 switch (anchor.m_object->type()) 19148 JSON_THROW(std::out_of_range("key not found"));
8156 { 19149 }
8157 // use integer array index as key
8158 case value_t::array:
8159 {
8160 return std::to_string(array_index);
8161 }
8162 19150
8163 // use key from the object 19151 template<class KeyType, detail::enable_if_t<
8164 case value_t::object: 19152 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
8165 { 19153 const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
8166 return anchor.key(); 19154 {
8167 } 19155 for (auto it = this->begin(); it != this->end(); ++it)
19156 {
19157 if (m_compare(it->first, key))
19158 {
19159 return it->second;
19160 }
19161 }
8168 19162
8169 // use an empty key for all primitive types 19163 JSON_THROW(std::out_of_range("key not found"));
8170 default: 19164 }
8171 { 19165
8172 return ""; 19166 size_type erase(const key_type& key)
8173 } 19167 {
19168 for (auto it = this->begin(); it != this->end(); ++it)
19169 {
19170 if (m_compare(it->first, key))
19171 {
19172 // Since we cannot move const Keys, re-construct them in place
19173 for (auto next = it; ++next != this->end(); ++it)
19174 {
19175 it->~value_type(); // Destroy but keep allocation
19176 new (&*it) value_type{std::move(*next)};
8174 } 19177 }
19178 Container::pop_back();
19179 return 1;
8175 } 19180 }
19181 }
19182 return 0;
19183 }
8176 19184
8177 /// return value of the iterator 19185 template<class KeyType, detail::enable_if_t<
8178 typename IteratorType::reference value() const 19186 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19187 size_type erase(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
19188 {
19189 for (auto it = this->begin(); it != this->end(); ++it)
19190 {
19191 if (m_compare(it->first, key))
8179 { 19192 {
8180 return anchor.value(); 19193 // Since we cannot move const Keys, re-construct them in place
19194 for (auto next = it; ++next != this->end(); ++it)
19195 {
19196 it->~value_type(); // Destroy but keep allocation
19197 new (&*it) value_type{std::move(*next)};
19198 }
19199 Container::pop_back();
19200 return 1;
8181 } 19201 }
8182 }; 19202 }
8183 19203 return 0;
8184 /// the container to iterate 19204 }
8185 typename IteratorType::reference container;
8186 19205
8187 public: 19206 iterator erase(iterator pos)
8188 /// construct iteration proxy from a container 19207 {
8189 explicit iteration_proxy(typename IteratorType::reference cont) 19208 return erase(pos, std::next(pos));
8190 : container(cont) 19209 }
8191 {}
8192 19210
8193 /// return iterator begin (needed for range-based for) 19211 iterator erase(iterator first, iterator last)
8194 iteration_proxy_internal begin() noexcept 19212 {
19213 if (first == last)
8195 { 19214 {
8196 return iteration_proxy_internal(container.begin()); 19215 return first;
8197 } 19216 }
8198 19217
8199 /// return iterator end (needed for range-based for) 19218 const auto elements_affected = std::distance(first, last);
8200 iteration_proxy_internal end() noexcept 19219 const auto offset = std::distance(Container::begin(), first);
19220
19221 // This is the start situation. We need to delete elements_affected
19222 // elements (3 in this example: e, f, g), and need to return an
19223 // iterator past the last deleted element (h in this example).
19224 // Note that offset is the distance from the start of the vector
19225 // to first. We will need this later.
19226
19227 // [ a, b, c, d, e, f, g, h, i, j ]
19228 // ^ ^
19229 // first last
19230
19231 // Since we cannot move const Keys, we re-construct them in place.
19232 // We start at first and re-construct (viz. copy) the elements from
19233 // the back of the vector. Example for first iteration:
19234
19235 // ,--------.
19236 // v | destroy e and re-construct with h
19237 // [ a, b, c, d, e, f, g, h, i, j ]
19238 // ^ ^
19239 // it it + elements_affected
19240
19241 for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it)
8201 { 19242 {
8202 return iteration_proxy_internal(container.end()); 19243 it->~value_type(); // destroy but keep allocation
19244 new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it
8203 } 19245 }
8204 };
8205 19246
8206 public: 19247 // [ a, b, c, d, h, i, j, h, i, j ]
8207 /*! 19248 // ^ ^
8208 @brief a template for a random access iterator for the @ref basic_json class 19249 // first last
8209
8210 This class implements a both iterators (iterator and const_iterator) for the
8211 @ref basic_json class.
8212
8213 @note An iterator is called *initialized* when a pointer to a JSON value
8214 has been set (e.g., by a constructor or a copy assignment). If the
8215 iterator is default-constructed, it is *uninitialized* and most
8216 methods are undefined. **The library uses assertions to detect calls
8217 on uninitialized iterators.**
8218
8219 @requirement The class satisfies the following concept requirements:
8220 - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
8221 The iterator that can be moved to point (forward and backward) to any
8222 element in constant time.
8223
8224 @since version 1.0.0, simplified in version 2.0.9
8225 */
8226 template<typename U>
8227 class iter_impl : public std::iterator<std::random_access_iterator_tag, U>
8228 {
8229 /// allow basic_json to access private members
8230 friend class basic_json;
8231
8232 // make sure U is basic_json or const basic_json
8233 static_assert(std::is_same<U, basic_json>::value
8234 or std::is_same<U, const basic_json>::value,
8235 "iter_impl only accepts (const) basic_json");
8236
8237 public:
8238 /// the type of the values when the iterator is dereferenced
8239 using value_type = typename basic_json::value_type;
8240 /// a type to represent differences between iterators
8241 using difference_type = typename basic_json::difference_type;
8242 /// defines a pointer to the type iterated over (value_type)
8243 using pointer = typename std::conditional<std::is_const<U>::value,
8244 typename basic_json::const_pointer,
8245 typename basic_json::pointer>::type;
8246 /// defines a reference to the type iterated over (value_type)
8247 using reference = typename std::conditional<std::is_const<U>::value,
8248 typename basic_json::const_reference,
8249 typename basic_json::reference>::type;
8250 /// the category of the iterator
8251 using iterator_category = std::bidirectional_iterator_tag;
8252
8253 /// default constructor
8254 iter_impl() = default;
8255
8256 /*!
8257 @brief constructor for a given JSON instance
8258 @param[in] object pointer to a JSON object for this iterator
8259 @pre object != nullptr
8260 @post The iterator is initialized; i.e. `m_object != nullptr`.
8261 */
8262 explicit iter_impl(pointer object) noexcept
8263 : m_object(object)
8264 {
8265 assert(m_object != nullptr);
8266
8267 switch (m_object->m_type)
8268 {
8269 case basic_json::value_t::object:
8270 {
8271 m_it.object_iterator = typename object_t::iterator();
8272 break;
8273 }
8274 19250
8275 case basic_json::value_t::array: 19251 // remove the unneeded elements at the end of the vector
8276 { 19252 Container::resize(this->size() - static_cast<size_type>(elements_affected));
8277 m_it.array_iterator = typename array_t::iterator();
8278 break;
8279 }
8280 19253
8281 default: 19254 // [ a, b, c, d, h, i, j ]
8282 { 19255 // ^ ^
8283 m_it.primitive_iterator = primitive_iterator_t(); 19256 // first last
8284 break; 19257
8285 } 19258 // first is now pointing past the last deleted element, but we cannot
19259 // use this iterator, because it may have been invalidated by the
19260 // resize call. Instead, we can return begin() + offset.
19261 return Container::begin() + offset;
19262 }
19263
19264 size_type count(const key_type& key) const
19265 {
19266 for (auto it = this->begin(); it != this->end(); ++it)
19267 {
19268 if (m_compare(it->first, key))
19269 {
19270 return 1;
8286 } 19271 }
8287 } 19272 }
19273 return 0;
19274 }
8288 19275
8289 /* 19276 template<class KeyType, detail::enable_if_t<
8290 Use operator `const_iterator` instead of `const_iterator(const iterator& 19277 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
8291 other) noexcept` to avoid two class definitions for @ref iterator and 19278 size_type count(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
8292 @ref const_iterator. 19279 {
19280 for (auto it = this->begin(); it != this->end(); ++it)
19281 {
19282 if (m_compare(it->first, key))
19283 {
19284 return 1;
19285 }
19286 }
19287 return 0;
19288 }
8293 19289
8294 This function is only called if this class is an @ref iterator. If this 19290 iterator find(const key_type& key)
8295 class is a @ref const_iterator this function is not called. 19291 {
8296 */ 19292 for (auto it = this->begin(); it != this->end(); ++it)
8297 operator const_iterator() const
8298 { 19293 {
8299 const_iterator ret; 19294 if (m_compare(it->first, key))
19295 {
19296 return it;
19297 }
19298 }
19299 return Container::end();
19300 }
8300 19301
8301 if (m_object) 19302 template<class KeyType, detail::enable_if_t<
19303 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19304 iterator find(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
19305 {
19306 for (auto it = this->begin(); it != this->end(); ++it)
19307 {
19308 if (m_compare(it->first, key))
8302 { 19309 {
8303 ret.m_object = m_object; 19310 return it;
8304 ret.m_it = m_it;
8305 } 19311 }
19312 }
19313 return Container::end();
19314 }
8306 19315
8307 return ret; 19316 const_iterator find(const key_type& key) const
19317 {
19318 for (auto it = this->begin(); it != this->end(); ++it)
19319 {
19320 if (m_compare(it->first, key))
19321 {
19322 return it;
19323 }
8308 } 19324 }
19325 return Container::end();
19326 }
8309 19327
8310 /*! 19328 std::pair<iterator, bool> insert( value_type&& value )
8311 @brief copy constructor 19329 {
8312 @param[in] other iterator to copy from 19330 return emplace(value.first, std::move(value.second));
8313 @note It is not checked whether @a other is initialized. 19331 }
8314 */
8315 iter_impl(const iter_impl& other) noexcept
8316 : m_object(other.m_object), m_it(other.m_it)
8317 {}
8318 19332
8319 /*! 19333 std::pair<iterator, bool> insert( const value_type& value )
8320 @brief copy assignment 19334 {
8321 @param[in,out] other iterator to copy from 19335 for (auto it = this->begin(); it != this->end(); ++it)
8322 @note It is not checked whether @a other is initialized.
8323 */
8324 iter_impl& operator=(iter_impl other) noexcept(
8325 std::is_nothrow_move_constructible<pointer>::value and
8326 std::is_nothrow_move_assignable<pointer>::value and
8327 std::is_nothrow_move_constructible<internal_iterator>::value and
8328 std::is_nothrow_move_assignable<internal_iterator>::value
8329 )
8330 { 19336 {
8331 std::swap(m_object, other.m_object); 19337 if (m_compare(it->first, value.first))
8332 std::swap(m_it, other.m_it); 19338 {
8333 return *this; 19339 return {it, false};
19340 }
8334 } 19341 }
19342 Container::push_back(value);
19343 return {--this->end(), true};
19344 }
8335 19345
8336 private: 19346 template<typename InputIt>
8337 /*! 19347 using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,
8338 @brief set the iterator to the first value 19348 std::input_iterator_tag>::value>::type;
8339 @pre The iterator is initialized; i.e. `m_object != nullptr`. 19349
8340 */ 19350 template<typename InputIt, typename = require_input_iter<InputIt>>
8341 void set_begin() noexcept 19351 void insert(InputIt first, InputIt last)
19352 {
19353 for (auto it = first; it != last; ++it)
8342 { 19354 {
8343 assert(m_object != nullptr); 19355 insert(*it);
19356 }
19357 }
19358
19359private:
19360 JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare();
19361};
19362
19363NLOHMANN_JSON_NAMESPACE_END
8344 19364
8345 switch (m_object->m_type) 19365
19366#if defined(JSON_HAS_CPP_17)
19367 #if JSON_HAS_STATIC_RTTI
19368 #include <any>
19369 #endif
19370 #include <string_view>
19371#endif
19372
19373/*!
19374@brief namespace for Niels Lohmann
19375@see https://github.com/nlohmann
19376@since version 1.0.0
19377*/
19378NLOHMANN_JSON_NAMESPACE_BEGIN
19379
19380/*!
19381@brief a class to store JSON values
19382
19383@internal
19384@invariant The member variables @a m_value and @a m_type have the following
19385relationship:
19386- If `m_type == value_t::object`, then `m_value.object != nullptr`.
19387- If `m_type == value_t::array`, then `m_value.array != nullptr`.
19388- If `m_type == value_t::string`, then `m_value.string != nullptr`.
19389The invariants are checked by member function assert_invariant().
19390
19391@note ObjectType trick from https://stackoverflow.com/a/9860911
19392@endinternal
19393
19394@since version 1.0.0
19395
19396@nosubgrouping
19397*/
19398NLOHMANN_BASIC_JSON_TPL_DECLARATION
19399class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
19400 : public ::nlohmann::detail::json_base_class<CustomBaseClass>
19401{
19402 private:
19403 template<detail::value_t> friend struct detail::external_constructor;
19404
19405 template<typename>
19406 friend class ::nlohmann::json_pointer;
19407 // can be restored when json_pointer backwards compatibility is removed
19408 // friend ::nlohmann::json_pointer<StringType>;
19409
19410 template<typename BasicJsonType, typename InputType>
19411 friend class ::nlohmann::detail::parser;
19412 friend ::nlohmann::detail::serializer<basic_json>;
19413 template<typename BasicJsonType>
19414 friend class ::nlohmann::detail::iter_impl;
19415 template<typename BasicJsonType, typename CharType>
19416 friend class ::nlohmann::detail::binary_writer;
19417 template<typename BasicJsonType, typename InputType, typename SAX>
19418 friend class ::nlohmann::detail::binary_reader;
19419 template<typename BasicJsonType>
19420 friend class ::nlohmann::detail::json_sax_dom_parser;
19421 template<typename BasicJsonType>
19422 friend class ::nlohmann::detail::json_sax_dom_callback_parser;
19423 friend class ::nlohmann::detail::exception;
19424
19425 /// workaround type for MSVC
19426 using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
19427 using json_base_class_t = ::nlohmann::detail::json_base_class<CustomBaseClass>;
19428
19429 JSON_PRIVATE_UNLESS_TESTED:
19430 // convenience aliases for types residing in namespace detail;
19431 using lexer = ::nlohmann::detail::lexer_base<basic_json>;
19432
19433 template<typename InputAdapterType>
19434 static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser(
19435 InputAdapterType adapter,
19436 detail::parser_callback_t<basic_json>cb = nullptr,
19437 const bool allow_exceptions = true,
19438 const bool ignore_comments = false
19439 )
19440 {
19441 return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
19442 std::move(cb), allow_exceptions, ignore_comments);
19443 }
19444
19445 private:
19446 using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;
19447 template<typename BasicJsonType>
19448 using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;
19449 template<typename BasicJsonType>
19450 using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;
19451 template<typename Iterator>
19452 using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;
19453 template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;
19454
19455 template<typename CharType>
19456 using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;
19457
19458 template<typename InputType>
19459 using binary_reader = ::nlohmann::detail::binary_reader<basic_json, InputType>;
19460 template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;
19461
19462 JSON_PRIVATE_UNLESS_TESTED:
19463 using serializer = ::nlohmann::detail::serializer<basic_json>;
19464
19465 public:
19466 using value_t = detail::value_t;
19467 /// JSON Pointer, see @ref nlohmann::json_pointer
19468 using json_pointer = ::nlohmann::json_pointer<StringType>;
19469 template<typename T, typename SFINAE>
19470 using json_serializer = JSONSerializer<T, SFINAE>;
19471 /// how to treat decoding errors
19472 using error_handler_t = detail::error_handler_t;
19473 /// how to treat CBOR tags
19474 using cbor_tag_handler_t = detail::cbor_tag_handler_t;
19475 /// helper type for initializer lists of basic_json values
19476 using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
19477
19478 using input_format_t = detail::input_format_t;
19479 /// SAX interface type, see @ref nlohmann::json_sax
19480 using json_sax_t = json_sax<basic_json>;
19481
19482 ////////////////
19483 // exceptions //
19484 ////////////////
19485
19486 /// @name exceptions
19487 /// Classes to implement user-defined exceptions.
19488 /// @{
19489
19490 using exception = detail::exception;
19491 using parse_error = detail::parse_error;
19492 using invalid_iterator = detail::invalid_iterator;
19493 using type_error = detail::type_error;
19494 using out_of_range = detail::out_of_range;
19495 using other_error = detail::other_error;
19496
19497 /// @}
19498
19499 /////////////////////
19500 // container types //
19501 /////////////////////
19502
19503 /// @name container types
19504 /// The canonic container types to use @ref basic_json like any other STL
19505 /// container.
19506 /// @{
19507
19508 /// the type of elements in a basic_json container
19509 using value_type = basic_json;
19510
19511 /// the type of an element reference
19512 using reference = value_type&;
19513 /// the type of an element const reference
19514 using const_reference = const value_type&;
19515
19516 /// a type to represent differences between iterators
19517 using difference_type = std::ptrdiff_t;
19518 /// a type to represent container sizes
19519 using size_type = std::size_t;
19520
19521 /// the allocator type
19522 using allocator_type = AllocatorType<basic_json>;
19523
19524 /// the type of an element pointer
19525 using pointer = typename std::allocator_traits<allocator_type>::pointer;
19526 /// the type of an element const pointer
19527 using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
19528
19529 /// an iterator for a basic_json container
19530 using iterator = iter_impl<basic_json>;
19531 /// a const iterator for a basic_json container
19532 using const_iterator = iter_impl<const basic_json>;
19533 /// a reverse iterator for a basic_json container
19534 using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
19535 /// a const reverse iterator for a basic_json container
19536 using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
19537
19538 /// @}
19539
19540 /// @brief returns the allocator associated with the container
19541 /// @sa https://json.nlohmann.me/api/basic_json/get_allocator/
19542 static allocator_type get_allocator()
19543 {
19544 return allocator_type();
19545 }
19546
19547 /// @brief returns version information on the library
19548 /// @sa https://json.nlohmann.me/api/basic_json/meta/
19549 JSON_HEDLEY_WARN_UNUSED_RESULT
19550 static basic_json meta()
19551 {
19552 basic_json result;
19553
19554 result["copyright"] = "(C) 2013-2023 Niels Lohmann";
19555 result["name"] = "JSON for Modern C++";
19556 result["url"] = "https://github.com/nlohmann/json";
19557 result["version"]["string"] =
19558 detail::concat(std::to_string(NLOHMANN_JSON_VERSION_MAJOR), '.',
19559 std::to_string(NLOHMANN_JSON_VERSION_MINOR), '.',
19560 std::to_string(NLOHMANN_JSON_VERSION_PATCH));
19561 result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR;
19562 result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR;
19563 result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH;
19564
19565#ifdef _WIN32
19566 result["platform"] = "win32";
19567#elif defined __linux__
19568 result["platform"] = "linux";
19569#elif defined __APPLE__
19570 result["platform"] = "apple";
19571#elif defined __unix__
19572 result["platform"] = "unix";
19573#else
19574 result["platform"] = "unknown";
19575#endif
19576
19577#if defined(__ICC) || defined(__INTEL_COMPILER)
19578 result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
19579#elif defined(__clang__)
19580 result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
19581#elif defined(__GNUC__) || defined(__GNUG__)
19582 result["compiler"] = {{"family", "gcc"}, {"version", detail::concat(
19583 std::to_string(__GNUC__), '.',
19584 std::to_string(__GNUC_MINOR__), '.',
19585 std::to_string(__GNUC_PATCHLEVEL__))
19586 }
19587 };
19588#elif defined(__HP_cc) || defined(__HP_aCC)
19589 result["compiler"] = "hp"
19590#elif defined(__IBMCPP__)
19591 result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
19592#elif defined(_MSC_VER)
19593 result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
19594#elif defined(__PGI)
19595 result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
19596#elif defined(__SUNPRO_CC)
19597 result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
19598#else
19599 result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
19600#endif
19601
19602#if defined(_MSVC_LANG)
19603 result["compiler"]["c++"] = std::to_string(_MSVC_LANG);
19604#elif defined(__cplusplus)
19605 result["compiler"]["c++"] = std::to_string(__cplusplus);
19606#else
19607 result["compiler"]["c++"] = "unknown";
19608#endif
19609 return result;
19610 }
19611
19612 ///////////////////////////
19613 // JSON value data types //
19614 ///////////////////////////
19615
19616 /// @name JSON value data types
19617 /// The data types to store a JSON value. These types are derived from
19618 /// the template arguments passed to class @ref basic_json.
19619 /// @{
19620
19621 /// @brief default object key comparator type
19622 /// The actual object key comparator type (@ref object_comparator_t) may be
19623 /// different.
19624 /// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/
19625#if defined(JSON_HAS_CPP_14)
19626 // use of transparent comparator avoids unnecessary repeated construction of temporaries
19627 // in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
19628 using default_object_comparator_t = std::less<>;
19629#else
19630 using default_object_comparator_t = std::less<StringType>;
19631#endif
19632
19633 /// @brief a type for an object
19634 /// @sa https://json.nlohmann.me/api/basic_json/object_t/
19635 using object_t = ObjectType<StringType,
19636 basic_json,
19637 default_object_comparator_t,
19638 AllocatorType<std::pair<const StringType,
19639 basic_json>>>;
19640
19641 /// @brief a type for an array
19642 /// @sa https://json.nlohmann.me/api/basic_json/array_t/
19643 using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
19644
19645 /// @brief a type for a string
19646 /// @sa https://json.nlohmann.me/api/basic_json/string_t/
19647 using string_t = StringType;
19648
19649 /// @brief a type for a boolean
19650 /// @sa https://json.nlohmann.me/api/basic_json/boolean_t/
19651 using boolean_t = BooleanType;
19652
19653 /// @brief a type for a number (integer)
19654 /// @sa https://json.nlohmann.me/api/basic_json/number_integer_t/
19655 using number_integer_t = NumberIntegerType;
19656
19657 /// @brief a type for a number (unsigned)
19658 /// @sa https://json.nlohmann.me/api/basic_json/number_unsigned_t/
19659 using number_unsigned_t = NumberUnsignedType;
19660
19661 /// @brief a type for a number (floating-point)
19662 /// @sa https://json.nlohmann.me/api/basic_json/number_float_t/
19663 using number_float_t = NumberFloatType;
19664
19665 /// @brief a type for a packed binary type
19666 /// @sa https://json.nlohmann.me/api/basic_json/binary_t/
19667 using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
19668
19669 /// @brief object key comparator type
19670 /// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/
19671 using object_comparator_t = detail::actual_object_comparator_t<basic_json>;
19672
19673 /// @}
19674
19675 private:
19676
19677 /// helper for exception-safe object creation
19678 template<typename T, typename... Args>
19679 JSON_HEDLEY_RETURNS_NON_NULL
19680 static T* create(Args&& ... args)
19681 {
19682 AllocatorType<T> alloc;
19683 using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
19684
19685 auto deleter = [&](T * obj)
19686 {
19687 AllocatorTraits::deallocate(alloc, obj, 1);
19688 };
19689 std::unique_ptr<T, decltype(deleter)> obj(AllocatorTraits::allocate(alloc, 1), deleter);
19690 AllocatorTraits::construct(alloc, obj.get(), std::forward<Args>(args)...);
19691 JSON_ASSERT(obj != nullptr);
19692 return obj.release();
19693 }
19694
19695 ////////////////////////
19696 // JSON value storage //
19697 ////////////////////////
19698
19699 JSON_PRIVATE_UNLESS_TESTED:
19700 /*!
19701 @brief a JSON value
19702
19703 The actual storage for a JSON value of the @ref basic_json class. This
19704 union combines the different storage types for the JSON value types
19705 defined in @ref value_t.
19706
19707 JSON type | value_t type | used type
19708 --------- | --------------- | ------------------------
19709 object | object | pointer to @ref object_t
19710 array | array | pointer to @ref array_t
19711 string | string | pointer to @ref string_t
19712 boolean | boolean | @ref boolean_t
19713 number | number_integer | @ref number_integer_t
19714 number | number_unsigned | @ref number_unsigned_t
19715 number | number_float | @ref number_float_t
19716 binary | binary | pointer to @ref binary_t
19717 null | null | *no value is stored*
19718
19719 @note Variable-length types (objects, arrays, and strings) are stored as
19720 pointers. The size of the union should not exceed 64 bits if the default
19721 value types are used.
19722
19723 @since version 1.0.0
19724 */
19725 union json_value
19726 {
19727 /// object (stored with pointer to save storage)
19728 object_t* object;
19729 /// array (stored with pointer to save storage)
19730 array_t* array;
19731 /// string (stored with pointer to save storage)
19732 string_t* string;
19733 /// binary (stored with pointer to save storage)
19734 binary_t* binary;
19735 /// boolean
19736 boolean_t boolean;
19737 /// number (integer)
19738 number_integer_t number_integer;
19739 /// number (unsigned integer)
19740 number_unsigned_t number_unsigned;
19741 /// number (floating-point)
19742 number_float_t number_float;
19743
19744 /// default constructor (for null values)
19745 json_value() = default;
19746 /// constructor for booleans
19747 json_value(boolean_t v) noexcept : boolean(v) {}
19748 /// constructor for numbers (integer)
19749 json_value(number_integer_t v) noexcept : number_integer(v) {}
19750 /// constructor for numbers (unsigned)
19751 json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
19752 /// constructor for numbers (floating-point)
19753 json_value(number_float_t v) noexcept : number_float(v) {}
19754 /// constructor for empty values of a given type
19755 json_value(value_t t)
19756 {
19757 switch (t)
8346 { 19758 {
8347 case basic_json::value_t::object: 19759 case value_t::object:
8348 { 19760 {
8349 m_it.object_iterator = m_object->m_value.object->begin(); 19761 object = create<object_t>();
8350 break; 19762 break;
8351 } 19763 }
8352 19764
8353 case basic_json::value_t::array: 19765 case value_t::array:
8354 { 19766 {
8355 m_it.array_iterator = m_object->m_value.array->begin(); 19767 array = create<array_t>();
8356 break; 19768 break;
8357 } 19769 }
8358 19770
8359 case basic_json::value_t::null: 19771 case value_t::string:
8360 { 19772 {
8361 // set to end so begin()==end() is true: null is empty 19773 string = create<string_t>("");
8362 m_it.primitive_iterator.set_end();
8363 break; 19774 break;
8364 } 19775 }
8365 19776
8366 default: 19777 case value_t::binary:
8367 { 19778 {
8368 m_it.primitive_iterator.set_begin(); 19779 binary = create<binary_t>();
8369 break; 19780 break;
8370 } 19781 }
8371 }
8372 }
8373
8374 /*!
8375 @brief set the iterator past the last value
8376 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8377 */
8378 void set_end() noexcept
8379 {
8380 assert(m_object != nullptr);
8381 19782
8382 switch (m_object->m_type) 19783 case value_t::boolean:
8383 {
8384 case basic_json::value_t::object:
8385 { 19784 {
8386 m_it.object_iterator = m_object->m_value.object->end(); 19785 boolean = static_cast<boolean_t>(false);
8387 break; 19786 break;
8388 } 19787 }
8389 19788
8390 case basic_json::value_t::array: 19789 case value_t::number_integer:
8391 { 19790 {
8392 m_it.array_iterator = m_object->m_value.array->end(); 19791 number_integer = static_cast<number_integer_t>(0);
8393 break; 19792 break;
8394 } 19793 }
8395 19794
8396 default: 19795 case value_t::number_unsigned:
8397 { 19796 {
8398 m_it.primitive_iterator.set_end(); 19797 number_unsigned = static_cast<number_unsigned_t>(0);
8399 break; 19798 break;
8400 } 19799 }
8401 }
8402 }
8403
8404 public:
8405 /*!
8406 @brief return a reference to the value pointed to by the iterator
8407 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8408 */
8409 reference operator*() const
8410 {
8411 assert(m_object != nullptr);
8412
8413 switch (m_object->m_type)
8414 {
8415 case basic_json::value_t::object:
8416 {
8417 assert(m_it.object_iterator != m_object->m_value.object->end());
8418 return m_it.object_iterator->second;
8419 }
8420 19800
8421 case basic_json::value_t::array: 19801 case value_t::number_float:
8422 { 19802 {
8423 assert(m_it.array_iterator != m_object->m_value.array->end()); 19803 number_float = static_cast<number_float_t>(0.0);
8424 return *m_it.array_iterator; 19804 break;
8425 } 19805 }
8426 19806
8427 case basic_json::value_t::null: 19807 case value_t::null:
8428 { 19808 {
8429 throw std::out_of_range("cannot get value"); 19809 object = nullptr; // silence warning, see #821
19810 break;
8430 } 19811 }
8431 19812
19813 case value_t::discarded:
8432 default: 19814 default:
8433 { 19815 {
8434 if (m_it.primitive_iterator.is_begin()) 19816 object = nullptr; // silence warning, see #821
8435 { 19817 if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
8436 return *m_object;
8437 }
8438 else
8439 { 19818 {
8440 throw std::out_of_range("cannot get value"); 19819 JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.3", nullptr)); // LCOV_EXCL_LINE
8441 } 19820 }
19821 break;
8442 } 19822 }
8443 } 19823 }
8444 } 19824 }
8445 19825
8446 /*! 19826 /// constructor for strings
8447 @brief dereference the iterator 19827 json_value(const string_t& value) : string(create<string_t>(value)) {}
8448 @pre The iterator is initialized; i.e. `m_object != nullptr`. 19828
8449 */ 19829 /// constructor for rvalue strings
8450 pointer operator->() const 19830 json_value(string_t&& value) : string(create<string_t>(std::move(value))) {}
8451 { 19831
8452 assert(m_object != nullptr); 19832 /// constructor for objects
19833 json_value(const object_t& value) : object(create<object_t>(value)) {}
19834
19835 /// constructor for rvalue objects
19836 json_value(object_t&& value) : object(create<object_t>(std::move(value))) {}
19837
19838 /// constructor for arrays
19839 json_value(const array_t& value) : array(create<array_t>(value)) {}
8453 19840
8454 switch (m_object->m_type) 19841 /// constructor for rvalue arrays
19842 json_value(array_t&& value) : array(create<array_t>(std::move(value))) {}
19843
19844 /// constructor for binary arrays
19845 json_value(const typename binary_t::container_type& value) : binary(create<binary_t>(value)) {}
19846
19847 /// constructor for rvalue binary arrays
19848 json_value(typename binary_t::container_type&& value) : binary(create<binary_t>(std::move(value))) {}
19849
19850 /// constructor for binary arrays (internal type)
19851 json_value(const binary_t& value) : binary(create<binary_t>(value)) {}
19852
19853 /// constructor for rvalue binary arrays (internal type)
19854 json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}
19855
19856 void destroy(value_t t)
19857 {
19858 if (
19859 (t == value_t::object && object == nullptr) ||
19860 (t == value_t::array && array == nullptr) ||
19861 (t == value_t::string && string == nullptr) ||
19862 (t == value_t::binary && binary == nullptr)
19863 )
8455 { 19864 {
8456 case basic_json::value_t::object: 19865 //not initialized (e.g. due to exception in the ctor)
19866 return;
19867 }
19868 if (t == value_t::array || t == value_t::object)
19869 {
19870 // flatten the current json_value to a heap-allocated stack
19871 std::vector<basic_json> stack;
19872
19873 // move the top-level items to stack
19874 if (t == value_t::array)
8457 { 19875 {
8458 assert(m_it.object_iterator != m_object->m_value.object->end()); 19876 stack.reserve(array->size());
8459 return &(m_it.object_iterator->second); 19877 std::move(array->begin(), array->end(), std::back_inserter(stack));
8460 } 19878 }
8461 19879 else
8462 case basic_json::value_t::array:
8463 { 19880 {
8464 assert(m_it.array_iterator != m_object->m_value.array->end()); 19881 stack.reserve(object->size());
8465 return &*m_it.array_iterator; 19882 for (auto&& it : *object)
19883 {
19884 stack.push_back(std::move(it.second));
19885 }
8466 } 19886 }
8467 19887
8468 default: 19888 while (!stack.empty())
8469 { 19889 {
8470 if (m_it.primitive_iterator.is_begin()) 19890 // move the last item to local variable to be processed
19891 basic_json current_item(std::move(stack.back()));
19892 stack.pop_back();
19893
19894 // if current_item is array/object, move
19895 // its children to the stack to be processed later
19896 if (current_item.is_array())
8471 { 19897 {
8472 return m_object; 19898 std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack));
19899
19900 current_item.m_data.m_value.array->clear();
8473 } 19901 }
8474 else 19902 else if (current_item.is_object())
8475 { 19903 {
8476 throw std::out_of_range("cannot get value"); 19904 for (auto&& it : *current_item.m_data.m_value.object)
19905 {
19906 stack.push_back(std::move(it.second));
19907 }
19908
19909 current_item.m_data.m_value.object->clear();
8477 } 19910 }
19911
19912 // it's now safe that current_item get destructed
19913 // since it doesn't have any children
8478 } 19914 }
8479 } 19915 }
8480 }
8481
8482 /*!
8483 @brief post-increment (it++)
8484 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8485 */
8486 iter_impl operator++(int)
8487 {
8488 auto result = *this;
8489 ++(*this);
8490 return result;
8491 }
8492 19916
8493 /*! 19917 switch (t)
8494 @brief pre-increment (++it)
8495 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8496 */
8497 iter_impl& operator++()
8498 {
8499 assert(m_object != nullptr);
8500
8501 switch (m_object->m_type)
8502 { 19918 {
8503 case basic_json::value_t::object: 19919 case value_t::object:
8504 {
8505 std::advance(m_it.object_iterator, 1);
8506 break;
8507 }
8508
8509 case basic_json::value_t::array:
8510 { 19920 {
8511 std::advance(m_it.array_iterator, 1); 19921 AllocatorType<object_t> alloc;
19922 std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
19923 std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
8512 break; 19924 break;
8513 } 19925 }
8514 19926
8515 default: 19927 case value_t::array:
8516 { 19928 {
8517 ++m_it.primitive_iterator; 19929 AllocatorType<array_t> alloc;
19930 std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
19931 std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
8518 break; 19932 break;
8519 } 19933 }
8520 }
8521
8522 return *this;
8523 }
8524
8525 /*!
8526 @brief post-decrement (it--)
8527 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8528 */
8529 iter_impl operator--(int)
8530 {
8531 auto result = *this;
8532 --(*this);
8533 return result;
8534 }
8535 19934
8536 /*! 19935 case value_t::string:
8537 @brief pre-decrement (--it)
8538 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8539 */
8540 iter_impl& operator--()
8541 {
8542 assert(m_object != nullptr);
8543
8544 switch (m_object->m_type)
8545 {
8546 case basic_json::value_t::object:
8547 { 19936 {
8548 std::advance(m_it.object_iterator, -1); 19937 AllocatorType<string_t> alloc;
19938 std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
19939 std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
8549 break; 19940 break;
8550 } 19941 }
8551 19942
8552 case basic_json::value_t::array: 19943 case value_t::binary:
8553 { 19944 {
8554 std::advance(m_it.array_iterator, -1); 19945 AllocatorType<binary_t> alloc;
19946 std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);
19947 std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);
8555 break; 19948 break;
8556 } 19949 }
8557 19950
19951 case value_t::null:
19952 case value_t::boolean:
19953 case value_t::number_integer:
19954 case value_t::number_unsigned:
19955 case value_t::number_float:
19956 case value_t::discarded:
8558 default: 19957 default:
8559 { 19958 {
8560 --m_it.primitive_iterator;
8561 break; 19959 break;
8562 } 19960 }
8563 } 19961 }
8564
8565 return *this;
8566 } 19962 }
19963 };
8567 19964
8568 /*! 19965 private:
8569 @brief comparison: equal 19966 /*!
8570 @pre The iterator is initialized; i.e. `m_object != nullptr`. 19967 @brief checks the class invariants
8571 */ 19968
8572 bool operator==(const iter_impl& other) const 19969 This function asserts the class invariants. It needs to be called at the
8573 { 19970 end of every constructor to make sure that created objects respect the
8574 // if objects are not the same, the comparison is undefined 19971 invariant. Furthermore, it has to be called each time the type of a JSON
8575 if (m_object != other.m_object) 19972 value is changed, because the invariant expresses a relationship between
8576 { 19973 @a m_type and @a m_value.
8577 throw std::domain_error("cannot compare iterators of different containers");
8578 }
8579 19974
8580 assert(m_object != nullptr); 19975 Furthermore, the parent relation is checked for arrays and objects: If
19976 @a check_parents true and the value is an array or object, then the
19977 container's elements must have the current value as parent.
8581 19978
8582 switch (m_object->m_type) 19979 @param[in] check_parents whether the parent relation should be checked.
19980 The value is true by default and should only be set to false
19981 during destruction of objects when the invariant does not
19982 need to hold.
19983 */
19984 void assert_invariant(bool check_parents = true) const noexcept
19985 {
19986 JSON_ASSERT(m_data.m_type != value_t::object || m_data.m_value.object != nullptr);
19987 JSON_ASSERT(m_data.m_type != value_t::array || m_data.m_value.array != nullptr);
19988 JSON_ASSERT(m_data.m_type != value_t::string || m_data.m_value.string != nullptr);
19989 JSON_ASSERT(m_data.m_type != value_t::binary || m_data.m_value.binary != nullptr);
19990
19991#if JSON_DIAGNOSTICS
19992 JSON_TRY
19993 {
19994 // cppcheck-suppress assertWithSideEffect
19995 JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j)
8583 { 19996 {
8584 case basic_json::value_t::object: 19997 return j.m_parent == this;
8585 { 19998 }));
8586 return (m_it.object_iterator == other.m_it.object_iterator); 19999 }
8587 } 20000 JSON_CATCH(...) {} // LCOV_EXCL_LINE
20001#endif
20002 static_cast<void>(check_parents);
20003 }
8588 20004
8589 case basic_json::value_t::array: 20005 void set_parents()
20006 {
20007#if JSON_DIAGNOSTICS
20008 switch (m_data.m_type)
20009 {
20010 case value_t::array:
20011 {
20012 for (auto& element : *m_data.m_value.array)
8590 { 20013 {
8591 return (m_it.array_iterator == other.m_it.array_iterator); 20014 element.m_parent = this;
8592 } 20015 }
20016 break;
20017 }
8593 20018
8594 default: 20019 case value_t::object:
20020 {
20021 for (auto& element : *m_data.m_value.object)
8595 { 20022 {
8596 return (m_it.primitive_iterator == other.m_it.primitive_iterator); 20023 element.second.m_parent = this;
8597 } 20024 }
20025 break;
8598 } 20026 }
20027
20028 case value_t::null:
20029 case value_t::string:
20030 case value_t::boolean:
20031 case value_t::number_integer:
20032 case value_t::number_unsigned:
20033 case value_t::number_float:
20034 case value_t::binary:
20035 case value_t::discarded:
20036 default:
20037 break;
8599 } 20038 }
20039#endif
20040 }
8600 20041
8601 /*! 20042 iterator set_parents(iterator it, typename iterator::difference_type count_set_parents)
8602 @brief comparison: not equal 20043 {
8603 @pre The iterator is initialized; i.e. `m_object != nullptr`. 20044#if JSON_DIAGNOSTICS
8604 */ 20045 for (typename iterator::difference_type i = 0; i < count_set_parents; ++i)
8605 bool operator!=(const iter_impl& other) const
8606 { 20046 {
8607 return not operator==(other); 20047 (it + i)->m_parent = this;
8608 } 20048 }
20049#else
20050 static_cast<void>(count_set_parents);
20051#endif
20052 return it;
20053 }
8609 20054
8610 /*! 20055 reference set_parent(reference j, std::size_t old_capacity = static_cast<std::size_t>(-1))
8611 @brief comparison: smaller 20056 {
8612 @pre The iterator is initialized; i.e. `m_object != nullptr`. 20057#if JSON_DIAGNOSTICS
8613 */ 20058 if (old_capacity != static_cast<std::size_t>(-1))
8614 bool operator<(const iter_impl& other) const
8615 { 20059 {
8616 // if objects are not the same, the comparison is undefined 20060 // see https://github.com/nlohmann/json/issues/2838
8617 if (m_object != other.m_object) 20061 JSON_ASSERT(type() == value_t::array);
20062 if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))
8618 { 20063 {
8619 throw std::domain_error("cannot compare iterators of different containers"); 20064 // capacity has changed: update all parents
20065 set_parents();
20066 return j;
8620 } 20067 }
20068 }
20069
20070 // ordered_json uses a vector internally, so pointers could have
20071 // been invalidated; see https://github.com/nlohmann/json/issues/2962
20072#ifdef JSON_HEDLEY_MSVC_VERSION
20073#pragma warning(push )
20074#pragma warning(disable : 4127) // ignore warning to replace if with if constexpr
20075#endif
20076 if (detail::is_ordered_map<object_t>::value)
20077 {
20078 set_parents();
20079 return j;
20080 }
20081#ifdef JSON_HEDLEY_MSVC_VERSION
20082#pragma warning( pop )
20083#endif
8621 20084
8622 assert(m_object != nullptr); 20085 j.m_parent = this;
20086#else
20087 static_cast<void>(j);
20088 static_cast<void>(old_capacity);
20089#endif
20090 return j;
20091 }
8623 20092
8624 switch (m_object->m_type) 20093 public:
8625 { 20094 //////////////////////////
8626 case basic_json::value_t::object: 20095 // JSON parser callback //
8627 { 20096 //////////////////////////
8628 throw std::domain_error("cannot compare order of object iterators");
8629 }
8630 20097
8631 case basic_json::value_t::array: 20098 /// @brief parser event types
8632 { 20099 /// @sa https://json.nlohmann.me/api/basic_json/parse_event_t/
8633 return (m_it.array_iterator < other.m_it.array_iterator); 20100 using parse_event_t = detail::parse_event_t;
8634 }
8635 20101
8636 default: 20102 /// @brief per-element parser callback type
8637 { 20103 /// @sa https://json.nlohmann.me/api/basic_json/parser_callback_t/
8638 return (m_it.primitive_iterator < other.m_it.primitive_iterator); 20104 using parser_callback_t = detail::parser_callback_t<basic_json>;
8639 }
8640 }
8641 }
8642 20105
8643 /*! 20106 //////////////////
8644 @brief comparison: less than or equal 20107 // constructors //
8645 @pre The iterator is initialized; i.e. `m_object != nullptr`. 20108 //////////////////
8646 */ 20109
8647 bool operator<=(const iter_impl& other) const 20110 /// @name constructors and destructors
8648 { 20111 /// Constructors of class @ref basic_json, copy/move constructor, copy
8649 return not other.operator < (*this); 20112 /// assignment, static functions creating objects, and the destructor.
8650 } 20113 /// @{
20114
20115 /// @brief create an empty value with a given type
20116 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
20117 basic_json(const value_t v)
20118 : m_data(v)
20119 {
20120 assert_invariant();
20121 }
20122
20123 /// @brief create a null object
20124 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
20125 basic_json(std::nullptr_t = nullptr) noexcept // NOLINT(bugprone-exception-escape)
20126 : basic_json(value_t::null)
20127 {
20128 assert_invariant();
20129 }
20130
20131 /// @brief create a JSON value from compatible types
20132 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
20133 template < typename CompatibleType,
20134 typename U = detail::uncvref_t<CompatibleType>,
20135 detail::enable_if_t <
20136 !detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 >
20137 basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape)
20138 JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
20139 std::forward<CompatibleType>(val))))
20140 {
20141 JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
20142 set_parents();
20143 assert_invariant();
20144 }
8651 20145
8652 /*! 20146 /// @brief create a JSON value from an existing one
8653 @brief comparison: greater than 20147 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
8654 @pre The iterator is initialized; i.e. `m_object != nullptr`. 20148 template < typename BasicJsonType,
8655 */ 20149 detail::enable_if_t <
8656 bool operator>(const iter_impl& other) const 20150 detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
20151 basic_json(const BasicJsonType& val)
20152 {
20153 using other_boolean_t = typename BasicJsonType::boolean_t;
20154 using other_number_float_t = typename BasicJsonType::number_float_t;
20155 using other_number_integer_t = typename BasicJsonType::number_integer_t;
20156 using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
20157 using other_string_t = typename BasicJsonType::string_t;
20158 using other_object_t = typename BasicJsonType::object_t;
20159 using other_array_t = typename BasicJsonType::array_t;
20160 using other_binary_t = typename BasicJsonType::binary_t;
20161
20162 switch (val.type())
8657 { 20163 {
8658 return not operator<=(other); 20164 case value_t::boolean:
20165 JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
20166 break;
20167 case value_t::number_float:
20168 JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
20169 break;
20170 case value_t::number_integer:
20171 JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
20172 break;
20173 case value_t::number_unsigned:
20174 JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
20175 break;
20176 case value_t::string:
20177 JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
20178 break;
20179 case value_t::object:
20180 JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
20181 break;
20182 case value_t::array:
20183 JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
20184 break;
20185 case value_t::binary:
20186 JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());
20187 break;
20188 case value_t::null:
20189 *this = nullptr;
20190 break;
20191 case value_t::discarded:
20192 m_data.m_type = value_t::discarded;
20193 break;
20194 default: // LCOV_EXCL_LINE
20195 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
8659 } 20196 }
20197 JSON_ASSERT(m_data.m_type == val.type());
20198 set_parents();
20199 assert_invariant();
20200 }
8660 20201
8661 /*! 20202 /// @brief create a container (array or object) from an initializer list
8662 @brief comparison: greater than or equal 20203 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
8663 @pre The iterator is initialized; i.e. `m_object != nullptr`. 20204 basic_json(initializer_list_t init,
8664 */ 20205 bool type_deduction = true,
8665 bool operator>=(const iter_impl& other) const 20206 value_t manual_type = value_t::array)
20207 {
20208 // check if each element is an array with two elements whose first
20209 // element is a string
20210 bool is_an_object = std::all_of(init.begin(), init.end(),
20211 [](const detail::json_ref<basic_json>& element_ref)
8666 { 20212 {
8667 return not operator<(other); 20213 // The cast is to ensure op[size_type] is called, bearing in mind size_type may not be int;
8668 } 20214 // (many string types can be constructed from 0 via its null-pointer guise, so we get a
20215 // broken call to op[key_type], the wrong semantics and a 4804 warning on Windows)
20216 return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[static_cast<size_type>(0)].is_string();
20217 });
8669 20218
8670 /*! 20219 // adjust type if type deduction is not wanted
8671 @brief add to iterator 20220 if (!type_deduction)
8672 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8673 */
8674 iter_impl& operator+=(difference_type i)
8675 { 20221 {
8676 assert(m_object != nullptr); 20222 // if array is wanted, do not create an object though possible
20223 if (manual_type == value_t::array)
20224 {
20225 is_an_object = false;
20226 }
8677 20227
8678 switch (m_object->m_type) 20228 // if object is wanted but impossible, throw an exception
20229 if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))
8679 { 20230 {
8680 case basic_json::value_t::object: 20231 JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr));
8681 { 20232 }
8682 throw std::domain_error("cannot use offsets with object iterators"); 20233 }
8683 }
8684 20234
8685 case basic_json::value_t::array: 20235 if (is_an_object)
8686 { 20236 {
8687 std::advance(m_it.array_iterator, i); 20237 // the initializer list is a list of pairs -> create object
8688 break; 20238 m_data.m_type = value_t::object;
8689 } 20239 m_data.m_value = value_t::object;
8690 20240
8691 default: 20241 for (auto& element_ref : init)
8692 { 20242 {
8693 m_it.primitive_iterator += i; 20243 auto element = element_ref.moved_or_copied();
8694 break; 20244 m_data.m_value.object->emplace(
8695 } 20245 std::move(*((*element.m_data.m_value.array)[0].m_data.m_value.string)),
20246 std::move((*element.m_data.m_value.array)[1]));
8696 } 20247 }
8697
8698 return *this;
8699 } 20248 }
8700 20249 else
8701 /*!
8702 @brief subtract from iterator
8703 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8704 */
8705 iter_impl& operator-=(difference_type i)
8706 { 20250 {
8707 return operator+=(-i); 20251 // the initializer list describes an array -> create array
20252 m_data.m_type = value_t::array;
20253 m_data.m_value.array = create<array_t>(init.begin(), init.end());
8708 } 20254 }
8709 20255
8710 /*! 20256 set_parents();
8711 @brief add to iterator 20257 assert_invariant();
8712 @pre The iterator is initialized; i.e. `m_object != nullptr`. 20258 }
8713 */ 20259
8714 iter_impl operator+(difference_type i) 20260 /// @brief explicitly create a binary array (without subtype)
20261 /// @sa https://json.nlohmann.me/api/basic_json/binary/
20262 JSON_HEDLEY_WARN_UNUSED_RESULT
20263 static basic_json binary(const typename binary_t::container_type& init)
20264 {
20265 auto res = basic_json();
20266 res.m_data.m_type = value_t::binary;
20267 res.m_data.m_value = init;
20268 return res;
20269 }
20270
20271 /// @brief explicitly create a binary array (with subtype)
20272 /// @sa https://json.nlohmann.me/api/basic_json/binary/
20273 JSON_HEDLEY_WARN_UNUSED_RESULT
20274 static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)
20275 {
20276 auto res = basic_json();
20277 res.m_data.m_type = value_t::binary;
20278 res.m_data.m_value = binary_t(init, subtype);
20279 return res;
20280 }
20281
20282 /// @brief explicitly create a binary array
20283 /// @sa https://json.nlohmann.me/api/basic_json/binary/
20284 JSON_HEDLEY_WARN_UNUSED_RESULT
20285 static basic_json binary(typename binary_t::container_type&& init)
20286 {
20287 auto res = basic_json();
20288 res.m_data.m_type = value_t::binary;
20289 res.m_data.m_value = std::move(init);
20290 return res;
20291 }
20292
20293 /// @brief explicitly create a binary array (with subtype)
20294 /// @sa https://json.nlohmann.me/api/basic_json/binary/
20295 JSON_HEDLEY_WARN_UNUSED_RESULT
20296 static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)
20297 {
20298 auto res = basic_json();
20299 res.m_data.m_type = value_t::binary;
20300 res.m_data.m_value = binary_t(std::move(init), subtype);
20301 return res;
20302 }
20303
20304 /// @brief explicitly create an array from an initializer list
20305 /// @sa https://json.nlohmann.me/api/basic_json/array/
20306 JSON_HEDLEY_WARN_UNUSED_RESULT
20307 static basic_json array(initializer_list_t init = {})
20308 {
20309 return basic_json(init, false, value_t::array);
20310 }
20311
20312 /// @brief explicitly create an object from an initializer list
20313 /// @sa https://json.nlohmann.me/api/basic_json/object/
20314 JSON_HEDLEY_WARN_UNUSED_RESULT
20315 static basic_json object(initializer_list_t init = {})
20316 {
20317 return basic_json(init, false, value_t::object);
20318 }
20319
20320 /// @brief construct an array with count copies of given value
20321 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
20322 basic_json(size_type cnt, const basic_json& val):
20323 m_data{cnt, val}
20324 {
20325 set_parents();
20326 assert_invariant();
20327 }
20328
20329 /// @brief construct a JSON container given an iterator range
20330 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
20331 template < class InputIT, typename std::enable_if <
20332 std::is_same<InputIT, typename basic_json_t::iterator>::value ||
20333 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 >
20334 basic_json(InputIT first, InputIT last)
20335 {
20336 JSON_ASSERT(first.m_object != nullptr);
20337 JSON_ASSERT(last.m_object != nullptr);
20338
20339 // make sure iterator fits the current value
20340 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
8715 { 20341 {
8716 auto result = *this; 20342 JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr));
8717 result += i;
8718 return result;
8719 } 20343 }
8720 20344
8721 /*! 20345 // copy type from first iterator
8722 @brief subtract from iterator 20346 m_data.m_type = first.m_object->m_data.m_type;
8723 @pre The iterator is initialized; i.e. `m_object != nullptr`. 20347
8724 */ 20348 // check if iterator range is complete for primitive values
8725 iter_impl operator-(difference_type i) 20349 switch (m_data.m_type)
8726 { 20350 {
8727 auto result = *this; 20351 case value_t::boolean:
8728 result -= i; 20352 case value_t::number_float:
8729 return result; 20353 case value_t::number_integer:
20354 case value_t::number_unsigned:
20355 case value_t::string:
20356 {
20357 if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
20358 || !last.m_it.primitive_iterator.is_end()))
20359 {
20360 JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object));
20361 }
20362 break;
20363 }
20364
20365 case value_t::null:
20366 case value_t::object:
20367 case value_t::array:
20368 case value_t::binary:
20369 case value_t::discarded:
20370 default:
20371 break;
8730 } 20372 }
8731 20373
8732 /*! 20374 switch (m_data.m_type)
8733 @brief return difference
8734 @pre The iterator is initialized; i.e. `m_object != nullptr`.
8735 */
8736 difference_type operator-(const iter_impl& other) const
8737 { 20375 {
8738 assert(m_object != nullptr); 20376 case value_t::number_integer:
20377 {
20378 m_data.m_value.number_integer = first.m_object->m_data.m_value.number_integer;
20379 break;
20380 }
8739 20381
8740 switch (m_object->m_type) 20382 case value_t::number_unsigned:
8741 { 20383 {
8742 case basic_json::value_t::object: 20384 m_data.m_value.number_unsigned = first.m_object->m_data.m_value.number_unsigned;
8743 { 20385 break;
8744 throw std::domain_error("cannot use offsets with object iterators"); 20386 }
8745 }
8746 20387
8747 case basic_json::value_t::array: 20388 case value_t::number_float:
8748 { 20389 {
8749 return m_it.array_iterator - other.m_it.array_iterator; 20390 m_data.m_value.number_float = first.m_object->m_data.m_value.number_float;
8750 } 20391 break;
20392 }
8751 20393
8752 default: 20394 case value_t::boolean:
8753 { 20395 {
8754 return m_it.primitive_iterator - other.m_it.primitive_iterator; 20396 m_data.m_value.boolean = first.m_object->m_data.m_value.boolean;
8755 } 20397 break;
20398 }
20399
20400 case value_t::string:
20401 {
20402 m_data.m_value = *first.m_object->m_data.m_value.string;
20403 break;
8756 } 20404 }
20405
20406 case value_t::object:
20407 {
20408 m_data.m_value.object = create<object_t>(first.m_it.object_iterator,
20409 last.m_it.object_iterator);
20410 break;
20411 }
20412
20413 case value_t::array:
20414 {
20415 m_data.m_value.array = create<array_t>(first.m_it.array_iterator,
20416 last.m_it.array_iterator);
20417 break;
20418 }
20419
20420 case value_t::binary:
20421 {
20422 m_data.m_value = *first.m_object->m_data.m_value.binary;
20423 break;
20424 }
20425
20426 case value_t::null:
20427 case value_t::discarded:
20428 default:
20429 JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object));
8757 } 20430 }
8758 20431
8759 /*! 20432 set_parents();
8760 @brief access to successor 20433 assert_invariant();
8761 @pre The iterator is initialized; i.e. `m_object != nullptr`. 20434 }
8762 */ 20435
8763 reference operator[](difference_type n) const 20436 ///////////////////////////////////////
20437 // other constructors and destructor //
20438 ///////////////////////////////////////
20439
20440 template<typename JsonRef,
20441 detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
20442 std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
20443 basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {}
20444
20445 /// @brief copy constructor
20446 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
20447 basic_json(const basic_json& other)
20448 : json_base_class_t(other)
20449 {
20450 m_data.m_type = other.m_data.m_type;
20451 // check of passed value is valid
20452 other.assert_invariant();
20453
20454 switch (m_data.m_type)
8764 { 20455 {
8765 assert(m_object != nullptr); 20456 case value_t::object:
20457 {
20458 m_data.m_value = *other.m_data.m_value.object;
20459 break;
20460 }
8766 20461
8767 switch (m_object->m_type) 20462 case value_t::array:
8768 { 20463 {
8769 case basic_json::value_t::object: 20464 m_data.m_value = *other.m_data.m_value.array;
8770 { 20465 break;
8771 throw std::domain_error("cannot use operator[] for object iterators"); 20466 }
8772 }
8773 20467
8774 case basic_json::value_t::array: 20468 case value_t::string:
8775 { 20469 {
8776 return *std::next(m_it.array_iterator, n); 20470 m_data.m_value = *other.m_data.m_value.string;
8777 } 20471 break;
20472 }
8778 20473
8779 case basic_json::value_t::null: 20474 case value_t::boolean:
8780 { 20475 {
8781 throw std::out_of_range("cannot get value"); 20476 m_data.m_value = other.m_data.m_value.boolean;
8782 } 20477 break;
20478 }
8783 20479
8784 default: 20480 case value_t::number_integer:
8785 { 20481 {
8786 if (m_it.primitive_iterator == -n) 20482 m_data.m_value = other.m_data.m_value.number_integer;
8787 { 20483 break;
8788 return *m_object;
8789 }
8790 else
8791 {
8792 throw std::out_of_range("cannot get value");
8793 }
8794 }
8795 } 20484 }
8796 }
8797 20485
8798 /*! 20486 case value_t::number_unsigned:
8799 @brief return the key of an object iterator 20487 {
8800 @pre The iterator is initialized; i.e. `m_object != nullptr`. 20488 m_data.m_value = other.m_data.m_value.number_unsigned;
8801 */ 20489 break;
8802 typename object_t::key_type key() const 20490 }
8803 {
8804 assert(m_object != nullptr);
8805 20491
8806 if (m_object->is_object()) 20492 case value_t::number_float:
8807 { 20493 {
8808 return m_it.object_iterator->first; 20494 m_data.m_value = other.m_data.m_value.number_float;
20495 break;
8809 } 20496 }
8810 else 20497
20498 case value_t::binary:
8811 { 20499 {
8812 throw std::domain_error("cannot use key() for non-object iterators"); 20500 m_data.m_value = *other.m_data.m_value.binary;
20501 break;
8813 } 20502 }
20503
20504 case value_t::null:
20505 case value_t::discarded:
20506 default:
20507 break;
8814 } 20508 }
8815 20509
8816 /*! 20510 set_parents();
8817 @brief return the value of an iterator 20511 assert_invariant();
8818 @pre The iterator is initialized; i.e. `m_object != nullptr`. 20512 }
8819 */ 20513
8820 reference value() const 20514 /// @brief move constructor
20515 /// @sa https://json.nlohmann.me/api/basic_json/basic_json/
20516 basic_json(basic_json&& other) noexcept
20517 : json_base_class_t(std::forward<json_base_class_t>(other)),
20518 m_data(std::move(other.m_data))
20519 {
20520 // check that passed value is valid
20521 other.assert_invariant(false);
20522
20523 // invalidate payload
20524 other.m_data.m_type = value_t::null;
20525 other.m_data.m_value = {};
20526
20527 set_parents();
20528 assert_invariant();
20529 }
20530
20531 /// @brief copy assignment
20532 /// @sa https://json.nlohmann.me/api/basic_json/operator=/
20533 basic_json& operator=(basic_json other) noexcept (
20534 std::is_nothrow_move_constructible<value_t>::value&&
20535 std::is_nothrow_move_assignable<value_t>::value&&
20536 std::is_nothrow_move_constructible<json_value>::value&&
20537 std::is_nothrow_move_assignable<json_value>::value&&
20538 std::is_nothrow_move_assignable<json_base_class_t>::value
20539 )
20540 {
20541 // check that passed value is valid
20542 other.assert_invariant();
20543
20544 using std::swap;
20545 swap(m_data.m_type, other.m_data.m_type);
20546 swap(m_data.m_value, other.m_data.m_value);
20547 json_base_class_t::operator=(std::move(other));
20548
20549 set_parents();
20550 assert_invariant();
20551 return *this;
20552 }
20553
20554 /// @brief destructor
20555 /// @sa https://json.nlohmann.me/api/basic_json/~basic_json/
20556 ~basic_json() noexcept
20557 {
20558 assert_invariant(false);
20559 }
20560
20561 /// @}
20562
20563 public:
20564 ///////////////////////
20565 // object inspection //
20566 ///////////////////////
20567
20568 /// @name object inspection
20569 /// Functions to inspect the type of a JSON value.
20570 /// @{
20571
20572 /// @brief serialization
20573 /// @sa https://json.nlohmann.me/api/basic_json/dump/
20574 string_t dump(const int indent = -1,
20575 const char indent_char = ' ',
20576 const bool ensure_ascii = false,
20577 const error_handler_t error_handler = error_handler_t::strict) const
20578 {
20579 string_t result;
20580 serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);
20581
20582 if (indent >= 0)
8821 { 20583 {
8822 return operator*(); 20584 s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
20585 }
20586 else
20587 {
20588 s.dump(*this, false, ensure_ascii, 0);
8823 } 20589 }
8824 20590
8825 private: 20591 return result;
8826 /// associated JSON instance 20592 }
8827 pointer m_object = nullptr; 20593
8828 /// the actual iterator of the associated instance 20594 /// @brief return the type of the JSON value (explicit)
8829 internal_iterator m_it = internal_iterator(); 20595 /// @sa https://json.nlohmann.me/api/basic_json/type/
8830 }; 20596 constexpr value_t type() const noexcept
20597 {
20598 return m_data.m_type;
20599 }
20600
20601 /// @brief return whether type is primitive
20602 /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/
20603 constexpr bool is_primitive() const noexcept
20604 {
20605 return is_null() || is_string() || is_boolean() || is_number() || is_binary();
20606 }
8831 20607
20608 /// @brief return whether type is structured
20609 /// @sa https://json.nlohmann.me/api/basic_json/is_structured/
20610 constexpr bool is_structured() const noexcept
20611 {
20612 return is_array() || is_object();
20613 }
20614
20615 /// @brief return whether value is null
20616 /// @sa https://json.nlohmann.me/api/basic_json/is_null/
20617 constexpr bool is_null() const noexcept
20618 {
20619 return m_data.m_type == value_t::null;
20620 }
20621
20622 /// @brief return whether value is a boolean
20623 /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/
20624 constexpr bool is_boolean() const noexcept
20625 {
20626 return m_data.m_type == value_t::boolean;
20627 }
20628
20629 /// @brief return whether value is a number
20630 /// @sa https://json.nlohmann.me/api/basic_json/is_number/
20631 constexpr bool is_number() const noexcept
20632 {
20633 return is_number_integer() || is_number_float();
20634 }
20635
20636 /// @brief return whether value is an integer number
20637 /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/
20638 constexpr bool is_number_integer() const noexcept
20639 {
20640 return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned;
20641 }
20642
20643 /// @brief return whether value is an unsigned integer number
20644 /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/
20645 constexpr bool is_number_unsigned() const noexcept
20646 {
20647 return m_data.m_type == value_t::number_unsigned;
20648 }
20649
20650 /// @brief return whether value is a floating-point number
20651 /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/
20652 constexpr bool is_number_float() const noexcept
20653 {
20654 return m_data.m_type == value_t::number_float;
20655 }
20656
20657 /// @brief return whether value is an object
20658 /// @sa https://json.nlohmann.me/api/basic_json/is_object/
20659 constexpr bool is_object() const noexcept
20660 {
20661 return m_data.m_type == value_t::object;
20662 }
20663
20664 /// @brief return whether value is an array
20665 /// @sa https://json.nlohmann.me/api/basic_json/is_array/
20666 constexpr bool is_array() const noexcept
20667 {
20668 return m_data.m_type == value_t::array;
20669 }
20670
20671 /// @brief return whether value is a string
20672 /// @sa https://json.nlohmann.me/api/basic_json/is_string/
20673 constexpr bool is_string() const noexcept
20674 {
20675 return m_data.m_type == value_t::string;
20676 }
20677
20678 /// @brief return whether value is a binary array
20679 /// @sa https://json.nlohmann.me/api/basic_json/is_binary/
20680 constexpr bool is_binary() const noexcept
20681 {
20682 return m_data.m_type == value_t::binary;
20683 }
20684
20685 /// @brief return whether value is discarded
20686 /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/
20687 constexpr bool is_discarded() const noexcept
20688 {
20689 return m_data.m_type == value_t::discarded;
20690 }
20691
20692 /// @brief return the type of the JSON value (implicit)
20693 /// @sa https://json.nlohmann.me/api/basic_json/operator_value_t/
20694 constexpr operator value_t() const noexcept
20695 {
20696 return m_data.m_type;
20697 }
20698
20699 /// @}
20700
20701 private:
20702 //////////////////
20703 // value access //
20704 //////////////////
20705
20706 /// get a boolean (explicit)
20707 boolean_t get_impl(boolean_t* /*unused*/) const
20708 {
20709 if (JSON_HEDLEY_LIKELY(is_boolean()))
20710 {
20711 return m_data.m_value.boolean;
20712 }
20713
20714 JSON_THROW(type_error::create(302, detail::concat("type must be boolean, but is ", type_name()), this));
20715 }
20716
20717 /// get a pointer to the value (object)
20718 object_t* get_impl_ptr(object_t* /*unused*/) noexcept
20719 {
20720 return is_object() ? m_data.m_value.object : nullptr;
20721 }
20722
20723 /// get a pointer to the value (object)
20724 constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
20725 {
20726 return is_object() ? m_data.m_value.object : nullptr;
20727 }
20728
20729 /// get a pointer to the value (array)
20730 array_t* get_impl_ptr(array_t* /*unused*/) noexcept
20731 {
20732 return is_array() ? m_data.m_value.array : nullptr;
20733 }
20734
20735 /// get a pointer to the value (array)
20736 constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
20737 {
20738 return is_array() ? m_data.m_value.array : nullptr;
20739 }
20740
20741 /// get a pointer to the value (string)
20742 string_t* get_impl_ptr(string_t* /*unused*/) noexcept
20743 {
20744 return is_string() ? m_data.m_value.string : nullptr;
20745 }
20746
20747 /// get a pointer to the value (string)
20748 constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
20749 {
20750 return is_string() ? m_data.m_value.string : nullptr;
20751 }
20752
20753 /// get a pointer to the value (boolean)
20754 boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
20755 {
20756 return is_boolean() ? &m_data.m_value.boolean : nullptr;
20757 }
20758
20759 /// get a pointer to the value (boolean)
20760 constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
20761 {
20762 return is_boolean() ? &m_data.m_value.boolean : nullptr;
20763 }
20764
20765 /// get a pointer to the value (integer number)
20766 number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
20767 {
20768 return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
20769 }
20770
20771 /// get a pointer to the value (integer number)
20772 constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
20773 {
20774 return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
20775 }
20776
20777 /// get a pointer to the value (unsigned number)
20778 number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
20779 {
20780 return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
20781 }
20782
20783 /// get a pointer to the value (unsigned number)
20784 constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
20785 {
20786 return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
20787 }
20788
20789 /// get a pointer to the value (floating-point number)
20790 number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
20791 {
20792 return is_number_float() ? &m_data.m_value.number_float : nullptr;
20793 }
20794
20795 /// get a pointer to the value (floating-point number)
20796 constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
20797 {
20798 return is_number_float() ? &m_data.m_value.number_float : nullptr;
20799 }
20800
20801 /// get a pointer to the value (binary)
20802 binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept
20803 {
20804 return is_binary() ? m_data.m_value.binary : nullptr;
20805 }
20806
20807 /// get a pointer to the value (binary)
20808 constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept
20809 {
20810 return is_binary() ? m_data.m_value.binary : nullptr;
20811 }
20812
20813 /*!
20814 @brief helper function to implement get_ref()
20815
20816 This function helps to implement get_ref() without code duplication for
20817 const and non-const overloads
20818
20819 @tparam ThisType will be deduced as `basic_json` or `const basic_json`
20820
20821 @throw type_error.303 if ReferenceType does not match underlying value
20822 type of the current JSON
20823 */
20824 template<typename ReferenceType, typename ThisType>
20825 static ReferenceType get_ref_impl(ThisType& obj)
20826 {
20827 // delegate the call to get_ptr<>()
20828 auto* ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();
20829
20830 if (JSON_HEDLEY_LIKELY(ptr != nullptr))
20831 {
20832 return *ptr;
20833 }
20834
20835 JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj));
20836 }
20837
20838 public:
20839 /// @name value access
20840 /// Direct access to the stored value of a JSON value.
20841 /// @{
20842
20843 /// @brief get a pointer value (implicit)
20844 /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/
20845 template<typename PointerType, typename std::enable_if<
20846 std::is_pointer<PointerType>::value, int>::type = 0>
20847 auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
20848 {
20849 // delegate the call to get_impl_ptr<>()
20850 return get_impl_ptr(static_cast<PointerType>(nullptr));
20851 }
20852
20853 /// @brief get a pointer value (implicit)
20854 /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/
20855 template < typename PointerType, typename std::enable_if <
20856 std::is_pointer<PointerType>::value&&
20857 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 >
20858 constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
20859 {
20860 // delegate the call to get_impl_ptr<>() const
20861 return get_impl_ptr(static_cast<PointerType>(nullptr));
20862 }
20863
20864 private:
8832 /*! 20865 /*!
8833 @brief a template for a reverse iterator class 20866 @brief get a value (explicit)
20867
20868 Explicit type conversion between the JSON value and a compatible value
20869 which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
20870 and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
20871 The value is converted by calling the @ref json_serializer<ValueType>
20872 `from_json()` method.
20873
20874 The function is equivalent to executing
20875 @code {.cpp}
20876 ValueType ret;
20877 JSONSerializer<ValueType>::from_json(*this, ret);
20878 return ret;
20879 @endcode
8834 20880
8835 @tparam Base the base iterator type to reverse. Valid types are @ref 20881 This overloads is chosen if:
8836 iterator (to create @ref reverse_iterator) and @ref const_iterator (to 20882 - @a ValueType is not @ref basic_json,
8837 create @ref const_reverse_iterator). 20883 - @ref json_serializer<ValueType> has a `from_json()` method of the form
20884 `void from_json(const basic_json&, ValueType&)`, and
20885 - @ref json_serializer<ValueType> does not have a `from_json()` method of
20886 the form `ValueType from_json(const basic_json&)`
8838 20887
8839 @requirement The class satisfies the following concept requirements: 20888 @tparam ValueType the returned value type
8840 - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): 20889
8841 The iterator that can be moved to point (forward and backward) to any 20890 @return copy of the JSON value, converted to @a ValueType
8842 element in constant time. 20891
8843 - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): 20892 @throw what @ref json_serializer<ValueType> `from_json()` method throws
8844 It is possible to write to the pointed-to element (only if @a Base is 20893
8845 @ref iterator). 20894 @liveexample{The example below shows several conversions from JSON values
20895 to other types. There a few things to note: (1) Floating-point numbers can
20896 be converted to integers\, (2) A JSON array can be converted to a standard
20897 `std::vector<short>`\, (3) A JSON object can be converted to C++
20898 associative containers such as `std::unordered_map<std::string\,
20899 json>`.,get__ValueType_const}
20900
20901 @since version 2.1.0
20902 */
20903 template < typename ValueType,
20904 detail::enable_if_t <
20905 detail::is_default_constructible<ValueType>::value&&
20906 detail::has_from_json<basic_json_t, ValueType>::value,
20907 int > = 0 >
20908 ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept(
20909 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))
20910 {
20911 auto ret = ValueType();
20912 JSONSerializer<ValueType>::from_json(*this, ret);
20913 return ret;
20914 }
20915
20916 /*!
20917 @brief get a value (explicit); special case
20918
20919 Explicit type conversion between the JSON value and a compatible value
20920 which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
20921 and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
20922 The value is converted by calling the @ref json_serializer<ValueType>
20923 `from_json()` method.
20924
20925 The function is equivalent to executing
20926 @code {.cpp}
20927 return JSONSerializer<ValueType>::from_json(*this);
20928 @endcode
20929
20930 This overloads is chosen if:
20931 - @a ValueType is not @ref basic_json and
20932 - @ref json_serializer<ValueType> has a `from_json()` method of the form
20933 `ValueType from_json(const basic_json&)`
20934
20935 @note If @ref json_serializer<ValueType> has both overloads of
20936 `from_json()`, this one is chosen.
20937
20938 @tparam ValueType the returned value type
20939
20940 @return copy of the JSON value, converted to @a ValueType
20941
20942 @throw what @ref json_serializer<ValueType> `from_json()` method throws
20943
20944 @since version 2.1.0
20945 */
20946 template < typename ValueType,
20947 detail::enable_if_t <
20948 detail::has_non_default_from_json<basic_json_t, ValueType>::value,
20949 int > = 0 >
20950 ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept(
20951 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>())))
20952 {
20953 return JSONSerializer<ValueType>::from_json(*this);
20954 }
20955
20956 /*!
20957 @brief get special-case overload
20958
20959 This overloads converts the current @ref basic_json in a different
20960 @ref basic_json type
20961
20962 @tparam BasicJsonType == @ref basic_json
20963
20964 @return a copy of *this, converted into @a BasicJsonType
20965
20966 @complexity Depending on the implementation of the called `from_json()`
20967 method.
20968
20969 @since version 3.2.0
20970 */
20971 template < typename BasicJsonType,
20972 detail::enable_if_t <
20973 detail::is_basic_json<BasicJsonType>::value,
20974 int > = 0 >
20975 BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
20976 {
20977 return *this;
20978 }
20979
20980 /*!
20981 @brief get special-case overload
20982
20983 This overloads avoids a lot of template boilerplate, it can be seen as the
20984 identity method
20985
20986 @tparam BasicJsonType == @ref basic_json
20987
20988 @return a copy of *this
20989
20990 @complexity Constant.
20991
20992 @since version 2.1.0
20993 */
20994 template<typename BasicJsonType,
20995 detail::enable_if_t<
20996 std::is_same<BasicJsonType, basic_json_t>::value,
20997 int> = 0>
20998 basic_json get_impl(detail::priority_tag<3> /*unused*/) const
20999 {
21000 return *this;
21001 }
21002
21003 /*!
21004 @brief get a pointer value (explicit)
21005 @copydoc get()
21006 */
21007 template<typename PointerType,
21008 detail::enable_if_t<
21009 std::is_pointer<PointerType>::value,
21010 int> = 0>
21011 constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept
21012 -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())
21013 {
21014 // delegate the call to get_ptr
21015 return get_ptr<PointerType>();
21016 }
21017
21018 public:
21019 /*!
21020 @brief get a (pointer) value (explicit)
21021
21022 Performs explicit type conversion between the JSON value and a compatible value if required.
21023
21024 - If the requested type is a pointer to the internally stored JSON value that pointer is returned.
21025 No copies are made.
21026
21027 - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible
21028 from the current @ref basic_json.
21029
21030 - Otherwise the value is converted by calling the @ref json_serializer<ValueType> `from_json()`
21031 method.
21032
21033 @tparam ValueTypeCV the provided value type
21034 @tparam ValueType the returned value type
21035
21036 @return copy of the JSON value, converted to @tparam ValueType if necessary
21037
21038 @throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required
21039
21040 @since version 2.1.0
21041 */
21042 template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>
21043#if defined(JSON_HAS_CPP_14)
21044 constexpr
21045#endif
21046 auto get() const noexcept(
21047 noexcept(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {})))
21048 -> decltype(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {}))
21049 {
21050 // we cannot static_assert on ValueTypeCV being non-const, because
21051 // there is support for get<const basic_json_t>(), which is why we
21052 // still need the uncvref
21053 static_assert(!std::is_reference<ValueTypeCV>::value,
21054 "get() cannot be used with reference types, you might want to use get_ref()");
21055 return get_impl<ValueType>(detail::priority_tag<4> {});
21056 }
21057
21058 /*!
21059 @brief get a pointer value (explicit)
21060
21061 Explicit pointer access to the internally stored JSON value. No copies are
21062 made.
21063
21064 @warning The pointer becomes invalid if the underlying JSON object
21065 changes.
21066
21067 @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
21068 object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
21069 @ref number_unsigned_t, or @ref number_float_t.
21070
21071 @return pointer to the internally stored JSON value if the requested
21072 pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
21073
21074 @complexity Constant.
21075
21076 @liveexample{The example below shows how pointers to internal values of a
21077 JSON value can be requested. Note that no type conversions are made and a
21078 `nullptr` is returned if the value and the requested pointer type does not
21079 match.,get__PointerType}
21080
21081 @sa see @ref get_ptr() for explicit pointer-member access
21082
21083 @since version 1.0.0
21084 */
21085 template<typename PointerType, typename std::enable_if<
21086 std::is_pointer<PointerType>::value, int>::type = 0>
21087 auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())
21088 {
21089 // delegate the call to get_ptr
21090 return get_ptr<PointerType>();
21091 }
21092
21093 /// @brief get a value (explicit)
21094 /// @sa https://json.nlohmann.me/api/basic_json/get_to/
21095 template < typename ValueType,
21096 detail::enable_if_t <
21097 !detail::is_basic_json<ValueType>::value&&
21098 detail::has_from_json<basic_json_t, ValueType>::value,
21099 int > = 0 >
21100 ValueType & get_to(ValueType& v) const noexcept(noexcept(
21101 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))
21102 {
21103 JSONSerializer<ValueType>::from_json(*this, v);
21104 return v;
21105 }
21106
21107 // specialization to allow calling get_to with a basic_json value
21108 // see https://github.com/nlohmann/json/issues/2175
21109 template<typename ValueType,
21110 detail::enable_if_t <
21111 detail::is_basic_json<ValueType>::value,
21112 int> = 0>
21113 ValueType & get_to(ValueType& v) const
21114 {
21115 v = *this;
21116 return v;
21117 }
21118
21119 template <
21120 typename T, std::size_t N,
21121 typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
21122 detail::enable_if_t <
21123 detail::has_from_json<basic_json_t, Array>::value, int > = 0 >
21124 Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
21125 noexcept(noexcept(JSONSerializer<Array>::from_json(
21126 std::declval<const basic_json_t&>(), v)))
21127 {
21128 JSONSerializer<Array>::from_json(*this, v);
21129 return v;
21130 }
21131
21132 /// @brief get a reference value (implicit)
21133 /// @sa https://json.nlohmann.me/api/basic_json/get_ref/
21134 template<typename ReferenceType, typename std::enable_if<
21135 std::is_reference<ReferenceType>::value, int>::type = 0>
21136 ReferenceType get_ref()
21137 {
21138 // delegate call to get_ref_impl
21139 return get_ref_impl<ReferenceType>(*this);
21140 }
21141
21142 /// @brief get a reference value (implicit)
21143 /// @sa https://json.nlohmann.me/api/basic_json/get_ref/
21144 template < typename ReferenceType, typename std::enable_if <
21145 std::is_reference<ReferenceType>::value&&
21146 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 >
21147 ReferenceType get_ref() const
21148 {
21149 // delegate call to get_ref_impl
21150 return get_ref_impl<ReferenceType>(*this);
21151 }
21152
21153 /*!
21154 @brief get a value (implicit)
21155
21156 Implicit type conversion between the JSON value and a compatible value.
21157 The call is realized by calling @ref get() const.
21158
21159 @tparam ValueType non-pointer type compatible to the JSON value, for
21160 instance `int` for JSON integer numbers, `bool` for JSON booleans, or
21161 `std::vector` types for JSON arrays. The character type of @ref string_t
21162 as well as an initializer list of this type is excluded to avoid
21163 ambiguities as these types implicitly convert to `std::string`.
21164
21165 @return copy of the JSON value, converted to type @a ValueType
21166
21167 @throw type_error.302 in case passed type @a ValueType is incompatible
21168 to the JSON value type (e.g., the JSON value is of type boolean, but a
21169 string is requested); see example below
21170
21171 @complexity Linear in the size of the JSON value.
21172
21173 @liveexample{The example below shows several conversions from JSON values
21174 to other types. There a few things to note: (1) Floating-point numbers can
21175 be converted to integers\, (2) A JSON array can be converted to a standard
21176 `std::vector<short>`\, (3) A JSON object can be converted to C++
21177 associative containers such as `std::unordered_map<std::string\,
21178 json>`.,operator__ValueType}
8846 21179
8847 @since version 1.0.0 21180 @since version 1.0.0
8848 */ 21181 */
8849 template<typename Base> 21182 template < typename ValueType, typename std::enable_if <
8850 class json_reverse_iterator : public std::reverse_iterator<Base> 21183 detail::conjunction <
21184 detail::negation<std::is_pointer<ValueType>>,
21185 detail::negation<std::is_same<ValueType, std::nullptr_t>>,
21186 detail::negation<std::is_same<ValueType, detail::json_ref<basic_json>>>,
21187 detail::negation<std::is_same<ValueType, typename string_t::value_type>>,
21188 detail::negation<detail::is_basic_json<ValueType>>,
21189 detail::negation<std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>>,
21190#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))
21191 detail::negation<std::is_same<ValueType, std::string_view>>,
21192#endif
21193#if defined(JSON_HAS_CPP_17) && JSON_HAS_STATIC_RTTI
21194 detail::negation<std::is_same<ValueType, std::any>>,
21195#endif
21196 detail::is_detected_lazy<detail::get_template_function, const basic_json_t&, ValueType>
21197 >::value, int >::type = 0 >
21198 JSON_EXPLICIT operator ValueType() const
21199 {
21200 // delegate the call to get<>() const
21201 return get<ValueType>();
21202 }
21203
21204 /// @brief get a binary value
21205 /// @sa https://json.nlohmann.me/api/basic_json/get_binary/
21206 binary_t& get_binary()
21207 {
21208 if (!is_binary())
21209 {
21210 JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
21211 }
21212
21213 return *get_ptr<binary_t*>();
21214 }
21215
21216 /// @brief get a binary value
21217 /// @sa https://json.nlohmann.me/api/basic_json/get_binary/
21218 const binary_t& get_binary() const
8851 { 21219 {
8852 public: 21220 if (!is_binary())
8853 /// shortcut to the reverse iterator adaptor 21221 {
8854 using base_iterator = std::reverse_iterator<Base>; 21222 JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
8855 /// the reference type for the pointed-to element 21223 }
8856 using reference = typename Base::reference; 21224
21225 return *get_ptr<const binary_t*>();
21226 }
21227
21228 /// @}
8857 21229
8858 /// create reverse iterator from iterator 21230 ////////////////////
8859 json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept 21231 // element access //
8860 : base_iterator(it) 21232 ////////////////////
8861 {}
8862 21233
8863 /// create reverse iterator from base class 21234 /// @name element access
8864 json_reverse_iterator(const base_iterator& it) noexcept 21235 /// Access to the JSON value.
8865 : base_iterator(it) 21236 /// @{
8866 {}
8867 21237
8868 /// post-increment (it++) 21238 /// @brief access specified array element with bounds checking
8869 json_reverse_iterator operator++(int) 21239 /// @sa https://json.nlohmann.me/api/basic_json/at/
21240 reference at(size_type idx)
21241 {
21242 // at only works for arrays
21243 if (JSON_HEDLEY_LIKELY(is_array()))
21244 {
21245 JSON_TRY
21246 {
21247 return set_parent(m_data.m_value.array->at(idx));
21248 }
21249 JSON_CATCH (std::out_of_range&)
21250 {
21251 // create better exception explanation
21252 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
21253 }
21254 }
21255 else
8870 { 21256 {
8871 return base_iterator::operator++(1); 21257 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
8872 } 21258 }
21259 }
8873 21260
8874 /// pre-increment (++it) 21261 /// @brief access specified array element with bounds checking
8875 json_reverse_iterator& operator++() 21262 /// @sa https://json.nlohmann.me/api/basic_json/at/
21263 const_reference at(size_type idx) const
21264 {
21265 // at only works for arrays
21266 if (JSON_HEDLEY_LIKELY(is_array()))
8876 { 21267 {
8877 base_iterator::operator++(); 21268 JSON_TRY
8878 return *this; 21269 {
21270 return m_data.m_value.array->at(idx);
21271 }
21272 JSON_CATCH (std::out_of_range&)
21273 {
21274 // create better exception explanation
21275 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
21276 }
21277 }
21278 else
21279 {
21280 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
8879 } 21281 }
21282 }
8880 21283
8881 /// post-decrement (it--) 21284 /// @brief access specified object element with bounds checking
8882 json_reverse_iterator operator--(int) 21285 /// @sa https://json.nlohmann.me/api/basic_json/at/
21286 reference at(const typename object_t::key_type& key)
21287 {
21288 // at only works for objects
21289 if (JSON_HEDLEY_UNLIKELY(!is_object()))
8883 { 21290 {
8884 return base_iterator::operator--(1); 21291 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
8885 } 21292 }
8886 21293
8887 /// pre-decrement (--it) 21294 auto it = m_data.m_value.object->find(key);
8888 json_reverse_iterator& operator--() 21295 if (it == m_data.m_value.object->end())
8889 { 21296 {
8890 base_iterator::operator--(); 21297 JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
8891 return *this;
8892 } 21298 }
21299 return set_parent(it->second);
21300 }
8893 21301
8894 /// add to iterator 21302 /// @brief access specified object element with bounds checking
8895 json_reverse_iterator& operator+=(difference_type i) 21303 /// @sa https://json.nlohmann.me/api/basic_json/at/
21304 template<class KeyType, detail::enable_if_t<
21305 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
21306 reference at(KeyType && key)
21307 {
21308 // at only works for objects
21309 if (JSON_HEDLEY_UNLIKELY(!is_object()))
8896 { 21310 {
8897 base_iterator::operator+=(i); 21311 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
8898 return *this;
8899 } 21312 }
8900 21313
8901 /// add to iterator 21314 auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
8902 json_reverse_iterator operator+(difference_type i) const 21315 if (it == m_data.m_value.object->end())
8903 { 21316 {
8904 auto result = *this; 21317 JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
8905 result += i;
8906 return result;
8907 } 21318 }
21319 return set_parent(it->second);
21320 }
8908 21321
8909 /// subtract from iterator 21322 /// @brief access specified object element with bounds checking
8910 json_reverse_iterator operator-(difference_type i) const 21323 /// @sa https://json.nlohmann.me/api/basic_json/at/
21324 const_reference at(const typename object_t::key_type& key) const
21325 {
21326 // at only works for objects
21327 if (JSON_HEDLEY_UNLIKELY(!is_object()))
8911 { 21328 {
8912 auto result = *this; 21329 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
8913 result -= i;
8914 return result;
8915 } 21330 }
8916 21331
8917 /// return difference 21332 auto it = m_data.m_value.object->find(key);
8918 difference_type operator-(const json_reverse_iterator& other) const 21333 if (it == m_data.m_value.object->end())
8919 { 21334 {
8920 return this->base() - other.base(); 21335 JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
8921 } 21336 }
21337 return it->second;
21338 }
8922 21339
8923 /// access to successor 21340 /// @brief access specified object element with bounds checking
8924 reference operator[](difference_type n) const 21341 /// @sa https://json.nlohmann.me/api/basic_json/at/
21342 template<class KeyType, detail::enable_if_t<
21343 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
21344 const_reference at(KeyType && key) const
21345 {
21346 // at only works for objects
21347 if (JSON_HEDLEY_UNLIKELY(!is_object()))
8925 { 21348 {
8926 return *(this->operator+(n)); 21349 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
8927 } 21350 }
8928 21351
8929 /// return the key of an object iterator 21352 auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
8930 typename object_t::key_type key() const 21353 if (it == m_data.m_value.object->end())
8931 { 21354 {
8932 auto it = --this->base(); 21355 JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
8933 return it.key();
8934 } 21356 }
21357 return it->second;
21358 }
8935 21359
8936 /// return the value of an iterator 21360 /// @brief access specified array element
8937 reference value() const 21361 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
21362 reference operator[](size_type idx)
21363 {
21364 // implicitly convert null value to an empty array
21365 if (is_null())
8938 { 21366 {
8939 auto it = --this->base(); 21367 m_data.m_type = value_t::array;
8940 return it.operator * (); 21368 m_data.m_value.array = create<array_t>();
21369 assert_invariant();
8941 } 21370 }
8942 };
8943 21371
21372 // operator[] only works for arrays
21373 if (JSON_HEDLEY_LIKELY(is_array()))
21374 {
21375 // fill up array with null values if given idx is outside range
21376 if (idx >= m_data.m_value.array->size())
21377 {
21378#if JSON_DIAGNOSTICS
21379 // remember array size & capacity before resizing
21380 const auto old_size = m_data.m_value.array->size();
21381 const auto old_capacity = m_data.m_value.array->capacity();
21382#endif
21383 m_data.m_value.array->resize(idx + 1);
8944 21384
8945 private: 21385#if JSON_DIAGNOSTICS
8946 ////////////////////// 21386 if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))
8947 // lexer and parser // 21387 {
8948 ////////////////////// 21388 // capacity has changed: update all parents
21389 set_parents();
21390 }
21391 else
21392 {
21393 // set parent for values added above
21394 set_parents(begin() + static_cast<typename iterator::difference_type>(old_size), static_cast<typename iterator::difference_type>(idx + 1 - old_size));
21395 }
21396#endif
21397 assert_invariant();
21398 }
8949 21399
8950 /*! 21400 return m_data.m_value.array->operator[](idx);
8951 @brief lexical analysis 21401 }
8952
8953 This class organizes the lexical analysis during JSON deserialization. The
8954 core of it is a scanner generated by [re2c](http://re2c.org) that
8955 processes a buffer and recognizes tokens according to RFC 7159.
8956 */
8957 class lexer
8958 {
8959 public:
8960 /// token types for the parser
8961 enum class token_type
8962 {
8963 uninitialized, ///< indicating the scanner is uninitialized
8964 literal_true, ///< the `true` literal
8965 literal_false, ///< the `false` literal
8966 literal_null, ///< the `null` literal
8967 value_string, ///< a string -- use get_string() for actual value
8968 value_number, ///< a number -- use get_number() for actual value
8969 begin_array, ///< the character for array begin `[`
8970 begin_object, ///< the character for object begin `{`
8971 end_array, ///< the character for array end `]`
8972 end_object, ///< the character for object end `}`
8973 name_separator, ///< the name separator `:`
8974 value_separator, ///< the value separator `,`
8975 parse_error, ///< indicating a parse error
8976 end_of_input ///< indicating the end of the input buffer
8977 };
8978 21402
8979 /// the char type to use in the lexer 21403 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
8980 using lexer_char_t = unsigned char; 21404 }
8981 21405
8982 /// a lexer from a buffer with given length 21406 /// @brief access specified array element
8983 lexer(const lexer_char_t* buff, const size_t len) noexcept 21407 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
8984 : m_content(buff) 21408 const_reference operator[](size_type idx) const
21409 {
21410 // const operator[] only works for arrays
21411 if (JSON_HEDLEY_LIKELY(is_array()))
8985 { 21412 {
8986 assert(m_content != nullptr); 21413 return m_data.m_value.array->operator[](idx);
8987 m_start = m_cursor = m_content;
8988 m_limit = m_content + len;
8989 } 21414 }
8990 21415
8991 /// a lexer from an input stream 21416 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
8992 explicit lexer(std::istream& s) 21417 }
8993 : m_stream(&s), m_line_buffer()
8994 {
8995 // immediately abort if stream is erroneous
8996 if (s.fail())
8997 {
8998 throw std::invalid_argument("stream error: " + std::string(strerror(errno)));
8999 }
9000 21418
9001 // fill buffer 21419 /// @brief access specified object element
9002 fill_line_buffer(); 21420 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
21421 reference operator[](typename object_t::key_type key)
21422 {
21423 // implicitly convert null value to an empty object
21424 if (is_null())
21425 {
21426 m_data.m_type = value_t::object;
21427 m_data.m_value.object = create<object_t>();
21428 assert_invariant();
21429 }
9003 21430
9004 // skip UTF-8 byte-order mark 21431 // operator[] only works for objects
9005 if (m_line_buffer.size() >= 3 and m_line_buffer.substr(0, 3) == "\xEF\xBB\xBF") 21432 if (JSON_HEDLEY_LIKELY(is_object()))
9006 { 21433 {
9007 m_line_buffer[0] = ' '; 21434 auto result = m_data.m_value.object->emplace(std::move(key), nullptr);
9008 m_line_buffer[1] = ' '; 21435 return set_parent(result.first->second);
9009 m_line_buffer[2] = ' ';
9010 }
9011 } 21436 }
9012 21437
9013 // switch off unwanted functions (due to pointer members) 21438 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
9014 lexer() = delete; 21439 }
9015 lexer(const lexer&) = delete; 21440
9016 lexer operator=(const lexer&) = delete; 21441 /// @brief access specified object element
21442 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
21443 const_reference operator[](const typename object_t::key_type& key) const
21444 {
21445 // const operator[] only works for objects
21446 if (JSON_HEDLEY_LIKELY(is_object()))
21447 {
21448 auto it = m_data.m_value.object->find(key);
21449 JSON_ASSERT(it != m_data.m_value.object->end());
21450 return it->second;
21451 }
9017 21452
9018 /*! 21453 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
9019 @brief create a string from one or two Unicode code points 21454 }
9020 21455
9021 There are two cases: (1) @a codepoint1 is in the Basic Multilingual 21456 // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
9022 Plane (U+0000 through U+FFFF) and @a codepoint2 is 0, or (2) 21457 // (they seemingly cannot be constrained to resolve the ambiguity)
9023 @a codepoint1 and @a codepoint2 are a UTF-16 surrogate pair to 21458 template<typename T>
9024 represent a code point above U+FFFF. 21459 reference operator[](T* key)
21460 {
21461 return operator[](typename object_t::key_type(key));
21462 }
9025 21463
9026 @param[in] codepoint1 the code point (can be high surrogate) 21464 template<typename T>
9027 @param[in] codepoint2 the code point (can be low surrogate or 0) 21465 const_reference operator[](T* key) const
21466 {
21467 return operator[](typename object_t::key_type(key));
21468 }
9028 21469
9029 @return string representation of the code point; the length of the 21470 /// @brief access specified object element
9030 result string is between 1 and 4 characters. 21471 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
21472 template<class KeyType, detail::enable_if_t<
21473 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
21474 reference operator[](KeyType && key)
21475 {
21476 // implicitly convert null value to an empty object
21477 if (is_null())
21478 {
21479 m_data.m_type = value_t::object;
21480 m_data.m_value.object = create<object_t>();
21481 assert_invariant();
21482 }
9031 21483
9032 @throw std::out_of_range if code point is > 0x10ffff; example: `"code 21484 // operator[] only works for objects
9033 points above 0x10FFFF are invalid"` 21485 if (JSON_HEDLEY_LIKELY(is_object()))
9034 @throw std::invalid_argument if the low surrogate is invalid; example: 21486 {
9035 `""missing or wrong low surrogate""` 21487 auto result = m_data.m_value.object->emplace(std::forward<KeyType>(key), nullptr);
21488 return set_parent(result.first->second);
21489 }
9036 21490
9037 @complexity Constant. 21491 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
21492 }
9038 21493
9039 @see <http://en.wikipedia.org/wiki/UTF-8#Sample_code> 21494 /// @brief access specified object element
9040 */ 21495 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
9041 static string_t to_unicode(const std::size_t codepoint1, 21496 template<class KeyType, detail::enable_if_t<
9042 const std::size_t codepoint2 = 0) 21497 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
21498 const_reference operator[](KeyType && key) const
21499 {
21500 // const operator[] only works for objects
21501 if (JSON_HEDLEY_LIKELY(is_object()))
9043 { 21502 {
9044 // calculate the code point from the given code points 21503 auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
9045 std::size_t codepoint = codepoint1; 21504 JSON_ASSERT(it != m_data.m_value.object->end());
21505 return it->second;
21506 }
21507
21508 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
21509 }
21510
21511 private:
21512 template<typename KeyType>
21513 using is_comparable_with_object_key = detail::is_comparable <
21514 object_comparator_t, const typename object_t::key_type&, KeyType >;
9046 21515
9047 // check if codepoint1 is a high surrogate 21516 template<typename ValueType>
9048 if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF) 21517 using value_return_type = std::conditional <
21518 detail::is_c_string_uncvref<ValueType>::value,
21519 string_t, typename std::decay<ValueType>::type >;
21520
21521 public:
21522 /// @brief access specified object element with default value
21523 /// @sa https://json.nlohmann.me/api/basic_json/value/
21524 template < class ValueType, detail::enable_if_t <
21525 !detail::is_transparent<object_comparator_t>::value
21526 && detail::is_getable<basic_json_t, ValueType>::value
21527 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21528 ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
21529 {
21530 // value only works for objects
21531 if (JSON_HEDLEY_LIKELY(is_object()))
21532 {
21533 // if key is found, return value and given default value otherwise
21534 const auto it = find(key);
21535 if (it != end())
9049 { 21536 {
9050 // check if codepoint2 is a low surrogate 21537 return it->template get<ValueType>();
9051 if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF)
9052 {
9053 codepoint =
9054 // high surrogate occupies the most significant 22 bits
9055 (codepoint1 << 10)
9056 // low surrogate occupies the least significant 15 bits
9057 + codepoint2
9058 // there is still the 0xD800, 0xDC00 and 0x10000 noise
9059 // in the result so we have to subtract with:
9060 // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
9061 - 0x35FDC00;
9062 }
9063 else
9064 {
9065 throw std::invalid_argument("missing or wrong low surrogate");
9066 }
9067 } 21538 }
9068 21539
9069 string_t result; 21540 return default_value;
21541 }
21542
21543 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
21544 }
9070 21545
9071 if (codepoint < 0x80) 21546 /// @brief access specified object element with default value
21547 /// @sa https://json.nlohmann.me/api/basic_json/value/
21548 template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
21549 detail::enable_if_t <
21550 !detail::is_transparent<object_comparator_t>::value
21551 && detail::is_getable<basic_json_t, ReturnType>::value
21552 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21553 ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const
21554 {
21555 // value only works for objects
21556 if (JSON_HEDLEY_LIKELY(is_object()))
21557 {
21558 // if key is found, return value and given default value otherwise
21559 const auto it = find(key);
21560 if (it != end())
9072 { 21561 {
9073 // 1-byte characters: 0xxxxxxx (ASCII) 21562 return it->template get<ReturnType>();
9074 result.append(1, static_cast<typename string_t::value_type>(codepoint));
9075 } 21563 }
9076 else if (codepoint <= 0x7ff) 21564
21565 return std::forward<ValueType>(default_value);
21566 }
21567
21568 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
21569 }
21570
21571 /// @brief access specified object element with default value
21572 /// @sa https://json.nlohmann.me/api/basic_json/value/
21573 template < class ValueType, class KeyType, detail::enable_if_t <
21574 detail::is_transparent<object_comparator_t>::value
21575 && !detail::is_json_pointer<KeyType>::value
21576 && is_comparable_with_object_key<KeyType>::value
21577 && detail::is_getable<basic_json_t, ValueType>::value
21578 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21579 ValueType value(KeyType && key, const ValueType& default_value) const
21580 {
21581 // value only works for objects
21582 if (JSON_HEDLEY_LIKELY(is_object()))
21583 {
21584 // if key is found, return value and given default value otherwise
21585 const auto it = find(std::forward<KeyType>(key));
21586 if (it != end())
9077 { 21587 {
9078 // 2-byte characters: 110xxxxx 10xxxxxx 21588 return it->template get<ValueType>();
9079 result.append(1, static_cast<typename string_t::value_type>(0xC0 | ((codepoint >> 6) & 0x1F)));
9080 result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
9081 } 21589 }
9082 else if (codepoint <= 0xffff) 21590
21591 return default_value;
21592 }
21593
21594 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
21595 }
21596
21597 /// @brief access specified object element via JSON Pointer with default value
21598 /// @sa https://json.nlohmann.me/api/basic_json/value/
21599 template < class ValueType, class KeyType, class ReturnType = typename value_return_type<ValueType>::type,
21600 detail::enable_if_t <
21601 detail::is_transparent<object_comparator_t>::value
21602 && !detail::is_json_pointer<KeyType>::value
21603 && is_comparable_with_object_key<KeyType>::value
21604 && detail::is_getable<basic_json_t, ReturnType>::value
21605 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21606 ReturnType value(KeyType && key, ValueType && default_value) const
21607 {
21608 // value only works for objects
21609 if (JSON_HEDLEY_LIKELY(is_object()))
21610 {
21611 // if key is found, return value and given default value otherwise
21612 const auto it = find(std::forward<KeyType>(key));
21613 if (it != end())
9083 { 21614 {
9084 // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx 21615 return it->template get<ReturnType>();
9085 result.append(1, static_cast<typename string_t::value_type>(0xE0 | ((codepoint >> 12) & 0x0F)));
9086 result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
9087 result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
9088 } 21616 }
9089 else if (codepoint <= 0x10ffff) 21617
21618 return std::forward<ValueType>(default_value);
21619 }
21620
21621 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
21622 }
21623
21624 /// @brief access specified object element via JSON Pointer with default value
21625 /// @sa https://json.nlohmann.me/api/basic_json/value/
21626 template < class ValueType, detail::enable_if_t <
21627 detail::is_getable<basic_json_t, ValueType>::value
21628 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21629 ValueType value(const json_pointer& ptr, const ValueType& default_value) const
21630 {
21631 // value only works for objects
21632 if (JSON_HEDLEY_LIKELY(is_object()))
21633 {
21634 // if pointer resolves a value, return it or use default value
21635 JSON_TRY
9090 { 21636 {
9091 // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 21637 return ptr.get_checked(this).template get<ValueType>();
9092 result.append(1, static_cast<typename string_t::value_type>(0xF0 | ((codepoint >> 18) & 0x07)));
9093 result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 12) & 0x3F)));
9094 result.append(1, static_cast<typename string_t::value_type>(0x80 | ((codepoint >> 6) & 0x3F)));
9095 result.append(1, static_cast<typename string_t::value_type>(0x80 | (codepoint & 0x3F)));
9096 } 21638 }
9097 else 21639 JSON_INTERNAL_CATCH (out_of_range&)
9098 { 21640 {
9099 throw std::out_of_range("code points above 0x10FFFF are invalid"); 21641 return default_value;
9100 } 21642 }
9101
9102 return result;
9103 } 21643 }
9104 21644
9105 /// return name of values of type token_type (only used for errors) 21645 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
9106 static std::string token_type_name(const token_type t) 21646 }
21647
21648 /// @brief access specified object element via JSON Pointer with default value
21649 /// @sa https://json.nlohmann.me/api/basic_json/value/
21650 template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
21651 detail::enable_if_t <
21652 detail::is_getable<basic_json_t, ReturnType>::value
21653 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21654 ReturnType value(const json_pointer& ptr, ValueType && default_value) const
21655 {
21656 // value only works for objects
21657 if (JSON_HEDLEY_LIKELY(is_object()))
9107 { 21658 {
9108 switch (t) 21659 // if pointer resolves a value, return it or use default value
21660 JSON_TRY
9109 { 21661 {
9110 case token_type::uninitialized: 21662 return ptr.get_checked(this).template get<ReturnType>();
9111 return "<uninitialized>"; 21663 }
9112 case token_type::literal_true: 21664 JSON_INTERNAL_CATCH (out_of_range&)
9113 return "true literal"; 21665 {
9114 case token_type::literal_false: 21666 return std::forward<ValueType>(default_value);
9115 return "false literal";
9116 case token_type::literal_null:
9117 return "null literal";
9118 case token_type::value_string:
9119 return "string literal";
9120 case token_type::value_number:
9121 return "number literal";
9122 case token_type::begin_array:
9123 return "'['";
9124 case token_type::begin_object:
9125 return "'{'";
9126 case token_type::end_array:
9127 return "']'";
9128 case token_type::end_object:
9129 return "'}'";
9130 case token_type::name_separator:
9131 return "':'";
9132 case token_type::value_separator:
9133 return "','";
9134 case token_type::parse_error:
9135 return "<parse error>";
9136 case token_type::end_of_input:
9137 return "end of input";
9138 default:
9139 {
9140 // catch non-enum values
9141 return "unknown token"; // LCOV_EXCL_LINE
9142 }
9143 } 21667 }
9144 } 21668 }
9145 21669
9146 /*! 21670 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
9147 This function implements a scanner for JSON. It is specified using 21671 }
9148 regular expressions that try to follow RFC 7159 as close as possible.
9149 These regular expressions are then translated into a minimized
9150 deterministic finite automaton (DFA) by the tool
9151 [re2c](http://re2c.org). As a result, the translated code for this
9152 function consists of a large block of code with `goto` jumps.
9153 21672
9154 @return the class of the next token read from the buffer 21673 template < class ValueType, class BasicJsonType, detail::enable_if_t <
21674 detail::is_basic_json<BasicJsonType>::value
21675 && detail::is_getable<basic_json_t, ValueType>::value
21676 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21677 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
21678 ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
21679 {
21680 return value(ptr.convert(), default_value);
21681 }
21682
21683 template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
21684 detail::enable_if_t <
21685 detail::is_basic_json<BasicJsonType>::value
21686 && detail::is_getable<basic_json_t, ReturnType>::value
21687 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21688 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
21689 ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const
21690 {
21691 return value(ptr.convert(), std::forward<ValueType>(default_value));
21692 }
21693
21694 /// @brief access the first element
21695 /// @sa https://json.nlohmann.me/api/basic_json/front/
21696 reference front()
21697 {
21698 return *begin();
21699 }
9155 21700
9156 @complexity Linear in the length of the input.\n 21701 /// @brief access the first element
21702 /// @sa https://json.nlohmann.me/api/basic_json/front/
21703 const_reference front() const
21704 {
21705 return *cbegin();
21706 }
21707
21708 /// @brief access the last element
21709 /// @sa https://json.nlohmann.me/api/basic_json/back/
21710 reference back()
21711 {
21712 auto tmp = end();
21713 --tmp;
21714 return *tmp;
21715 }
9157 21716
9158 Proposition: The loop below will always terminate for finite input.\n 21717 /// @brief access the last element
21718 /// @sa https://json.nlohmann.me/api/basic_json/back/
21719 const_reference back() const
21720 {
21721 auto tmp = cend();
21722 --tmp;
21723 return *tmp;
21724 }
9159 21725
9160 Proof (by contradiction): Assume a finite input. To loop forever, the 21726 /// @brief remove element given an iterator
9161 loop must never hit code with a `break` statement. The only code 21727 /// @sa https://json.nlohmann.me/api/basic_json/erase/
9162 snippets without a `break` statement are the continue statements for 21728 template < class IteratorType, detail::enable_if_t <
9163 whitespace and byte-order-marks. To loop forever, the input must be an 21729 std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
9164 infinite sequence of whitespace or byte-order-marks. This contradicts 21730 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
9165 the assumption of finite input, q.e.d. 21731 IteratorType erase(IteratorType pos)
9166 */ 21732 {
9167 token_type scan() 21733 // make sure iterator fits the current value
21734 if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))
9168 { 21735 {
9169 while (true) 21736 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
9170 { 21737 }
9171 // pointer for backtracking information
9172 m_marker = nullptr;
9173 21738
9174 // remember the begin of the token 21739 IteratorType result = end();
9175 m_start = m_cursor;
9176 assert(m_start != nullptr);
9177 21740
21741 switch (m_data.m_type)
21742 {
21743 case value_t::boolean:
21744 case value_t::number_float:
21745 case value_t::number_integer:
21746 case value_t::number_unsigned:
21747 case value_t::string:
21748 case value_t::binary:
21749 {
21750 if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))
21751 {
21752 JSON_THROW(invalid_iterator::create(205, "iterator out of range", this));
21753 }
9178 21754
21755 if (is_string())
9179 { 21756 {
9180 lexer_char_t yych; 21757 AllocatorType<string_t> alloc;
9181 unsigned int yyaccept = 0; 21758 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);
9182 static const unsigned char yybm[] = 21759 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);
9183 { 21760 m_data.m_value.string = nullptr;
9184 0, 0, 0, 0, 0, 0, 0, 0, 21761 }
9185 0, 32, 32, 0, 0, 32, 0, 0, 21762 else if (is_binary())
9186 0, 0, 0, 0, 0, 0, 0, 0, 21763 {
9187 0, 0, 0, 0, 0, 0, 0, 0, 21764 AllocatorType<binary_t> alloc;
9188 160, 128, 0, 128, 128, 128, 128, 128, 21765 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);
9189 128, 128, 128, 128, 128, 128, 128, 128, 21766 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);
9190 192, 192, 192, 192, 192, 192, 192, 192, 21767 m_data.m_value.binary = nullptr;
9191 192, 192, 128, 128, 128, 128, 128, 128,
9192 128, 128, 128, 128, 128, 128, 128, 128,
9193 128, 128, 128, 128, 128, 128, 128, 128,
9194 128, 128, 128, 128, 128, 128, 128, 128,
9195 128, 128, 128, 128, 0, 128, 128, 128,
9196 128, 128, 128, 128, 128, 128, 128, 128,
9197 128, 128, 128, 128, 128, 128, 128, 128,
9198 128, 128, 128, 128, 128, 128, 128, 128,
9199 128, 128, 128, 128, 128, 128, 128, 128,
9200 0, 0, 0, 0, 0, 0, 0, 0,
9201 0, 0, 0, 0, 0, 0, 0, 0,
9202 0, 0, 0, 0, 0, 0, 0, 0,
9203 0, 0, 0, 0, 0, 0, 0, 0,
9204 0, 0, 0, 0, 0, 0, 0, 0,
9205 0, 0, 0, 0, 0, 0, 0, 0,
9206 0, 0, 0, 0, 0, 0, 0, 0,
9207 0, 0, 0, 0, 0, 0, 0, 0,
9208 0, 0, 0, 0, 0, 0, 0, 0,
9209 0, 0, 0, 0, 0, 0, 0, 0,
9210 0, 0, 0, 0, 0, 0, 0, 0,
9211 0, 0, 0, 0, 0, 0, 0, 0,
9212 0, 0, 0, 0, 0, 0, 0, 0,
9213 0, 0, 0, 0, 0, 0, 0, 0,
9214 0, 0, 0, 0, 0, 0, 0, 0,
9215 0, 0, 0, 0, 0, 0, 0, 0,
9216 };
9217 if ((m_limit - m_cursor) < 5)
9218 {
9219 fill_line_buffer(5); // LCOV_EXCL_LINE
9220 }
9221 yych = *m_cursor;
9222 if (yybm[0 + yych] & 32)
9223 {
9224 goto basic_json_parser_6;
9225 }
9226 if (yych <= '[')
9227 {
9228 if (yych <= '-')
9229 {
9230 if (yych <= '"')
9231 {
9232 if (yych <= 0x00)
9233 {
9234 goto basic_json_parser_2;
9235 }
9236 if (yych <= '!')
9237 {
9238 goto basic_json_parser_4;
9239 }
9240 goto basic_json_parser_9;
9241 }
9242 else
9243 {
9244 if (yych <= '+')
9245 {
9246 goto basic_json_parser_4;
9247 }
9248 if (yych <= ',')
9249 {
9250 goto basic_json_parser_10;
9251 }
9252 goto basic_json_parser_12;
9253 }
9254 }
9255 else
9256 {
9257 if (yych <= '9')
9258 {
9259 if (yych <= '/')
9260 {
9261 goto basic_json_parser_4;
9262 }
9263 if (yych <= '0')
9264 {
9265 goto basic_json_parser_13;
9266 }
9267 goto basic_json_parser_15;
9268 }
9269 else
9270 {
9271 if (yych <= ':')
9272 {
9273 goto basic_json_parser_17;
9274 }
9275 if (yych <= 'Z')
9276 {
9277 goto basic_json_parser_4;
9278 }
9279 goto basic_json_parser_19;
9280 }
9281 }
9282 }
9283 else
9284 {
9285 if (yych <= 'n')
9286 {
9287 if (yych <= 'e')
9288 {
9289 if (yych == ']')
9290 {
9291 goto basic_json_parser_21;
9292 }
9293 goto basic_json_parser_4;
9294 }
9295 else
9296 {
9297 if (yych <= 'f')
9298 {
9299 goto basic_json_parser_23;
9300 }
9301 if (yych <= 'm')
9302 {
9303 goto basic_json_parser_4;
9304 }
9305 goto basic_json_parser_24;
9306 }
9307 }
9308 else
9309 {
9310 if (yych <= 'z')
9311 {
9312 if (yych == 't')
9313 {
9314 goto basic_json_parser_25;
9315 }
9316 goto basic_json_parser_4;
9317 }
9318 else
9319 {
9320 if (yych <= '{')
9321 {
9322 goto basic_json_parser_26;
9323 }
9324 if (yych == '}')
9325 {
9326 goto basic_json_parser_28;
9327 }
9328 goto basic_json_parser_4;
9329 }
9330 }
9331 }
9332basic_json_parser_2:
9333 ++m_cursor;
9334 {
9335 last_token_type = token_type::end_of_input;
9336 break;
9337 }
9338basic_json_parser_4:
9339 ++m_cursor;
9340basic_json_parser_5:
9341 {
9342 last_token_type = token_type::parse_error;
9343 break;
9344 }
9345basic_json_parser_6:
9346 ++m_cursor;
9347 if (m_limit <= m_cursor)
9348 {
9349 fill_line_buffer(1); // LCOV_EXCL_LINE
9350 }
9351 yych = *m_cursor;
9352 if (yybm[0 + yych] & 32)
9353 {
9354 goto basic_json_parser_6;
9355 }
9356 {
9357 continue;
9358 }
9359basic_json_parser_9:
9360 yyaccept = 0;
9361 yych = *(m_marker = ++m_cursor);
9362 if (yych <= 0x1F)
9363 {
9364 goto basic_json_parser_5;
9365 }
9366 if (yych <= 0x7F)
9367 {
9368 goto basic_json_parser_31;
9369 }
9370 if (yych <= 0xC1)
9371 {
9372 goto basic_json_parser_5;
9373 }
9374 if (yych <= 0xF4)
9375 {
9376 goto basic_json_parser_31;
9377 }
9378 goto basic_json_parser_5;
9379basic_json_parser_10:
9380 ++m_cursor;
9381 {
9382 last_token_type = token_type::value_separator;
9383 break;
9384 }
9385basic_json_parser_12:
9386 yych = *++m_cursor;
9387 if (yych <= '/')
9388 {
9389 goto basic_json_parser_5;
9390 }
9391 if (yych <= '0')
9392 {
9393 goto basic_json_parser_13;
9394 }
9395 if (yych <= '9')
9396 {
9397 goto basic_json_parser_15;
9398 }
9399 goto basic_json_parser_5;
9400basic_json_parser_13:
9401 yyaccept = 1;
9402 yych = *(m_marker = ++m_cursor);
9403 if (yych <= 'D')
9404 {
9405 if (yych == '.')
9406 {
9407 goto basic_json_parser_43;
9408 }
9409 }
9410 else
9411 {
9412 if (yych <= 'E')
9413 {
9414 goto basic_json_parser_44;
9415 }
9416 if (yych == 'e')
9417 {
9418 goto basic_json_parser_44;
9419 }
9420 }
9421basic_json_parser_14:
9422 {
9423 last_token_type = token_type::value_number;
9424 break;
9425 }
9426basic_json_parser_15:
9427 yyaccept = 1;
9428 m_marker = ++m_cursor;
9429 if ((m_limit - m_cursor) < 3)
9430 {
9431 fill_line_buffer(3); // LCOV_EXCL_LINE
9432 }
9433 yych = *m_cursor;
9434 if (yybm[0 + yych] & 64)
9435 {
9436 goto basic_json_parser_15;
9437 }
9438 if (yych <= 'D')
9439 {
9440 if (yych == '.')
9441 {
9442 goto basic_json_parser_43;
9443 }
9444 goto basic_json_parser_14;
9445 }
9446 else
9447 {
9448 if (yych <= 'E')
9449 {
9450 goto basic_json_parser_44;
9451 }
9452 if (yych == 'e')
9453 {
9454 goto basic_json_parser_44;
9455 }
9456 goto basic_json_parser_14;
9457 }
9458basic_json_parser_17:
9459 ++m_cursor;
9460 {
9461 last_token_type = token_type::name_separator;
9462 break;
9463 }
9464basic_json_parser_19:
9465 ++m_cursor;
9466 {
9467 last_token_type = token_type::begin_array;
9468 break;
9469 }
9470basic_json_parser_21:
9471 ++m_cursor;
9472 {
9473 last_token_type = token_type::end_array;
9474 break;
9475 }
9476basic_json_parser_23:
9477 yyaccept = 0;
9478 yych = *(m_marker = ++m_cursor);
9479 if (yych == 'a')
9480 {
9481 goto basic_json_parser_45;
9482 }
9483 goto basic_json_parser_5;
9484basic_json_parser_24:
9485 yyaccept = 0;
9486 yych = *(m_marker = ++m_cursor);
9487 if (yych == 'u')
9488 {
9489 goto basic_json_parser_46;
9490 }
9491 goto basic_json_parser_5;
9492basic_json_parser_25:
9493 yyaccept = 0;
9494 yych = *(m_marker = ++m_cursor);
9495 if (yych == 'r')
9496 {
9497 goto basic_json_parser_47;
9498 }
9499 goto basic_json_parser_5;
9500basic_json_parser_26:
9501 ++m_cursor;
9502 {
9503 last_token_type = token_type::begin_object;
9504 break;
9505 }
9506basic_json_parser_28:
9507 ++m_cursor;
9508 {
9509 last_token_type = token_type::end_object;
9510 break;
9511 }
9512basic_json_parser_30:
9513 ++m_cursor;
9514 if (m_limit <= m_cursor)
9515 {
9516 fill_line_buffer(1); // LCOV_EXCL_LINE
9517 }
9518 yych = *m_cursor;
9519basic_json_parser_31:
9520 if (yybm[0 + yych] & 128)
9521 {
9522 goto basic_json_parser_30;
9523 }
9524 if (yych <= 0xE0)
9525 {
9526 if (yych <= '\\')
9527 {
9528 if (yych <= 0x1F)
9529 {
9530 goto basic_json_parser_32;
9531 }
9532 if (yych <= '"')
9533 {
9534 goto basic_json_parser_33;
9535 }
9536 goto basic_json_parser_35;
9537 }
9538 else
9539 {
9540 if (yych <= 0xC1)
9541 {
9542 goto basic_json_parser_32;
9543 }
9544 if (yych <= 0xDF)
9545 {
9546 goto basic_json_parser_36;
9547 }
9548 goto basic_json_parser_37;
9549 }
9550 }
9551 else
9552 {
9553 if (yych <= 0xEF)
9554 {
9555 if (yych == 0xED)
9556 {
9557 goto basic_json_parser_39;
9558 }
9559 goto basic_json_parser_38;
9560 }
9561 else
9562 {
9563 if (yych <= 0xF0)
9564 {
9565 goto basic_json_parser_40;
9566 }
9567 if (yych <= 0xF3)
9568 {
9569 goto basic_json_parser_41;
9570 }
9571 if (yych <= 0xF4)
9572 {
9573 goto basic_json_parser_42;
9574 }
9575 }
9576 }
9577basic_json_parser_32:
9578 m_cursor = m_marker;
9579 if (yyaccept == 0)
9580 {
9581 goto basic_json_parser_5;
9582 }
9583 else
9584 {
9585 goto basic_json_parser_14;
9586 }
9587basic_json_parser_33:
9588 ++m_cursor;
9589 {
9590 last_token_type = token_type::value_string;
9591 break;
9592 }
9593basic_json_parser_35:
9594 ++m_cursor;
9595 if (m_limit <= m_cursor)
9596 {
9597 fill_line_buffer(1); // LCOV_EXCL_LINE
9598 }
9599 yych = *m_cursor;
9600 if (yych <= 'e')
9601 {
9602 if (yych <= '/')
9603 {
9604 if (yych == '"')
9605 {
9606 goto basic_json_parser_30;
9607 }
9608 if (yych <= '.')
9609 {
9610 goto basic_json_parser_32;
9611 }
9612 goto basic_json_parser_30;
9613 }
9614 else
9615 {
9616 if (yych <= '\\')
9617 {
9618 if (yych <= '[')
9619 {
9620 goto basic_json_parser_32;
9621 }
9622 goto basic_json_parser_30;
9623 }
9624 else
9625 {
9626 if (yych == 'b')
9627 {
9628 goto basic_json_parser_30;
9629 }
9630 goto basic_json_parser_32;
9631 }
9632 }
9633 }
9634 else
9635 {
9636 if (yych <= 'q')
9637 {
9638 if (yych <= 'f')
9639 {
9640 goto basic_json_parser_30;
9641 }
9642 if (yych == 'n')
9643 {
9644 goto basic_json_parser_30;
9645 }
9646 goto basic_json_parser_32;
9647 }
9648 else
9649 {
9650 if (yych <= 's')
9651 {
9652 if (yych <= 'r')
9653 {
9654 goto basic_json_parser_30;
9655 }
9656 goto basic_json_parser_32;
9657 }
9658 else
9659 {
9660 if (yych <= 't')
9661 {
9662 goto basic_json_parser_30;
9663 }
9664 if (yych <= 'u')
9665 {
9666 goto basic_json_parser_48;
9667 }
9668 goto basic_json_parser_32;
9669 }
9670 }
9671 }
9672basic_json_parser_36:
9673 ++m_cursor;
9674 if (m_limit <= m_cursor)
9675 {
9676 fill_line_buffer(1); // LCOV_EXCL_LINE
9677 }
9678 yych = *m_cursor;
9679 if (yych <= 0x7F)
9680 {
9681 goto basic_json_parser_32;
9682 }
9683 if (yych <= 0xBF)
9684 {
9685 goto basic_json_parser_30;
9686 }
9687 goto basic_json_parser_32;
9688basic_json_parser_37:
9689 ++m_cursor;
9690 if (m_limit <= m_cursor)
9691 {
9692 fill_line_buffer(1); // LCOV_EXCL_LINE
9693 }
9694 yych = *m_cursor;
9695 if (yych <= 0x9F)
9696 {
9697 goto basic_json_parser_32;
9698 }
9699 if (yych <= 0xBF)
9700 {
9701 goto basic_json_parser_36;
9702 }
9703 goto basic_json_parser_32;
9704basic_json_parser_38:
9705 ++m_cursor;
9706 if (m_limit <= m_cursor)
9707 {
9708 fill_line_buffer(1); // LCOV_EXCL_LINE
9709 }
9710 yych = *m_cursor;
9711 if (yych <= 0x7F)
9712 {
9713 goto basic_json_parser_32;
9714 }
9715 if (yych <= 0xBF)
9716 {
9717 goto basic_json_parser_36;
9718 }
9719 goto basic_json_parser_32;
9720basic_json_parser_39:
9721 ++m_cursor;
9722 if (m_limit <= m_cursor)
9723 {
9724 fill_line_buffer(1); // LCOV_EXCL_LINE
9725 }
9726 yych = *m_cursor;
9727 if (yych <= 0x7F)
9728 {
9729 goto basic_json_parser_32;
9730 }
9731 if (yych <= 0x9F)
9732 {
9733 goto basic_json_parser_36;
9734 }
9735 goto basic_json_parser_32;
9736basic_json_parser_40:
9737 ++m_cursor;
9738 if (m_limit <= m_cursor)
9739 {
9740 fill_line_buffer(1); // LCOV_EXCL_LINE
9741 }
9742 yych = *m_cursor;
9743 if (yych <= 0x8F)
9744 {
9745 goto basic_json_parser_32;
9746 }
9747 if (yych <= 0xBF)
9748 {
9749 goto basic_json_parser_38;
9750 }
9751 goto basic_json_parser_32;
9752basic_json_parser_41:
9753 ++m_cursor;
9754 if (m_limit <= m_cursor)
9755 {
9756 fill_line_buffer(1); // LCOV_EXCL_LINE
9757 }
9758 yych = *m_cursor;
9759 if (yych <= 0x7F)
9760 {
9761 goto basic_json_parser_32;
9762 }
9763 if (yych <= 0xBF)
9764 {
9765 goto basic_json_parser_38;
9766 }
9767 goto basic_json_parser_32;
9768basic_json_parser_42:
9769 ++m_cursor;
9770 if (m_limit <= m_cursor)
9771 {
9772 fill_line_buffer(1); // LCOV_EXCL_LINE
9773 }
9774 yych = *m_cursor;
9775 if (yych <= 0x7F)
9776 {
9777 goto basic_json_parser_32;
9778 }
9779 if (yych <= 0x8F)
9780 {
9781 goto basic_json_parser_38;
9782 }
9783 goto basic_json_parser_32;
9784basic_json_parser_43:
9785 yych = *++m_cursor;
9786 if (yych <= '/')
9787 {
9788 goto basic_json_parser_32;
9789 }
9790 if (yych <= '9')
9791 {
9792 goto basic_json_parser_49;
9793 }
9794 goto basic_json_parser_32;
9795basic_json_parser_44:
9796 yych = *++m_cursor;
9797 if (yych <= ',')
9798 {
9799 if (yych == '+')
9800 {
9801 goto basic_json_parser_51;
9802 }
9803 goto basic_json_parser_32;
9804 }
9805 else
9806 {
9807 if (yych <= '-')
9808 {
9809 goto basic_json_parser_51;
9810 }
9811 if (yych <= '/')
9812 {
9813 goto basic_json_parser_32;
9814 }
9815 if (yych <= '9')
9816 {
9817 goto basic_json_parser_52;
9818 }
9819 goto basic_json_parser_32;
9820 }
9821basic_json_parser_45:
9822 yych = *++m_cursor;
9823 if (yych == 'l')
9824 {
9825 goto basic_json_parser_54;
9826 }
9827 goto basic_json_parser_32;
9828basic_json_parser_46:
9829 yych = *++m_cursor;
9830 if (yych == 'l')
9831 {
9832 goto basic_json_parser_55;
9833 }
9834 goto basic_json_parser_32;
9835basic_json_parser_47:
9836 yych = *++m_cursor;
9837 if (yych == 'u')
9838 {
9839 goto basic_json_parser_56;
9840 }
9841 goto basic_json_parser_32;
9842basic_json_parser_48:
9843 ++m_cursor;
9844 if (m_limit <= m_cursor)
9845 {
9846 fill_line_buffer(1); // LCOV_EXCL_LINE
9847 }
9848 yych = *m_cursor;
9849 if (yych <= '@')
9850 {
9851 if (yych <= '/')
9852 {
9853 goto basic_json_parser_32;
9854 }
9855 if (yych <= '9')
9856 {
9857 goto basic_json_parser_57;
9858 }
9859 goto basic_json_parser_32;
9860 }
9861 else
9862 {
9863 if (yych <= 'F')
9864 {
9865 goto basic_json_parser_57;
9866 }
9867 if (yych <= '`')
9868 {
9869 goto basic_json_parser_32;
9870 }
9871 if (yych <= 'f')
9872 {
9873 goto basic_json_parser_57;
9874 }
9875 goto basic_json_parser_32;
9876 }
9877basic_json_parser_49:
9878 yyaccept = 1;
9879 m_marker = ++m_cursor;
9880 if ((m_limit - m_cursor) < 3)
9881 {
9882 fill_line_buffer(3); // LCOV_EXCL_LINE
9883 }
9884 yych = *m_cursor;
9885 if (yych <= 'D')
9886 {
9887 if (yych <= '/')
9888 {
9889 goto basic_json_parser_14;
9890 }
9891 if (yych <= '9')
9892 {
9893 goto basic_json_parser_49;
9894 }
9895 goto basic_json_parser_14;
9896 }
9897 else
9898 {
9899 if (yych <= 'E')
9900 {
9901 goto basic_json_parser_44;
9902 }
9903 if (yych == 'e')
9904 {
9905 goto basic_json_parser_44;
9906 }
9907 goto basic_json_parser_14;
9908 }
9909basic_json_parser_51:
9910 yych = *++m_cursor;
9911 if (yych <= '/')
9912 {
9913 goto basic_json_parser_32;
9914 }
9915 if (yych >= ':')
9916 {
9917 goto basic_json_parser_32;
9918 }
9919basic_json_parser_52:
9920 ++m_cursor;
9921 if (m_limit <= m_cursor)
9922 {
9923 fill_line_buffer(1); // LCOV_EXCL_LINE
9924 }
9925 yych = *m_cursor;
9926 if (yych <= '/')
9927 {
9928 goto basic_json_parser_14;
9929 }
9930 if (yych <= '9')
9931 {
9932 goto basic_json_parser_52;
9933 }
9934 goto basic_json_parser_14;
9935basic_json_parser_54:
9936 yych = *++m_cursor;
9937 if (yych == 's')
9938 {
9939 goto basic_json_parser_58;
9940 }
9941 goto basic_json_parser_32;
9942basic_json_parser_55:
9943 yych = *++m_cursor;
9944 if (yych == 'l')
9945 {
9946 goto basic_json_parser_59;
9947 }
9948 goto basic_json_parser_32;
9949basic_json_parser_56:
9950 yych = *++m_cursor;
9951 if (yych == 'e')
9952 {
9953 goto basic_json_parser_61;
9954 }
9955 goto basic_json_parser_32;
9956basic_json_parser_57:
9957 ++m_cursor;
9958 if (m_limit <= m_cursor)
9959 {
9960 fill_line_buffer(1); // LCOV_EXCL_LINE
9961 }
9962 yych = *m_cursor;
9963 if (yych <= '@')
9964 {
9965 if (yych <= '/')
9966 {
9967 goto basic_json_parser_32;
9968 }
9969 if (yych <= '9')
9970 {
9971 goto basic_json_parser_63;
9972 }
9973 goto basic_json_parser_32;
9974 }
9975 else
9976 {
9977 if (yych <= 'F')
9978 {
9979 goto basic_json_parser_63;
9980 }
9981 if (yych <= '`')
9982 {
9983 goto basic_json_parser_32;
9984 }
9985 if (yych <= 'f')
9986 {
9987 goto basic_json_parser_63;
9988 }
9989 goto basic_json_parser_32;
9990 }
9991basic_json_parser_58:
9992 yych = *++m_cursor;
9993 if (yych == 'e')
9994 {
9995 goto basic_json_parser_64;
9996 }
9997 goto basic_json_parser_32;
9998basic_json_parser_59:
9999 ++m_cursor;
10000 {
10001 last_token_type = token_type::literal_null;
10002 break;
10003 }
10004basic_json_parser_61:
10005 ++m_cursor;
10006 {
10007 last_token_type = token_type::literal_true;
10008 break;
10009 }
10010basic_json_parser_63:
10011 ++m_cursor;
10012 if (m_limit <= m_cursor)
10013 {
10014 fill_line_buffer(1); // LCOV_EXCL_LINE
10015 }
10016 yych = *m_cursor;
10017 if (yych <= '@')
10018 {
10019 if (yych <= '/')
10020 {
10021 goto basic_json_parser_32;
10022 }
10023 if (yych <= '9')
10024 {
10025 goto basic_json_parser_66;
10026 }
10027 goto basic_json_parser_32;
10028 }
10029 else
10030 {
10031 if (yych <= 'F')
10032 {
10033 goto basic_json_parser_66;
10034 }
10035 if (yych <= '`')
10036 {
10037 goto basic_json_parser_32;
10038 }
10039 if (yych <= 'f')
10040 {
10041 goto basic_json_parser_66;
10042 }
10043 goto basic_json_parser_32;
10044 }
10045basic_json_parser_64:
10046 ++m_cursor;
10047 {
10048 last_token_type = token_type::literal_false;
10049 break;
10050 }
10051basic_json_parser_66:
10052 ++m_cursor;
10053 if (m_limit <= m_cursor)
10054 {
10055 fill_line_buffer(1); // LCOV_EXCL_LINE
10056 }
10057 yych = *m_cursor;
10058 if (yych <= '@')
10059 {
10060 if (yych <= '/')
10061 {
10062 goto basic_json_parser_32;
10063 }
10064 if (yych <= '9')
10065 {
10066 goto basic_json_parser_30;
10067 }
10068 goto basic_json_parser_32;
10069 }
10070 else
10071 {
10072 if (yych <= 'F')
10073 {
10074 goto basic_json_parser_30;
10075 }
10076 if (yych <= '`')
10077 {
10078 goto basic_json_parser_32;
10079 }
10080 if (yych <= 'f')
10081 {
10082 goto basic_json_parser_30;
10083 }
10084 goto basic_json_parser_32;
10085 }
10086 } 21768 }
10087 21769
21770 m_data.m_type = value_t::null;
21771 assert_invariant();
21772 break;
10088 } 21773 }
10089 21774
10090 return last_token_type; 21775 case value_t::object:
10091 } 21776 {
10092 21777 result.m_it.object_iterator = m_data.m_value.object->erase(pos.m_it.object_iterator);
10093 /*! 21778 break;
10094 @brief append data from the stream to the line buffer 21779 }
10095
10096 This function is called by the scan() function when the end of the
10097 buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be
10098 incremented without leaving the limits of the line buffer. Note re2c
10099 decides when to call this function.
10100 21780
10101 If the lexer reads from contiguous storage, there is no trailing null 21781 case value_t::array:
10102 byte. Therefore, this function must make sure to add these padding 21782 {
10103 null bytes. 21783 result.m_it.array_iterator = m_data.m_value.array->erase(pos.m_it.array_iterator);
21784 break;
21785 }
10104 21786
10105 If the lexer reads from an input stream, this function reads the next 21787 case value_t::null:
10106 line of the input. 21788 case value_t::discarded:
21789 default:
21790 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
21791 }
10107 21792
10108 @pre 21793 return result;
10109 p p p p p p u u u u u x . . . . . . 21794 }
10110 ^ ^ ^ ^
10111 m_content m_start | m_limit
10112 m_cursor
10113 21795
10114 @post 21796 /// @brief remove elements given an iterator range
10115 u u u u u x x x x x x x . . . . . . 21797 /// @sa https://json.nlohmann.me/api/basic_json/erase/
10116 ^ ^ ^ 21798 template < class IteratorType, detail::enable_if_t <
10117 | m_cursor m_limit 21799 std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
10118 m_start 21800 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
10119 m_content 21801 IteratorType erase(IteratorType first, IteratorType last)
10120 */ 21802 {
10121 void fill_line_buffer(size_t n = 0) 21803 // make sure iterator fits the current value
21804 if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))
10122 { 21805 {
10123 // if line buffer is used, m_content points to its data 21806 JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this));
10124 assert(m_line_buffer.empty() 21807 }
10125 or m_content == reinterpret_cast<const lexer_char_t*>(m_line_buffer.data()));
10126
10127 // if line buffer is used, m_limit is set past the end of its data
10128 assert(m_line_buffer.empty()
10129 or m_limit == m_content + m_line_buffer.size());
10130
10131 // pointer relationships
10132 assert(m_content <= m_start);
10133 assert(m_start <= m_cursor);
10134 assert(m_cursor <= m_limit);
10135 assert(m_marker == nullptr or m_marker <= m_limit);
10136 21808
10137 // number of processed characters (p) 21809 IteratorType result = end();
10138 const size_t num_processed_chars = static_cast<size_t>(m_start - m_content);
10139 // offset for m_marker wrt. to m_start
10140 const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
10141 // number of unprocessed characters (u)
10142 const auto offset_cursor = m_cursor - m_start;
10143 21810
10144 // no stream is used or end of file is reached 21811 switch (m_data.m_type)
10145 if (m_stream == nullptr or m_stream->eof()) 21812 {
21813 case value_t::boolean:
21814 case value_t::number_float:
21815 case value_t::number_integer:
21816 case value_t::number_unsigned:
21817 case value_t::string:
21818 case value_t::binary:
10146 { 21819 {
10147 // m_start may or may not be pointing into m_line_buffer at 21820 if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin()
10148 // this point. We trust the standand library to do the right 21821 || !last.m_it.primitive_iterator.is_end()))
10149 // thing. See http://stackoverflow.com/q/28142011/266378 21822 {
10150 m_line_buffer.assign(m_start, m_limit); 21823 JSON_THROW(invalid_iterator::create(204, "iterators out of range", this));
21824 }
10151 21825
10152 // append n characters to make sure that there is sufficient 21826 if (is_string())
10153 // space between m_cursor and m_limit
10154 m_line_buffer.append(1, '\x00');
10155 if (n > 0)
10156 { 21827 {
10157 m_line_buffer.append(n - 1, '\x01'); 21828 AllocatorType<string_t> alloc;
21829 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);
21830 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);
21831 m_data.m_value.string = nullptr;
10158 } 21832 }
21833 else if (is_binary())
21834 {
21835 AllocatorType<binary_t> alloc;
21836 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);
21837 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);
21838 m_data.m_value.binary = nullptr;
21839 }
21840
21841 m_data.m_type = value_t::null;
21842 assert_invariant();
21843 break;
10159 } 21844 }
10160 else 21845
21846 case value_t::object:
10161 { 21847 {
10162 // delete processed characters from line buffer 21848 result.m_it.object_iterator = m_data.m_value.object->erase(first.m_it.object_iterator,
10163 m_line_buffer.erase(0, num_processed_chars); 21849 last.m_it.object_iterator);
10164 // read next line from input stream 21850 break;
10165 m_line_buffer_tmp.clear(); 21851 }
10166 std::getline(*m_stream, m_line_buffer_tmp, '\n');
10167 21852
10168 // add line with newline symbol to the line buffer 21853 case value_t::array:
10169 m_line_buffer += m_line_buffer_tmp; 21854 {
10170 m_line_buffer.push_back('\n'); 21855 result.m_it.array_iterator = m_data.m_value.array->erase(first.m_it.array_iterator,
21856 last.m_it.array_iterator);
21857 break;
10171 } 21858 }
10172 21859
10173 // set pointers 21860 case value_t::null:
10174 m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.data()); 21861 case value_t::discarded:
10175 assert(m_content != nullptr); 21862 default:
10176 m_start = m_content; 21863 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
10177 m_marker = m_start + offset_marker;
10178 m_cursor = m_start + offset_cursor;
10179 m_limit = m_start + m_line_buffer.size();
10180 } 21864 }
10181 21865
10182 /// return string representation of last read token 21866 return result;
10183 string_t get_token_string() const 21867 }
21868
21869 private:
21870 template < typename KeyType, detail::enable_if_t <
21871 detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
21872 size_type erase_internal(KeyType && key)
21873 {
21874 // this erase only works for objects
21875 if (JSON_HEDLEY_UNLIKELY(!is_object()))
10184 { 21876 {
10185 assert(m_start != nullptr); 21877 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
10186 return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
10187 static_cast<size_t>(m_cursor - m_start));
10188 } 21878 }
10189 21879
10190 /*! 21880 return m_data.m_value.object->erase(std::forward<KeyType>(key));
10191 @brief return string value for string tokens 21881 }
21882
21883 template < typename KeyType, detail::enable_if_t <
21884 !detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
21885 size_type erase_internal(KeyType && key)
21886 {
21887 // this erase only works for objects
21888 if (JSON_HEDLEY_UNLIKELY(!is_object()))
21889 {
21890 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
21891 }
10192 21892
10193 The function iterates the characters between the opening and closing 21893 const auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
10194 quotes of the string value. The complete string is the range 21894 if (it != m_data.m_value.object->end())
10195 [m_start,m_cursor). Consequently, we iterate from m_start+1 to 21895 {
10196 m_cursor-1. 21896 m_data.m_value.object->erase(it);
21897 return 1;
21898 }
21899 return 0;
21900 }
10197 21901
10198 We differentiate two cases: 21902 public:
10199 21903
10200 1. Escaped characters. In this case, a new character is constructed 21904 /// @brief remove element from a JSON object given a key
10201 according to the nature of the escape. Some escapes create new 21905 /// @sa https://json.nlohmann.me/api/basic_json/erase/
10202 characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied 21906 size_type erase(const typename object_t::key_type& key)
10203 as is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape 21907 {
10204 `"\\uxxxx"` need special care. In this case, to_unicode takes care 21908 // the indirection via erase_internal() is added to avoid making this
10205 of the construction of the values. 21909 // function a template and thus de-rank it during overload resolution
10206 2. Unescaped characters are copied as is. 21910 return erase_internal(key);
21911 }
10207 21912
10208 @pre `m_cursor - m_start >= 2`, meaning the length of the last token 21913 /// @brief remove element from a JSON object given a key
10209 is at least 2 bytes which is trivially true for any string (which 21914 /// @sa https://json.nlohmann.me/api/basic_json/erase/
10210 consists of at least two quotes). 21915 template<class KeyType, detail::enable_if_t<
21916 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
21917 size_type erase(KeyType && key)
21918 {
21919 return erase_internal(std::forward<KeyType>(key));
21920 }
10211 21921
10212 " c1 c2 c3 ... " 21922 /// @brief remove element from a JSON array given an index
10213 ^ ^ 21923 /// @sa https://json.nlohmann.me/api/basic_json/erase/
10214 m_start m_cursor 21924 void erase(const size_type idx)
21925 {
21926 // this erase only works for arrays
21927 if (JSON_HEDLEY_LIKELY(is_array()))
21928 {
21929 if (JSON_HEDLEY_UNLIKELY(idx >= size()))
21930 {
21931 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
21932 }
10215 21933
10216 @complexity Linear in the length of the string.\n 21934 m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast<difference_type>(idx));
21935 }
21936 else
21937 {
21938 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
21939 }
21940 }
10217 21941
10218 Lemma: The loop body will always terminate.\n 21942 /// @}
10219 21943
10220 Proof (by contradiction): Assume the loop body does not terminate. As 21944 ////////////
10221 the loop body does not contain another loop, one of the called 21945 // lookup //
10222 functions must never return. The called functions are `std::strtoul` 21946 ////////////
10223 and to_unicode. Neither function can loop forever, so the loop body
10224 will never loop forever which contradicts the assumption that the loop
10225 body does not terminate, q.e.d.\n
10226 21947
10227 Lemma: The loop condition for the for loop is eventually false.\n 21948 /// @name lookup
21949 /// @{
10228 21950
10229 Proof (by contradiction): Assume the loop does not terminate. Due to 21951 /// @brief find an element in a JSON object
10230 the above lemma, this can only be due to a tautological loop 21952 /// @sa https://json.nlohmann.me/api/basic_json/find/
10231 condition; that is, the loop condition i < m_cursor - 1 must always be 21953 iterator find(const typename object_t::key_type& key)
10232 true. Let x be the change of i for any loop iteration. Then 21954 {
10233 m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This 21955 auto result = end();
10234 can be rephrased to m_cursor - m_start - 2 > x. With the
10235 precondition, we x <= 0, meaning that the loop condition holds
10236 indefinitly if i is always decreased. However, observe that the value
10237 of i is strictly increasing with each iteration, as it is incremented
10238 by 1 in the iteration expression and never decremented inside the loop
10239 body. Hence, the loop condition will eventually be false which
10240 contradicts the assumption that the loop condition is a tautology,
10241 q.e.d.
10242 21956
10243 @return string value of current token without opening and closing 21957 if (is_object())
10244 quotes
10245 @throw std::out_of_range if to_unicode fails
10246 */
10247 string_t get_string() const
10248 { 21958 {
10249 assert(m_cursor - m_start >= 2); 21959 result.m_it.object_iterator = m_data.m_value.object->find(key);
10250 21960 }
10251 string_t result;
10252 result.reserve(static_cast<size_t>(m_cursor - m_start - 2));
10253 21961
10254 // iterate the result between the quotes 21962 return result;
10255 for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) 21963 }
10256 {
10257 // find next escape character
10258 auto e = std::find(i, m_cursor - 1, '\\');
10259 if (e != i)
10260 {
10261 // see https://github.com/nlohmann/json/issues/365#issuecomment-262874705
10262 for (auto k = i; k < e; k++)
10263 {
10264 result.push_back(static_cast<typename string_t::value_type>(*k));
10265 }
10266 i = e - 1; // -1 because of ++i
10267 }
10268 else
10269 {
10270 // processing escaped character
10271 // read next character
10272 ++i;
10273 21964
10274 switch (*i) 21965 /// @brief find an element in a JSON object
10275 { 21966 /// @sa https://json.nlohmann.me/api/basic_json/find/
10276 // the default escapes 21967 const_iterator find(const typename object_t::key_type& key) const
10277 case 't': 21968 {
10278 { 21969 auto result = cend();
10279 result += "\t";
10280 break;
10281 }
10282 case 'b':
10283 {
10284 result += "\b";
10285 break;
10286 }
10287 case 'f':
10288 {
10289 result += "\f";
10290 break;
10291 }
10292 case 'n':
10293 {
10294 result += "\n";
10295 break;
10296 }
10297 case 'r':
10298 {
10299 result += "\r";
10300 break;
10301 }
10302 case '\\':
10303 {
10304 result += "\\";
10305 break;
10306 }
10307 case '/':
10308 {
10309 result += "/";
10310 break;
10311 }
10312 case '"':
10313 {
10314 result += "\"";
10315 break;
10316 }
10317 21970
10318 // unicode 21971 if (is_object())
10319 case 'u': 21972 {
10320 { 21973 result.m_it.object_iterator = m_data.m_value.object->find(key);
10321 // get code xxxx from uxxxx 21974 }
10322 auto codepoint = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer>(i + 1),
10323 4).c_str(), nullptr, 16);
10324 21975
10325 // check if codepoint is a high surrogate 21976 return result;
10326 if (codepoint >= 0xD800 and codepoint <= 0xDBFF) 21977 }
10327 {
10328 // make sure there is a subsequent unicode
10329 if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u')
10330 {
10331 throw std::invalid_argument("missing low surrogate");
10332 }
10333 21978
10334 // get code yyyy from uxxxx\uyyyy 21979 /// @brief find an element in a JSON object
10335 auto codepoint2 = std::strtoul(std::string(reinterpret_cast<typename string_t::const_pointer> 21980 /// @sa https://json.nlohmann.me/api/basic_json/find/
10336 (i + 7), 4).c_str(), nullptr, 16); 21981 template<class KeyType, detail::enable_if_t<
10337 result += to_unicode(codepoint, codepoint2); 21982 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
10338 // skip the next 10 characters (xxxx\uyyyy) 21983 iterator find(KeyType && key)
10339 i += 10; 21984 {
10340 } 21985 auto result = end();
10341 else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF)
10342 {
10343 // we found a lone low surrogate
10344 throw std::invalid_argument("missing high surrogate");
10345 }
10346 else
10347 {
10348 // add unicode character(s)
10349 result += to_unicode(codepoint);
10350 // skip the next four characters (xxxx)
10351 i += 4;
10352 }
10353 break;
10354 }
10355 }
10356 }
10357 }
10358 21986
10359 return result; 21987 if (is_object())
21988 {
21989 result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
10360 } 21990 }
10361 21991
10362 /*! 21992 return result;
10363 @brief parse floating point number 21993 }
10364
10365 This function (and its overloads) serves to select the most approprate
10366 standard floating point number parsing function based on the type
10367 supplied via the first parameter. Set this to @a
10368 static_cast<number_float_t*>(nullptr).
10369 21994
10370 @param[in,out] endptr recieves a pointer to the first character after 21995 /// @brief find an element in a JSON object
10371 the number 21996 /// @sa https://json.nlohmann.me/api/basic_json/find/
21997 template<class KeyType, detail::enable_if_t<
21998 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
21999 const_iterator find(KeyType && key) const
22000 {
22001 auto result = cend();
10372 22002
10373 @return the floating point number 22003 if (is_object())
10374 */
10375 long double str_to_float_t(long double* /* type */, char** endptr) const
10376 { 22004 {
10377 return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr); 22005 result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
10378 } 22006 }
10379 22007
10380 /*! 22008 return result;
10381 @brief parse floating point number 22009 }
10382 22010
10383 This function (and its overloads) serves to select the most approprate 22011 /// @brief returns the number of occurrences of a key in a JSON object
10384 standard floating point number parsing function based on the type 22012 /// @sa https://json.nlohmann.me/api/basic_json/count/
10385 supplied via the first parameter. Set this to @a 22013 size_type count(const typename object_t::key_type& key) const
10386 static_cast<number_float_t*>(nullptr). 22014 {
22015 // return 0 for all nonobject types
22016 return is_object() ? m_data.m_value.object->count(key) : 0;
22017 }
10387 22018
10388 @param[in,out] endptr recieves a pointer to the first character after 22019 /// @brief returns the number of occurrences of a key in a JSON object
10389 the number 22020 /// @sa https://json.nlohmann.me/api/basic_json/count/
22021 template<class KeyType, detail::enable_if_t<
22022 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
22023 size_type count(KeyType && key) const
22024 {
22025 // return 0 for all nonobject types
22026 return is_object() ? m_data.m_value.object->count(std::forward<KeyType>(key)) : 0;
22027 }
10390 22028
10391 @return the floating point number 22029 /// @brief check the existence of an element in a JSON object
10392 */ 22030 /// @sa https://json.nlohmann.me/api/basic_json/contains/
10393 double str_to_float_t(double* /* type */, char** endptr) const 22031 bool contains(const typename object_t::key_type& key) const
10394 { 22032 {
10395 return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr); 22033 return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end();
10396 } 22034 }
10397 22035
10398 /*! 22036 /// @brief check the existence of an element in a JSON object
10399 @brief parse floating point number 22037 /// @sa https://json.nlohmann.me/api/basic_json/contains/
22038 template<class KeyType, detail::enable_if_t<
22039 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
22040 bool contains(KeyType && key) const
22041 {
22042 return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end();
22043 }
10400 22044
10401 This function (and its overloads) serves to select the most approprate 22045 /// @brief check the existence of an element in a JSON object given a JSON pointer
10402 standard floating point number parsing function based on the type 22046 /// @sa https://json.nlohmann.me/api/basic_json/contains/
10403 supplied via the first parameter. Set this to @a 22047 bool contains(const json_pointer& ptr) const
10404 static_cast<number_float_t*>(nullptr). 22048 {
22049 return ptr.contains(this);
22050 }
10405 22051
10406 @param[in,out] endptr recieves a pointer to the first character after 22052 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
10407 the number 22053 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
22054 bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
22055 {
22056 return ptr.contains(this);
22057 }
10408 22058
10409 @return the floating point number 22059 /// @}
10410 */
10411 float str_to_float_t(float* /* type */, char** endptr) const
10412 {
10413 return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
10414 }
10415 22060
10416 /*! 22061 ///////////////
10417 @brief return number value for number tokens 22062 // iterators //
22063 ///////////////
10418 22064
10419 This function translates the last token into the most appropriate 22065 /// @name iterators
10420 number type (either integer, unsigned integer or floating point), 22066 /// @{
10421 which is passed back to the caller via the result parameter.
10422 22067
10423 This function parses the integer component up to the radix point or 22068 /// @brief returns an iterator to the first element
10424 exponent while collecting information about the 'floating point 22069 /// @sa https://json.nlohmann.me/api/basic_json/begin/
10425 representation', which it stores in the result parameter. If there is 22070 iterator begin() noexcept
10426 no radix point or exponent, and the number can fit into a @ref 22071 {
10427 number_integer_t or @ref number_unsigned_t then it sets the result 22072 iterator result(this);
10428 parameter accordingly. 22073 result.set_begin();
22074 return result;
22075 }
10429 22076
10430 If the number is a floating point number the number is then parsed 22077 /// @brief returns an iterator to the first element
10431 using @a std:strtod (or @a std:strtof or @a std::strtold). 22078 /// @sa https://json.nlohmann.me/api/basic_json/begin/
22079 const_iterator begin() const noexcept
22080 {
22081 return cbegin();
22082 }
10432 22083
10433 @param[out] result @ref basic_json object to receive the number, or 22084 /// @brief returns a const iterator to the first element
10434 NAN if the conversion read past the current token. The latter case 22085 /// @sa https://json.nlohmann.me/api/basic_json/cbegin/
10435 needs to be treated by the caller function. 22086 const_iterator cbegin() const noexcept
10436 */ 22087 {
10437 void get_number(basic_json& result) const 22088 const_iterator result(this);
10438 { 22089 result.set_begin();
10439 assert(m_start != nullptr); 22090 return result;
22091 }
10440 22092
10441 const lexer::lexer_char_t* curptr = m_start; 22093 /// @brief returns an iterator to one past the last element
22094 /// @sa https://json.nlohmann.me/api/basic_json/end/
22095 iterator end() noexcept
22096 {
22097 iterator result(this);
22098 result.set_end();
22099 return result;
22100 }
10442 22101
10443 // accumulate the integer conversion result (unsigned for now) 22102 /// @brief returns an iterator to one past the last element
10444 number_unsigned_t value = 0; 22103 /// @sa https://json.nlohmann.me/api/basic_json/end/
22104 const_iterator end() const noexcept
22105 {
22106 return cend();
22107 }
10445 22108
10446 // maximum absolute value of the relevant integer type 22109 /// @brief returns an iterator to one past the last element
10447 number_unsigned_t max; 22110 /// @sa https://json.nlohmann.me/api/basic_json/cend/
22111 const_iterator cend() const noexcept
22112 {
22113 const_iterator result(this);
22114 result.set_end();
22115 return result;
22116 }
22117
22118 /// @brief returns an iterator to the reverse-beginning
22119 /// @sa https://json.nlohmann.me/api/basic_json/rbegin/
22120 reverse_iterator rbegin() noexcept
22121 {
22122 return reverse_iterator(end());
22123 }
22124
22125 /// @brief returns an iterator to the reverse-beginning
22126 /// @sa https://json.nlohmann.me/api/basic_json/rbegin/
22127 const_reverse_iterator rbegin() const noexcept
22128 {
22129 return crbegin();
22130 }
22131
22132 /// @brief returns an iterator to the reverse-end
22133 /// @sa https://json.nlohmann.me/api/basic_json/rend/
22134 reverse_iterator rend() noexcept
22135 {
22136 return reverse_iterator(begin());
22137 }
22138
22139 /// @brief returns an iterator to the reverse-end
22140 /// @sa https://json.nlohmann.me/api/basic_json/rend/
22141 const_reverse_iterator rend() const noexcept
22142 {
22143 return crend();
22144 }
22145
22146 /// @brief returns a const reverse iterator to the last element
22147 /// @sa https://json.nlohmann.me/api/basic_json/crbegin/
22148 const_reverse_iterator crbegin() const noexcept
22149 {
22150 return const_reverse_iterator(cend());
22151 }
22152
22153 /// @brief returns a const reverse iterator to one before the first
22154 /// @sa https://json.nlohmann.me/api/basic_json/crend/
22155 const_reverse_iterator crend() const noexcept
22156 {
22157 return const_reverse_iterator(cbegin());
22158 }
22159
22160 public:
22161 /// @brief wrapper to access iterator member functions in range-based for
22162 /// @sa https://json.nlohmann.me/api/basic_json/items/
22163 /// @deprecated This function is deprecated since 3.1.0 and will be removed in
22164 /// version 4.0.0 of the library. Please use @ref items() instead;
22165 /// that is, replace `json::iterator_wrapper(j)` with `j.items()`.
22166 JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
22167 static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
22168 {
22169 return ref.items();
22170 }
22171
22172 /// @brief wrapper to access iterator member functions in range-based for
22173 /// @sa https://json.nlohmann.me/api/basic_json/items/
22174 /// @deprecated This function is deprecated since 3.1.0 and will be removed in
22175 /// version 4.0.0 of the library. Please use @ref items() instead;
22176 /// that is, replace `json::iterator_wrapper(j)` with `j.items()`.
22177 JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
22178 static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
22179 {
22180 return ref.items();
22181 }
22182
22183 /// @brief helper to access iterator member functions in range-based for
22184 /// @sa https://json.nlohmann.me/api/basic_json/items/
22185 iteration_proxy<iterator> items() noexcept
22186 {
22187 return iteration_proxy<iterator>(*this);
22188 }
22189
22190 /// @brief helper to access iterator member functions in range-based for
22191 /// @sa https://json.nlohmann.me/api/basic_json/items/
22192 iteration_proxy<const_iterator> items() const noexcept
22193 {
22194 return iteration_proxy<const_iterator>(*this);
22195 }
22196
22197 /// @}
22198
22199 //////////////
22200 // capacity //
22201 //////////////
10448 22202
10449 // temporarily store the type to avoid unecessary bitfield access 22203 /// @name capacity
10450 value_t type; 22204 /// @{
10451 22205
10452 // look for sign 22206 /// @brief checks whether the container is empty.
10453 if (*curptr == '-') 22207 /// @sa https://json.nlohmann.me/api/basic_json/empty/
22208 bool empty() const noexcept
22209 {
22210 switch (m_data.m_type)
22211 {
22212 case value_t::null:
10454 { 22213 {
10455 type = value_t::number_integer; 22214 // null values are empty
10456 max = static_cast<uint64_t>((std::numeric_limits<number_integer_t>::max)()) + 1; 22215 return true;
10457 curptr++;
10458 } 22216 }
10459 else 22217
22218 case value_t::array:
10460 { 22219 {
10461 type = value_t::number_unsigned; 22220 // delegate call to array_t::empty()
10462 max = static_cast<uint64_t>((std::numeric_limits<number_unsigned_t>::max)()); 22221 return m_data.m_value.array->empty();
10463 } 22222 }
10464 22223
10465 // count the significant figures 22224 case value_t::object:
10466 for (; curptr < m_cursor; curptr++)
10467 { 22225 {
10468 // quickly skip tests if a digit 22226 // delegate call to object_t::empty()
10469 if (*curptr < '0' || *curptr > '9') 22227 return m_data.m_value.object->empty();
10470 { 22228 }
10471 if (*curptr == '.')
10472 {
10473 // don't count '.' but change to float
10474 type = value_t::number_float;
10475 continue;
10476 }
10477 // assume exponent (if not then will fail parse): change to
10478 // float, stop counting and record exponent details
10479 type = value_t::number_float;
10480 break;
10481 }
10482 22229
10483 // skip if definitely not an integer 22230 case value_t::string:
10484 if (type != value_t::number_float) 22231 case value_t::boolean:
10485 { 22232 case value_t::number_integer:
10486 auto digit = static_cast<number_unsigned_t>(*curptr - '0'); 22233 case value_t::number_unsigned:
22234 case value_t::number_float:
22235 case value_t::binary:
22236 case value_t::discarded:
22237 default:
22238 {
22239 // all other types are nonempty
22240 return false;
22241 }
22242 }
22243 }
10487 22244
10488 // overflow if value * 10 + digit > max, move terms around 22245 /// @brief returns the number of elements
10489 // to avoid overflow in intermediate values 22246 /// @sa https://json.nlohmann.me/api/basic_json/size/
10490 if (value > (max - digit) / 10) 22247 size_type size() const noexcept
10491 { 22248 {
10492 // overflow 22249 switch (m_data.m_type)
10493 type = value_t::number_float; 22250 {
10494 } 22251 case value_t::null:
10495 else 22252 {
10496 { 22253 // null values are empty
10497 // no overflow 22254 return 0;
10498 value = value * 10 + digit;
10499 }
10500 }
10501 } 22255 }
10502 22256
10503 // save the value (if not a float) 22257 case value_t::array:
10504 if (type == value_t::number_unsigned)
10505 { 22258 {
10506 result.m_value.number_unsigned = value; 22259 // delegate call to array_t::size()
22260 return m_data.m_value.array->size();
10507 } 22261 }
10508 else if (type == value_t::number_integer) 22262
22263 case value_t::object:
10509 { 22264 {
10510 // invariant: if we parsed a '-', the absolute value is between 22265 // delegate call to object_t::size()
10511 // 0 (we allow -0) and max == -INT64_MIN 22266 return m_data.m_value.object->size();
10512 assert(value >= 0); 22267 }
10513 assert(value <= max);
10514 22268
10515 if (value == max) 22269 case value_t::string:
10516 { 22270 case value_t::boolean:
10517 // we cannot simply negate value (== max == -INT64_MIN), 22271 case value_t::number_integer:
10518 // see https://github.com/nlohmann/json/issues/389 22272 case value_t::number_unsigned:
10519 result.m_value.number_integer = static_cast<number_integer_t>(INT64_MIN); 22273 case value_t::number_float:
10520 } 22274 case value_t::binary:
10521 else 22275 case value_t::discarded:
10522 { 22276 default:
10523 // all other values can be negated safely 22277 {
10524 result.m_value.number_integer = -static_cast<number_integer_t>(value); 22278 // all other types have size 1
10525 } 22279 return 1;
10526 } 22280 }
10527 else 22281 }
22282 }
22283
22284 /// @brief returns the maximum possible number of elements
22285 /// @sa https://json.nlohmann.me/api/basic_json/max_size/
22286 size_type max_size() const noexcept
22287 {
22288 switch (m_data.m_type)
22289 {
22290 case value_t::array:
10528 { 22291 {
10529 // parse with strtod 22292 // delegate call to array_t::max_size()
10530 result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), NULL); 22293 return m_data.m_value.array->max_size();
22294 }
10531 22295
10532 // replace infinity and NAN by null 22296 case value_t::object:
10533 if (not std::isfinite(result.m_value.number_float)) 22297 {
10534 { 22298 // delegate call to object_t::max_size()
10535 type = value_t::null; 22299 return m_data.m_value.object->max_size();
10536 result.m_value = basic_json::json_value();
10537 }
10538 } 22300 }
10539 22301
10540 // save the type 22302 case value_t::null:
10541 result.m_type = type; 22303 case value_t::string:
22304 case value_t::boolean:
22305 case value_t::number_integer:
22306 case value_t::number_unsigned:
22307 case value_t::number_float:
22308 case value_t::binary:
22309 case value_t::discarded:
22310 default:
22311 {
22312 // all other types have max_size() == size()
22313 return size();
22314 }
10542 } 22315 }
22316 }
10543 22317
10544 private: 22318 /// @}
10545 /// optional input stream
10546 std::istream* m_stream = nullptr;
10547 /// line buffer buffer for m_stream
10548 string_t m_line_buffer {};
10549 /// used for filling m_line_buffer
10550 string_t m_line_buffer_tmp {};
10551 /// the buffer pointer
10552 const lexer_char_t* m_content = nullptr;
10553 /// pointer to the beginning of the current symbol
10554 const lexer_char_t* m_start = nullptr;
10555 /// pointer for backtracking information
10556 const lexer_char_t* m_marker = nullptr;
10557 /// pointer to the current symbol
10558 const lexer_char_t* m_cursor = nullptr;
10559 /// pointer to the end of the buffer
10560 const lexer_char_t* m_limit = nullptr;
10561 /// the last token type
10562 token_type last_token_type = token_type::end_of_input;
10563 };
10564 22319
10565 /*! 22320 ///////////////
10566 @brief syntax analysis 22321 // modifiers //
22322 ///////////////
10567 22323
10568 This class implements a recursive decent parser. 22324 /// @name modifiers
10569 */ 22325 /// @{
10570 class parser 22326
22327 /// @brief clears the contents
22328 /// @sa https://json.nlohmann.me/api/basic_json/clear/
22329 void clear() noexcept
10571 { 22330 {
10572 public: 22331 switch (m_data.m_type)
10573 /// a parser reading from a string literal 22332 {
10574 parser(const char* buff, const parser_callback_t cb = nullptr) 22333 case value_t::number_integer:
10575 : callback(cb), 22334 {
10576 m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), std::strlen(buff)) 22335 m_data.m_value.number_integer = 0;
10577 {} 22336 break;
22337 }
22338
22339 case value_t::number_unsigned:
22340 {
22341 m_data.m_value.number_unsigned = 0;
22342 break;
22343 }
10578 22344
10579 /// a parser reading from an input stream 22345 case value_t::number_float:
10580 parser(std::istream& is, const parser_callback_t cb = nullptr) 22346 {
10581 : callback(cb), m_lexer(is) 22347 m_data.m_value.number_float = 0.0;
10582 {} 22348 break;
22349 }
10583 22350
10584 /// a parser reading from an iterator range with contiguous storage 22351 case value_t::boolean:
10585 template<class IteratorType, typename std::enable_if< 22352 {
10586 std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value 22353 m_data.m_value.boolean = false;
10587 , int>::type 22354 break;
10588 = 0> 22355 }
10589 parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr)
10590 : callback(cb),
10591 m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(&(*first)),
10592 static_cast<size_t>(std::distance(first, last)))
10593 {}
10594 22356
10595 /// public parser interface 22357 case value_t::string:
10596 basic_json parse() 22358 {
10597 { 22359 m_data.m_value.string->clear();
10598 // read first token 22360 break;
10599 get_token(); 22361 }
22362
22363 case value_t::binary:
22364 {
22365 m_data.m_value.binary->clear();
22366 break;
22367 }
10600 22368
10601 basic_json result = parse_internal(true); 22369 case value_t::array:
10602 result.assert_invariant(); 22370 {
22371 m_data.m_value.array->clear();
22372 break;
22373 }
10603 22374
10604 expect(lexer::token_type::end_of_input); 22375 case value_t::object:
22376 {
22377 m_data.m_value.object->clear();
22378 break;
22379 }
10605 22380
10606 // return parser result and replace it with null in case the 22381 case value_t::null:
10607 // top-level value was discarded by the callback function 22382 case value_t::discarded:
10608 return result.is_discarded() ? basic_json() : std::move(result); 22383 default:
22384 break;
10609 } 22385 }
22386 }
10610 22387
10611 private: 22388 /// @brief add an object to an array
10612 /// the actual parser 22389 /// @sa https://json.nlohmann.me/api/basic_json/push_back/
10613 basic_json parse_internal(bool keep) 22390 void push_back(basic_json&& val)
22391 {
22392 // push_back only works for null objects or arrays
22393 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
10614 { 22394 {
10615 auto result = basic_json(value_t::discarded); 22395 JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
22396 }
10616 22397
10617 switch (last_token) 22398 // transform null object into an array
10618 { 22399 if (is_null())
10619 case lexer::token_type::begin_object: 22400 {
10620 { 22401 m_data.m_type = value_t::array;
10621 if (keep and (not callback 22402 m_data.m_value = value_t::array;
10622 or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0))) 22403 assert_invariant();
10623 { 22404 }
10624 // explicitly set result to object to cope with {}
10625 result.m_type = value_t::object;
10626 result.m_value = value_t::object;
10627 }
10628 22405
10629 // read next token 22406 // add element to array (move semantics)
10630 get_token(); 22407 const auto old_capacity = m_data.m_value.array->capacity();
22408 m_data.m_value.array->push_back(std::move(val));
22409 set_parent(m_data.m_value.array->back(), old_capacity);
22410 // if val is moved from, basic_json move constructor marks it null, so we do not call the destructor
22411 }
10631 22412
10632 // closing } -> we are done 22413 /// @brief add an object to an array
10633 if (last_token == lexer::token_type::end_object) 22414 /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
10634 { 22415 reference operator+=(basic_json&& val)
10635 get_token(); 22416 {
10636 if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) 22417 push_back(std::move(val));
10637 { 22418 return *this;
10638 result = basic_json(value_t::discarded); 22419 }
10639 }
10640 return result;
10641 }
10642 22420
10643 // no comma is expected here 22421 /// @brief add an object to an array
10644 unexpect(lexer::token_type::value_separator); 22422 /// @sa https://json.nlohmann.me/api/basic_json/push_back/
22423 void push_back(const basic_json& val)
22424 {
22425 // push_back only works for null objects or arrays
22426 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
22427 {
22428 JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
22429 }
10645 22430
10646 // otherwise: parse key-value pairs 22431 // transform null object into an array
10647 do 22432 if (is_null())
10648 { 22433 {
10649 // ugly, but could be fixed with loop reorganization 22434 m_data.m_type = value_t::array;
10650 if (last_token == lexer::token_type::value_separator) 22435 m_data.m_value = value_t::array;
10651 { 22436 assert_invariant();
10652 get_token(); 22437 }
10653 }
10654 22438
10655 // store key 22439 // add element to array
10656 expect(lexer::token_type::value_string); 22440 const auto old_capacity = m_data.m_value.array->capacity();
10657 const auto key = m_lexer.get_string(); 22441 m_data.m_value.array->push_back(val);
22442 set_parent(m_data.m_value.array->back(), old_capacity);
22443 }
10658 22444
10659 bool keep_tag = false; 22445 /// @brief add an object to an array
10660 if (keep) 22446 /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
10661 { 22447 reference operator+=(const basic_json& val)
10662 if (callback) 22448 {
10663 { 22449 push_back(val);
10664 basic_json k(key); 22450 return *this;
10665 keep_tag = callback(depth, parse_event_t::key, k); 22451 }
10666 }
10667 else
10668 {
10669 keep_tag = true;
10670 }
10671 }
10672 22452
10673 // parse separator (:) 22453 /// @brief add an object to an object
10674 get_token(); 22454 /// @sa https://json.nlohmann.me/api/basic_json/push_back/
10675 expect(lexer::token_type::name_separator); 22455 void push_back(const typename object_t::value_type& val)
22456 {
22457 // push_back only works for null objects or objects
22458 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
22459 {
22460 JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
22461 }
10676 22462
10677 // parse and add value 22463 // transform null object into an object
10678 get_token(); 22464 if (is_null())
10679 auto value = parse_internal(keep); 22465 {
10680 if (keep and keep_tag and not value.is_discarded()) 22466 m_data.m_type = value_t::object;
10681 { 22467 m_data.m_value = value_t::object;
10682 result[key] = std::move(value); 22468 assert_invariant();
10683 } 22469 }
10684 }
10685 while (last_token == lexer::token_type::value_separator);
10686 22470
10687 // closing } 22471 // add element to object
10688 expect(lexer::token_type::end_object); 22472 auto res = m_data.m_value.object->insert(val);
10689 get_token(); 22473 set_parent(res.first->second);
10690 if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) 22474 }
10691 {
10692 result = basic_json(value_t::discarded);
10693 }
10694 22475
10695 return result; 22476 /// @brief add an object to an object
10696 } 22477 /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
22478 reference operator+=(const typename object_t::value_type& val)
22479 {
22480 push_back(val);
22481 return *this;
22482 }
10697 22483
10698 case lexer::token_type::begin_array: 22484 /// @brief add an object to an object
10699 { 22485 /// @sa https://json.nlohmann.me/api/basic_json/push_back/
10700 if (keep and (not callback 22486 void push_back(initializer_list_t init)
10701 or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0))) 22487 {
10702 { 22488 if (is_object() && init.size() == 2 && (*init.begin())->is_string())
10703 // explicitly set result to object to cope with [] 22489 {
10704 result.m_type = value_t::array; 22490 basic_json&& key = init.begin()->moved_or_copied();
10705 result.m_value = value_t::array; 22491 push_back(typename object_t::value_type(
10706 } 22492 std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));
22493 }
22494 else
22495 {
22496 push_back(basic_json(init));
22497 }
22498 }
10707 22499
10708 // read next token 22500 /// @brief add an object to an object
10709 get_token(); 22501 /// @sa https://json.nlohmann.me/api/basic_json/operator+=/
22502 reference operator+=(initializer_list_t init)
22503 {
22504 push_back(init);
22505 return *this;
22506 }
10710 22507
10711 // closing ] -> we are done 22508 /// @brief add an object to an array
10712 if (last_token == lexer::token_type::end_array) 22509 /// @sa https://json.nlohmann.me/api/basic_json/emplace_back/
10713 { 22510 template<class... Args>
10714 get_token(); 22511 reference emplace_back(Args&& ... args)
10715 if (callback and not callback(--depth, parse_event_t::array_end, result)) 22512 {
10716 { 22513 // emplace_back only works for null objects or arrays
10717 result = basic_json(value_t::discarded); 22514 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
10718 } 22515 {
10719 return result; 22516 JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this));
10720 } 22517 }
10721 22518
10722 // no comma is expected here 22519 // transform null object into an array
10723 unexpect(lexer::token_type::value_separator); 22520 if (is_null())
22521 {
22522 m_data.m_type = value_t::array;
22523 m_data.m_value = value_t::array;
22524 assert_invariant();
22525 }
10724 22526
10725 // otherwise: parse values 22527 // add element to array (perfect forwarding)
10726 do 22528 const auto old_capacity = m_data.m_value.array->capacity();
10727 { 22529 m_data.m_value.array->emplace_back(std::forward<Args>(args)...);
10728 // ugly, but could be fixed with loop reorganization 22530 return set_parent(m_data.m_value.array->back(), old_capacity);
10729 if (last_token == lexer::token_type::value_separator) 22531 }
10730 {
10731 get_token();
10732 }
10733 22532
10734 // parse value 22533 /// @brief add an object to an object if key does not exist
10735 auto value = parse_internal(keep); 22534 /// @sa https://json.nlohmann.me/api/basic_json/emplace/
10736 if (keep and not value.is_discarded()) 22535 template<class... Args>
10737 { 22536 std::pair<iterator, bool> emplace(Args&& ... args)
10738 result.push_back(std::move(value)); 22537 {
10739 } 22538 // emplace only works for null objects or arrays
10740 } 22539 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
10741 while (last_token == lexer::token_type::value_separator); 22540 {
22541 JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this));
22542 }
10742 22543
10743 // closing ] 22544 // transform null object into an object
10744 expect(lexer::token_type::end_array); 22545 if (is_null())
10745 get_token(); 22546 {
10746 if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) 22547 m_data.m_type = value_t::object;
10747 { 22548 m_data.m_value = value_t::object;
10748 result = basic_json(value_t::discarded); 22549 assert_invariant();
10749 } 22550 }
10750 22551
10751 return result; 22552 // add element to array (perfect forwarding)
10752 } 22553 auto res = m_data.m_value.object->emplace(std::forward<Args>(args)...);
22554 set_parent(res.first->second);
10753 22555
10754 case lexer::token_type::literal_null: 22556 // create result iterator and set iterator to the result of emplace
10755 { 22557 auto it = begin();
10756 get_token(); 22558 it.m_it.object_iterator = res.first;
10757 result.m_type = value_t::null;
10758 break;
10759 }
10760 22559
10761 case lexer::token_type::value_string: 22560 // return pair of iterator and boolean
10762 { 22561 return {it, res.second};
10763 const auto s = m_lexer.get_string(); 22562 }
10764 get_token();
10765 result = basic_json(s);
10766 break;
10767 }
10768 22563
10769 case lexer::token_type::literal_true: 22564 /// Helper for insertion of an iterator
10770 { 22565 /// @note: This uses std::distance to support GCC 4.8,
10771 get_token(); 22566 /// see https://github.com/nlohmann/json/pull/1257
10772 result.m_type = value_t::boolean; 22567 template<typename... Args>
10773 result.m_value = true; 22568 iterator insert_iterator(const_iterator pos, Args&& ... args)
10774 break; 22569 {
10775 } 22570 iterator result(this);
22571 JSON_ASSERT(m_data.m_value.array != nullptr);
10776 22572
10777 case lexer::token_type::literal_false: 22573 auto insert_pos = std::distance(m_data.m_value.array->begin(), pos.m_it.array_iterator);
10778 { 22574 m_data.m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);
10779 get_token(); 22575 result.m_it.array_iterator = m_data.m_value.array->begin() + insert_pos;
10780 result.m_type = value_t::boolean;
10781 result.m_value = false;
10782 break;
10783 }
10784 22576
10785 case lexer::token_type::value_number: 22577 // This could have been written as:
10786 { 22578 // result.m_it.array_iterator = m_data.m_value.array->insert(pos.m_it.array_iterator, cnt, val);
10787 m_lexer.get_number(result); 22579 // but the return value of insert is missing in GCC 4.8, so it is written this way instead.
10788 get_token();
10789 break;
10790 }
10791 22580
10792 default: 22581 set_parents();
10793 { 22582 return result;
10794 // the last token was unexpected 22583 }
10795 unexpect(last_token);
10796 }
10797 }
10798 22584
10799 if (keep and callback and not callback(depth, parse_event_t::value, result)) 22585 /// @brief inserts element into array
22586 /// @sa https://json.nlohmann.me/api/basic_json/insert/
22587 iterator insert(const_iterator pos, const basic_json& val)
22588 {
22589 // insert only works for arrays
22590 if (JSON_HEDLEY_LIKELY(is_array()))
22591 {
22592 // check if iterator pos fits to this JSON value
22593 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
10800 { 22594 {
10801 result = basic_json(value_t::discarded); 22595 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
10802 } 22596 }
10803 return result;
10804 }
10805 22597
10806 /// get next token from lexer 22598 // insert to array and return iterator
10807 typename lexer::token_type get_token() 22599 return insert_iterator(pos, val);
10808 {
10809 last_token = m_lexer.scan();
10810 return last_token;
10811 } 22600 }
10812 22601
10813 void expect(typename lexer::token_type t) const 22602 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
22603 }
22604
22605 /// @brief inserts element into array
22606 /// @sa https://json.nlohmann.me/api/basic_json/insert/
22607 iterator insert(const_iterator pos, basic_json&& val)
22608 {
22609 return insert(pos, val);
22610 }
22611
22612 /// @brief inserts copies of element into array
22613 /// @sa https://json.nlohmann.me/api/basic_json/insert/
22614 iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
22615 {
22616 // insert only works for arrays
22617 if (JSON_HEDLEY_LIKELY(is_array()))
10814 { 22618 {
10815 if (t != last_token) 22619 // check if iterator pos fits to this JSON value
22620 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
10816 { 22621 {
10817 std::string error_msg = "parse error - unexpected "; 22622 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
10818 error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() +
10819 "'") :
10820 lexer::token_type_name(last_token));
10821 error_msg += "; expected " + lexer::token_type_name(t);
10822 throw std::invalid_argument(error_msg);
10823 } 22623 }
22624
22625 // insert to array and return iterator
22626 return insert_iterator(pos, cnt, val);
10824 } 22627 }
10825 22628
10826 void unexpect(typename lexer::token_type t) const 22629 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
22630 }
22631
22632 /// @brief inserts range of elements into array
22633 /// @sa https://json.nlohmann.me/api/basic_json/insert/
22634 iterator insert(const_iterator pos, const_iterator first, const_iterator last)
22635 {
22636 // insert only works for arrays
22637 if (JSON_HEDLEY_UNLIKELY(!is_array()))
10827 { 22638 {
10828 if (t == last_token) 22639 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
10829 {
10830 std::string error_msg = "parse error - unexpected ";
10831 error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() +
10832 "'") :
10833 lexer::token_type_name(last_token));
10834 throw std::invalid_argument(error_msg);
10835 }
10836 } 22640 }
10837 22641
10838 private: 22642 // check if iterator pos fits to this JSON value
10839 /// current level of recursion 22643 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
10840 int depth = 0; 22644 {
10841 /// callback function 22645 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
10842 const parser_callback_t callback = nullptr; 22646 }
10843 /// the type of the last read token
10844 typename lexer::token_type last_token = lexer::token_type::uninitialized;
10845 /// the lexer
10846 lexer m_lexer;
10847 };
10848 22647
10849 public: 22648 // check if range iterators belong to the same JSON object
10850 /*! 22649 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
10851 @brief JSON Pointer 22650 {
22651 JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
22652 }
10852 22653
10853 A JSON pointer defines a string syntax for identifying a specific value 22654 if (JSON_HEDLEY_UNLIKELY(first.m_object == this))
10854 within a JSON document. It can be used with functions `at` and 22655 {
10855 `operator[]`. Furthermore, JSON pointers are the base for JSON patches. 22656 JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this));
22657 }
10856 22658
10857 @sa [RFC 6901](https://tools.ietf.org/html/rfc6901) 22659 // insert to array and return iterator
22660 return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);
22661 }
10858 22662
10859 @since version 2.0.0 22663 /// @brief inserts elements from initializer list into array
10860 */ 22664 /// @sa https://json.nlohmann.me/api/basic_json/insert/
10861 class json_pointer 22665 iterator insert(const_iterator pos, initializer_list_t ilist)
10862 { 22666 {
10863 /// allow basic_json to access private members 22667 // insert only works for arrays
10864 friend class basic_json; 22668 if (JSON_HEDLEY_UNLIKELY(!is_array()))
10865 22669 {
10866 public: 22670 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
10867 /*! 22671 }
10868 @brief create JSON pointer
10869 22672
10870 Create a JSON pointer according to the syntax described in 22673 // check if iterator pos fits to this JSON value
10871 [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). 22674 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
22675 {
22676 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
22677 }
10872 22678
10873 @param[in] s string representing the JSON pointer; if omitted, the 22679 // insert to array and return iterator
10874 empty string is assumed which references the whole JSON 22680 return insert_iterator(pos, ilist.begin(), ilist.end());
10875 value 22681 }
10876 22682
10877 @throw std::domain_error if reference token is nonempty and does not 22683 /// @brief inserts range of elements into object
10878 begin with a slash (`/`); example: `"JSON pointer must be empty or 22684 /// @sa https://json.nlohmann.me/api/basic_json/insert/
10879 begin with /"` 22685 void insert(const_iterator first, const_iterator last)
10880 @throw std::domain_error if a tilde (`~`) is not followed by `0` 22686 {
10881 (representing `~`) or `1` (representing `/`); example: `"escape error: 22687 // insert only works for objects
10882 ~ must be followed with 0 or 1"` 22688 if (JSON_HEDLEY_UNLIKELY(!is_object()))
22689 {
22690 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
22691 }
10883 22692
10884 @liveexample{The example shows the construction several valid JSON 22693 // check if range iterators belong to the same JSON object
10885 pointers as well as the exceptional behavior.,json_pointer} 22694 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
22695 {
22696 JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
22697 }
10886 22698
10887 @since version 2.0.0 22699 // passed iterators must belong to objects
10888 */ 22700 if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
10889 explicit json_pointer(const std::string& s = "") 22701 {
10890 : reference_tokens(split(s)) 22702 JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this));
10891 {} 22703 }
10892 22704
10893 /*! 22705 m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
10894 @brief return a string representation of the JSON pointer 22706 }
10895 22707
10896 @invariant For each JSON pointer `ptr`, it holds: 22708 /// @brief updates a JSON object from another object, overwriting existing keys
10897 @code {.cpp} 22709 /// @sa https://json.nlohmann.me/api/basic_json/update/
10898 ptr == json_pointer(ptr.to_string()); 22710 void update(const_reference j, bool merge_objects = false)
10899 @endcode 22711 {
22712 update(j.begin(), j.end(), merge_objects);
22713 }
10900 22714
10901 @return a string representation of the JSON pointer 22715 /// @brief updates a JSON object from another object, overwriting existing keys
22716 /// @sa https://json.nlohmann.me/api/basic_json/update/
22717 void update(const_iterator first, const_iterator last, bool merge_objects = false)
22718 {
22719 // implicitly convert null value to an empty object
22720 if (is_null())
22721 {
22722 m_data.m_type = value_t::object;
22723 m_data.m_value.object = create<object_t>();
22724 assert_invariant();
22725 }
10902 22726
10903 @liveexample{The example shows the result of `to_string`., 22727 if (JSON_HEDLEY_UNLIKELY(!is_object()))
10904 json_pointer__to_string} 22728 {
22729 JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", type_name()), this));
22730 }
10905 22731
10906 @since version 2.0.0 22732 // check if range iterators belong to the same JSON object
10907 */ 22733 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
10908 std::string to_string() const noexcept
10909 { 22734 {
10910 return std::accumulate(reference_tokens.begin(), 22735 JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
10911 reference_tokens.end(), std::string{},
10912 [](const std::string & a, const std::string & b)
10913 {
10914 return a + "/" + escape(b);
10915 });
10916 } 22736 }
10917 22737
10918 /// @copydoc to_string() 22738 // passed iterators must belong to objects
10919 operator std::string() const 22739 if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
10920 { 22740 {
10921 return to_string(); 22741 JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", first.m_object->type_name()), first.m_object));
10922 } 22742 }
10923 22743
10924 private: 22744 for (auto it = first; it != last; ++it)
10925 /// remove and return last reference pointer
10926 std::string pop_back()
10927 { 22745 {
10928 if (is_root()) 22746 if (merge_objects && it.value().is_object())
10929 { 22747 {
10930 throw std::domain_error("JSON pointer has no parent"); 22748 auto it2 = m_data.m_value.object->find(it.key());
22749 if (it2 != m_data.m_value.object->end())
22750 {
22751 it2->second.update(it.value(), true);
22752 continue;
22753 }
10931 } 22754 }
10932 22755 m_data.m_value.object->operator[](it.key()) = it.value();
10933 auto last = reference_tokens.back(); 22756#if JSON_DIAGNOSTICS
10934 reference_tokens.pop_back(); 22757 m_data.m_value.object->operator[](it.key()).m_parent = this;
10935 return last; 22758#endif
10936 } 22759 }
22760 }
22761
22762 /// @brief exchanges the values
22763 /// @sa https://json.nlohmann.me/api/basic_json/swap/
22764 void swap(reference other) noexcept (
22765 std::is_nothrow_move_constructible<value_t>::value&&
22766 std::is_nothrow_move_assignable<value_t>::value&&
22767 std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
22768 std::is_nothrow_move_assignable<json_value>::value
22769 )
22770 {
22771 std::swap(m_data.m_type, other.m_data.m_type);
22772 std::swap(m_data.m_value, other.m_data.m_value);
22773
22774 set_parents();
22775 other.set_parents();
22776 assert_invariant();
22777 }
22778
22779 /// @brief exchanges the values
22780 /// @sa https://json.nlohmann.me/api/basic_json/swap/
22781 friend void swap(reference left, reference right) noexcept (
22782 std::is_nothrow_move_constructible<value_t>::value&&
22783 std::is_nothrow_move_assignable<value_t>::value&&
22784 std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
22785 std::is_nothrow_move_assignable<json_value>::value
22786 )
22787 {
22788 left.swap(right);
22789 }
10937 22790
10938 /// return whether pointer points to the root document 22791 /// @brief exchanges the values
10939 bool is_root() const 22792 /// @sa https://json.nlohmann.me/api/basic_json/swap/
22793 void swap(array_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
22794 {
22795 // swap only works for arrays
22796 if (JSON_HEDLEY_LIKELY(is_array()))
10940 { 22797 {
10941 return reference_tokens.empty(); 22798 using std::swap;
22799 swap(*(m_data.m_value.array), other);
10942 } 22800 }
10943 22801 else
10944 json_pointer top() const
10945 { 22802 {
10946 if (is_root()) 22803 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(array_t&) with ", type_name()), this));
10947 { 22804 }
10948 throw std::domain_error("JSON pointer has no parent"); 22805 }
10949 }
10950 22806
10951 json_pointer result = *this; 22807 /// @brief exchanges the values
10952 result.reference_tokens = {reference_tokens[0]}; 22808 /// @sa https://json.nlohmann.me/api/basic_json/swap/
10953 return result; 22809 void swap(object_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
22810 {
22811 // swap only works for objects
22812 if (JSON_HEDLEY_LIKELY(is_object()))
22813 {
22814 using std::swap;
22815 swap(*(m_data.m_value.object), other);
22816 }
22817 else
22818 {
22819 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(object_t&) with ", type_name()), this));
10954 } 22820 }
22821 }
10955 22822
10956 /*! 22823 /// @brief exchanges the values
10957 @brief create and return a reference to the pointed to value 22824 /// @sa https://json.nlohmann.me/api/basic_json/swap/
22825 void swap(string_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
22826 {
22827 // swap only works for strings
22828 if (JSON_HEDLEY_LIKELY(is_string()))
22829 {
22830 using std::swap;
22831 swap(*(m_data.m_value.string), other);
22832 }
22833 else
22834 {
22835 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(string_t&) with ", type_name()), this));
22836 }
22837 }
10958 22838
10959 @complexity Linear in the number of reference tokens. 22839 /// @brief exchanges the values
10960 */ 22840 /// @sa https://json.nlohmann.me/api/basic_json/swap/
10961 reference get_and_create(reference j) const 22841 void swap(binary_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
22842 {
22843 // swap only works for strings
22844 if (JSON_HEDLEY_LIKELY(is_binary()))
10962 { 22845 {
10963 pointer result = &j; 22846 using std::swap;
22847 swap(*(m_data.m_value.binary), other);
22848 }
22849 else
22850 {
22851 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t&) with ", type_name()), this));
22852 }
22853 }
10964 22854
10965 // in case no reference tokens exist, return a reference to the 22855 /// @brief exchanges the values
10966 // JSON value j which will be overwritten by a primitive value 22856 /// @sa https://json.nlohmann.me/api/basic_json/swap/
10967 for (const auto& reference_token : reference_tokens) 22857 void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape)
10968 { 22858 {
10969 switch (result->m_type) 22859 // swap only works for strings
10970 { 22860 if (JSON_HEDLEY_LIKELY(is_binary()))
10971 case value_t::null: 22861 {
10972 { 22862 using std::swap;
10973 if (reference_token == "0") 22863 swap(*(m_data.m_value.binary), other);
10974 { 22864 }
10975 // start a new array if reference token is 0 22865 else
10976 result = &result->operator[](0); 22866 {
10977 } 22867 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t::container_type&) with ", type_name()), this));
10978 else 22868 }
10979 { 22869 }
10980 // start a new object otherwise
10981 result = &result->operator[](reference_token);
10982 }
10983 break;
10984 }
10985 22870
10986 case value_t::object: 22871 /// @}
10987 {
10988 // create an entry in the object
10989 result = &result->operator[](reference_token);
10990 break;
10991 }
10992 22872
10993 case value_t::array: 22873 //////////////////////////////////////////
10994 { 22874 // lexicographical comparison operators //
10995 // create an entry in the array 22875 //////////////////////////////////////////
10996 result = &result->operator[](static_cast<size_type>(std::stoi(reference_token)));
10997 break;
10998 }
10999 22876
11000 /* 22877 /// @name lexicographical comparison operators
11001 The following code is only reached if there exists a 22878 /// @{
11002 reference token _and_ the current value is primitive. In
11003 this case, we have an error situation, because primitive
11004 values may only occur as single value; that is, with an
11005 empty list of reference tokens.
11006 */
11007 default:
11008 {
11009 throw std::domain_error("invalid value to unflatten");
11010 }
11011 }
11012 }
11013 22879
11014 return *result; 22880 // note parentheses around operands are necessary; see
22881 // https://github.com/nlohmann/json/issues/1530
22882#define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result) \
22883 const auto lhs_type = lhs.type(); \
22884 const auto rhs_type = rhs.type(); \
22885 \
22886 if (lhs_type == rhs_type) /* NOLINT(readability/braces) */ \
22887 { \
22888 switch (lhs_type) \
22889 { \
22890 case value_t::array: \
22891 return (*lhs.m_data.m_value.array) op (*rhs.m_data.m_value.array); \
22892 \
22893 case value_t::object: \
22894 return (*lhs.m_data.m_value.object) op (*rhs.m_data.m_value.object); \
22895 \
22896 case value_t::null: \
22897 return (null_result); \
22898 \
22899 case value_t::string: \
22900 return (*lhs.m_data.m_value.string) op (*rhs.m_data.m_value.string); \
22901 \
22902 case value_t::boolean: \
22903 return (lhs.m_data.m_value.boolean) op (rhs.m_data.m_value.boolean); \
22904 \
22905 case value_t::number_integer: \
22906 return (lhs.m_data.m_value.number_integer) op (rhs.m_data.m_value.number_integer); \
22907 \
22908 case value_t::number_unsigned: \
22909 return (lhs.m_data.m_value.number_unsigned) op (rhs.m_data.m_value.number_unsigned); \
22910 \
22911 case value_t::number_float: \
22912 return (lhs.m_data.m_value.number_float) op (rhs.m_data.m_value.number_float); \
22913 \
22914 case value_t::binary: \
22915 return (*lhs.m_data.m_value.binary) op (*rhs.m_data.m_value.binary); \
22916 \
22917 case value_t::discarded: \
22918 default: \
22919 return (unordered_result); \
22920 } \
22921 } \
22922 else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) \
22923 { \
22924 return static_cast<number_float_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_float; \
22925 } \
22926 else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) \
22927 { \
22928 return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_integer); \
22929 } \
22930 else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) \
22931 { \
22932 return static_cast<number_float_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_float; \
22933 } \
22934 else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) \
22935 { \
22936 return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_unsigned); \
22937 } \
22938 else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \
22939 { \
22940 return static_cast<number_integer_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \
22941 } \
22942 else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) \
22943 { \
22944 return lhs.m_data.m_value.number_integer op static_cast<number_integer_t>(rhs.m_data.m_value.number_unsigned); \
22945 } \
22946 else if(compares_unordered(lhs, rhs))\
22947 {\
22948 return (unordered_result);\
22949 }\
22950 \
22951 return (default_result);
22952
22953 JSON_PRIVATE_UNLESS_TESTED:
22954 // returns true if:
22955 // - any operand is NaN and the other operand is of number type
22956 // - any operand is discarded
22957 // in legacy mode, discarded values are considered ordered if
22958 // an operation is computed as an odd number of inverses of others
22959 static bool compares_unordered(const_reference lhs, const_reference rhs, bool inverse = false) noexcept
22960 {
22961 if ((lhs.is_number_float() && std::isnan(lhs.m_data.m_value.number_float) && rhs.is_number())
22962 || (rhs.is_number_float() && std::isnan(rhs.m_data.m_value.number_float) && lhs.is_number()))
22963 {
22964 return true;
11015 } 22965 }
22966#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
22967 return (lhs.is_discarded() || rhs.is_discarded()) && !inverse;
22968#else
22969 static_cast<void>(inverse);
22970 return lhs.is_discarded() || rhs.is_discarded();
22971#endif
22972 }
22973
22974 private:
22975 bool compares_unordered(const_reference rhs, bool inverse = false) const noexcept
22976 {
22977 return compares_unordered(*this, rhs, inverse);
22978 }
22979
22980 public:
22981#if JSON_HAS_THREE_WAY_COMPARISON
22982 /// @brief comparison: equal
22983 /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
22984 bool operator==(const_reference rhs) const noexcept
22985 {
22986#ifdef __GNUC__
22987#pragma GCC diagnostic push
22988#pragma GCC diagnostic ignored "-Wfloat-equal"
22989#endif
22990 const_reference lhs = *this;
22991 JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
22992#ifdef __GNUC__
22993#pragma GCC diagnostic pop
22994#endif
22995 }
11016 22996
11017 /*! 22997 /// @brief comparison: equal
11018 @brief return a reference to the pointed to value 22998 /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
22999 template<typename ScalarType>
23000 requires std::is_scalar_v<ScalarType>
23001 bool operator==(ScalarType rhs) const noexcept
23002 {
23003 return *this == basic_json(rhs);
23004 }
11019 23005
11020 @note This version does not throw if a value is not present, but tries 23006 /// @brief comparison: not equal
11021 to create nested values instead. For instance, calling this function 23007 /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
11022 with pointer `"/this/that"` on a null value is equivalent to calling 23008 bool operator!=(const_reference rhs) const noexcept
11023 `operator[]("this").operator[]("that")` on that value, effectively 23009 {
11024 changing the null value to an object. 23010 if (compares_unordered(rhs, true))
23011 {
23012 return false;
23013 }
23014 return !operator==(rhs);
23015 }
11025 23016
11026 @param[in] ptr a JSON value 23017 /// @brief comparison: 3-way
23018 /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
23019 std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
23020 {
23021 const_reference lhs = *this;
23022 // default_result is used if we cannot compare values. In that case,
23023 // we compare types.
23024 JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD*
23025 std::partial_ordering::equivalent,
23026 std::partial_ordering::unordered,
23027 lhs_type <=> rhs_type) // *NOPAD*
23028 }
11027 23029
11028 @return reference to the JSON value pointed to by the JSON pointer 23030 /// @brief comparison: 3-way
23031 /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
23032 template<typename ScalarType>
23033 requires std::is_scalar_v<ScalarType>
23034 std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD*
23035 {
23036 return *this <=> basic_json(rhs); // *NOPAD*
23037 }
11029 23038
11030 @complexity Linear in the length of the JSON pointer. 23039#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
23040 // all operators that are computed as an odd number of inverses of others
23041 // need to be overloaded to emulate the legacy comparison behavior
11031 23042
11032 @throw std::out_of_range if the JSON pointer can not be resolved 23043 /// @brief comparison: less than or equal
11033 @throw std::domain_error if an array index begins with '0' 23044 /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
11034 @throw std::invalid_argument if an array index was not a number 23045 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
11035 */ 23046 bool operator<=(const_reference rhs) const noexcept
11036 reference get_unchecked(pointer ptr) const 23047 {
23048 if (compares_unordered(rhs, true))
11037 { 23049 {
11038 for (const auto& reference_token : reference_tokens) 23050 return false;
11039 { 23051 }
11040 // convert null values to arrays or objects before continuing 23052 return !(rhs < *this);
11041 if (ptr->m_type == value_t::null) 23053 }
11042 {
11043 // check if reference token is a number
11044 const bool nums = std::all_of(reference_token.begin(),
11045 reference_token.end(),
11046 [](const char x)
11047 {
11048 return std::isdigit(x);
11049 });
11050 23054
11051 // change value to array for numbers or "-" or to object 23055 /// @brief comparison: less than or equal
11052 // otherwise 23056 /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
11053 if (nums or reference_token == "-") 23057 template<typename ScalarType>
11054 { 23058 requires std::is_scalar_v<ScalarType>
11055 *ptr = value_t::array; 23059 bool operator<=(ScalarType rhs) const noexcept
11056 } 23060 {
11057 else 23061 return *this <= basic_json(rhs);
11058 { 23062 }
11059 *ptr = value_t::object;
11060 }
11061 }
11062 23063
11063 switch (ptr->m_type) 23064 /// @brief comparison: greater than or equal
11064 { 23065 /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
11065 case value_t::object: 23066 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
11066 { 23067 bool operator>=(const_reference rhs) const noexcept
11067 // use unchecked object access 23068 {
11068 ptr = &ptr->operator[](reference_token); 23069 if (compares_unordered(rhs, true))
11069 break; 23070 {
11070 } 23071 return false;
23072 }
23073 return !(*this < rhs);
23074 }
11071 23075
11072 case value_t::array: 23076 /// @brief comparison: greater than or equal
11073 { 23077 /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
11074 // error condition (cf. RFC 6901, Sect. 4) 23078 template<typename ScalarType>
11075 if (reference_token.size() > 1 and reference_token[0] == '0') 23079 requires std::is_scalar_v<ScalarType>
11076 { 23080 bool operator>=(ScalarType rhs) const noexcept
11077 throw std::domain_error("array index must not begin with '0'"); 23081 {
11078 } 23082 return *this >= basic_json(rhs);
23083 }
23084#endif
23085#else
23086 /// @brief comparison: equal
23087 /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
23088 friend bool operator==(const_reference lhs, const_reference rhs) noexcept
23089 {
23090#ifdef __GNUC__
23091#pragma GCC diagnostic push
23092#pragma GCC diagnostic ignored "-Wfloat-equal"
23093#endif
23094 JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
23095#ifdef __GNUC__
23096#pragma GCC diagnostic pop
23097#endif
23098 }
11079 23099
11080 if (reference_token == "-") 23100 /// @brief comparison: equal
11081 { 23101 /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
11082 // explicityly treat "-" as index beyond the end 23102 template<typename ScalarType, typename std::enable_if<
11083 ptr = &ptr->operator[](ptr->m_value.array->size()); 23103 std::is_scalar<ScalarType>::value, int>::type = 0>
11084 } 23104 friend bool operator==(const_reference lhs, ScalarType rhs) noexcept
11085 else 23105 {
11086 { 23106 return lhs == basic_json(rhs);
11087 // convert array index to number; unchecked access 23107 }
11088 ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
11089 }
11090 break;
11091 }
11092 23108
11093 default: 23109 /// @brief comparison: equal
11094 { 23110 /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
11095 throw std::out_of_range("unresolved reference token '" + reference_token + "'"); 23111 template<typename ScalarType, typename std::enable_if<
11096 } 23112 std::is_scalar<ScalarType>::value, int>::type = 0>
11097 } 23113 friend bool operator==(ScalarType lhs, const_reference rhs) noexcept
11098 } 23114 {
23115 return basic_json(lhs) == rhs;
23116 }
11099 23117
11100 return *ptr; 23118 /// @brief comparison: not equal
23119 /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
23120 friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
23121 {
23122 if (compares_unordered(lhs, rhs, true))
23123 {
23124 return false;
11101 } 23125 }
23126 return !(lhs == rhs);
23127 }
11102 23128
11103 reference get_checked(pointer ptr) const 23129 /// @brief comparison: not equal
11104 { 23130 /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
11105 for (const auto& reference_token : reference_tokens) 23131 template<typename ScalarType, typename std::enable_if<
11106 { 23132 std::is_scalar<ScalarType>::value, int>::type = 0>
11107 switch (ptr->m_type) 23133 friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept
11108 { 23134 {
11109 case value_t::object: 23135 return lhs != basic_json(rhs);
11110 { 23136 }
11111 // note: at performs range check
11112 ptr = &ptr->at(reference_token);
11113 break;
11114 }
11115 23137
11116 case value_t::array: 23138 /// @brief comparison: not equal
11117 { 23139 /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
11118 if (reference_token == "-") 23140 template<typename ScalarType, typename std::enable_if<
11119 { 23141 std::is_scalar<ScalarType>::value, int>::type = 0>
11120 // "-" always fails the range check 23142 friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept
11121 throw std::out_of_range("array index '-' (" + 23143 {
11122 std::to_string(ptr->m_value.array->size()) + 23144 return basic_json(lhs) != rhs;
11123 ") is out of range"); 23145 }
11124 }
11125 23146
11126 // error condition (cf. RFC 6901, Sect. 4) 23147 /// @brief comparison: less than
11127 if (reference_token.size() > 1 and reference_token[0] == '0') 23148 /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
11128 { 23149 friend bool operator<(const_reference lhs, const_reference rhs) noexcept
11129 throw std::domain_error("array index must not begin with '0'"); 23150 {
11130 } 23151 // default_result is used if we cannot compare values. In that case,
23152 // we compare types. Note we have to call the operator explicitly,
23153 // because MSVC has problems otherwise.
23154 JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type))
23155 }
11131 23156
11132 // note: at performs range check 23157 /// @brief comparison: less than
11133 ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token))); 23158 /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
11134 break; 23159 template<typename ScalarType, typename std::enable_if<
11135 } 23160 std::is_scalar<ScalarType>::value, int>::type = 0>
23161 friend bool operator<(const_reference lhs, ScalarType rhs) noexcept
23162 {
23163 return lhs < basic_json(rhs);
23164 }
11136 23165
11137 default: 23166 /// @brief comparison: less than
11138 { 23167 /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
11139 throw std::out_of_range("unresolved reference token '" + reference_token + "'"); 23168 template<typename ScalarType, typename std::enable_if<
11140 } 23169 std::is_scalar<ScalarType>::value, int>::type = 0>
11141 } 23170 friend bool operator<(ScalarType lhs, const_reference rhs) noexcept
11142 } 23171 {
23172 return basic_json(lhs) < rhs;
23173 }
11143 23174
11144 return *ptr; 23175 /// @brief comparison: less than or equal
23176 /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
23177 friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
23178 {
23179 if (compares_unordered(lhs, rhs, true))
23180 {
23181 return false;
11145 } 23182 }
23183 return !(rhs < lhs);
23184 }
11146 23185
11147 /*! 23186 /// @brief comparison: less than or equal
11148 @brief return a const reference to the pointed to value 23187 /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
23188 template<typename ScalarType, typename std::enable_if<
23189 std::is_scalar<ScalarType>::value, int>::type = 0>
23190 friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept
23191 {
23192 return lhs <= basic_json(rhs);
23193 }
11149 23194
11150 @param[in] ptr a JSON value 23195 /// @brief comparison: less than or equal
23196 /// @sa https://json.nlohmann.me/api/basic_json/operator_le/
23197 template<typename ScalarType, typename std::enable_if<
23198 std::is_scalar<ScalarType>::value, int>::type = 0>
23199 friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept
23200 {
23201 return basic_json(lhs) <= rhs;
23202 }
11151 23203
11152 @return const reference to the JSON value pointed to by the JSON 23204 /// @brief comparison: greater than
11153 pointer 23205 /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
11154 */ 23206 friend bool operator>(const_reference lhs, const_reference rhs) noexcept
11155 const_reference get_unchecked(const_pointer ptr) const 23207 {
23208 // double inverse
23209 if (compares_unordered(lhs, rhs))
11156 { 23210 {
11157 for (const auto& reference_token : reference_tokens) 23211 return false;
11158 { 23212 }
11159 switch (ptr->m_type) 23213 return !(lhs <= rhs);
11160 { 23214 }
11161 case value_t::object:
11162 {
11163 // use unchecked object access
11164 ptr = &ptr->operator[](reference_token);
11165 break;
11166 }
11167 23215
11168 case value_t::array: 23216 /// @brief comparison: greater than
11169 { 23217 /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
11170 if (reference_token == "-") 23218 template<typename ScalarType, typename std::enable_if<
11171 { 23219 std::is_scalar<ScalarType>::value, int>::type = 0>
11172 // "-" cannot be used for const access 23220 friend bool operator>(const_reference lhs, ScalarType rhs) noexcept
11173 throw std::out_of_range("array index '-' (" + 23221 {
11174 std::to_string(ptr->m_value.array->size()) + 23222 return lhs > basic_json(rhs);
11175 ") is out of range"); 23223 }
11176 }
11177 23224
11178 // error condition (cf. RFC 6901, Sect. 4) 23225 /// @brief comparison: greater than
11179 if (reference_token.size() > 1 and reference_token[0] == '0') 23226 /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
11180 { 23227 template<typename ScalarType, typename std::enable_if<
11181 throw std::domain_error("array index must not begin with '0'"); 23228 std::is_scalar<ScalarType>::value, int>::type = 0>
11182 } 23229 friend bool operator>(ScalarType lhs, const_reference rhs) noexcept
23230 {
23231 return basic_json(lhs) > rhs;
23232 }
11183 23233
11184 // use unchecked array access 23234 /// @brief comparison: greater than or equal
11185 ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token))); 23235 /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
11186 break; 23236 friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
11187 } 23237 {
23238 if (compares_unordered(lhs, rhs, true))
23239 {
23240 return false;
23241 }
23242 return !(lhs < rhs);
23243 }
11188 23244
11189 default: 23245 /// @brief comparison: greater than or equal
11190 { 23246 /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
11191 throw std::out_of_range("unresolved reference token '" + reference_token + "'"); 23247 template<typename ScalarType, typename std::enable_if<
11192 } 23248 std::is_scalar<ScalarType>::value, int>::type = 0>
11193 } 23249 friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept
11194 } 23250 {
23251 return lhs >= basic_json(rhs);
23252 }
11195 23253
11196 return *ptr; 23254 /// @brief comparison: greater than or equal
11197 } 23255 /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
23256 template<typename ScalarType, typename std::enable_if<
23257 std::is_scalar<ScalarType>::value, int>::type = 0>
23258 friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept
23259 {
23260 return basic_json(lhs) >= rhs;
23261 }
23262#endif
11198 23263
11199 const_reference get_checked(const_pointer ptr) const 23264#undef JSON_IMPLEMENT_OPERATOR
11200 {
11201 for (const auto& reference_token : reference_tokens)
11202 {
11203 switch (ptr->m_type)
11204 {
11205 case value_t::object:
11206 {
11207 // note: at performs range check
11208 ptr = &ptr->at(reference_token);
11209 break;
11210 }
11211 23265
11212 case value_t::array: 23266 /// @}
11213 {
11214 if (reference_token == "-")
11215 {
11216 // "-" always fails the range check
11217 throw std::out_of_range("array index '-' (" +
11218 std::to_string(ptr->m_value.array->size()) +
11219 ") is out of range");
11220 }
11221 23267
11222 // error condition (cf. RFC 6901, Sect. 4) 23268 ///////////////////
11223 if (reference_token.size() > 1 and reference_token[0] == '0') 23269 // serialization //
11224 { 23270 ///////////////////
11225 throw std::domain_error("array index must not begin with '0'");
11226 }
11227 23271
11228 // note: at performs range check 23272 /// @name serialization
11229 ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token))); 23273 /// @{
11230 break; 23274#ifndef JSON_NO_IO
11231 } 23275 /// @brief serialize to stream
23276 /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
23277 friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
23278 {
23279 // read width member and use it as indentation parameter if nonzero
23280 const bool pretty_print = o.width() > 0;
23281 const auto indentation = pretty_print ? o.width() : 0;
11232 23282
11233 default: 23283 // reset width to 0 for subsequent calls to this stream
11234 { 23284 o.width(0);
11235 throw std::out_of_range("unresolved reference token '" + reference_token + "'");
11236 }
11237 }
11238 }
11239 23285
11240 return *ptr; 23286 // do the actual serialization
11241 } 23287 serializer s(detail::output_adapter<char>(o), o.fill());
23288 s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
23289 return o;
23290 }
11242 23291
11243 /// split the string input to reference tokens 23292 /// @brief serialize to stream
11244 static std::vector<std::string> split(const std::string& reference_string) 23293 /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/
11245 { 23294 /// @deprecated This function is deprecated since 3.0.0 and will be removed in
11246 std::vector<std::string> result; 23295 /// version 4.0.0 of the library. Please use
23296 /// operator<<(std::ostream&, const basic_json&) instead; that is,
23297 /// replace calls like `j >> o;` with `o << j;`.
23298 JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))
23299 friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
23300 {
23301 return o << j;
23302 }
23303#endif // JSON_NO_IO
23304 /// @}
11247 23305
11248 // special case: empty reference string -> no reference tokens 23306 /////////////////////
11249 if (reference_string.empty()) 23307 // deserialization //
11250 { 23308 /////////////////////
11251 return result;
11252 }
11253 23309
11254 // check if nonempty reference string begins with slash 23310 /// @name deserialization
11255 if (reference_string[0] != '/') 23311 /// @{
11256 {
11257 throw std::domain_error("JSON pointer must be empty or begin with '/'");
11258 }
11259 23312
11260 // extract the reference tokens: 23313 /// @brief deserialize from a compatible input
11261 // - slash: position of the last read slash (or end of string) 23314 /// @sa https://json.nlohmann.me/api/basic_json/parse/
11262 // - start: position after the previous slash 23315 template<typename InputType>
11263 for ( 23316 JSON_HEDLEY_WARN_UNUSED_RESULT
11264 // search for the first slash after the first character 23317 static basic_json parse(InputType&& i,
11265 size_t slash = reference_string.find_first_of("/", 1), 23318 const parser_callback_t cb = nullptr,
11266 // set the beginning of the first reference token 23319 const bool allow_exceptions = true,
11267 start = 1; 23320 const bool ignore_comments = false)
11268 // we can stop if start == string::npos+1 = 0 23321 {
11269 start != 0; 23322 basic_json result;
11270 // set the beginning of the next reference token 23323 parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions, ignore_comments).parse(true, result);
11271 // (will eventually be 0 if slash == std::string::npos) 23324 return result;
11272 start = slash + 1, 23325 }
11273 // find next slash
11274 slash = reference_string.find_first_of("/", start))
11275 {
11276 // use the text between the beginning of the reference token
11277 // (start) and the last slash (slash).
11278 auto reference_token = reference_string.substr(start, slash - start);
11279 23326
11280 // check reference tokens are properly escaped 23327 /// @brief deserialize from a pair of character iterators
11281 for (size_t pos = reference_token.find_first_of("~"); 23328 /// @sa https://json.nlohmann.me/api/basic_json/parse/
11282 pos != std::string::npos; 23329 template<typename IteratorType>
11283 pos = reference_token.find_first_of("~", pos + 1)) 23330 JSON_HEDLEY_WARN_UNUSED_RESULT
11284 { 23331 static basic_json parse(IteratorType first,
11285 assert(reference_token[pos] == '~'); 23332 IteratorType last,
23333 const parser_callback_t cb = nullptr,
23334 const bool allow_exceptions = true,
23335 const bool ignore_comments = false)
23336 {
23337 basic_json result;
23338 parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result);
23339 return result;
23340 }
11286 23341
11287 // ~ must be followed by 0 or 1 23342 JSON_HEDLEY_WARN_UNUSED_RESULT
11288 if (pos == reference_token.size() - 1 or 23343 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
11289 (reference_token[pos + 1] != '0' and 23344 static basic_json parse(detail::span_input_adapter&& i,
11290 reference_token[pos + 1] != '1')) 23345 const parser_callback_t cb = nullptr,
11291 { 23346 const bool allow_exceptions = true,
11292 throw std::domain_error("escape error: '~' must be followed with '0' or '1'"); 23347 const bool ignore_comments = false)
11293 } 23348 {
11294 } 23349 basic_json result;
23350 parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result);
23351 return result;
23352 }
11295 23353
11296 // finally, store the reference token 23354 /// @brief check if the input is valid JSON
11297 unescape(reference_token); 23355 /// @sa https://json.nlohmann.me/api/basic_json/accept/
11298 result.push_back(reference_token); 23356 template<typename InputType>
11299 } 23357 static bool accept(InputType&& i,
23358 const bool ignore_comments = false)
23359 {
23360 return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);
23361 }
11300 23362
11301 return result; 23363 /// @brief check if the input is valid JSON
11302 } 23364 /// @sa https://json.nlohmann.me/api/basic_json/accept/
23365 template<typename IteratorType>
23366 static bool accept(IteratorType first, IteratorType last,
23367 const bool ignore_comments = false)
23368 {
23369 return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);
23370 }
11303 23371
11304 private: 23372 JSON_HEDLEY_WARN_UNUSED_RESULT
11305 /*! 23373 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
11306 @brief replace all occurrences of a substring by another string 23374 static bool accept(detail::span_input_adapter&& i,
23375 const bool ignore_comments = false)
23376 {
23377 return parser(i.get(), nullptr, false, ignore_comments).accept(true);
23378 }
23379
23380 /// @brief generate SAX events
23381 /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
23382 template <typename InputType, typename SAX>
23383 JSON_HEDLEY_NON_NULL(2)
23384 static bool sax_parse(InputType&& i, SAX* sax,
23385 input_format_t format = input_format_t::json,
23386 const bool strict = true,
23387 const bool ignore_comments = false)
23388 {
23389 auto ia = detail::input_adapter(std::forward<InputType>(i));
23390 return format == input_format_t::json
23391 ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
23392 : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
23393 }
11307 23394
11308 @param[in,out] s the string to manipulate; changed so that all 23395 /// @brief generate SAX events
11309 occurrences of @a f are replaced with @a t 23396 /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
11310 @param[in] f the substring to replace with @a t 23397 template<class IteratorType, class SAX>
11311 @param[in] t the string to replace @a f 23398 JSON_HEDLEY_NON_NULL(3)
23399 static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
23400 input_format_t format = input_format_t::json,
23401 const bool strict = true,
23402 const bool ignore_comments = false)
23403 {
23404 auto ia = detail::input_adapter(std::move(first), std::move(last));
23405 return format == input_format_t::json
23406 ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
23407 : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
23408 }
11312 23409
11313 @pre The search string @a f must not be empty. 23410 /// @brief generate SAX events
23411 /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/
23412 /// @deprecated This function is deprecated since 3.8.0 and will be removed in
23413 /// version 4.0.0 of the library. Please use
23414 /// sax_parse(ptr, ptr + len) instead.
23415 template <typename SAX>
23416 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...))
23417 JSON_HEDLEY_NON_NULL(2)
23418 static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
23419 input_format_t format = input_format_t::json,
23420 const bool strict = true,
23421 const bool ignore_comments = false)
23422 {
23423 auto ia = i.get();
23424 return format == input_format_t::json
23425 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
23426 ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
23427 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
23428 : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
23429 }
23430#ifndef JSON_NO_IO
23431 /// @brief deserialize from stream
23432 /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
23433 /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in
23434 /// version 4.0.0 of the library. Please use
23435 /// operator>>(std::istream&, basic_json&) instead; that is,
23436 /// replace calls like `j << i;` with `i >> j;`.
23437 JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))
23438 friend std::istream& operator<<(basic_json& j, std::istream& i)
23439 {
23440 return operator>>(i, j);
23441 }
11314 23442
11315 @since version 2.0.0 23443 /// @brief deserialize from stream
11316 */ 23444 /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/
11317 static void replace_substring(std::string& s, 23445 friend std::istream& operator>>(std::istream& i, basic_json& j)
11318 const std::string& f, 23446 {
11319 const std::string& t) 23447 parser(detail::input_adapter(i)).parse(false, j);
11320 { 23448 return i;
11321 assert(not f.empty()); 23449 }
23450#endif // JSON_NO_IO
23451 /// @}
11322 23452
11323 for ( 23453 ///////////////////////////
11324 size_t pos = s.find(f); // find first occurrence of f 23454 // convenience functions //
11325 pos != std::string::npos; // make sure f was found 23455 ///////////////////////////
11326 s.replace(pos, f.size(), t), // replace with t
11327 pos = s.find(f, pos + t.size()) // find next occurrence of f
11328 );
11329 }
11330 23456
11331 /// escape tilde and slash 23457 /// @brief return the type as string
11332 static std::string escape(std::string s) 23458 /// @sa https://json.nlohmann.me/api/basic_json/type_name/
23459 JSON_HEDLEY_RETURNS_NON_NULL
23460 const char* type_name() const noexcept
23461 {
23462 switch (m_data.m_type)
11333 { 23463 {
11334 // escape "~"" to "~0" and "/" to "~1" 23464 case value_t::null:
11335 replace_substring(s, "~", "~0"); 23465 return "null";
11336 replace_substring(s, "/", "~1"); 23466 case value_t::object:
11337 return s; 23467 return "object";
23468 case value_t::array:
23469 return "array";
23470 case value_t::string:
23471 return "string";
23472 case value_t::boolean:
23473 return "boolean";
23474 case value_t::binary:
23475 return "binary";
23476 case value_t::discarded:
23477 return "discarded";
23478 case value_t::number_integer:
23479 case value_t::number_unsigned:
23480 case value_t::number_float:
23481 default:
23482 return "number";
11338 } 23483 }
23484 }
11339 23485
11340 /// unescape tilde and slash 23486 JSON_PRIVATE_UNLESS_TESTED:
11341 static void unescape(std::string& s) 23487 //////////////////////
11342 { 23488 // member variables //
11343 // first transform any occurrence of the sequence '~1' to '/' 23489 //////////////////////
11344 replace_substring(s, "~1", "/");
11345 // then transform any occurrence of the sequence '~0' to '~'
11346 replace_substring(s, "~0", "~");
11347 }
11348 23490
11349 /*! 23491 struct data
11350 @param[in] reference_string the reference string to the current value 23492 {
11351 @param[in] value the value to consider 23493 /// the type of the current element
11352 @param[in,out] result the result object to insert values to 23494 value_t m_type = value_t::null;
11353 23495
11354 @note Empty objects or arrays are flattened to `null`. 23496 /// the value of the current element
11355 */ 23497 json_value m_value = {};
11356 static void flatten(const std::string& reference_string,
11357 const basic_json& value,
11358 basic_json& result)
11359 {
11360 switch (value.m_type)
11361 {
11362 case value_t::array:
11363 {
11364 if (value.m_value.array->empty())
11365 {
11366 // flatten empty array as null
11367 result[reference_string] = nullptr;
11368 }
11369 else
11370 {
11371 // iterate array and use index as reference string
11372 for (size_t i = 0; i < value.m_value.array->size(); ++i)
11373 {
11374 flatten(reference_string + "/" + std::to_string(i),
11375 value.m_value.array->operator[](i), result);
11376 }
11377 }
11378 break;
11379 }
11380 23498
11381 case value_t::object: 23499 data(const value_t v)
11382 { 23500 : m_type(v), m_value(v)
11383 if (value.m_value.object->empty()) 23501 {
11384 { 23502 }
11385 // flatten empty object as null
11386 result[reference_string] = nullptr;
11387 }
11388 else
11389 {
11390 // iterate object and use keys as reference string
11391 for (const auto& element : *value.m_value.object)
11392 {
11393 flatten(reference_string + "/" + escape(element.first),
11394 element.second, result);
11395 }
11396 }
11397 break;
11398 }
11399 23503
11400 default: 23504 data(size_type cnt, const basic_json& val)
11401 { 23505 : m_type(value_t::array)
11402 // add primitive value with its reference string 23506 {
11403 result[reference_string] = value; 23507 m_value.array = create<array_t>(cnt, val);
11404 break;
11405 }
11406 }
11407 } 23508 }
11408 23509
11409 /*! 23510 data() noexcept = default;
11410 @param[in] value flattened JSON 23511 data(data&&) noexcept = default;
23512 data(const data&) noexcept = delete;
23513 data& operator=(data&&) noexcept = delete;
23514 data& operator=(const data&) noexcept = delete;
11411 23515
11412 @return unflattened JSON 23516 ~data() noexcept
11413 */
11414 static basic_json unflatten(const basic_json& value)
11415 { 23517 {
11416 if (not value.is_object()) 23518 m_value.destroy(m_type);
11417 { 23519 }
11418 throw std::domain_error("only objects can be unflattened"); 23520 };
11419 }
11420 23521
11421 basic_json result; 23522 data m_data = {};
11422 23523
11423 // iterate the JSON object values 23524#if JSON_DIAGNOSTICS
11424 for (const auto& element : *value.m_value.object) 23525 /// a pointer to a parent value (for debugging purposes)
11425 { 23526 basic_json* m_parent = nullptr;
11426 if (not element.second.is_primitive()) 23527#endif
11427 {
11428 throw std::domain_error("values in object must be primitive");
11429 }
11430 23528
11431 // assign value to reference pointed to by JSON pointer; Note 23529 //////////////////////////////////////////
11432 // that if the JSON pointer is "" (i.e., points to the whole 23530 // binary serialization/deserialization //
11433 // value), function get_and_create returns a reference to 23531 //////////////////////////////////////////
11434 // result itself. An assignment will then create a primitive
11435 // value.
11436 json_pointer(element.first).get_and_create(result) = element.second;
11437 }
11438 23532
11439 return result; 23533 /// @name binary serialization/deserialization support
11440 } 23534 /// @{
11441 23535
11442 private: 23536 public:
11443 /// the reference tokens 23537 /// @brief create a CBOR serialization of a given JSON value
11444 std::vector<std::string> reference_tokens {}; 23538 /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
11445 }; 23539 static std::vector<std::uint8_t> to_cbor(const basic_json& j)
23540 {
23541 std::vector<std::uint8_t> result;
23542 to_cbor(j, result);
23543 return result;
23544 }
11446 23545
11447 ////////////////////////// 23546 /// @brief create a CBOR serialization of a given JSON value
11448 // JSON Pointer support // 23547 /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
11449 ////////////////////////// 23548 static void to_cbor(const basic_json& j, detail::output_adapter<std::uint8_t> o)
23549 {
23550 binary_writer<std::uint8_t>(o).write_cbor(j);
23551 }
11450 23552
11451 /// @name JSON Pointer functions 23553 /// @brief create a CBOR serialization of a given JSON value
11452 /// @{ 23554 /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/
23555 static void to_cbor(const basic_json& j, detail::output_adapter<char> o)
23556 {
23557 binary_writer<char>(o).write_cbor(j);
23558 }
11453 23559
11454 /*! 23560 /// @brief create a MessagePack serialization of a given JSON value
11455 @brief access specified element via JSON Pointer 23561 /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
23562 static std::vector<std::uint8_t> to_msgpack(const basic_json& j)
23563 {
23564 std::vector<std::uint8_t> result;
23565 to_msgpack(j, result);
23566 return result;
23567 }
11456 23568
11457 Uses a JSON pointer to retrieve a reference to the respective JSON value. 23569 /// @brief create a MessagePack serialization of a given JSON value
11458 No bound checking is performed. Similar to @ref operator[](const typename 23570 /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
11459 object_t::key_type&), `null` values are created in arrays and objects if 23571 static void to_msgpack(const basic_json& j, detail::output_adapter<std::uint8_t> o)
11460 necessary. 23572 {
23573 binary_writer<std::uint8_t>(o).write_msgpack(j);
23574 }
11461 23575
11462 In particular: 23576 /// @brief create a MessagePack serialization of a given JSON value
11463 - If the JSON pointer points to an object key that does not exist, it 23577 /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/
11464 is created an filled with a `null` value before a reference to it 23578 static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)
11465 is returned. 23579 {
11466 - If the JSON pointer points to an array index that does not exist, it 23580 binary_writer<char>(o).write_msgpack(j);
11467 is created an filled with a `null` value before a reference to it 23581 }
11468 is returned. All indices between the current maximum and the given
11469 index are also filled with `null`.
11470 - The special value `-` is treated as a synonym for the index past the
11471 end.
11472 23582
11473 @param[in] ptr a JSON pointer 23583 /// @brief create a UBJSON serialization of a given JSON value
23584 /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
23585 static std::vector<std::uint8_t> to_ubjson(const basic_json& j,
23586 const bool use_size = false,
23587 const bool use_type = false)
23588 {
23589 std::vector<std::uint8_t> result;
23590 to_ubjson(j, result, use_size, use_type);
23591 return result;
23592 }
11474 23593
11475 @return reference to the element pointed to by @a ptr 23594 /// @brief create a UBJSON serialization of a given JSON value
23595 /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
23596 static void to_ubjson(const basic_json& j, detail::output_adapter<std::uint8_t> o,
23597 const bool use_size = false, const bool use_type = false)
23598 {
23599 binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type);
23600 }
11476 23601
11477 @complexity Constant. 23602 /// @brief create a UBJSON serialization of a given JSON value
23603 /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/
23604 static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,
23605 const bool use_size = false, const bool use_type = false)
23606 {
23607 binary_writer<char>(o).write_ubjson(j, use_size, use_type);
23608 }
11478 23609
11479 @throw std::out_of_range if the JSON pointer can not be resolved 23610 /// @brief create a BJData serialization of a given JSON value
11480 @throw std::domain_error if an array index begins with '0' 23611 /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
11481 @throw std::invalid_argument if an array index was not a number 23612 static std::vector<std::uint8_t> to_bjdata(const basic_json& j,
23613 const bool use_size = false,
23614 const bool use_type = false)
23615 {
23616 std::vector<std::uint8_t> result;
23617 to_bjdata(j, result, use_size, use_type);
23618 return result;
23619 }
11482 23620
11483 @liveexample{The behavior is shown in the example.,operatorjson_pointer} 23621 /// @brief create a BJData serialization of a given JSON value
23622 /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
23623 static void to_bjdata(const basic_json& j, detail::output_adapter<std::uint8_t> o,
23624 const bool use_size = false, const bool use_type = false)
23625 {
23626 binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type, true, true);
23627 }
11484 23628
11485 @since version 2.0.0 23629 /// @brief create a BJData serialization of a given JSON value
11486 */ 23630 /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/
11487 reference operator[](const json_pointer& ptr) 23631 static void to_bjdata(const basic_json& j, detail::output_adapter<char> o,
23632 const bool use_size = false, const bool use_type = false)
11488 { 23633 {
11489 return ptr.get_unchecked(this); 23634 binary_writer<char>(o).write_ubjson(j, use_size, use_type, true, true);
11490 } 23635 }
11491 23636
11492 /*! 23637 /// @brief create a BSON serialization of a given JSON value
11493 @brief access specified element via JSON Pointer 23638 /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
23639 static std::vector<std::uint8_t> to_bson(const basic_json& j)
23640 {
23641 std::vector<std::uint8_t> result;
23642 to_bson(j, result);
23643 return result;
23644 }
11494 23645
11495 Uses a JSON pointer to retrieve a reference to the respective JSON value. 23646 /// @brief create a BSON serialization of a given JSON value
11496 No bound checking is performed. The function does not change the JSON 23647 /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
11497 value; no `null` values are created. In particular, the the special value 23648 static void to_bson(const basic_json& j, detail::output_adapter<std::uint8_t> o)
11498 `-` yields an exception. 23649 {
23650 binary_writer<std::uint8_t>(o).write_bson(j);
23651 }
11499 23652
11500 @param[in] ptr JSON pointer to the desired element 23653 /// @brief create a BSON serialization of a given JSON value
23654 /// @sa https://json.nlohmann.me/api/basic_json/to_bson/
23655 static void to_bson(const basic_json& j, detail::output_adapter<char> o)
23656 {
23657 binary_writer<char>(o).write_bson(j);
23658 }
11501 23659
11502 @return const reference to the element pointed to by @a ptr 23660 /// @brief create a JSON value from an input in CBOR format
23661 /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
23662 template<typename InputType>
23663 JSON_HEDLEY_WARN_UNUSED_RESULT
23664 static basic_json from_cbor(InputType&& i,
23665 const bool strict = true,
23666 const bool allow_exceptions = true,
23667 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
23668 {
23669 basic_json result;
23670 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23671 auto ia = detail::input_adapter(std::forward<InputType>(i));
23672 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
23673 return res ? result : basic_json(value_t::discarded);
23674 }
11503 23675
11504 @complexity Constant. 23676 /// @brief create a JSON value from an input in CBOR format
23677 /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/
23678 template<typename IteratorType>
23679 JSON_HEDLEY_WARN_UNUSED_RESULT
23680 static basic_json from_cbor(IteratorType first, IteratorType last,
23681 const bool strict = true,
23682 const bool allow_exceptions = true,
23683 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
23684 {
23685 basic_json result;
23686 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23687 auto ia = detail::input_adapter(std::move(first), std::move(last));
23688 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
23689 return res ? result : basic_json(value_t::discarded);
23690 }
11505 23691
11506 @throw std::out_of_range if the JSON pointer can not be resolved 23692 template<typename T>
11507 @throw std::domain_error if an array index begins with '0' 23693 JSON_HEDLEY_WARN_UNUSED_RESULT
11508 @throw std::invalid_argument if an array index was not a number 23694 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
23695 static basic_json from_cbor(const T* ptr, std::size_t len,
23696 const bool strict = true,
23697 const bool allow_exceptions = true,
23698 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
23699 {
23700 return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
23701 }
11509 23702
11510 @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} 23703 JSON_HEDLEY_WARN_UNUSED_RESULT
23704 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
23705 static basic_json from_cbor(detail::span_input_adapter&& i,
23706 const bool strict = true,
23707 const bool allow_exceptions = true,
23708 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
23709 {
23710 basic_json result;
23711 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23712 auto ia = i.get();
23713 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
23714 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
23715 return res ? result : basic_json(value_t::discarded);
23716 }
11511 23717
11512 @since version 2.0.0 23718 /// @brief create a JSON value from an input in MessagePack format
11513 */ 23719 /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
11514 const_reference operator[](const json_pointer& ptr) const 23720 template<typename InputType>
23721 JSON_HEDLEY_WARN_UNUSED_RESULT
23722 static basic_json from_msgpack(InputType&& i,
23723 const bool strict = true,
23724 const bool allow_exceptions = true)
11515 { 23725 {
11516 return ptr.get_unchecked(this); 23726 basic_json result;
23727 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23728 auto ia = detail::input_adapter(std::forward<InputType>(i));
23729 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
23730 return res ? result : basic_json(value_t::discarded);
11517 } 23731 }
11518 23732
11519 /*! 23733 /// @brief create a JSON value from an input in MessagePack format
11520 @brief access specified element via JSON Pointer 23734 /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/
23735 template<typename IteratorType>
23736 JSON_HEDLEY_WARN_UNUSED_RESULT
23737 static basic_json from_msgpack(IteratorType first, IteratorType last,
23738 const bool strict = true,
23739 const bool allow_exceptions = true)
23740 {
23741 basic_json result;
23742 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23743 auto ia = detail::input_adapter(std::move(first), std::move(last));
23744 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
23745 return res ? result : basic_json(value_t::discarded);
23746 }
11521 23747
11522 Returns a reference to the element at with specified JSON pointer @a ptr, 23748 template<typename T>
11523 with bounds checking. 23749 JSON_HEDLEY_WARN_UNUSED_RESULT
23750 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
23751 static basic_json from_msgpack(const T* ptr, std::size_t len,
23752 const bool strict = true,
23753 const bool allow_exceptions = true)
23754 {
23755 return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
23756 }
11524 23757
11525 @param[in] ptr JSON pointer to the desired element 23758 JSON_HEDLEY_WARN_UNUSED_RESULT
23759 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
23760 static basic_json from_msgpack(detail::span_input_adapter&& i,
23761 const bool strict = true,
23762 const bool allow_exceptions = true)
23763 {
23764 basic_json result;
23765 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23766 auto ia = i.get();
23767 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
23768 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
23769 return res ? result : basic_json(value_t::discarded);
23770 }
11526 23771
11527 @return reference to the element pointed to by @a ptr 23772 /// @brief create a JSON value from an input in UBJSON format
23773 /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
23774 template<typename InputType>
23775 JSON_HEDLEY_WARN_UNUSED_RESULT
23776 static basic_json from_ubjson(InputType&& i,
23777 const bool strict = true,
23778 const bool allow_exceptions = true)
23779 {
23780 basic_json result;
23781 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23782 auto ia = detail::input_adapter(std::forward<InputType>(i));
23783 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
23784 return res ? result : basic_json(value_t::discarded);
23785 }
11528 23786
11529 @complexity Constant. 23787 /// @brief create a JSON value from an input in UBJSON format
23788 /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/
23789 template<typename IteratorType>
23790 JSON_HEDLEY_WARN_UNUSED_RESULT
23791 static basic_json from_ubjson(IteratorType first, IteratorType last,
23792 const bool strict = true,
23793 const bool allow_exceptions = true)
23794 {
23795 basic_json result;
23796 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23797 auto ia = detail::input_adapter(std::move(first), std::move(last));
23798 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
23799 return res ? result : basic_json(value_t::discarded);
23800 }
11530 23801
11531 @throw std::out_of_range if the JSON pointer can not be resolved 23802 template<typename T>
11532 @throw std::domain_error if an array index begins with '0' 23803 JSON_HEDLEY_WARN_UNUSED_RESULT
11533 @throw std::invalid_argument if an array index was not a number 23804 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
23805 static basic_json from_ubjson(const T* ptr, std::size_t len,
23806 const bool strict = true,
23807 const bool allow_exceptions = true)
23808 {
23809 return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
23810 }
11534 23811
11535 @liveexample{The behavior is shown in the example.,at_json_pointer} 23812 JSON_HEDLEY_WARN_UNUSED_RESULT
23813 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
23814 static basic_json from_ubjson(detail::span_input_adapter&& i,
23815 const bool strict = true,
23816 const bool allow_exceptions = true)
23817 {
23818 basic_json result;
23819 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23820 auto ia = i.get();
23821 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
23822 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
23823 return res ? result : basic_json(value_t::discarded);
23824 }
11536 23825
11537 @since version 2.0.0 23826 /// @brief create a JSON value from an input in BJData format
11538 */ 23827 /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
11539 reference at(const json_pointer& ptr) 23828 template<typename InputType>
23829 JSON_HEDLEY_WARN_UNUSED_RESULT
23830 static basic_json from_bjdata(InputType&& i,
23831 const bool strict = true,
23832 const bool allow_exceptions = true)
11540 { 23833 {
11541 return ptr.get_checked(this); 23834 basic_json result;
23835 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23836 auto ia = detail::input_adapter(std::forward<InputType>(i));
23837 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict);
23838 return res ? result : basic_json(value_t::discarded);
11542 } 23839 }
11543 23840
11544 /*! 23841 /// @brief create a JSON value from an input in BJData format
11545 @brief access specified element via JSON Pointer 23842 /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/
23843 template<typename IteratorType>
23844 JSON_HEDLEY_WARN_UNUSED_RESULT
23845 static basic_json from_bjdata(IteratorType first, IteratorType last,
23846 const bool strict = true,
23847 const bool allow_exceptions = true)
23848 {
23849 basic_json result;
23850 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23851 auto ia = detail::input_adapter(std::move(first), std::move(last));
23852 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict);
23853 return res ? result : basic_json(value_t::discarded);
23854 }
11546 23855
11547 Returns a const reference to the element at with specified JSON pointer @a 23856 /// @brief create a JSON value from an input in BSON format
11548 ptr, with bounds checking. 23857 /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
23858 template<typename InputType>
23859 JSON_HEDLEY_WARN_UNUSED_RESULT
23860 static basic_json from_bson(InputType&& i,
23861 const bool strict = true,
23862 const bool allow_exceptions = true)
23863 {
23864 basic_json result;
23865 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23866 auto ia = detail::input_adapter(std::forward<InputType>(i));
23867 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
23868 return res ? result : basic_json(value_t::discarded);
23869 }
11549 23870
11550 @param[in] ptr JSON pointer to the desired element 23871 /// @brief create a JSON value from an input in BSON format
23872 /// @sa https://json.nlohmann.me/api/basic_json/from_bson/
23873 template<typename IteratorType>
23874 JSON_HEDLEY_WARN_UNUSED_RESULT
23875 static basic_json from_bson(IteratorType first, IteratorType last,
23876 const bool strict = true,
23877 const bool allow_exceptions = true)
23878 {
23879 basic_json result;
23880 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23881 auto ia = detail::input_adapter(std::move(first), std::move(last));
23882 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
23883 return res ? result : basic_json(value_t::discarded);
23884 }
11551 23885
11552 @return reference to the element pointed to by @a ptr 23886 template<typename T>
23887 JSON_HEDLEY_WARN_UNUSED_RESULT
23888 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
23889 static basic_json from_bson(const T* ptr, std::size_t len,
23890 const bool strict = true,
23891 const bool allow_exceptions = true)
23892 {
23893 return from_bson(ptr, ptr + len, strict, allow_exceptions);
23894 }
11553 23895
11554 @complexity Constant. 23896 JSON_HEDLEY_WARN_UNUSED_RESULT
23897 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
23898 static basic_json from_bson(detail::span_input_adapter&& i,
23899 const bool strict = true,
23900 const bool allow_exceptions = true)
23901 {
23902 basic_json result;
23903 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23904 auto ia = i.get();
23905 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
23906 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
23907 return res ? result : basic_json(value_t::discarded);
23908 }
23909 /// @}
11555 23910
11556 @throw std::out_of_range if the JSON pointer can not be resolved 23911 //////////////////////////
11557 @throw std::domain_error if an array index begins with '0' 23912 // JSON Pointer support //
11558 @throw std::invalid_argument if an array index was not a number 23913 //////////////////////////
11559 23914
11560 @liveexample{The behavior is shown in the example.,at_json_pointer_const} 23915 /// @name JSON Pointer functions
23916 /// @{
11561 23917
11562 @since version 2.0.0 23918 /// @brief access specified element via JSON Pointer
11563 */ 23919 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
11564 const_reference at(const json_pointer& ptr) const 23920 reference operator[](const json_pointer& ptr)
11565 { 23921 {
11566 return ptr.get_checked(this); 23922 return ptr.get_unchecked(this);
11567 } 23923 }
11568 23924
11569 /*! 23925 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
11570 @brief return flattened JSON value 23926 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
23927 reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
23928 {
23929 return ptr.get_unchecked(this);
23930 }
11571 23931
11572 The function creates a JSON object whose keys are JSON pointers (see [RFC 23932 /// @brief access specified element via JSON Pointer
11573 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all 23933 /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/
11574 primitive. The original JSON value can be restored using the @ref 23934 const_reference operator[](const json_pointer& ptr) const
11575 unflatten() function. 23935 {
23936 return ptr.get_unchecked(this);
23937 }
11576 23938
11577 @return an object that maps JSON pointers to primitve values 23939 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
23940 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
23941 const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
23942 {
23943 return ptr.get_unchecked(this);
23944 }
11578 23945
11579 @note Empty objects and arrays are flattened to `null` and will not be 23946 /// @brief access specified element via JSON Pointer
11580 reconstructed correctly by the @ref unflatten() function. 23947 /// @sa https://json.nlohmann.me/api/basic_json/at/
23948 reference at(const json_pointer& ptr)
23949 {
23950 return ptr.get_checked(this);
23951 }
11581 23952
11582 @complexity Linear in the size the JSON value. 23953 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
23954 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
23955 reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
23956 {
23957 return ptr.get_checked(this);
23958 }
11583 23959
11584 @liveexample{The following code shows how a JSON object is flattened to an 23960 /// @brief access specified element via JSON Pointer
11585 object whose keys consist of JSON pointers.,flatten} 23961 /// @sa https://json.nlohmann.me/api/basic_json/at/
23962 const_reference at(const json_pointer& ptr) const
23963 {
23964 return ptr.get_checked(this);
23965 }
11586 23966
11587 @sa @ref unflatten() for the reverse function 23967 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
23968 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
23969 const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
23970 {
23971 return ptr.get_checked(this);
23972 }
11588 23973
11589 @since version 2.0.0 23974 /// @brief return flattened JSON value
11590 */ 23975 /// @sa https://json.nlohmann.me/api/basic_json/flatten/
11591 basic_json flatten() const 23976 basic_json flatten() const
11592 { 23977 {
11593 basic_json result(value_t::object); 23978 basic_json result(value_t::object);
@@ -11595,33 +23980,8 @@ basic_json_parser_66:
11595 return result; 23980 return result;
11596 } 23981 }
11597 23982
11598 /*! 23983 /// @brief unflatten a previously flattened JSON value
11599 @brief unflatten a previously flattened JSON value 23984 /// @sa https://json.nlohmann.me/api/basic_json/unflatten/
11600
11601 The function restores the arbitrary nesting of a JSON value that has been
11602 flattened before using the @ref flatten() function. The JSON value must
11603 meet certain constraints:
11604 1. The value must be an object.
11605 2. The keys must be JSON pointers (see
11606 [RFC 6901](https://tools.ietf.org/html/rfc6901))
11607 3. The mapped values must be primitive JSON types.
11608
11609 @return the original JSON from a flattened version
11610
11611 @note Empty objects and arrays are flattened by @ref flatten() to `null`
11612 values and can not unflattened to their original type. Apart from
11613 this example, for a JSON value `j`, the following is always true:
11614 `j == j.flatten().unflatten()`.
11615
11616 @complexity Linear in the size the JSON value.
11617
11618 @liveexample{The following code shows how a flattened JSON object is
11619 unflattened into the original nested JSON object.,unflatten}
11620
11621 @sa @ref flatten() for the reverse function
11622
11623 @since version 2.0.0
11624 */
11625 basic_json unflatten() const 23985 basic_json unflatten() const
11626 { 23986 {
11627 return json_pointer::unflatten(*this); 23987 return json_pointer::unflatten(*this);
@@ -11636,51 +23996,15 @@ basic_json_parser_66:
11636 /// @name JSON Patch functions 23996 /// @name JSON Patch functions
11637 /// @{ 23997 /// @{
11638 23998
11639 /*! 23999 /// @brief applies a JSON patch in-place without copying the object
11640 @brief applies a JSON patch 24000 /// @sa https://json.nlohmann.me/api/basic_json/patch/
11641 24001 void patch_inplace(const basic_json& json_patch)
11642 [JSON Patch](http://jsonpatch.com) defines a JSON document structure for
11643 expressing a sequence of operations to apply to a JSON) document. With
11644 this funcion, a JSON Patch is applied to the current JSON value by
11645 executing all operations from the patch.
11646
11647 @param[in] json_patch JSON patch document
11648 @return patched document
11649
11650 @note The application of a patch is atomic: Either all operations succeed
11651 and the patched document is returned or an exception is thrown. In
11652 any case, the original value is not changed: the patch is applied
11653 to a copy of the value.
11654
11655 @throw std::out_of_range if a JSON pointer inside the patch could not
11656 be resolved successfully in the current JSON value; example: `"key baz
11657 not found"`
11658 @throw invalid_argument if the JSON patch is malformed (e.g., mandatory
11659 attributes are missing); example: `"operation add must have member path"`
11660
11661 @complexity Linear in the size of the JSON value and the length of the
11662 JSON patch. As usually only a fraction of the JSON value is affected by
11663 the patch, the complexity can usually be neglected.
11664
11665 @liveexample{The following code shows how a JSON patch is applied to a
11666 value.,patch}
11667
11668 @sa @ref diff -- create a JSON patch by comparing two JSON values
11669
11670 @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
11671 @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)
11672
11673 @since version 2.0.0
11674 */
11675 basic_json patch(const basic_json& json_patch) const
11676 { 24002 {
11677 // make a working copy to apply the patch to 24003 basic_json& result = *this;
11678 basic_json result = *this;
11679
11680 // the valid JSON Patch operations 24004 // the valid JSON Patch operations
11681 enum class patch_operations {add, remove, replace, move, copy, test, invalid}; 24005 enum class patch_operations {add, remove, replace, move, copy, test, invalid};
11682 24006
11683 const auto get_op = [](const std::string op) 24007 const auto get_op = [](const std::string & op)
11684 { 24008 {
11685 if (op == "add") 24009 if (op == "add")
11686 { 24010 {
@@ -11714,71 +24038,76 @@ basic_json_parser_66:
11714 const auto operation_add = [&result](json_pointer & ptr, basic_json val) 24038 const auto operation_add = [&result](json_pointer & ptr, basic_json val)
11715 { 24039 {
11716 // adding to the root of the target document means replacing it 24040 // adding to the root of the target document means replacing it
11717 if (ptr.is_root()) 24041 if (ptr.empty())
11718 { 24042 {
11719 result = val; 24043 result = val;
24044 return;
11720 } 24045 }
11721 else 24046
24047 // make sure the top element of the pointer exists
24048 json_pointer const top_pointer = ptr.top();
24049 if (top_pointer != ptr)
24050 {
24051 result.at(top_pointer);
24052 }
24053
24054 // get reference to parent of JSON pointer ptr
24055 const auto last_path = ptr.back();
24056 ptr.pop_back();
24057 // parent must exist when performing patch add per RFC6902 specs
24058 basic_json& parent = result.at(ptr);
24059
24060 switch (parent.m_data.m_type)
11722 { 24061 {
11723 // make sure the top element of the pointer exists 24062 case value_t::null:
11724 json_pointer top_pointer = ptr.top(); 24063 case value_t::object:
11725 if (top_pointer != ptr)
11726 { 24064 {
11727 result.at(top_pointer); 24065 // use operator[] to add value
24066 parent[last_path] = val;
24067 break;
11728 } 24068 }
11729 24069
11730 // get reference to parent of JSON pointer ptr 24070 case value_t::array:
11731 const auto last_path = ptr.pop_back();
11732 basic_json& parent = result[ptr];
11733
11734 switch (parent.m_type)
11735 { 24071 {
11736 case value_t::null: 24072 if (last_path == "-")
11737 case value_t::object:
11738 { 24073 {
11739 // use operator[] to add value 24074 // special case: append to back
11740 parent[last_path] = val; 24075 parent.push_back(val);
11741 break;
11742 } 24076 }
11743 24077 else
11744 case value_t::array:
11745 { 24078 {
11746 if (last_path == "-") 24079 const auto idx = json_pointer::template array_index<basic_json_t>(last_path);
11747 { 24080 if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))
11748 // special case: append to back
11749 parent.push_back(val);
11750 }
11751 else
11752 { 24081 {
11753 const auto idx = std::stoi(last_path); 24082 // avoid undefined behavior
11754 if (static_cast<size_type>(idx) > parent.size()) 24083 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent));
11755 {
11756 // avoid undefined behavior
11757 throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
11758 }
11759 else
11760 {
11761 // default case: insert add offset
11762 parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
11763 }
11764 } 24084 }
11765 break;
11766 }
11767 24085
11768 default: 24086 // default case: insert add offset
11769 { 24087 parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
11770 // if there exists a parent it cannot be primitive
11771 assert(false); // LCOV_EXCL_LINE
11772 } 24088 }
24089 break;
11773 } 24090 }
24091
24092 // if there exists a parent it cannot be primitive
24093 case value_t::string: // LCOV_EXCL_LINE
24094 case value_t::boolean: // LCOV_EXCL_LINE
24095 case value_t::number_integer: // LCOV_EXCL_LINE
24096 case value_t::number_unsigned: // LCOV_EXCL_LINE
24097 case value_t::number_float: // LCOV_EXCL_LINE
24098 case value_t::binary: // LCOV_EXCL_LINE
24099 case value_t::discarded: // LCOV_EXCL_LINE
24100 default: // LCOV_EXCL_LINE
24101 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
11774 } 24102 }
11775 }; 24103 };
11776 24104
11777 // wrapper for "remove" operation; remove value at ptr 24105 // wrapper for "remove" operation; remove value at ptr
11778 const auto operation_remove = [&result](json_pointer & ptr) 24106 const auto operation_remove = [this, & result](json_pointer & ptr)
11779 { 24107 {
11780 // get reference to parent of JSON pointer ptr 24108 // get reference to parent of JSON pointer ptr
11781 const auto last_path = ptr.pop_back(); 24109 const auto last_path = ptr.back();
24110 ptr.pop_back();
11782 basic_json& parent = result.at(ptr); 24111 basic_json& parent = result.at(ptr);
11783 24112
11784 // remove child 24113 // remove child
@@ -11786,68 +24115,69 @@ basic_json_parser_66:
11786 { 24115 {
11787 // perform range check 24116 // perform range check
11788 auto it = parent.find(last_path); 24117 auto it = parent.find(last_path);
11789 if (it != parent.end()) 24118 if (JSON_HEDLEY_LIKELY(it != parent.end()))
11790 { 24119 {
11791 parent.erase(it); 24120 parent.erase(it);
11792 } 24121 }
11793 else 24122 else
11794 { 24123 {
11795 throw std::out_of_range("key '" + last_path + "' not found"); 24124 JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this));
11796 } 24125 }
11797 } 24126 }
11798 else if (parent.is_array()) 24127 else if (parent.is_array())
11799 { 24128 {
11800 // note erase performs range check 24129 // note erase performs range check
11801 parent.erase(static_cast<size_type>(std::stoi(last_path))); 24130 parent.erase(json_pointer::template array_index<basic_json_t>(last_path));
11802 } 24131 }
11803 }; 24132 };
11804 24133
11805 // type check 24134 // type check: top level value must be an array
11806 if (not json_patch.is_array()) 24135 if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))
11807 { 24136 {
11808 // a JSON patch must be an array of objects 24137 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch));
11809 throw std::invalid_argument("JSON patch must be an array of objects");
11810 } 24138 }
11811 24139
11812 // iterate and apply th eoperations 24140 // iterate and apply the operations
11813 for (const auto& val : json_patch) 24141 for (const auto& val : json_patch)
11814 { 24142 {
11815 // wrapper to get a value for an operation 24143 // wrapper to get a value for an operation
11816 const auto get_value = [&val](const std::string & op, 24144 const auto get_value = [&val](const std::string & op,
11817 const std::string & member, 24145 const std::string & member,
11818 bool string_type) -> basic_json& 24146 bool string_type) -> basic_json &
11819 { 24147 {
11820 // find value 24148 // find value
11821 auto it = val.m_value.object->find(member); 24149 auto it = val.m_data.m_value.object->find(member);
11822 24150
11823 // context-sensitive error message 24151 // context-sensitive error message
11824 const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; 24152 const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\'');
11825 24153
11826 // check if desired value is present 24154 // check if desired value is present
11827 if (it == val.m_value.object->end()) 24155 if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end()))
11828 { 24156 {
11829 throw std::invalid_argument(error_msg + " must have member '" + member + "'"); 24157 // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
24158 JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val));
11830 } 24159 }
11831 24160
11832 // check if result is of type string 24161 // check if result is of type string
11833 if (string_type and not it->second.is_string()) 24162 if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))
11834 { 24163 {
11835 throw std::invalid_argument(error_msg + " must have string member '" + member + "'"); 24164 // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
24165 JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val));
11836 } 24166 }
11837 24167
11838 // no error: return value 24168 // no error: return value
11839 return it->second; 24169 return it->second;
11840 }; 24170 };
11841 24171
11842 // type check 24172 // type check: every element of the array must be an object
11843 if (not val.is_object()) 24173 if (JSON_HEDLEY_UNLIKELY(!val.is_object()))
11844 { 24174 {
11845 throw std::invalid_argument("JSON patch must be an array of objects"); 24175 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val));
11846 } 24176 }
11847 24177
11848 // collect mandatory members 24178 // collect mandatory members
11849 const std::string op = get_value("op", "op", true); 24179 const auto op = get_value("op", "op", true).template get<std::string>();
11850 const std::string path = get_value(op, "path", true); 24180 const auto path = get_value(op, "path", true).template get<std::string>();
11851 json_pointer ptr(path); 24181 json_pointer ptr(path);
11852 24182
11853 switch (get_op(op)) 24183 switch (get_op(op))
@@ -11873,11 +24203,11 @@ basic_json_parser_66:
11873 24203
11874 case patch_operations::move: 24204 case patch_operations::move:
11875 { 24205 {
11876 const std::string from_path = get_value("move", "from", true); 24206 const auto from_path = get_value("move", "from", true).template get<std::string>();
11877 json_pointer from_ptr(from_path); 24207 json_pointer from_ptr(from_path);
11878 24208
11879 // the "from" location must exist - use at() 24209 // the "from" location must exist - use at()
11880 basic_json v = result.at(from_ptr); 24210 basic_json const v = result.at(from_ptr);
11881 24211
11882 // The move operation is functionally identical to a 24212 // The move operation is functionally identical to a
11883 // "remove" operation on the "from" location, followed 24213 // "remove" operation on the "from" location, followed
@@ -11890,83 +24220,66 @@ basic_json_parser_66:
11890 24220
11891 case patch_operations::copy: 24221 case patch_operations::copy:
11892 { 24222 {
11893 const std::string from_path = get_value("copy", "from", true);; 24223 const auto from_path = get_value("copy", "from", true).template get<std::string>();
11894 const json_pointer from_ptr(from_path); 24224 const json_pointer from_ptr(from_path);
11895 24225
11896 // the "from" location must exist - use at() 24226 // the "from" location must exist - use at()
11897 result[ptr] = result.at(from_ptr); 24227 basic_json const v = result.at(from_ptr);
24228
24229 // The copy is functionally identical to an "add"
24230 // operation at the target location using the value
24231 // specified in the "from" member.
24232 operation_add(ptr, v);
11898 break; 24233 break;
11899 } 24234 }
11900 24235
11901 case patch_operations::test: 24236 case patch_operations::test:
11902 { 24237 {
11903 bool success = false; 24238 bool success = false;
11904 try 24239 JSON_TRY
11905 { 24240 {
11906 // check if "value" matches the one at "path" 24241 // check if "value" matches the one at "path"
11907 // the "path" location must exist - use at() 24242 // the "path" location must exist - use at()
11908 success = (result.at(ptr) == get_value("test", "value", false)); 24243 success = (result.at(ptr) == get_value("test", "value", false));
11909 } 24244 }
11910 catch (std::out_of_range&) 24245 JSON_INTERNAL_CATCH (out_of_range&)
11911 { 24246 {
11912 // ignore out of range errors: success remains false 24247 // ignore out of range errors: success remains false
11913 } 24248 }
11914 24249
11915 // throw an exception if test fails 24250 // throw an exception if test fails
11916 if (not success) 24251 if (JSON_HEDLEY_UNLIKELY(!success))
11917 { 24252 {
11918 throw std::domain_error("unsuccessful: " + val.dump()); 24253 JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val));
11919 } 24254 }
11920 24255
11921 break; 24256 break;
11922 } 24257 }
11923 24258
11924 case patch_operations::invalid: 24259 case patch_operations::invalid:
24260 default:
11925 { 24261 {
11926 // op must be "add", "remove", "replace", "move", "copy", or 24262 // op must be "add", "remove", "replace", "move", "copy", or
11927 // "test" 24263 // "test"
11928 throw std::invalid_argument("operation value '" + op + "' is invalid"); 24264 JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val));
11929 } 24265 }
11930 } 24266 }
11931 } 24267 }
24268 }
11932 24269
24270 /// @brief applies a JSON patch to a copy of the current object
24271 /// @sa https://json.nlohmann.me/api/basic_json/patch/
24272 basic_json patch(const basic_json& json_patch) const
24273 {
24274 basic_json result = *this;
24275 result.patch_inplace(json_patch);
11933 return result; 24276 return result;
11934 } 24277 }
11935 24278
11936 /*! 24279 /// @brief creates a diff as a JSON patch
11937 @brief creates a diff as a JSON patch 24280 /// @sa https://json.nlohmann.me/api/basic_json/diff/
11938 24281 JSON_HEDLEY_WARN_UNUSED_RESULT
11939 Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can 24282 static basic_json diff(const basic_json& source, const basic_json& target,
11940 be changed into the value @a target by calling @ref patch function.
11941
11942 @invariant For two JSON values @a source and @a target, the following code
11943 yields always `true`:
11944 @code {.cpp}
11945 source.patch(diff(source, target)) == target;
11946 @endcode
11947
11948 @note Currently, only `remove`, `add`, and `replace` operations are
11949 generated.
11950
11951 @param[in] source JSON value to copare from
11952 @param[in] target JSON value to copare against
11953 @param[in] path helper value to create JSON pointers
11954
11955 @return a JSON patch to convert the @a source to @a target
11956
11957 @complexity Linear in the lengths of @a source and @a target.
11958
11959 @liveexample{The following code shows how a JSON patch is created as a
11960 diff for two JSON values.,diff}
11961
11962 @sa @ref patch -- apply a JSON patch
11963
11964 @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
11965
11966 @since version 2.0.0
11967 */
11968 static basic_json diff(const basic_json& source,
11969 const basic_json& target,
11970 const std::string& path = "") 24283 const std::string& path = "")
11971 { 24284 {
11972 // the patch 24285 // the patch
@@ -11983,219 +24296,470 @@ basic_json_parser_66:
11983 // different types: replace value 24296 // different types: replace value
11984 result.push_back( 24297 result.push_back(
11985 { 24298 {
11986 {"op", "replace"}, 24299 {"op", "replace"}, {"path", path}, {"value", target}
11987 {"path", path},
11988 {"value", target}
11989 }); 24300 });
24301 return result;
11990 } 24302 }
11991 else 24303
24304 switch (source.type())
11992 { 24305 {
11993 switch (source.type()) 24306 case value_t::array:
11994 { 24307 {
11995 case value_t::array: 24308 // first pass: traverse common elements
24309 std::size_t i = 0;
24310 while (i < source.size() && i < target.size())
24311 {
24312 // recursive call to compare array values at index i
24313 auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', std::to_string(i)));
24314 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
24315 ++i;
24316 }
24317
24318 // We now reached the end of at least one array
24319 // in a second pass, traverse the remaining elements
24320
24321 // remove my remaining elements
24322 const auto end_index = static_cast<difference_type>(result.size());
24323 while (i < source.size())
11996 { 24324 {
11997 // first pass: traverse common elements 24325 // add operations in reverse order to avoid invalid
11998 size_t i = 0; 24326 // indices
11999 while (i < source.size() and i < target.size()) 24327 result.insert(result.begin() + end_index, object(
12000 { 24328 {
12001 // recursive call to compare array values at index i 24329 {"op", "remove"},
12002 auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); 24330 {"path", detail::concat(path, '/', std::to_string(i))}
12003 result.insert(result.end(), temp_diff.begin(), temp_diff.end()); 24331 }));
12004 ++i; 24332 ++i;
12005 } 24333 }
24334
24335 // add other remaining elements
24336 while (i < target.size())
24337 {
24338 result.push_back(
24339 {
24340 {"op", "add"},
24341 {"path", detail::concat(path, "/-")},
24342 {"value", target[i]}
24343 });
24344 ++i;
24345 }
12006 24346
12007 // i now reached the end of at least one array 24347 break;
12008 // in a second pass, traverse the remaining elements 24348 }
24349
24350 case value_t::object:
24351 {
24352 // first pass: traverse this object's elements
24353 for (auto it = source.cbegin(); it != source.cend(); ++it)
24354 {
24355 // escape the key name to be used in a JSON patch
24356 const auto path_key = detail::concat(path, '/', detail::escape(it.key()));
12009 24357
12010 // remove my remaining elements 24358 if (target.find(it.key()) != target.end())
12011 const auto end_index = static_cast<difference_type>(result.size()); 24359 {
12012 while (i < source.size()) 24360 // recursive call to compare object values at key it
24361 auto temp_diff = diff(it.value(), target[it.key()], path_key);
24362 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
24363 }
24364 else
12013 { 24365 {
12014 // add operations in reverse order to avoid invalid 24366 // found a key that is not in o -> remove it
12015 // indices 24367 result.push_back(object(
12016 result.insert(result.begin() + end_index, object(
12017 { 24368 {
12018 {"op", "remove"}, 24369 {"op", "remove"}, {"path", path_key}
12019 {"path", path + "/" + std::to_string(i)}
12020 })); 24370 }));
12021 ++i;
12022 } 24371 }
24372 }
12023 24373
12024 // add other remaining elements 24374 // second pass: traverse other object's elements
12025 while (i < target.size()) 24375 for (auto it = target.cbegin(); it != target.cend(); ++it)
24376 {
24377 if (source.find(it.key()) == source.end())
12026 { 24378 {
24379 // found a key that is not in this -> add it
24380 const auto path_key = detail::concat(path, '/', detail::escape(it.key()));
12027 result.push_back( 24381 result.push_back(
12028 { 24382 {
12029 {"op", "add"}, 24383 {"op", "add"}, {"path", path_key},
12030 {"path", path + "/" + std::to_string(i)}, 24384 {"value", it.value()}
12031 {"value", target[i]}
12032 }); 24385 });
12033 ++i;
12034 } 24386 }
12035
12036 break;
12037 } 24387 }
12038 24388
12039 case value_t::object: 24389 break;
24390 }
24391
24392 case value_t::null:
24393 case value_t::string:
24394 case value_t::boolean:
24395 case value_t::number_integer:
24396 case value_t::number_unsigned:
24397 case value_t::number_float:
24398 case value_t::binary:
24399 case value_t::discarded:
24400 default:
24401 {
24402 // both primitive type: replace value
24403 result.push_back(
12040 { 24404 {
12041 // first pass: traverse this object's elements 24405 {"op", "replace"}, {"path", path}, {"value", target}
12042 for (auto it = source.begin(); it != source.end(); ++it) 24406 });
12043 { 24407 break;
12044 // escape the key name to be used in a JSON patch 24408 }
12045 const auto key = json_pointer::escape(it.key()); 24409 }
12046 24410
12047 if (target.find(it.key()) != target.end()) 24411 return result;
12048 { 24412 }
12049 // recursive call to compare object values at key it 24413 /// @}
12050 auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key);
12051 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
12052 }
12053 else
12054 {
12055 // found a key that is not in o -> remove it
12056 result.push_back(object(
12057 {
12058 {"op", "remove"},
12059 {"path", path + "/" + key}
12060 }));
12061 }
12062 }
12063 24414
12064 // second pass: traverse other object's elements 24415 ////////////////////////////////
12065 for (auto it = target.begin(); it != target.end(); ++it) 24416 // JSON Merge Patch functions //
12066 { 24417 ////////////////////////////////
12067 if (source.find(it.key()) == source.end())
12068 {
12069 // found a key that is not in this -> add it
12070 const auto key = json_pointer::escape(it.key());
12071 result.push_back(
12072 {
12073 {"op", "add"},
12074 {"path", path + "/" + key},
12075 {"value", it.value()}
12076 });
12077 }
12078 }
12079 24418
12080 break; 24419 /// @name JSON Merge Patch functions
12081 } 24420 /// @{
12082 24421
12083 default: 24422 /// @brief applies a JSON Merge Patch
24423 /// @sa https://json.nlohmann.me/api/basic_json/merge_patch/
24424 void merge_patch(const basic_json& apply_patch)
24425 {
24426 if (apply_patch.is_object())
24427 {
24428 if (!is_object())
24429 {
24430 *this = object();
24431 }
24432 for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)
24433 {
24434 if (it.value().is_null())
12084 { 24435 {
12085 // both primitive type: replace value 24436 erase(it.key());
12086 result.push_back( 24437 }
12087 { 24438 else
12088 {"op", "replace"}, 24439 {
12089 {"path", path}, 24440 operator[](it.key()).merge_patch(it.value());
12090 {"value", target}
12091 });
12092 break;
12093 } 24441 }
12094 } 24442 }
12095 } 24443 }
12096 24444 else
12097 return result; 24445 {
24446 *this = apply_patch;
24447 }
12098 } 24448 }
12099 24449
12100 /// @} 24450 /// @}
12101}; 24451};
12102 24452
24453/// @brief user-defined to_string function for JSON values
24454/// @sa https://json.nlohmann.me/api/basic_json/to_string/
24455NLOHMANN_BASIC_JSON_TPL_DECLARATION
24456std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j)
24457{
24458 return j.dump();
24459}
12103 24460
12104///////////// 24461inline namespace literals
12105// presets // 24462{
12106///////////// 24463inline namespace json_literals
12107 24464{
12108/*!
12109@brief default JSON class
12110 24465
12111This type is the default specialization of the @ref basic_json class which 24466/// @brief user-defined string literal for JSON values
12112uses the standard template types. 24467/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/
24468JSON_HEDLEY_NON_NULL(1)
24469#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
24470 inline nlohmann::json operator ""_json(const char* s, std::size_t n)
24471#else
24472 inline nlohmann::json operator "" _json(const char* s, std::size_t n)
24473#endif
24474{
24475 return nlohmann::json::parse(s, s + n);
24476}
12113 24477
12114@since version 1.0.0 24478/// @brief user-defined string literal for JSON pointer
12115*/ 24479/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/
12116using json = basic_json<>; 24480JSON_HEDLEY_NON_NULL(1)
24481#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
24482 inline nlohmann::json::json_pointer operator ""_json_pointer(const char* s, std::size_t n)
24483#else
24484 inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
24485#endif
24486{
24487 return nlohmann::json::json_pointer(std::string(s, n));
12117} 24488}
12118 24489
24490} // namespace json_literals
24491} // namespace literals
24492NLOHMANN_JSON_NAMESPACE_END
12119 24493
12120/////////////////////// 24494///////////////////////
12121// nonmember support // 24495// nonmember support //
12122/////////////////////// 24496///////////////////////
12123 24497
12124// specialization of std::swap, and std::hash 24498namespace std // NOLINT(cert-dcl58-cpp)
12125namespace std
12126{ 24499{
12127/*!
12128@brief exchanges the values of two JSON objects
12129 24500
12130@since version 1.0.0 24501/// @brief hash value for JSON objects
12131*/ 24502/// @sa https://json.nlohmann.me/api/basic_json/std_hash/
12132template<> 24503NLOHMANN_BASIC_JSON_TPL_DECLARATION
12133inline void swap(nlohmann::json& j1, 24504struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL> // NOLINT(cert-dcl58-cpp)
12134 nlohmann::json& j2) noexcept(
12135 is_nothrow_move_constructible<nlohmann::json>::value and
12136 is_nothrow_move_assignable<nlohmann::json>::value
12137 )
12138{ 24505{
12139 j1.swap(j2); 24506 std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const
12140} 24507 {
24508 return nlohmann::detail::hash(j);
24509 }
24510};
12141 24511
12142/// hash value for JSON objects 24512// specialization for std::less<value_t>
12143template<> 24513template<>
12144struct hash<nlohmann::json> 24514struct less< ::nlohmann::detail::value_t> // do not remove the space after '<', see https://github.com/nlohmann/json/pull/679
12145{ 24515{
12146 /*! 24516 /*!
12147 @brief return a hash value for a JSON object 24517 @brief compare two value_t enum values
12148 24518 @since version 3.0.0
12149 @since version 1.0.0
12150 */ 24519 */
12151 std::size_t operator()(const nlohmann::json& j) const 24520 bool operator()(::nlohmann::detail::value_t lhs,
24521 ::nlohmann::detail::value_t rhs) const noexcept
12152 { 24522 {
12153 // a naive hashing via the string representation 24523#if JSON_HAS_THREE_WAY_COMPARISON
12154 const auto& h = hash<nlohmann::json::string_t>(); 24524 return std::is_lt(lhs <=> rhs); // *NOPAD*
12155 return h(j.dump()); 24525#else
24526 return ::nlohmann::detail::operator<(lhs, rhs);
24527#endif
12156 } 24528 }
12157}; 24529};
12158}
12159 24530
12160/*! 24531// C++20 prohibit function specialization in the std namespace.
12161@brief user-defined string literal for JSON values 24532#ifndef JSON_HAS_CPP_20
12162
12163This operator implements a user-defined string literal for JSON objects. It
12164can be used by adding `"_json"` to a string literal and returns a JSON object
12165if no parse error occurred.
12166
12167@param[in] s a string representation of a JSON object
12168@param[in] n the length of string @a s
12169@return a JSON object
12170 24533
12171@since version 1.0.0 24534/// @brief exchanges the values of two JSON objects
12172*/ 24535/// @sa https://json.nlohmann.me/api/basic_json/std_swap/
12173inline nlohmann::json operator "" _json(const char* s, std::size_t n) 24536NLOHMANN_BASIC_JSON_TPL_DECLARATION
24537inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp)
24538 is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&& // NOLINT(misc-redundant-expression,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
24539 is_nothrow_move_assignable<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value)
12174{ 24540{
12175 return nlohmann::json::parse(s, s + n); 24541 j1.swap(j2);
12176} 24542}
12177 24543
12178/*! 24544#endif
12179@brief user-defined string literal for JSON pointer 24545
24546} // namespace std
12180 24547
12181This operator implements a user-defined string literal for JSON Pointers. It 24548#if JSON_USE_GLOBAL_UDLS
12182can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer 24549 #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
12183object if no parse error occurred. 24550 using nlohmann::literals::json_literals::operator ""_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
24551 using nlohmann::literals::json_literals::operator ""_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
24552 #else
24553 using nlohmann::literals::json_literals::operator "" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
24554 using nlohmann::literals::json_literals::operator "" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
24555 #endif
24556#endif
24557
24558// #include <nlohmann/detail/macro_unscope.hpp>
24559// __ _____ _____ _____
24560// __| | __| | | | JSON for Modern C++
24561// | | |__ | | | | | | version 3.11.3
24562// |_____|_____|_____|_|___| https://github.com/nlohmann/json
24563//
24564// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
24565// SPDX-License-Identifier: MIT
12184 24566
12185@param[in] s a string representation of a JSON Pointer
12186@param[in] n the length of string @a s
12187@return a JSON pointer object
12188 24567
12189@since version 2.0.0
12190*/
12191inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
12192{
12193 return nlohmann::json::json_pointer(std::string(s, n));
12194}
12195 24568
12196// restore GCC/clang diagnostic settings 24569// restore clang diagnostic settings
12197#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) 24570#if defined(__clang__)
12198 #pragma GCC diagnostic pop 24571 #pragma clang diagnostic pop
12199#endif 24572#endif
12200 24573
24574// clean up
24575#undef JSON_ASSERT
24576#undef JSON_INTERNAL_CATCH
24577#undef JSON_THROW
24578#undef JSON_PRIVATE_UNLESS_TESTED
24579#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
24580#undef NLOHMANN_BASIC_JSON_TPL
24581#undef JSON_EXPLICIT
24582#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL
24583#undef JSON_INLINE_VARIABLE
24584#undef JSON_NO_UNIQUE_ADDRESS
24585#undef JSON_DISABLE_ENUM_SERIALIZATION
24586#undef JSON_USE_GLOBAL_UDLS
24587
24588#ifndef JSON_TEST_KEEP_MACROS
24589 #undef JSON_CATCH
24590 #undef JSON_TRY
24591 #undef JSON_HAS_CPP_11
24592 #undef JSON_HAS_CPP_14
24593 #undef JSON_HAS_CPP_17
24594 #undef JSON_HAS_CPP_20
24595 #undef JSON_HAS_FILESYSTEM
24596 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
24597 #undef JSON_HAS_THREE_WAY_COMPARISON
24598 #undef JSON_HAS_RANGES
24599 #undef JSON_HAS_STATIC_RTTI
24600 #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
12201#endif 24601#endif
24602
24603// #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
24604// __ _____ _____ _____
24605// __| | __| | | | JSON for Modern C++
24606// | | |__ | | | | | | version 3.11.3
24607// |_____|_____|_____|_|___| https://github.com/nlohmann/json
24608//
24609// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
24610// SPDX-License-Identifier: MIT
24611
24612
24613
24614#undef JSON_HEDLEY_ALWAYS_INLINE
24615#undef JSON_HEDLEY_ARM_VERSION
24616#undef JSON_HEDLEY_ARM_VERSION_CHECK
24617#undef JSON_HEDLEY_ARRAY_PARAM
24618#undef JSON_HEDLEY_ASSUME
24619#undef JSON_HEDLEY_BEGIN_C_DECLS
24620#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
24621#undef JSON_HEDLEY_CLANG_HAS_BUILTIN
24622#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
24623#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
24624#undef JSON_HEDLEY_CLANG_HAS_EXTENSION
24625#undef JSON_HEDLEY_CLANG_HAS_FEATURE
24626#undef JSON_HEDLEY_CLANG_HAS_WARNING
24627#undef JSON_HEDLEY_COMPCERT_VERSION
24628#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK
24629#undef JSON_HEDLEY_CONCAT
24630#undef JSON_HEDLEY_CONCAT3
24631#undef JSON_HEDLEY_CONCAT3_EX
24632#undef JSON_HEDLEY_CONCAT_EX
24633#undef JSON_HEDLEY_CONST
24634#undef JSON_HEDLEY_CONSTEXPR
24635#undef JSON_HEDLEY_CONST_CAST
24636#undef JSON_HEDLEY_CPP_CAST
24637#undef JSON_HEDLEY_CRAY_VERSION
24638#undef JSON_HEDLEY_CRAY_VERSION_CHECK
24639#undef JSON_HEDLEY_C_DECL
24640#undef JSON_HEDLEY_DEPRECATED
24641#undef JSON_HEDLEY_DEPRECATED_FOR
24642#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
24643#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_
24644#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
24645#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
24646#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
24647#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
24648#undef JSON_HEDLEY_DIAGNOSTIC_POP
24649#undef JSON_HEDLEY_DIAGNOSTIC_PUSH
24650#undef JSON_HEDLEY_DMC_VERSION
24651#undef JSON_HEDLEY_DMC_VERSION_CHECK
24652#undef JSON_HEDLEY_EMPTY_BASES
24653#undef JSON_HEDLEY_EMSCRIPTEN_VERSION
24654#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK
24655#undef JSON_HEDLEY_END_C_DECLS
24656#undef JSON_HEDLEY_FLAGS
24657#undef JSON_HEDLEY_FLAGS_CAST
24658#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE
24659#undef JSON_HEDLEY_GCC_HAS_BUILTIN
24660#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE
24661#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE
24662#undef JSON_HEDLEY_GCC_HAS_EXTENSION
24663#undef JSON_HEDLEY_GCC_HAS_FEATURE
24664#undef JSON_HEDLEY_GCC_HAS_WARNING
24665#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK
24666#undef JSON_HEDLEY_GCC_VERSION
24667#undef JSON_HEDLEY_GCC_VERSION_CHECK
24668#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE
24669#undef JSON_HEDLEY_GNUC_HAS_BUILTIN
24670#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE
24671#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE
24672#undef JSON_HEDLEY_GNUC_HAS_EXTENSION
24673#undef JSON_HEDLEY_GNUC_HAS_FEATURE
24674#undef JSON_HEDLEY_GNUC_HAS_WARNING
24675#undef JSON_HEDLEY_GNUC_VERSION
24676#undef JSON_HEDLEY_GNUC_VERSION_CHECK
24677#undef JSON_HEDLEY_HAS_ATTRIBUTE
24678#undef JSON_HEDLEY_HAS_BUILTIN
24679#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE
24680#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS
24681#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE
24682#undef JSON_HEDLEY_HAS_EXTENSION
24683#undef JSON_HEDLEY_HAS_FEATURE
24684#undef JSON_HEDLEY_HAS_WARNING
24685#undef JSON_HEDLEY_IAR_VERSION
24686#undef JSON_HEDLEY_IAR_VERSION_CHECK
24687#undef JSON_HEDLEY_IBM_VERSION
24688#undef JSON_HEDLEY_IBM_VERSION_CHECK
24689#undef JSON_HEDLEY_IMPORT
24690#undef JSON_HEDLEY_INLINE
24691#undef JSON_HEDLEY_INTEL_CL_VERSION
24692#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK
24693#undef JSON_HEDLEY_INTEL_VERSION
24694#undef JSON_HEDLEY_INTEL_VERSION_CHECK
24695#undef JSON_HEDLEY_IS_CONSTANT
24696#undef JSON_HEDLEY_IS_CONSTEXPR_
24697#undef JSON_HEDLEY_LIKELY
24698#undef JSON_HEDLEY_MALLOC
24699#undef JSON_HEDLEY_MCST_LCC_VERSION
24700#undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK
24701#undef JSON_HEDLEY_MESSAGE
24702#undef JSON_HEDLEY_MSVC_VERSION
24703#undef JSON_HEDLEY_MSVC_VERSION_CHECK
24704#undef JSON_HEDLEY_NEVER_INLINE
24705#undef JSON_HEDLEY_NON_NULL
24706#undef JSON_HEDLEY_NO_ESCAPE
24707#undef JSON_HEDLEY_NO_RETURN
24708#undef JSON_HEDLEY_NO_THROW
24709#undef JSON_HEDLEY_NULL
24710#undef JSON_HEDLEY_PELLES_VERSION
24711#undef JSON_HEDLEY_PELLES_VERSION_CHECK
24712#undef JSON_HEDLEY_PGI_VERSION
24713#undef JSON_HEDLEY_PGI_VERSION_CHECK
24714#undef JSON_HEDLEY_PREDICT
24715#undef JSON_HEDLEY_PRINTF_FORMAT
24716#undef JSON_HEDLEY_PRIVATE
24717#undef JSON_HEDLEY_PUBLIC
24718#undef JSON_HEDLEY_PURE
24719#undef JSON_HEDLEY_REINTERPRET_CAST
24720#undef JSON_HEDLEY_REQUIRE
24721#undef JSON_HEDLEY_REQUIRE_CONSTEXPR
24722#undef JSON_HEDLEY_REQUIRE_MSG
24723#undef JSON_HEDLEY_RESTRICT
24724#undef JSON_HEDLEY_RETURNS_NON_NULL
24725#undef JSON_HEDLEY_SENTINEL
24726#undef JSON_HEDLEY_STATIC_ASSERT
24727#undef JSON_HEDLEY_STATIC_CAST
24728#undef JSON_HEDLEY_STRINGIFY
24729#undef JSON_HEDLEY_STRINGIFY_EX
24730#undef JSON_HEDLEY_SUNPRO_VERSION
24731#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK
24732#undef JSON_HEDLEY_TINYC_VERSION
24733#undef JSON_HEDLEY_TINYC_VERSION_CHECK
24734#undef JSON_HEDLEY_TI_ARMCL_VERSION
24735#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK
24736#undef JSON_HEDLEY_TI_CL2000_VERSION
24737#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK
24738#undef JSON_HEDLEY_TI_CL430_VERSION
24739#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK
24740#undef JSON_HEDLEY_TI_CL6X_VERSION
24741#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK
24742#undef JSON_HEDLEY_TI_CL7X_VERSION
24743#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK
24744#undef JSON_HEDLEY_TI_CLPRU_VERSION
24745#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK
24746#undef JSON_HEDLEY_TI_VERSION
24747#undef JSON_HEDLEY_TI_VERSION_CHECK
24748#undef JSON_HEDLEY_UNAVAILABLE
24749#undef JSON_HEDLEY_UNLIKELY
24750#undef JSON_HEDLEY_UNPREDICTABLE
24751#undef JSON_HEDLEY_UNREACHABLE
24752#undef JSON_HEDLEY_UNREACHABLE_RETURN
24753#undef JSON_HEDLEY_VERSION
24754#undef JSON_HEDLEY_VERSION_DECODE_MAJOR
24755#undef JSON_HEDLEY_VERSION_DECODE_MINOR
24756#undef JSON_HEDLEY_VERSION_DECODE_REVISION
24757#undef JSON_HEDLEY_VERSION_ENCODE
24758#undef JSON_HEDLEY_WARNING
24759#undef JSON_HEDLEY_WARN_UNUSED_RESULT
24760#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG
24761#undef JSON_HEDLEY_FALL_THROUGH
24762
24763
24764
24765#endif // INCLUDE_NLOHMANN_JSON_HPP_
diff --git a/vendor/stduuid b/vendor/stduuid new file mode 160000
Subproject 3afe7193facd5d674de709fccc44d5055e144d7
diff --git a/wizard.cpp b/wizard.cpp index 1541fed..a1d7df4 100644 --- a/wizard.cpp +++ b/wizard.cpp
@@ -50,6 +50,10 @@ wizard::wizard(const cardset& cards, const imagestore& images, std::string text,
50 std::cout << std::endl; 50 std::cout << std::endl;
51} 51}
52 52
53void wizard::set_status_callback(status_callback_type callback) {
54 status_callback_ = callback;
55}
56
53Magick::Image wizard::run() { 57Magick::Image wizard::run() {
54 std::string text = text_; //"what the heck, it's just some gay guy"; 58 std::string text = text_; //"what the heck, it's just some gay guy";
55 // getline(std::cin, text); 59 // getline(std::cin, text);
@@ -58,6 +62,9 @@ Magick::Image wizard::run() {
58 } 62 }
59 63
60 std::cout << "Calculating card list..." << std::endl; 64 std::cout << "Calculating card list..." << std::endl;
65 if (status_callback_) {
66 status_callback_("Calculating card list...");
67 }
61 68
62 std::string canonText = hatkirby::lowercase(text); 69 std::string canonText = hatkirby::lowercase(text);
63 designer des(canonText, cards_.getTitles()); 70 designer des(canonText, cards_.getTitles());
@@ -76,10 +83,16 @@ Magick::Image wizard::run() {
76 << cardName.substr(u.strIndex + u.strLen) << std::endl; 83 << cardName.substr(u.strIndex + u.strLen) << std::endl;
77 84
78 std::cout << "Downloading image..." << std::endl; 85 std::cout << "Downloading image..." << std::endl;
86 if (status_callback_) {
87 status_callback_("Downloading image...");
88 }
79 89
80 Magick::Image cardImg = images_.get(theCard.uuid, theCard.imageUri); 90 Magick::Image cardImg = images_.get(theCard.uuid, theCard.imageUri);
81 91
82 std::cout << "Reading text..." << std::endl; 92 std::cout << "Reading text..." << std::endl;
93 if (status_callback_) {
94 status_callback_("Reading text...");
95 }
83 96
84 Magick::Image titleImg = cardImg; 97 Magick::Image titleImg = cardImg;
85 titleImg.magick("TIFF"); 98 titleImg.magick("TIFF");
@@ -139,9 +152,10 @@ Magick::Image wizard::run() {
139 152
140 size_t leadin = hatkirby::lowercase(lineStr).find( 153 size_t leadin = hatkirby::lowercase(lineStr).find(
141 hatkirby::lowercase((cardName))); 154 hatkirby::lowercase((cardName)));
142 if (leadin != std::string::npos) { 155 // if (leadin != std::string::npos)
156 {
143 foundName = true; 157 foundName = true;
144 extraChars = leadin; 158 // extraChars = leadin;
145 159
146 break; 160 break;
147 } /* else { 161 } /* else {
diff --git a/wizard.h b/wizard.h index a02197b..8269852 100644 --- a/wizard.h +++ b/wizard.h
@@ -3,6 +3,7 @@
3 3
4#include <Magick++.h> 4#include <Magick++.h>
5 5
6#include <functional>
6#include <random> 7#include <random>
7#include <string> 8#include <string>
8 9
@@ -11,9 +12,13 @@
11 12
12class wizard { 13class wizard {
13 public: 14 public:
15 using status_callback_type = std::function<void(const std::string& status)>;
16
14 wizard(const cardset& cards, const imagestore& images, std::string text, 17 wizard(const cardset& cards, const imagestore& images, std::string text,
15 std::mt19937& rng); 18 std::mt19937& rng);
16 19
20 void set_status_callback(status_callback_type callback);
21
17 Magick::Image run(); 22 Magick::Image run();
18 23
19 private: 24 private:
@@ -22,6 +27,8 @@ class wizard {
22 std::string text_; 27 std::string text_;
23 28
24 std::mt19937 rng_; 29 std::mt19937 rng_;
30
31 status_callback_type status_callback_;
25}; 32};
26 33
27#endif /* end of include guard: WIZARD_H_1014B13E */ 34#endif /* end of include guard: WIZARD_H_1014B13E */