annotate common/json.h @ 0:a4671277546c tip

created the repository for the thymian project
author ferencd
date Tue, 17 Aug 2021 11:19:54 +0200
parents
children
rev   line source
ferencd@0 1 /*
ferencd@0 2 __ _____ _____ _____
ferencd@0 3 __| | __| | | | JSON for Modern C++
ferencd@0 4 | | |__ | | | | | | version 3.7.0
ferencd@0 5 |_____|_____|_____|_|___| https://github.com/nlohmann/json
ferencd@0 6
ferencd@0 7 Licensed under the MIT License <http://opensource.org/licenses/MIT>.
ferencd@0 8 SPDX-License-Identifier: MIT
ferencd@0 9 Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
ferencd@0 10
ferencd@0 11 Permission is hereby granted, free of charge, to any person obtaining a copy
ferencd@0 12 of this software and associated documentation files (the "Software"), to deal
ferencd@0 13 in the Software without restriction, including without limitation the rights
ferencd@0 14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
ferencd@0 15 copies of the Software, and to permit persons to whom the Software is
ferencd@0 16 furnished to do so, subject to the following conditions:
ferencd@0 17
ferencd@0 18 The above copyright notice and this permission notice shall be included in all
ferencd@0 19 copies or substantial portions of the Software.
ferencd@0 20
ferencd@0 21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
ferencd@0 22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
ferencd@0 23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
ferencd@0 24 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
ferencd@0 25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
ferencd@0 26 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
ferencd@0 27 SOFTWARE.
ferencd@0 28 */
ferencd@0 29
ferencd@0 30 #ifndef INCLUDE_NLOHMANN_JSON_HPP_
ferencd@0 31 #define INCLUDE_NLOHMANN_JSON_HPP_
ferencd@0 32
ferencd@0 33 #define NLOHMANN_JSON_VERSION_MAJOR 3
ferencd@0 34 #define NLOHMANN_JSON_VERSION_MINOR 7
ferencd@0 35 #define NLOHMANN_JSON_VERSION_PATCH 0
ferencd@0 36
ferencd@0 37 #include <algorithm> // all_of, find, for_each
ferencd@0 38 #include <cassert> // assert
ferencd@0 39 #include <ciso646> // and, not, or
ferencd@0 40 #include <cstddef> // nullptr_t, ptrdiff_t, size_t
ferencd@0 41 #include <functional> // hash, less
ferencd@0 42 #include <initializer_list> // initializer_list
ferencd@0 43 #include <iosfwd> // istream, ostream
ferencd@0 44 #include <iterator> // random_access_iterator_tag
ferencd@0 45 #include <memory> // unique_ptr
ferencd@0 46 #include <numeric> // accumulate
ferencd@0 47 #include <string> // string, stoi, to_string
ferencd@0 48 #include <utility> // declval, forward, move, pair, swap
ferencd@0 49 #include <vector> // vector
ferencd@0 50
ferencd@0 51 // #include <nlohmann/adl_serializer.hpp>
ferencd@0 52
ferencd@0 53
ferencd@0 54 #include <utility>
ferencd@0 55
ferencd@0 56 // #include <nlohmann/detail/conversions/from_json.hpp>
ferencd@0 57
ferencd@0 58
ferencd@0 59 #include <algorithm> // transform
ferencd@0 60 #include <array> // array
ferencd@0 61 #include <ciso646> // and, not
ferencd@0 62 #include <forward_list> // forward_list
ferencd@0 63 #include <iterator> // inserter, front_inserter, end
ferencd@0 64 #include <map> // map
ferencd@0 65 #include <string> // string
ferencd@0 66 #include <tuple> // tuple, make_tuple
ferencd@0 67 #include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
ferencd@0 68 #include <unordered_map> // unordered_map
ferencd@0 69 #include <utility> // pair, declval
ferencd@0 70 #include <valarray> // valarray
ferencd@0 71
ferencd@0 72 // #include <nlohmann/detail/exceptions.hpp>
ferencd@0 73
ferencd@0 74
ferencd@0 75 #include <exception> // exception
ferencd@0 76 #include <stdexcept> // runtime_error
ferencd@0 77 #include <string> // to_string
ferencd@0 78
ferencd@0 79 // #include <nlohmann/detail/input/position_t.hpp>
ferencd@0 80
ferencd@0 81
ferencd@0 82 #include <cstddef> // size_t
ferencd@0 83
ferencd@0 84 namespace nlohmann
ferencd@0 85 {
ferencd@0 86 namespace detail
ferencd@0 87 {
ferencd@0 88 /// struct to capture the start position of the current token
ferencd@0 89 struct position_t
ferencd@0 90 {
ferencd@0 91 /// the total number of characters read
ferencd@0 92 std::size_t chars_read_total = 0;
ferencd@0 93 /// the number of characters read in the current line
ferencd@0 94 std::size_t chars_read_current_line = 0;
ferencd@0 95 /// the number of lines read
ferencd@0 96 std::size_t lines_read = 0;
ferencd@0 97
ferencd@0 98 /// conversion to size_t to preserve SAX interface
ferencd@0 99 constexpr operator size_t() const
ferencd@0 100 {
ferencd@0 101 return chars_read_total;
ferencd@0 102 }
ferencd@0 103 };
ferencd@0 104
ferencd@0 105 } // namespace detail
ferencd@0 106 } // namespace nlohmann
ferencd@0 107
ferencd@0 108 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 109
ferencd@0 110
ferencd@0 111 #include <utility> // pair
ferencd@0 112 // #include <nlohmann/thirdparty/hedley/hedley.hpp>
ferencd@0 113 /* Hedley - https://nemequ.github.io/hedley
ferencd@0 114 * Created by Evan Nemerson <evan@nemerson.com>
ferencd@0 115 *
ferencd@0 116 * To the extent possible under law, the author(s) have dedicated all
ferencd@0 117 * copyright and related and neighboring rights to this software to
ferencd@0 118 * the public domain worldwide. This software is distributed without
ferencd@0 119 * any warranty.
ferencd@0 120 *
ferencd@0 121 * For details, see <http://creativecommons.org/publicdomain/zero/1.0/>.
ferencd@0 122 * SPDX-License-Identifier: CC0-1.0
ferencd@0 123 */
ferencd@0 124
ferencd@0 125 #if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 9)
ferencd@0 126 #if defined(JSON_HEDLEY_VERSION)
ferencd@0 127 #undef JSON_HEDLEY_VERSION
ferencd@0 128 #endif
ferencd@0 129 #define JSON_HEDLEY_VERSION 9
ferencd@0 130
ferencd@0 131 #if defined(JSON_HEDLEY_STRINGIFY_EX)
ferencd@0 132 #undef JSON_HEDLEY_STRINGIFY_EX
ferencd@0 133 #endif
ferencd@0 134 #define JSON_HEDLEY_STRINGIFY_EX(x) #x
ferencd@0 135
ferencd@0 136 #if defined(JSON_HEDLEY_STRINGIFY)
ferencd@0 137 #undef JSON_HEDLEY_STRINGIFY
ferencd@0 138 #endif
ferencd@0 139 #define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x)
ferencd@0 140
ferencd@0 141 #if defined(JSON_HEDLEY_CONCAT_EX)
ferencd@0 142 #undef JSON_HEDLEY_CONCAT_EX
ferencd@0 143 #endif
ferencd@0 144 #define JSON_HEDLEY_CONCAT_EX(a,b) a##b
ferencd@0 145
ferencd@0 146 #if defined(JSON_HEDLEY_CONCAT)
ferencd@0 147 #undef JSON_HEDLEY_CONCAT
ferencd@0 148 #endif
ferencd@0 149 #define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b)
ferencd@0 150
ferencd@0 151 #if defined(JSON_HEDLEY_VERSION_ENCODE)
ferencd@0 152 #undef JSON_HEDLEY_VERSION_ENCODE
ferencd@0 153 #endif
ferencd@0 154 #define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision))
ferencd@0 155
ferencd@0 156 #if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR)
ferencd@0 157 #undef JSON_HEDLEY_VERSION_DECODE_MAJOR
ferencd@0 158 #endif
ferencd@0 159 #define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000)
ferencd@0 160
ferencd@0 161 #if defined(JSON_HEDLEY_VERSION_DECODE_MINOR)
ferencd@0 162 #undef JSON_HEDLEY_VERSION_DECODE_MINOR
ferencd@0 163 #endif
ferencd@0 164 #define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000)
ferencd@0 165
ferencd@0 166 #if defined(JSON_HEDLEY_VERSION_DECODE_REVISION)
ferencd@0 167 #undef JSON_HEDLEY_VERSION_DECODE_REVISION
ferencd@0 168 #endif
ferencd@0 169 #define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000)
ferencd@0 170
ferencd@0 171 #if defined(JSON_HEDLEY_GNUC_VERSION)
ferencd@0 172 #undef JSON_HEDLEY_GNUC_VERSION
ferencd@0 173 #endif
ferencd@0 174 #if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)
ferencd@0 175 #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
ferencd@0 176 #elif defined(__GNUC__)
ferencd@0 177 #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0)
ferencd@0 178 #endif
ferencd@0 179
ferencd@0 180 #if defined(JSON_HEDLEY_GNUC_VERSION_CHECK)
ferencd@0 181 #undef JSON_HEDLEY_GNUC_VERSION_CHECK
ferencd@0 182 #endif
ferencd@0 183 #if defined(JSON_HEDLEY_GNUC_VERSION)
ferencd@0 184 #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 185 #else
ferencd@0 186 #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 187 #endif
ferencd@0 188
ferencd@0 189 #if defined(JSON_HEDLEY_MSVC_VERSION)
ferencd@0 190 #undef JSON_HEDLEY_MSVC_VERSION
ferencd@0 191 #endif
ferencd@0 192 #if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000)
ferencd@0 193 #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100)
ferencd@0 194 #elif defined(_MSC_FULL_VER)
ferencd@0 195 #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10)
ferencd@0 196 #elif defined(_MSC_VER)
ferencd@0 197 #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0)
ferencd@0 198 #endif
ferencd@0 199
ferencd@0 200 #if defined(JSON_HEDLEY_MSVC_VERSION_CHECK)
ferencd@0 201 #undef JSON_HEDLEY_MSVC_VERSION_CHECK
ferencd@0 202 #endif
ferencd@0 203 #if !defined(_MSC_VER)
ferencd@0 204 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 205 #elif defined(_MSC_VER) && (_MSC_VER >= 1400)
ferencd@0 206 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))
ferencd@0 207 #elif defined(_MSC_VER) && (_MSC_VER >= 1200)
ferencd@0 208 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))
ferencd@0 209 #else
ferencd@0 210 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor)))
ferencd@0 211 #endif
ferencd@0 212
ferencd@0 213 #if defined(JSON_HEDLEY_INTEL_VERSION)
ferencd@0 214 #undef JSON_HEDLEY_INTEL_VERSION
ferencd@0 215 #endif
ferencd@0 216 #if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE)
ferencd@0 217 #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE)
ferencd@0 218 #elif defined(__INTEL_COMPILER)
ferencd@0 219 #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)
ferencd@0 220 #endif
ferencd@0 221
ferencd@0 222 #if defined(JSON_HEDLEY_INTEL_VERSION_CHECK)
ferencd@0 223 #undef JSON_HEDLEY_INTEL_VERSION_CHECK
ferencd@0 224 #endif
ferencd@0 225 #if defined(JSON_HEDLEY_INTEL_VERSION)
ferencd@0 226 #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 227 #else
ferencd@0 228 #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 229 #endif
ferencd@0 230
ferencd@0 231 #if defined(JSON_HEDLEY_PGI_VERSION)
ferencd@0 232 #undef JSON_HEDLEY_PGI_VERSION
ferencd@0 233 #endif
ferencd@0 234 #if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)
ferencd@0 235 #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)
ferencd@0 236 #endif
ferencd@0 237
ferencd@0 238 #if defined(JSON_HEDLEY_PGI_VERSION_CHECK)
ferencd@0 239 #undef JSON_HEDLEY_PGI_VERSION_CHECK
ferencd@0 240 #endif
ferencd@0 241 #if defined(JSON_HEDLEY_PGI_VERSION)
ferencd@0 242 #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 243 #else
ferencd@0 244 #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 245 #endif
ferencd@0 246
ferencd@0 247 #if defined(JSON_HEDLEY_SUNPRO_VERSION)
ferencd@0 248 #undef JSON_HEDLEY_SUNPRO_VERSION
ferencd@0 249 #endif
ferencd@0 250 #if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
ferencd@0 251 #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)
ferencd@0 252 #elif defined(__SUNPRO_C)
ferencd@0 253 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf)
ferencd@0 254 #elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
ferencd@0 255 #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)
ferencd@0 256 #elif defined(__SUNPRO_CC)
ferencd@0 257 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf)
ferencd@0 258 #endif
ferencd@0 259
ferencd@0 260 #if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK)
ferencd@0 261 #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK
ferencd@0 262 #endif
ferencd@0 263 #if defined(JSON_HEDLEY_SUNPRO_VERSION)
ferencd@0 264 #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 265 #else
ferencd@0 266 #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 267 #endif
ferencd@0 268
ferencd@0 269 #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)
ferencd@0 270 #undef JSON_HEDLEY_EMSCRIPTEN_VERSION
ferencd@0 271 #endif
ferencd@0 272 #if defined(__EMSCRIPTEN__)
ferencd@0 273 #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__)
ferencd@0 274 #endif
ferencd@0 275
ferencd@0 276 #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK)
ferencd@0 277 #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK
ferencd@0 278 #endif
ferencd@0 279 #if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)
ferencd@0 280 #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 281 #else
ferencd@0 282 #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 283 #endif
ferencd@0 284
ferencd@0 285 #if defined(JSON_HEDLEY_ARM_VERSION)
ferencd@0 286 #undef JSON_HEDLEY_ARM_VERSION
ferencd@0 287 #endif
ferencd@0 288 #if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)
ferencd@0 289 #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100)
ferencd@0 290 #elif defined(__CC_ARM) && defined(__ARMCC_VERSION)
ferencd@0 291 #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100)
ferencd@0 292 #endif
ferencd@0 293
ferencd@0 294 #if defined(JSON_HEDLEY_ARM_VERSION_CHECK)
ferencd@0 295 #undef JSON_HEDLEY_ARM_VERSION_CHECK
ferencd@0 296 #endif
ferencd@0 297 #if defined(JSON_HEDLEY_ARM_VERSION)
ferencd@0 298 #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 299 #else
ferencd@0 300 #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 301 #endif
ferencd@0 302
ferencd@0 303 #if defined(JSON_HEDLEY_IBM_VERSION)
ferencd@0 304 #undef JSON_HEDLEY_IBM_VERSION
ferencd@0 305 #endif
ferencd@0 306 #if defined(__ibmxl__)
ferencd@0 307 #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__)
ferencd@0 308 #elif defined(__xlC__) && defined(__xlC_ver__)
ferencd@0 309 #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)
ferencd@0 310 #elif defined(__xlC__)
ferencd@0 311 #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0)
ferencd@0 312 #endif
ferencd@0 313
ferencd@0 314 #if defined(JSON_HEDLEY_IBM_VERSION_CHECK)
ferencd@0 315 #undef JSON_HEDLEY_IBM_VERSION_CHECK
ferencd@0 316 #endif
ferencd@0 317 #if defined(JSON_HEDLEY_IBM_VERSION)
ferencd@0 318 #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 319 #else
ferencd@0 320 #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 321 #endif
ferencd@0 322
ferencd@0 323 #if defined(JSON_HEDLEY_TI_VERSION)
ferencd@0 324 #undef JSON_HEDLEY_TI_VERSION
ferencd@0 325 #endif
ferencd@0 326 #if defined(__TI_COMPILER_VERSION__)
ferencd@0 327 #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
ferencd@0 328 #endif
ferencd@0 329
ferencd@0 330 #if defined(JSON_HEDLEY_TI_VERSION_CHECK)
ferencd@0 331 #undef JSON_HEDLEY_TI_VERSION_CHECK
ferencd@0 332 #endif
ferencd@0 333 #if defined(JSON_HEDLEY_TI_VERSION)
ferencd@0 334 #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 335 #else
ferencd@0 336 #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 337 #endif
ferencd@0 338
ferencd@0 339 #if defined(JSON_HEDLEY_CRAY_VERSION)
ferencd@0 340 #undef JSON_HEDLEY_CRAY_VERSION
ferencd@0 341 #endif
ferencd@0 342 #if defined(_CRAYC)
ferencd@0 343 #if defined(_RELEASE_PATCHLEVEL)
ferencd@0 344 #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL)
ferencd@0 345 #else
ferencd@0 346 #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0)
ferencd@0 347 #endif
ferencd@0 348 #endif
ferencd@0 349
ferencd@0 350 #if defined(JSON_HEDLEY_CRAY_VERSION_CHECK)
ferencd@0 351 #undef JSON_HEDLEY_CRAY_VERSION_CHECK
ferencd@0 352 #endif
ferencd@0 353 #if defined(JSON_HEDLEY_CRAY_VERSION)
ferencd@0 354 #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 355 #else
ferencd@0 356 #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 357 #endif
ferencd@0 358
ferencd@0 359 #if defined(JSON_HEDLEY_IAR_VERSION)
ferencd@0 360 #undef JSON_HEDLEY_IAR_VERSION
ferencd@0 361 #endif
ferencd@0 362 #if defined(__IAR_SYSTEMS_ICC__)
ferencd@0 363 #if __VER__ > 1000
ferencd@0 364 #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000))
ferencd@0 365 #else
ferencd@0 366 #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(VER / 100, __VER__ % 100, 0)
ferencd@0 367 #endif
ferencd@0 368 #endif
ferencd@0 369
ferencd@0 370 #if defined(JSON_HEDLEY_IAR_VERSION_CHECK)
ferencd@0 371 #undef JSON_HEDLEY_IAR_VERSION_CHECK
ferencd@0 372 #endif
ferencd@0 373 #if defined(JSON_HEDLEY_IAR_VERSION)
ferencd@0 374 #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 375 #else
ferencd@0 376 #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 377 #endif
ferencd@0 378
ferencd@0 379 #if defined(JSON_HEDLEY_TINYC_VERSION)
ferencd@0 380 #undef JSON_HEDLEY_TINYC_VERSION
ferencd@0 381 #endif
ferencd@0 382 #if defined(__TINYC__)
ferencd@0 383 #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)
ferencd@0 384 #endif
ferencd@0 385
ferencd@0 386 #if defined(JSON_HEDLEY_TINYC_VERSION_CHECK)
ferencd@0 387 #undef JSON_HEDLEY_TINYC_VERSION_CHECK
ferencd@0 388 #endif
ferencd@0 389 #if defined(JSON_HEDLEY_TINYC_VERSION)
ferencd@0 390 #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 391 #else
ferencd@0 392 #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 393 #endif
ferencd@0 394
ferencd@0 395 #if defined(JSON_HEDLEY_DMC_VERSION)
ferencd@0 396 #undef JSON_HEDLEY_DMC_VERSION
ferencd@0 397 #endif
ferencd@0 398 #if defined(__DMC__)
ferencd@0 399 #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf)
ferencd@0 400 #endif
ferencd@0 401
ferencd@0 402 #if defined(JSON_HEDLEY_DMC_VERSION_CHECK)
ferencd@0 403 #undef JSON_HEDLEY_DMC_VERSION_CHECK
ferencd@0 404 #endif
ferencd@0 405 #if defined(JSON_HEDLEY_DMC_VERSION)
ferencd@0 406 #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 407 #else
ferencd@0 408 #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 409 #endif
ferencd@0 410
ferencd@0 411 #if defined(JSON_HEDLEY_COMPCERT_VERSION)
ferencd@0 412 #undef JSON_HEDLEY_COMPCERT_VERSION
ferencd@0 413 #endif
ferencd@0 414 #if defined(__COMPCERT_VERSION__)
ferencd@0 415 #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100)
ferencd@0 416 #endif
ferencd@0 417
ferencd@0 418 #if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK)
ferencd@0 419 #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK
ferencd@0 420 #endif
ferencd@0 421 #if defined(JSON_HEDLEY_COMPCERT_VERSION)
ferencd@0 422 #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 423 #else
ferencd@0 424 #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 425 #endif
ferencd@0 426
ferencd@0 427 #if defined(JSON_HEDLEY_PELLES_VERSION)
ferencd@0 428 #undef JSON_HEDLEY_PELLES_VERSION
ferencd@0 429 #endif
ferencd@0 430 #if defined(__POCC__)
ferencd@0 431 #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0)
ferencd@0 432 #endif
ferencd@0 433
ferencd@0 434 #if defined(JSON_HEDLEY_PELLES_VERSION_CHECK)
ferencd@0 435 #undef JSON_HEDLEY_PELLES_VERSION_CHECK
ferencd@0 436 #endif
ferencd@0 437 #if defined(JSON_HEDLEY_PELLES_VERSION)
ferencd@0 438 #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 439 #else
ferencd@0 440 #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 441 #endif
ferencd@0 442
ferencd@0 443 #if defined(JSON_HEDLEY_GCC_VERSION)
ferencd@0 444 #undef JSON_HEDLEY_GCC_VERSION
ferencd@0 445 #endif
ferencd@0 446 #if \
ferencd@0 447 defined(JSON_HEDLEY_GNUC_VERSION) && \
ferencd@0 448 !defined(__clang__) && \
ferencd@0 449 !defined(JSON_HEDLEY_INTEL_VERSION) && \
ferencd@0 450 !defined(JSON_HEDLEY_PGI_VERSION) && \
ferencd@0 451 !defined(JSON_HEDLEY_ARM_VERSION) && \
ferencd@0 452 !defined(JSON_HEDLEY_TI_VERSION) && \
ferencd@0 453 !defined(__COMPCERT__)
ferencd@0 454 #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION
ferencd@0 455 #endif
ferencd@0 456
ferencd@0 457 #if defined(JSON_HEDLEY_GCC_VERSION_CHECK)
ferencd@0 458 #undef JSON_HEDLEY_GCC_VERSION_CHECK
ferencd@0 459 #endif
ferencd@0 460 #if defined(JSON_HEDLEY_GCC_VERSION)
ferencd@0 461 #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
ferencd@0 462 #else
ferencd@0 463 #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 464 #endif
ferencd@0 465
ferencd@0 466 #if defined(JSON_HEDLEY_HAS_ATTRIBUTE)
ferencd@0 467 #undef JSON_HEDLEY_HAS_ATTRIBUTE
ferencd@0 468 #endif
ferencd@0 469 #if defined(__has_attribute)
ferencd@0 470 #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute)
ferencd@0 471 #else
ferencd@0 472 #define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0)
ferencd@0 473 #endif
ferencd@0 474
ferencd@0 475 #if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE)
ferencd@0 476 #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE
ferencd@0 477 #endif
ferencd@0 478 #if defined(__has_attribute)
ferencd@0 479 #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute)
ferencd@0 480 #else
ferencd@0 481 #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
ferencd@0 482 #endif
ferencd@0 483
ferencd@0 484 #if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE)
ferencd@0 485 #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE
ferencd@0 486 #endif
ferencd@0 487 #if defined(__has_attribute)
ferencd@0 488 #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) __has_attribute(attribute)
ferencd@0 489 #else
ferencd@0 490 #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
ferencd@0 491 #endif
ferencd@0 492
ferencd@0 493 #if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE)
ferencd@0 494 #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE
ferencd@0 495 #endif
ferencd@0 496 #if defined(__has_cpp_attribute) && defined(__cplusplus)
ferencd@0 497 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute)
ferencd@0 498 #else
ferencd@0 499 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0)
ferencd@0 500 #endif
ferencd@0 501
ferencd@0 502 #if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE)
ferencd@0 503 #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE
ferencd@0 504 #endif
ferencd@0 505 #if defined(__has_cpp_attribute) && defined(__cplusplus)
ferencd@0 506 #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
ferencd@0 507 #else
ferencd@0 508 #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
ferencd@0 509 #endif
ferencd@0 510
ferencd@0 511 #if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE)
ferencd@0 512 #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE
ferencd@0 513 #endif
ferencd@0 514 #if defined(__has_cpp_attribute) && defined(__cplusplus)
ferencd@0 515 #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
ferencd@0 516 #else
ferencd@0 517 #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
ferencd@0 518 #endif
ferencd@0 519
ferencd@0 520 #if defined(JSON_HEDLEY_HAS_BUILTIN)
ferencd@0 521 #undef JSON_HEDLEY_HAS_BUILTIN
ferencd@0 522 #endif
ferencd@0 523 #if defined(__has_builtin)
ferencd@0 524 #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin)
ferencd@0 525 #else
ferencd@0 526 #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0)
ferencd@0 527 #endif
ferencd@0 528
ferencd@0 529 #if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN)
ferencd@0 530 #undef JSON_HEDLEY_GNUC_HAS_BUILTIN
ferencd@0 531 #endif
ferencd@0 532 #if defined(__has_builtin)
ferencd@0 533 #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
ferencd@0 534 #else
ferencd@0 535 #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
ferencd@0 536 #endif
ferencd@0 537
ferencd@0 538 #if defined(JSON_HEDLEY_GCC_HAS_BUILTIN)
ferencd@0 539 #undef JSON_HEDLEY_GCC_HAS_BUILTIN
ferencd@0 540 #endif
ferencd@0 541 #if defined(__has_builtin)
ferencd@0 542 #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
ferencd@0 543 #else
ferencd@0 544 #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
ferencd@0 545 #endif
ferencd@0 546
ferencd@0 547 #if defined(JSON_HEDLEY_HAS_FEATURE)
ferencd@0 548 #undef JSON_HEDLEY_HAS_FEATURE
ferencd@0 549 #endif
ferencd@0 550 #if defined(__has_feature)
ferencd@0 551 #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature)
ferencd@0 552 #else
ferencd@0 553 #define JSON_HEDLEY_HAS_FEATURE(feature) (0)
ferencd@0 554 #endif
ferencd@0 555
ferencd@0 556 #if defined(JSON_HEDLEY_GNUC_HAS_FEATURE)
ferencd@0 557 #undef JSON_HEDLEY_GNUC_HAS_FEATURE
ferencd@0 558 #endif
ferencd@0 559 #if defined(__has_feature)
ferencd@0 560 #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
ferencd@0 561 #else
ferencd@0 562 #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
ferencd@0 563 #endif
ferencd@0 564
ferencd@0 565 #if defined(JSON_HEDLEY_GCC_HAS_FEATURE)
ferencd@0 566 #undef JSON_HEDLEY_GCC_HAS_FEATURE
ferencd@0 567 #endif
ferencd@0 568 #if defined(__has_feature)
ferencd@0 569 #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
ferencd@0 570 #else
ferencd@0 571 #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
ferencd@0 572 #endif
ferencd@0 573
ferencd@0 574 #if defined(JSON_HEDLEY_HAS_EXTENSION)
ferencd@0 575 #undef JSON_HEDLEY_HAS_EXTENSION
ferencd@0 576 #endif
ferencd@0 577 #if defined(__has_extension)
ferencd@0 578 #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension)
ferencd@0 579 #else
ferencd@0 580 #define JSON_HEDLEY_HAS_EXTENSION(extension) (0)
ferencd@0 581 #endif
ferencd@0 582
ferencd@0 583 #if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION)
ferencd@0 584 #undef JSON_HEDLEY_GNUC_HAS_EXTENSION
ferencd@0 585 #endif
ferencd@0 586 #if defined(__has_extension)
ferencd@0 587 #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
ferencd@0 588 #else
ferencd@0 589 #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
ferencd@0 590 #endif
ferencd@0 591
ferencd@0 592 #if defined(JSON_HEDLEY_GCC_HAS_EXTENSION)
ferencd@0 593 #undef JSON_HEDLEY_GCC_HAS_EXTENSION
ferencd@0 594 #endif
ferencd@0 595 #if defined(__has_extension)
ferencd@0 596 #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
ferencd@0 597 #else
ferencd@0 598 #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
ferencd@0 599 #endif
ferencd@0 600
ferencd@0 601 #if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE)
ferencd@0 602 #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE
ferencd@0 603 #endif
ferencd@0 604 #if defined(__has_declspec_attribute)
ferencd@0 605 #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute)
ferencd@0 606 #else
ferencd@0 607 #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0)
ferencd@0 608 #endif
ferencd@0 609
ferencd@0 610 #if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE)
ferencd@0 611 #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE
ferencd@0 612 #endif
ferencd@0 613 #if defined(__has_declspec_attribute)
ferencd@0 614 #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
ferencd@0 615 #else
ferencd@0 616 #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
ferencd@0 617 #endif
ferencd@0 618
ferencd@0 619 #if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE)
ferencd@0 620 #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE
ferencd@0 621 #endif
ferencd@0 622 #if defined(__has_declspec_attribute)
ferencd@0 623 #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
ferencd@0 624 #else
ferencd@0 625 #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
ferencd@0 626 #endif
ferencd@0 627
ferencd@0 628 #if defined(JSON_HEDLEY_HAS_WARNING)
ferencd@0 629 #undef JSON_HEDLEY_HAS_WARNING
ferencd@0 630 #endif
ferencd@0 631 #if defined(__has_warning)
ferencd@0 632 #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning)
ferencd@0 633 #else
ferencd@0 634 #define JSON_HEDLEY_HAS_WARNING(warning) (0)
ferencd@0 635 #endif
ferencd@0 636
ferencd@0 637 #if defined(JSON_HEDLEY_GNUC_HAS_WARNING)
ferencd@0 638 #undef JSON_HEDLEY_GNUC_HAS_WARNING
ferencd@0 639 #endif
ferencd@0 640 #if defined(__has_warning)
ferencd@0 641 #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
ferencd@0 642 #else
ferencd@0 643 #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
ferencd@0 644 #endif
ferencd@0 645
ferencd@0 646 #if defined(JSON_HEDLEY_GCC_HAS_WARNING)
ferencd@0 647 #undef JSON_HEDLEY_GCC_HAS_WARNING
ferencd@0 648 #endif
ferencd@0 649 #if defined(__has_warning)
ferencd@0 650 #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
ferencd@0 651 #else
ferencd@0 652 #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
ferencd@0 653 #endif
ferencd@0 654
ferencd@0 655 #if \
ferencd@0 656 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
ferencd@0 657 defined(__clang__) || \
ferencd@0 658 JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
ferencd@0 659 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 660 JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
ferencd@0 661 JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
ferencd@0 662 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
ferencd@0 663 JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) || \
ferencd@0 664 JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \
ferencd@0 665 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \
ferencd@0 666 JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \
ferencd@0 667 (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR))
ferencd@0 668 #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value)
ferencd@0 669 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
ferencd@0 670 #define JSON_HEDLEY_PRAGMA(value) __pragma(value)
ferencd@0 671 #else
ferencd@0 672 #define JSON_HEDLEY_PRAGMA(value)
ferencd@0 673 #endif
ferencd@0 674
ferencd@0 675 #if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH)
ferencd@0 676 #undef JSON_HEDLEY_DIAGNOSTIC_PUSH
ferencd@0 677 #endif
ferencd@0 678 #if defined(JSON_HEDLEY_DIAGNOSTIC_POP)
ferencd@0 679 #undef JSON_HEDLEY_DIAGNOSTIC_POP
ferencd@0 680 #endif
ferencd@0 681 #if defined(__clang__)
ferencd@0 682 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push")
ferencd@0 683 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop")
ferencd@0 684 #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
ferencd@0 685 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
ferencd@0 686 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
ferencd@0 687 #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)
ferencd@0 688 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
ferencd@0 689 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
ferencd@0 690 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
ferencd@0 691 #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push))
ferencd@0 692 #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop))
ferencd@0 693 #elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0)
ferencd@0 694 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push")
ferencd@0 695 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop")
ferencd@0 696 #elif JSON_HEDLEY_TI_VERSION_CHECK(8,1,0)
ferencd@0 697 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push")
ferencd@0 698 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop")
ferencd@0 699 #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
ferencd@0 700 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
ferencd@0 701 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
ferencd@0 702 #else
ferencd@0 703 #define JSON_HEDLEY_DIAGNOSTIC_PUSH
ferencd@0 704 #define JSON_HEDLEY_DIAGNOSTIC_POP
ferencd@0 705 #endif
ferencd@0 706
ferencd@0 707 #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED)
ferencd@0 708 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
ferencd@0 709 #endif
ferencd@0 710 #if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations")
ferencd@0 711 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
ferencd@0 712 #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
ferencd@0 713 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)")
ferencd@0 714 #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
ferencd@0 715 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444")
ferencd@0 716 #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
ferencd@0 717 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
ferencd@0 718 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
ferencd@0 719 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996))
ferencd@0 720 #elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0)
ferencd@0 721 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718")
ferencd@0 722 #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus)
ferencd@0 723 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)")
ferencd@0 724 #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus)
ferencd@0 725 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)")
ferencd@0 726 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
ferencd@0 727 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215")
ferencd@0 728 #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
ferencd@0 729 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)")
ferencd@0 730 #else
ferencd@0 731 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
ferencd@0 732 #endif
ferencd@0 733
ferencd@0 734 #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS)
ferencd@0 735 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
ferencd@0 736 #endif
ferencd@0 737 #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
ferencd@0 738 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"")
ferencd@0 739 #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
ferencd@0 740 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)")
ferencd@0 741 #elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
ferencd@0 742 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675")
ferencd@0 743 #elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
ferencd@0 744 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"")
ferencd@0 745 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
ferencd@0 746 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068))
ferencd@0 747 #elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0)
ferencd@0 748 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163")
ferencd@0 749 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
ferencd@0 750 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161")
ferencd@0 751 #else
ferencd@0 752 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
ferencd@0 753 #endif
ferencd@0 754
ferencd@0 755 #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL)
ferencd@0 756 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
ferencd@0 757 #endif
ferencd@0 758 #if JSON_HEDLEY_HAS_WARNING("-Wcast-qual")
ferencd@0 759 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"")
ferencd@0 760 #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
ferencd@0 761 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)")
ferencd@0 762 #elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0)
ferencd@0 763 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
ferencd@0 764 #else
ferencd@0 765 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
ferencd@0 766 #endif
ferencd@0 767
ferencd@0 768 #if defined(JSON_HEDLEY_DEPRECATED)
ferencd@0 769 #undef JSON_HEDLEY_DEPRECATED
ferencd@0 770 #endif
ferencd@0 771 #if defined(JSON_HEDLEY_DEPRECATED_FOR)
ferencd@0 772 #undef JSON_HEDLEY_DEPRECATED_FOR
ferencd@0 773 #endif
ferencd@0 774 #if defined(__cplusplus) && (__cplusplus >= 201402L)
ferencd@0 775 #define JSON_HEDLEY_DEPRECATED(since) [[deprecated("Since " #since)]]
ferencd@0 776 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]]
ferencd@0 777 #elif \
ferencd@0 778 JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \
ferencd@0 779 JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
ferencd@0 780 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 781 JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \
ferencd@0 782 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \
ferencd@0 783 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
ferencd@0 784 JSON_HEDLEY_TI_VERSION_CHECK(8,3,0)
ferencd@0 785 #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since)))
ferencd@0 786 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement)))
ferencd@0 787 #elif \
ferencd@0 788 JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \
ferencd@0 789 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
ferencd@0 790 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
ferencd@0 791 JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \
ferencd@0 792 (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
ferencd@0 793 #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))
ferencd@0 794 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))
ferencd@0 795 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0)
ferencd@0 796 #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since))
ferencd@0 797 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement))
ferencd@0 798 #elif \
ferencd@0 799 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
ferencd@0 800 JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0)
ferencd@0 801 #define JSON_HEDLEY_DEPRECATED(since) _declspec(deprecated)
ferencd@0 802 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)
ferencd@0 803 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
ferencd@0 804 #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated")
ferencd@0 805 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated")
ferencd@0 806 #else
ferencd@0 807 #define JSON_HEDLEY_DEPRECATED(since)
ferencd@0 808 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement)
ferencd@0 809 #endif
ferencd@0 810
ferencd@0 811 #if defined(JSON_HEDLEY_UNAVAILABLE)
ferencd@0 812 #undef JSON_HEDLEY_UNAVAILABLE
ferencd@0 813 #endif
ferencd@0 814 #if \
ferencd@0 815 JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \
ferencd@0 816 JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \
ferencd@0 817 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
ferencd@0 818 #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since)))
ferencd@0 819 #else
ferencd@0 820 #define JSON_HEDLEY_UNAVAILABLE(available_since)
ferencd@0 821 #endif
ferencd@0 822
ferencd@0 823 #if defined(JSON_HEDLEY_WARN_UNUSED_RESULT)
ferencd@0 824 #undef JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 825 #endif
ferencd@0 826 #if defined(__cplusplus) && (__cplusplus >= 201703L)
ferencd@0 827 #define JSON_HEDLEY_WARN_UNUSED_RESULT [[nodiscard]]
ferencd@0 828 #elif \
ferencd@0 829 JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \
ferencd@0 830 JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
ferencd@0 831 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 832 JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \
ferencd@0 833 (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
ferencd@0 834 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \
ferencd@0 835 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
ferencd@0 836 #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
ferencd@0 837 #elif defined(_Check_return_) /* SAL */
ferencd@0 838 #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_
ferencd@0 839 #else
ferencd@0 840 #define JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 841 #endif
ferencd@0 842
ferencd@0 843 #if defined(JSON_HEDLEY_SENTINEL)
ferencd@0 844 #undef JSON_HEDLEY_SENTINEL
ferencd@0 845 #endif
ferencd@0 846 #if \
ferencd@0 847 JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \
ferencd@0 848 JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
ferencd@0 849 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 850 JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0)
ferencd@0 851 #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position)))
ferencd@0 852 #else
ferencd@0 853 #define JSON_HEDLEY_SENTINEL(position)
ferencd@0 854 #endif
ferencd@0 855
ferencd@0 856 #if defined(JSON_HEDLEY_NO_RETURN)
ferencd@0 857 #undef JSON_HEDLEY_NO_RETURN
ferencd@0 858 #endif
ferencd@0 859 #if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
ferencd@0 860 #define JSON_HEDLEY_NO_RETURN __noreturn
ferencd@0 861 #elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
ferencd@0 862 #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))
ferencd@0 863 #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
ferencd@0 864 #define JSON_HEDLEY_NO_RETURN _Noreturn
ferencd@0 865 #elif defined(__cplusplus) && (__cplusplus >= 201103L)
ferencd@0 866 #define JSON_HEDLEY_NO_RETURN [[noreturn]]
ferencd@0 867 #elif \
ferencd@0 868 JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \
ferencd@0 869 JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \
ferencd@0 870 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
ferencd@0 871 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
ferencd@0 872 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
ferencd@0 873 JSON_HEDLEY_TI_VERSION_CHECK(18,0,0) || \
ferencd@0 874 (JSON_HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
ferencd@0 875 #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))
ferencd@0 876 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0)
ferencd@0 877 #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)
ferencd@0 878 #elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus)
ferencd@0 879 #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;")
ferencd@0 880 #elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)
ferencd@0 881 #define JSON_HEDLEY_NO_RETURN __attribute((noreturn))
ferencd@0 882 #elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)
ferencd@0 883 #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)
ferencd@0 884 #else
ferencd@0 885 #define JSON_HEDLEY_NO_RETURN
ferencd@0 886 #endif
ferencd@0 887
ferencd@0 888 #if defined(JSON_HEDLEY_UNREACHABLE)
ferencd@0 889 #undef JSON_HEDLEY_UNREACHABLE
ferencd@0 890 #endif
ferencd@0 891 #if defined(JSON_HEDLEY_UNREACHABLE_RETURN)
ferencd@0 892 #undef JSON_HEDLEY_UNREACHABLE_RETURN
ferencd@0 893 #endif
ferencd@0 894 #if \
ferencd@0 895 (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \
ferencd@0 896 JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
ferencd@0 897 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 898 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5)
ferencd@0 899 #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable()
ferencd@0 900 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0)
ferencd@0 901 #define JSON_HEDLEY_UNREACHABLE() __assume(0)
ferencd@0 902 #elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0)
ferencd@0 903 #if defined(__cplusplus)
ferencd@0 904 #define JSON_HEDLEY_UNREACHABLE() std::_nassert(0)
ferencd@0 905 #else
ferencd@0 906 #define JSON_HEDLEY_UNREACHABLE() _nassert(0)
ferencd@0 907 #endif
ferencd@0 908 #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value
ferencd@0 909 #elif defined(EXIT_FAILURE)
ferencd@0 910 #define JSON_HEDLEY_UNREACHABLE() abort()
ferencd@0 911 #else
ferencd@0 912 #define JSON_HEDLEY_UNREACHABLE()
ferencd@0 913 #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return value
ferencd@0 914 #endif
ferencd@0 915 #if !defined(JSON_HEDLEY_UNREACHABLE_RETURN)
ferencd@0 916 #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE()
ferencd@0 917 #endif
ferencd@0 918
ferencd@0 919 #if defined(JSON_HEDLEY_ASSUME)
ferencd@0 920 #undef JSON_HEDLEY_ASSUME
ferencd@0 921 #endif
ferencd@0 922 #if \
ferencd@0 923 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
ferencd@0 924 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
ferencd@0 925 #define JSON_HEDLEY_ASSUME(expr) __assume(expr)
ferencd@0 926 #elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume)
ferencd@0 927 #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr)
ferencd@0 928 #elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0)
ferencd@0 929 #if defined(__cplusplus)
ferencd@0 930 #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr)
ferencd@0 931 #else
ferencd@0 932 #define JSON_HEDLEY_ASSUME(expr) _nassert(expr)
ferencd@0 933 #endif
ferencd@0 934 #elif \
ferencd@0 935 (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && !defined(JSON_HEDLEY_ARM_VERSION)) || \
ferencd@0 936 JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
ferencd@0 937 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 938 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5)
ferencd@0 939 #define JSON_HEDLEY_ASSUME(expr) ((void) ((expr) ? 1 : (__builtin_unreachable(), 1)))
ferencd@0 940 #else
ferencd@0 941 #define JSON_HEDLEY_ASSUME(expr) ((void) (expr))
ferencd@0 942 #endif
ferencd@0 943
ferencd@0 944
ferencd@0 945 JSON_HEDLEY_DIAGNOSTIC_PUSH
ferencd@0 946 #if \
ferencd@0 947 JSON_HEDLEY_HAS_WARNING("-Wvariadic-macros") || \
ferencd@0 948 JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0)
ferencd@0 949 #if defined(__clang__)
ferencd@0 950 #pragma clang diagnostic ignored "-Wvariadic-macros"
ferencd@0 951 #elif defined(JSON_HEDLEY_GCC_VERSION)
ferencd@0 952 #pragma GCC diagnostic ignored "-Wvariadic-macros"
ferencd@0 953 #endif
ferencd@0 954 #endif
ferencd@0 955 #if defined(JSON_HEDLEY_NON_NULL)
ferencd@0 956 #undef JSON_HEDLEY_NON_NULL
ferencd@0 957 #endif
ferencd@0 958 #if \
ferencd@0 959 JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \
ferencd@0 960 JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
ferencd@0 961 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 962 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)
ferencd@0 963 #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__)))
ferencd@0 964 #else
ferencd@0 965 #define JSON_HEDLEY_NON_NULL(...)
ferencd@0 966 #endif
ferencd@0 967 JSON_HEDLEY_DIAGNOSTIC_POP
ferencd@0 968
ferencd@0 969 #if defined(JSON_HEDLEY_PRINTF_FORMAT)
ferencd@0 970 #undef JSON_HEDLEY_PRINTF_FORMAT
ferencd@0 971 #endif
ferencd@0 972 #if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO)
ferencd@0 973 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check)))
ferencd@0 974 #elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO)
ferencd@0 975 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check)))
ferencd@0 976 #elif \
ferencd@0 977 JSON_HEDLEY_HAS_ATTRIBUTE(format) || \
ferencd@0 978 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
ferencd@0 979 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 980 JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \
ferencd@0 981 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
ferencd@0 982 JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \
ferencd@0 983 (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
ferencd@0 984 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check)))
ferencd@0 985 #elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0)
ferencd@0 986 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check))
ferencd@0 987 #else
ferencd@0 988 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check)
ferencd@0 989 #endif
ferencd@0 990
ferencd@0 991 #if defined(JSON_HEDLEY_CONSTEXPR)
ferencd@0 992 #undef JSON_HEDLEY_CONSTEXPR
ferencd@0 993 #endif
ferencd@0 994 #if defined(__cplusplus)
ferencd@0 995 #if __cplusplus >= 201103L
ferencd@0 996 #define JSON_HEDLEY_CONSTEXPR constexpr
ferencd@0 997 #endif
ferencd@0 998 #endif
ferencd@0 999 #if !defined(JSON_HEDLEY_CONSTEXPR)
ferencd@0 1000 #define JSON_HEDLEY_CONSTEXPR
ferencd@0 1001 #endif
ferencd@0 1002
ferencd@0 1003 #if defined(JSON_HEDLEY_PREDICT)
ferencd@0 1004 #undef JSON_HEDLEY_PREDICT
ferencd@0 1005 #endif
ferencd@0 1006 #if defined(JSON_HEDLEY_LIKELY)
ferencd@0 1007 #undef JSON_HEDLEY_LIKELY
ferencd@0 1008 #endif
ferencd@0 1009 #if defined(JSON_HEDLEY_UNLIKELY)
ferencd@0 1010 #undef JSON_HEDLEY_UNLIKELY
ferencd@0 1011 #endif
ferencd@0 1012 #if defined(JSON_HEDLEY_UNPREDICTABLE)
ferencd@0 1013 #undef JSON_HEDLEY_UNPREDICTABLE
ferencd@0 1014 #endif
ferencd@0 1015 #if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable)
ferencd@0 1016 #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable(!!(expr))
ferencd@0 1017 #endif
ferencd@0 1018 #if \
ferencd@0 1019 JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) || \
ferencd@0 1020 JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0)
ferencd@0 1021 # define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(expr, value, probability)
ferencd@0 1022 # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1, probability)
ferencd@0 1023 # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0, probability)
ferencd@0 1024 # define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1)
ferencd@0 1025 # define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0)
ferencd@0 1026 #if !defined(JSON_HEDLEY_BUILTIN_UNPREDICTABLE)
ferencd@0 1027 #define JSON_HEDLEY_BUILTIN_UNPREDICTABLE(expr) __builtin_expect_with_probability(!!(expr), 1, 0.5)
ferencd@0 1028 #endif
ferencd@0 1029 #elif \
ferencd@0 1030 JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) || \
ferencd@0 1031 JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
ferencd@0 1032 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 1033 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \
ferencd@0 1034 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
ferencd@0 1035 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
ferencd@0 1036 JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \
ferencd@0 1037 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27)
ferencd@0 1038 # define JSON_HEDLEY_PREDICT(expr, expected, probability) \
ferencd@0 1039 (((probability) >= 0.9) ? __builtin_expect(!!(expr), (expected)) : (((void) (expected)), !!(expr)))
ferencd@0 1040 # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \
ferencd@0 1041 (__extension__ ({ \
ferencd@0 1042 JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \
ferencd@0 1043 ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \
ferencd@0 1044 }))
ferencd@0 1045 # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \
ferencd@0 1046 (__extension__ ({ \
ferencd@0 1047 JSON_HEDLEY_CONSTEXPR double hedley_probability_ = (probability); \
ferencd@0 1048 ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \
ferencd@0 1049 }))
ferencd@0 1050 # define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1)
ferencd@0 1051 # define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0)
ferencd@0 1052 #else
ferencd@0 1053 # define JSON_HEDLEY_PREDICT(expr, expected, probability) (((void) (expected)), !!(expr))
ferencd@0 1054 # define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr))
ferencd@0 1055 # define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr))
ferencd@0 1056 # define JSON_HEDLEY_LIKELY(expr) (!!(expr))
ferencd@0 1057 # define JSON_HEDLEY_UNLIKELY(expr) (!!(expr))
ferencd@0 1058 #endif
ferencd@0 1059 #if !defined(JSON_HEDLEY_UNPREDICTABLE)
ferencd@0 1060 #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5)
ferencd@0 1061 #endif
ferencd@0 1062
ferencd@0 1063 #if defined(JSON_HEDLEY_MALLOC)
ferencd@0 1064 #undef JSON_HEDLEY_MALLOC
ferencd@0 1065 #endif
ferencd@0 1066 #if \
ferencd@0 1067 JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \
ferencd@0 1068 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
ferencd@0 1069 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 1070 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
ferencd@0 1071 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
ferencd@0 1072 JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \
ferencd@0 1073 JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \
ferencd@0 1074 (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
ferencd@0 1075 #define JSON_HEDLEY_MALLOC __attribute__((__malloc__))
ferencd@0 1076 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0)
ferencd@0 1077 #define JSON_HEDLEY_MALLOC __declspec(restrict)
ferencd@0 1078 #else
ferencd@0 1079 #define JSON_HEDLEY_MALLOC
ferencd@0 1080 #endif
ferencd@0 1081
ferencd@0 1082 #if defined(JSON_HEDLEY_PURE)
ferencd@0 1083 #undef JSON_HEDLEY_PURE
ferencd@0 1084 #endif
ferencd@0 1085 #if \
ferencd@0 1086 JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \
ferencd@0 1087 JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \
ferencd@0 1088 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 1089 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
ferencd@0 1090 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
ferencd@0 1091 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
ferencd@0 1092 JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \
ferencd@0 1093 (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
ferencd@0 1094 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
ferencd@0 1095 #define JSON_HEDLEY_PURE __attribute__((__pure__))
ferencd@0 1096 #elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus)
ferencd@0 1097 #define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;")
ferencd@0 1098 #else
ferencd@0 1099 #define JSON_HEDLEY_PURE
ferencd@0 1100 #endif
ferencd@0 1101
ferencd@0 1102 #if defined(JSON_HEDLEY_CONST)
ferencd@0 1103 #undef JSON_HEDLEY_CONST
ferencd@0 1104 #endif
ferencd@0 1105 #if \
ferencd@0 1106 JSON_HEDLEY_HAS_ATTRIBUTE(const) || \
ferencd@0 1107 JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \
ferencd@0 1108 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 1109 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
ferencd@0 1110 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
ferencd@0 1111 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
ferencd@0 1112 JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \
ferencd@0 1113 (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
ferencd@0 1114 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
ferencd@0 1115 #define JSON_HEDLEY_CONST __attribute__((__const__))
ferencd@0 1116 #else
ferencd@0 1117 #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE
ferencd@0 1118 #endif
ferencd@0 1119
ferencd@0 1120 #if defined(JSON_HEDLEY_RESTRICT)
ferencd@0 1121 #undef JSON_HEDLEY_RESTRICT
ferencd@0 1122 #endif
ferencd@0 1123 #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus)
ferencd@0 1124 #define JSON_HEDLEY_RESTRICT restrict
ferencd@0 1125 #elif \
ferencd@0 1126 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
ferencd@0 1127 JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
ferencd@0 1128 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 1129 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
ferencd@0 1130 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
ferencd@0 1131 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
ferencd@0 1132 JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \
ferencd@0 1133 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \
ferencd@0 1134 JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
ferencd@0 1135 defined(__clang__)
ferencd@0 1136 #define JSON_HEDLEY_RESTRICT __restrict
ferencd@0 1137 #elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus)
ferencd@0 1138 #define JSON_HEDLEY_RESTRICT _Restrict
ferencd@0 1139 #else
ferencd@0 1140 #define JSON_HEDLEY_RESTRICT
ferencd@0 1141 #endif
ferencd@0 1142
ferencd@0 1143 #if defined(JSON_HEDLEY_INLINE)
ferencd@0 1144 #undef JSON_HEDLEY_INLINE
ferencd@0 1145 #endif
ferencd@0 1146 #if \
ferencd@0 1147 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
ferencd@0 1148 (defined(__cplusplus) && (__cplusplus >= 199711L))
ferencd@0 1149 #define JSON_HEDLEY_INLINE inline
ferencd@0 1150 #elif \
ferencd@0 1151 defined(JSON_HEDLEY_GCC_VERSION) || \
ferencd@0 1152 JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0)
ferencd@0 1153 #define JSON_HEDLEY_INLINE __inline__
ferencd@0 1154 #elif \
ferencd@0 1155 JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \
ferencd@0 1156 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
ferencd@0 1157 JSON_HEDLEY_TI_VERSION_CHECK(8,0,0)
ferencd@0 1158 #define JSON_HEDLEY_INLINE __inline
ferencd@0 1159 #else
ferencd@0 1160 #define JSON_HEDLEY_INLINE
ferencd@0 1161 #endif
ferencd@0 1162
ferencd@0 1163 #if defined(JSON_HEDLEY_ALWAYS_INLINE)
ferencd@0 1164 #undef JSON_HEDLEY_ALWAYS_INLINE
ferencd@0 1165 #endif
ferencd@0 1166 #if \
ferencd@0 1167 JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \
ferencd@0 1168 JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
ferencd@0 1169 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 1170 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
ferencd@0 1171 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
ferencd@0 1172 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
ferencd@0 1173 JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \
ferencd@0 1174 (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
ferencd@0 1175 #define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE
ferencd@0 1176 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0)
ferencd@0 1177 #define JSON_HEDLEY_ALWAYS_INLINE __forceinline
ferencd@0 1178 #elif JSON_HEDLEY_TI_VERSION_CHECK(7,0,0) && defined(__cplusplus)
ferencd@0 1179 #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;")
ferencd@0 1180 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
ferencd@0 1181 #define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced")
ferencd@0 1182 #else
ferencd@0 1183 #define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE
ferencd@0 1184 #endif
ferencd@0 1185
ferencd@0 1186 #if defined(JSON_HEDLEY_NEVER_INLINE)
ferencd@0 1187 #undef JSON_HEDLEY_NEVER_INLINE
ferencd@0 1188 #endif
ferencd@0 1189 #if \
ferencd@0 1190 JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \
ferencd@0 1191 JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
ferencd@0 1192 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 1193 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
ferencd@0 1194 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
ferencd@0 1195 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
ferencd@0 1196 JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \
ferencd@0 1197 (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
ferencd@0 1198 #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__))
ferencd@0 1199 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0)
ferencd@0 1200 #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)
ferencd@0 1201 #elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0)
ferencd@0 1202 #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline")
ferencd@0 1203 #elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus)
ferencd@0 1204 #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
ferencd@0 1205 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
ferencd@0 1206 #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never")
ferencd@0 1207 #elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)
ferencd@0 1208 #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline))
ferencd@0 1209 #elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)
ferencd@0 1210 #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)
ferencd@0 1211 #else
ferencd@0 1212 #define JSON_HEDLEY_NEVER_INLINE
ferencd@0 1213 #endif
ferencd@0 1214
ferencd@0 1215 #if defined(JSON_HEDLEY_PRIVATE)
ferencd@0 1216 #undef JSON_HEDLEY_PRIVATE
ferencd@0 1217 #endif
ferencd@0 1218 #if defined(JSON_HEDLEY_PUBLIC)
ferencd@0 1219 #undef JSON_HEDLEY_PUBLIC
ferencd@0 1220 #endif
ferencd@0 1221 #if defined(JSON_HEDLEY_IMPORT)
ferencd@0 1222 #undef JSON_HEDLEY_IMPORT
ferencd@0 1223 #endif
ferencd@0 1224 #if defined(_WIN32) || defined(__CYGWIN__)
ferencd@0 1225 #define JSON_HEDLEY_PRIVATE
ferencd@0 1226 #define JSON_HEDLEY_PUBLIC __declspec(dllexport)
ferencd@0 1227 #define JSON_HEDLEY_IMPORT __declspec(dllimport)
ferencd@0 1228 #else
ferencd@0 1229 #if \
ferencd@0 1230 JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \
ferencd@0 1231 JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
ferencd@0 1232 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
ferencd@0 1233 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 1234 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
ferencd@0 1235 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
ferencd@0 1236 JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \
ferencd@0 1237 (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_EABI__) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
ferencd@0 1238 #define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden")))
ferencd@0 1239 #define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default")))
ferencd@0 1240 #else
ferencd@0 1241 #define JSON_HEDLEY_PRIVATE
ferencd@0 1242 #define JSON_HEDLEY_PUBLIC
ferencd@0 1243 #endif
ferencd@0 1244 #define JSON_HEDLEY_IMPORT extern
ferencd@0 1245 #endif
ferencd@0 1246
ferencd@0 1247 #if defined(JSON_HEDLEY_NO_THROW)
ferencd@0 1248 #undef JSON_HEDLEY_NO_THROW
ferencd@0 1249 #endif
ferencd@0 1250 #if \
ferencd@0 1251 JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \
ferencd@0 1252 JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
ferencd@0 1253 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
ferencd@0 1254 #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__))
ferencd@0 1255 #elif \
ferencd@0 1256 JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \
ferencd@0 1257 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)
ferencd@0 1258 #define JSON_HEDLEY_NO_THROW __declspec(nothrow)
ferencd@0 1259 #else
ferencd@0 1260 #define JSON_HEDLEY_NO_THROW
ferencd@0 1261 #endif
ferencd@0 1262
ferencd@0 1263 #if defined(JSON_HEDLEY_FALL_THROUGH)
ferencd@0 1264 #undef JSON_HEDLEY_FALL_THROUGH
ferencd@0 1265 #endif
ferencd@0 1266 #if \
ferencd@0 1267 defined(__cplusplus) && \
ferencd@0 1268 (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \
ferencd@0 1269 !defined(JSON_HEDLEY_PGI_VERSION)
ferencd@0 1270 #if \
ferencd@0 1271 (__cplusplus >= 201703L) || \
ferencd@0 1272 ((__cplusplus >= 201103L) && JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough))
ferencd@0 1273 #define JSON_HEDLEY_FALL_THROUGH [[fallthrough]]
ferencd@0 1274 #elif (__cplusplus >= 201103L) && JSON_HEDLEY_HAS_CPP_ATTRIBUTE(clang::fallthrough)
ferencd@0 1275 #define JSON_HEDLEY_FALL_THROUGH [[clang::fallthrough]]
ferencd@0 1276 #elif (__cplusplus >= 201103L) && JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0)
ferencd@0 1277 #define JSON_HEDLEY_FALL_THROUGH [[gnu::fallthrough]]
ferencd@0 1278 #endif
ferencd@0 1279 #endif
ferencd@0 1280 #if !defined(JSON_HEDLEY_FALL_THROUGH)
ferencd@0 1281 #if JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(JSON_HEDLEY_PGI_VERSION)
ferencd@0 1282 #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__))
ferencd@0 1283 #elif defined(__fallthrough) /* SAL */
ferencd@0 1284 #define JSON_HEDLEY_FALL_THROUGH __fallthrough
ferencd@0 1285 #else
ferencd@0 1286 #define JSON_HEDLEY_FALL_THROUGH
ferencd@0 1287 #endif
ferencd@0 1288 #endif
ferencd@0 1289
ferencd@0 1290 #if defined(JSON_HEDLEY_RETURNS_NON_NULL)
ferencd@0 1291 #undef JSON_HEDLEY_RETURNS_NON_NULL
ferencd@0 1292 #endif
ferencd@0 1293 #if \
ferencd@0 1294 JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \
ferencd@0 1295 JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
ferencd@0 1296 #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__))
ferencd@0 1297 #elif defined(_Ret_notnull_) /* SAL */
ferencd@0 1298 #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_
ferencd@0 1299 #else
ferencd@0 1300 #define JSON_HEDLEY_RETURNS_NON_NULL
ferencd@0 1301 #endif
ferencd@0 1302
ferencd@0 1303 #if defined(JSON_HEDLEY_ARRAY_PARAM)
ferencd@0 1304 #undef JSON_HEDLEY_ARRAY_PARAM
ferencd@0 1305 #endif
ferencd@0 1306 #if \
ferencd@0 1307 defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
ferencd@0 1308 !defined(__STDC_NO_VLA__) && \
ferencd@0 1309 !defined(__cplusplus) && \
ferencd@0 1310 !defined(JSON_HEDLEY_PGI_VERSION) && \
ferencd@0 1311 !defined(JSON_HEDLEY_TINYC_VERSION)
ferencd@0 1312 #define JSON_HEDLEY_ARRAY_PARAM(name) (name)
ferencd@0 1313 #else
ferencd@0 1314 #define JSON_HEDLEY_ARRAY_PARAM(name)
ferencd@0 1315 #endif
ferencd@0 1316
ferencd@0 1317 #if defined(JSON_HEDLEY_IS_CONSTANT)
ferencd@0 1318 #undef JSON_HEDLEY_IS_CONSTANT
ferencd@0 1319 #endif
ferencd@0 1320 #if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR)
ferencd@0 1321 #undef JSON_HEDLEY_REQUIRE_CONSTEXPR
ferencd@0 1322 #endif
ferencd@0 1323 /* Note the double-underscore. For internal use only; no API
ferencd@0 1324 * guarantees! */
ferencd@0 1325 #if defined(JSON_HEDLEY__IS_CONSTEXPR)
ferencd@0 1326 #undef JSON_HEDLEY__IS_CONSTEXPR
ferencd@0 1327 #endif
ferencd@0 1328
ferencd@0 1329 #if \
ferencd@0 1330 JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \
ferencd@0 1331 JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
ferencd@0 1332 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 1333 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \
ferencd@0 1334 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
ferencd@0 1335 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
ferencd@0 1336 JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \
ferencd@0 1337 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) || \
ferencd@0 1338 JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0)
ferencd@0 1339 #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr)
ferencd@0 1340 #endif
ferencd@0 1341 #if !defined(__cplusplus)
ferencd@0 1342 # if \
ferencd@0 1343 JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \
ferencd@0 1344 JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
ferencd@0 1345 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 1346 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
ferencd@0 1347 JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
ferencd@0 1348 JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \
ferencd@0 1349 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24)
ferencd@0 1350 #if defined(__INTPTR_TYPE__)
ferencd@0 1351 #define JSON_HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*)
ferencd@0 1352 #else
ferencd@0 1353 #include <stdint.h>
ferencd@0 1354 #define JSON_HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*)
ferencd@0 1355 #endif
ferencd@0 1356 # elif \
ferencd@0 1357 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(JSON_HEDLEY_SUNPRO_VERSION) && !defined(JSON_HEDLEY_PGI_VERSION)) || \
ferencd@0 1358 JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) || \
ferencd@0 1359 JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \
ferencd@0 1360 JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \
ferencd@0 1361 JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \
ferencd@0 1362 JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0)
ferencd@0 1363 #if defined(__INTPTR_TYPE__)
ferencd@0 1364 #define JSON_HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0)
ferencd@0 1365 #else
ferencd@0 1366 #include <stdint.h>
ferencd@0 1367 #define JSON_HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0)
ferencd@0 1368 #endif
ferencd@0 1369 # elif \
ferencd@0 1370 defined(JSON_HEDLEY_GCC_VERSION) || \
ferencd@0 1371 defined(JSON_HEDLEY_INTEL_VERSION) || \
ferencd@0 1372 defined(JSON_HEDLEY_TINYC_VERSION) || \
ferencd@0 1373 defined(JSON_HEDLEY_TI_VERSION) || \
ferencd@0 1374 defined(__clang__)
ferencd@0 1375 # define JSON_HEDLEY__IS_CONSTEXPR(expr) ( \
ferencd@0 1376 sizeof(void) != \
ferencd@0 1377 sizeof(*( \
ferencd@0 1378 1 ? \
ferencd@0 1379 ((void*) ((expr) * 0L) ) : \
ferencd@0 1380 ((struct { char v[sizeof(void) * 2]; } *) 1) \
ferencd@0 1381 ) \
ferencd@0 1382 ) \
ferencd@0 1383 )
ferencd@0 1384 # endif
ferencd@0 1385 #endif
ferencd@0 1386 #if defined(JSON_HEDLEY__IS_CONSTEXPR)
ferencd@0 1387 #if !defined(JSON_HEDLEY_IS_CONSTANT)
ferencd@0 1388 #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY__IS_CONSTEXPR(expr)
ferencd@0 1389 #endif
ferencd@0 1390 #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY__IS_CONSTEXPR(expr) ? (expr) : (-1))
ferencd@0 1391 #else
ferencd@0 1392 #if !defined(JSON_HEDLEY_IS_CONSTANT)
ferencd@0 1393 #define JSON_HEDLEY_IS_CONSTANT(expr) (0)
ferencd@0 1394 #endif
ferencd@0 1395 #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr)
ferencd@0 1396 #endif
ferencd@0 1397
ferencd@0 1398 #if defined(JSON_HEDLEY_BEGIN_C_DECLS)
ferencd@0 1399 #undef JSON_HEDLEY_BEGIN_C_DECLS
ferencd@0 1400 #endif
ferencd@0 1401 #if defined(JSON_HEDLEY_END_C_DECLS)
ferencd@0 1402 #undef JSON_HEDLEY_END_C_DECLS
ferencd@0 1403 #endif
ferencd@0 1404 #if defined(JSON_HEDLEY_C_DECL)
ferencd@0 1405 #undef JSON_HEDLEY_C_DECL
ferencd@0 1406 #endif
ferencd@0 1407 #if defined(__cplusplus)
ferencd@0 1408 #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" {
ferencd@0 1409 #define JSON_HEDLEY_END_C_DECLS }
ferencd@0 1410 #define JSON_HEDLEY_C_DECL extern "C"
ferencd@0 1411 #else
ferencd@0 1412 #define JSON_HEDLEY_BEGIN_C_DECLS
ferencd@0 1413 #define JSON_HEDLEY_END_C_DECLS
ferencd@0 1414 #define JSON_HEDLEY_C_DECL
ferencd@0 1415 #endif
ferencd@0 1416
ferencd@0 1417 #if defined(JSON_HEDLEY_STATIC_ASSERT)
ferencd@0 1418 #undef JSON_HEDLEY_STATIC_ASSERT
ferencd@0 1419 #endif
ferencd@0 1420 #if \
ferencd@0 1421 !defined(__cplusplus) && ( \
ferencd@0 1422 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \
ferencd@0 1423 JSON_HEDLEY_HAS_FEATURE(c_static_assert) || \
ferencd@0 1424 JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \
ferencd@0 1425 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
ferencd@0 1426 defined(_Static_assert) \
ferencd@0 1427 )
ferencd@0 1428 # define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message)
ferencd@0 1429 #elif \
ferencd@0 1430 (defined(__cplusplus) && (__cplusplus >= 201703L)) || \
ferencd@0 1431 JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \
ferencd@0 1432 (defined(__cplusplus) && JSON_HEDLEY_TI_VERSION_CHECK(8,3,0))
ferencd@0 1433 # define JSON_HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr, message)
ferencd@0 1434 #elif defined(__cplusplus) && (__cplusplus >= 201103L)
ferencd@0 1435 # define JSON_HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr)
ferencd@0 1436 #else
ferencd@0 1437 # define JSON_HEDLEY_STATIC_ASSERT(expr, message)
ferencd@0 1438 #endif
ferencd@0 1439
ferencd@0 1440 #if defined(JSON_HEDLEY_CONST_CAST)
ferencd@0 1441 #undef JSON_HEDLEY_CONST_CAST
ferencd@0 1442 #endif
ferencd@0 1443 #if defined(__cplusplus)
ferencd@0 1444 # define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast<T>(expr))
ferencd@0 1445 #elif \
ferencd@0 1446 JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \
ferencd@0 1447 JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \
ferencd@0 1448 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
ferencd@0 1449 # define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \
ferencd@0 1450 JSON_HEDLEY_DIAGNOSTIC_PUSH \
ferencd@0 1451 JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \
ferencd@0 1452 ((T) (expr)); \
ferencd@0 1453 JSON_HEDLEY_DIAGNOSTIC_POP \
ferencd@0 1454 }))
ferencd@0 1455 #else
ferencd@0 1456 # define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr))
ferencd@0 1457 #endif
ferencd@0 1458
ferencd@0 1459 #if defined(JSON_HEDLEY_REINTERPRET_CAST)
ferencd@0 1460 #undef JSON_HEDLEY_REINTERPRET_CAST
ferencd@0 1461 #endif
ferencd@0 1462 #if defined(__cplusplus)
ferencd@0 1463 #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast<T>(expr))
ferencd@0 1464 #else
ferencd@0 1465 #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (*((T*) &(expr)))
ferencd@0 1466 #endif
ferencd@0 1467
ferencd@0 1468 #if defined(JSON_HEDLEY_STATIC_CAST)
ferencd@0 1469 #undef JSON_HEDLEY_STATIC_CAST
ferencd@0 1470 #endif
ferencd@0 1471 #if defined(__cplusplus)
ferencd@0 1472 #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast<T>(expr))
ferencd@0 1473 #else
ferencd@0 1474 #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr))
ferencd@0 1475 #endif
ferencd@0 1476
ferencd@0 1477 #if defined(JSON_HEDLEY_CPP_CAST)
ferencd@0 1478 #undef JSON_HEDLEY_CPP_CAST
ferencd@0 1479 #endif
ferencd@0 1480 #if defined(__cplusplus)
ferencd@0 1481 #define JSON_HEDLEY_CPP_CAST(T, expr) static_cast<T>(expr)
ferencd@0 1482 #else
ferencd@0 1483 #define JSON_HEDLEY_CPP_CAST(T, expr) (expr)
ferencd@0 1484 #endif
ferencd@0 1485
ferencd@0 1486 #if defined(JSON_HEDLEY_MESSAGE)
ferencd@0 1487 #undef JSON_HEDLEY_MESSAGE
ferencd@0 1488 #endif
ferencd@0 1489 #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
ferencd@0 1490 # define JSON_HEDLEY_MESSAGE(msg) \
ferencd@0 1491 JSON_HEDLEY_DIAGNOSTIC_PUSH \
ferencd@0 1492 JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
ferencd@0 1493 JSON_HEDLEY_PRAGMA(message msg) \
ferencd@0 1494 JSON_HEDLEY_DIAGNOSTIC_POP
ferencd@0 1495 #elif \
ferencd@0 1496 JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \
ferencd@0 1497 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
ferencd@0 1498 # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg)
ferencd@0 1499 #elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0)
ferencd@0 1500 # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg)
ferencd@0 1501 #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
ferencd@0 1502 # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))
ferencd@0 1503 #elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0)
ferencd@0 1504 # define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))
ferencd@0 1505 #else
ferencd@0 1506 # define JSON_HEDLEY_MESSAGE(msg)
ferencd@0 1507 #endif
ferencd@0 1508
ferencd@0 1509 #if defined(JSON_HEDLEY_WARNING)
ferencd@0 1510 #undef JSON_HEDLEY_WARNING
ferencd@0 1511 #endif
ferencd@0 1512 #if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
ferencd@0 1513 # define JSON_HEDLEY_WARNING(msg) \
ferencd@0 1514 JSON_HEDLEY_DIAGNOSTIC_PUSH \
ferencd@0 1515 JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
ferencd@0 1516 JSON_HEDLEY_PRAGMA(clang warning msg) \
ferencd@0 1517 JSON_HEDLEY_DIAGNOSTIC_POP
ferencd@0 1518 #elif \
ferencd@0 1519 JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \
ferencd@0 1520 JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0)
ferencd@0 1521 # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg)
ferencd@0 1522 #elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
ferencd@0 1523 # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg))
ferencd@0 1524 #else
ferencd@0 1525 # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg)
ferencd@0 1526 #endif
ferencd@0 1527
ferencd@0 1528 #if defined(JSON_HEDLEY_REQUIRE_MSG)
ferencd@0 1529 #undef JSON_HEDLEY_REQUIRE_MSG
ferencd@0 1530 #endif
ferencd@0 1531 #if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if)
ferencd@0 1532 # if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat")
ferencd@0 1533 # define JSON_HEDLEY_REQUIRE_MSG(expr, msg) \
ferencd@0 1534 JSON_HEDLEY_DIAGNOSTIC_PUSH \
ferencd@0 1535 _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
ferencd@0 1536 __attribute__((__diagnose_if__(!(expr), msg, "error"))) \
ferencd@0 1537 JSON_HEDLEY_DIAGNOSTIC_POP
ferencd@0 1538 # else
ferencd@0 1539 # define JSON_HEDLEY_REQUIRE_MSG(expr, msg) __attribute__((__diagnose_if__(!(expr), msg, "error")))
ferencd@0 1540 # endif
ferencd@0 1541 #else
ferencd@0 1542 # define JSON_HEDLEY_REQUIRE_MSG(expr, msg)
ferencd@0 1543 #endif
ferencd@0 1544
ferencd@0 1545 #if defined(JSON_HEDLEY_REQUIRE)
ferencd@0 1546 #undef JSON_HEDLEY_REQUIRE
ferencd@0 1547 #endif
ferencd@0 1548 #define JSON_HEDLEY_REQUIRE(expr) JSON_HEDLEY_REQUIRE_MSG(expr, #expr)
ferencd@0 1549
ferencd@0 1550 #if defined(JSON_HEDLEY_FLAGS)
ferencd@0 1551 #undef JSON_HEDLEY_FLAGS
ferencd@0 1552 #endif
ferencd@0 1553 #if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum)
ferencd@0 1554 #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__))
ferencd@0 1555 #endif
ferencd@0 1556
ferencd@0 1557 #if defined(JSON_HEDLEY_FLAGS_CAST)
ferencd@0 1558 #undef JSON_HEDLEY_FLAGS_CAST
ferencd@0 1559 #endif
ferencd@0 1560 #if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0)
ferencd@0 1561 # define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \
ferencd@0 1562 JSON_HEDLEY_DIAGNOSTIC_PUSH \
ferencd@0 1563 _Pragma("warning(disable:188)") \
ferencd@0 1564 ((T) (expr)); \
ferencd@0 1565 JSON_HEDLEY_DIAGNOSTIC_POP \
ferencd@0 1566 }))
ferencd@0 1567 #else
ferencd@0 1568 # define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr)
ferencd@0 1569 #endif
ferencd@0 1570
ferencd@0 1571 /* Remaining macros are deprecated. */
ferencd@0 1572
ferencd@0 1573 #if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK)
ferencd@0 1574 #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK
ferencd@0 1575 #endif
ferencd@0 1576 #if defined(__clang__)
ferencd@0 1577 #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0)
ferencd@0 1578 #else
ferencd@0 1579 #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
ferencd@0 1580 #endif
ferencd@0 1581
ferencd@0 1582 #if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE)
ferencd@0 1583 #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
ferencd@0 1584 #endif
ferencd@0 1585 #define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
ferencd@0 1586
ferencd@0 1587 #if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE)
ferencd@0 1588 #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
ferencd@0 1589 #endif
ferencd@0 1590 #define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute)
ferencd@0 1591
ferencd@0 1592 #if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN)
ferencd@0 1593 #undef JSON_HEDLEY_CLANG_HAS_BUILTIN
ferencd@0 1594 #endif
ferencd@0 1595 #define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin)
ferencd@0 1596
ferencd@0 1597 #if defined(JSON_HEDLEY_CLANG_HAS_FEATURE)
ferencd@0 1598 #undef JSON_HEDLEY_CLANG_HAS_FEATURE
ferencd@0 1599 #endif
ferencd@0 1600 #define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature)
ferencd@0 1601
ferencd@0 1602 #if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION)
ferencd@0 1603 #undef JSON_HEDLEY_CLANG_HAS_EXTENSION
ferencd@0 1604 #endif
ferencd@0 1605 #define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension)
ferencd@0 1606
ferencd@0 1607 #if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE)
ferencd@0 1608 #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
ferencd@0 1609 #endif
ferencd@0 1610 #define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute)
ferencd@0 1611
ferencd@0 1612 #if defined(JSON_HEDLEY_CLANG_HAS_WARNING)
ferencd@0 1613 #undef JSON_HEDLEY_CLANG_HAS_WARNING
ferencd@0 1614 #endif
ferencd@0 1615 #define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning)
ferencd@0 1616
ferencd@0 1617 #endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */
ferencd@0 1618
ferencd@0 1619
ferencd@0 1620 // This file contains all internal macro definitions
ferencd@0 1621 // You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
ferencd@0 1622
ferencd@0 1623 // exclude unsupported compilers
ferencd@0 1624 #if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)
ferencd@0 1625 #if defined(__clang__)
ferencd@0 1626 #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
ferencd@0 1627 #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
ferencd@0 1628 #endif
ferencd@0 1629 #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
ferencd@0 1630 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800
ferencd@0 1631 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
ferencd@0 1632 #endif
ferencd@0 1633 #endif
ferencd@0 1634 #endif
ferencd@0 1635
ferencd@0 1636 // C++ language standard detection
ferencd@0 1637 #if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
ferencd@0 1638 #define JSON_HAS_CPP_17
ferencd@0 1639 #define JSON_HAS_CPP_14
ferencd@0 1640 #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
ferencd@0 1641 #define JSON_HAS_CPP_14
ferencd@0 1642 #endif
ferencd@0 1643
ferencd@0 1644 // disable float-equal warnings on GCC/clang
ferencd@0 1645 #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
ferencd@0 1646 #pragma GCC diagnostic push
ferencd@0 1647 #pragma GCC diagnostic ignored "-Wfloat-equal"
ferencd@0 1648 #endif
ferencd@0 1649
ferencd@0 1650 // disable documentation warnings on clang
ferencd@0 1651 #if defined(__clang__)
ferencd@0 1652 #pragma GCC diagnostic push
ferencd@0 1653 #pragma GCC diagnostic ignored "-Wdocumentation"
ferencd@0 1654 #endif
ferencd@0 1655
ferencd@0 1656 // allow to disable exceptions
ferencd@0 1657 #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
ferencd@0 1658 #define JSON_THROW(exception) throw exception
ferencd@0 1659 #define JSON_TRY try
ferencd@0 1660 #define JSON_CATCH(exception) catch(exception)
ferencd@0 1661 #define JSON_INTERNAL_CATCH(exception) catch(exception)
ferencd@0 1662 #else
ferencd@0 1663 #include <cstdlib>
ferencd@0 1664 #define JSON_THROW(exception) std::abort()
ferencd@0 1665 #define JSON_TRY if(true)
ferencd@0 1666 #define JSON_CATCH(exception) if(false)
ferencd@0 1667 #define JSON_INTERNAL_CATCH(exception) if(false)
ferencd@0 1668 #endif
ferencd@0 1669
ferencd@0 1670 // override exception macros
ferencd@0 1671 #if defined(JSON_THROW_USER)
ferencd@0 1672 #undef JSON_THROW
ferencd@0 1673 #define JSON_THROW JSON_THROW_USER
ferencd@0 1674 #endif
ferencd@0 1675 #if defined(JSON_TRY_USER)
ferencd@0 1676 #undef JSON_TRY
ferencd@0 1677 #define JSON_TRY JSON_TRY_USER
ferencd@0 1678 #endif
ferencd@0 1679 #if defined(JSON_CATCH_USER)
ferencd@0 1680 #undef JSON_CATCH
ferencd@0 1681 #define JSON_CATCH JSON_CATCH_USER
ferencd@0 1682 #undef JSON_INTERNAL_CATCH
ferencd@0 1683 #define JSON_INTERNAL_CATCH JSON_CATCH_USER
ferencd@0 1684 #endif
ferencd@0 1685 #if defined(JSON_INTERNAL_CATCH_USER)
ferencd@0 1686 #undef JSON_INTERNAL_CATCH
ferencd@0 1687 #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
ferencd@0 1688 #endif
ferencd@0 1689
ferencd@0 1690 /*!
ferencd@0 1691 @brief macro to briefly define a mapping between an enum and JSON
ferencd@0 1692 @def NLOHMANN_JSON_SERIALIZE_ENUM
ferencd@0 1693 @since version 3.4.0
ferencd@0 1694 */
ferencd@0 1695 #define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \
ferencd@0 1696 template<typename BasicJsonType> \
ferencd@0 1697 inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \
ferencd@0 1698 { \
ferencd@0 1699 static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
ferencd@0 1700 static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
ferencd@0 1701 auto it = std::find_if(std::begin(m), std::end(m), \
ferencd@0 1702 [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
ferencd@0 1703 { \
ferencd@0 1704 return ej_pair.first == e; \
ferencd@0 1705 }); \
ferencd@0 1706 j = ((it != std::end(m)) ? it : std::begin(m))->second; \
ferencd@0 1707 } \
ferencd@0 1708 template<typename BasicJsonType> \
ferencd@0 1709 inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
ferencd@0 1710 { \
ferencd@0 1711 static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
ferencd@0 1712 static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
ferencd@0 1713 auto it = std::find_if(std::begin(m), std::end(m), \
ferencd@0 1714 [j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
ferencd@0 1715 { \
ferencd@0 1716 return ej_pair.second == j; \
ferencd@0 1717 }); \
ferencd@0 1718 e = ((it != std::end(m)) ? it : std::begin(m))->first; \
ferencd@0 1719 }
ferencd@0 1720
ferencd@0 1721 // Ugly macros to avoid uglier copy-paste when specializing basic_json. They
ferencd@0 1722 // may be removed in the future once the class is split.
ferencd@0 1723
ferencd@0 1724 #define NLOHMANN_BASIC_JSON_TPL_DECLARATION \
ferencd@0 1725 template<template<typename, typename, typename...> class ObjectType, \
ferencd@0 1726 template<typename, typename...> class ArrayType, \
ferencd@0 1727 class StringType, class BooleanType, class NumberIntegerType, \
ferencd@0 1728 class NumberUnsignedType, class NumberFloatType, \
ferencd@0 1729 template<typename> class AllocatorType, \
ferencd@0 1730 template<typename, typename = void> class JSONSerializer>
ferencd@0 1731
ferencd@0 1732 #define NLOHMANN_BASIC_JSON_TPL \
ferencd@0 1733 basic_json<ObjectType, ArrayType, StringType, BooleanType, \
ferencd@0 1734 NumberIntegerType, NumberUnsignedType, NumberFloatType, \
ferencd@0 1735 AllocatorType, JSONSerializer>
ferencd@0 1736
ferencd@0 1737
ferencd@0 1738 namespace nlohmann
ferencd@0 1739 {
ferencd@0 1740 namespace detail
ferencd@0 1741 {
ferencd@0 1742 ////////////////
ferencd@0 1743 // exceptions //
ferencd@0 1744 ////////////////
ferencd@0 1745
ferencd@0 1746 /*!
ferencd@0 1747 @brief general exception of the @ref basic_json class
ferencd@0 1748
ferencd@0 1749 This class is an extension of `std::exception` objects with a member @a id for
ferencd@0 1750 exception ids. It is used as the base class for all exceptions thrown by the
ferencd@0 1751 @ref basic_json class. This class can hence be used as "wildcard" to catch
ferencd@0 1752 exceptions.
ferencd@0 1753
ferencd@0 1754 Subclasses:
ferencd@0 1755 - @ref parse_error for exceptions indicating a parse error
ferencd@0 1756 - @ref invalid_iterator for exceptions indicating errors with iterators
ferencd@0 1757 - @ref type_error for exceptions indicating executing a member function with
ferencd@0 1758 a wrong type
ferencd@0 1759 - @ref out_of_range for exceptions indicating access out of the defined range
ferencd@0 1760 - @ref other_error for exceptions indicating other library errors
ferencd@0 1761
ferencd@0 1762 @internal
ferencd@0 1763 @note To have nothrow-copy-constructible exceptions, we internally use
ferencd@0 1764 `std::runtime_error` which can cope with arbitrary-length error messages.
ferencd@0 1765 Intermediate strings are built with static functions and then passed to
ferencd@0 1766 the actual constructor.
ferencd@0 1767 @endinternal
ferencd@0 1768
ferencd@0 1769 @liveexample{The following code shows how arbitrary library exceptions can be
ferencd@0 1770 caught.,exception}
ferencd@0 1771
ferencd@0 1772 @since version 3.0.0
ferencd@0 1773 */
ferencd@0 1774 class exception : public std::exception
ferencd@0 1775 {
ferencd@0 1776 public:
ferencd@0 1777 /// returns the explanatory string
ferencd@0 1778 JSON_HEDLEY_RETURNS_NON_NULL
ferencd@0 1779 const char* what() const noexcept override
ferencd@0 1780 {
ferencd@0 1781 return m.what();
ferencd@0 1782 }
ferencd@0 1783
ferencd@0 1784 /// the id of the exception
ferencd@0 1785 const int id;
ferencd@0 1786
ferencd@0 1787 protected:
ferencd@0 1788 JSON_HEDLEY_NON_NULL(3)
ferencd@0 1789 exception(int id_, const char* what_arg) : id(id_), m(what_arg) {}
ferencd@0 1790
ferencd@0 1791 static std::string name(const std::string& ename, int id_)
ferencd@0 1792 {
ferencd@0 1793 return "[json.exception." + ename + "." + std::to_string(id_) + "] ";
ferencd@0 1794 }
ferencd@0 1795
ferencd@0 1796 private:
ferencd@0 1797 /// an exception object as storage for error messages
ferencd@0 1798 std::runtime_error m;
ferencd@0 1799 };
ferencd@0 1800
ferencd@0 1801 /*!
ferencd@0 1802 @brief exception indicating a parse error
ferencd@0 1803
ferencd@0 1804 This exception is thrown by the library when a parse error occurs. Parse errors
ferencd@0 1805 can occur during the deserialization of JSON text, CBOR, MessagePack, as well
ferencd@0 1806 as when using JSON Patch.
ferencd@0 1807
ferencd@0 1808 Member @a byte holds the byte index of the last read character in the input
ferencd@0 1809 file.
ferencd@0 1810
ferencd@0 1811 Exceptions have ids 1xx.
ferencd@0 1812
ferencd@0 1813 name / id | example message | description
ferencd@0 1814 ------------------------------ | --------------- | -------------------------
ferencd@0 1815 json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position.
ferencd@0 1816 json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point.
ferencd@0 1817 json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid.
ferencd@0 1818 json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects.
ferencd@0 1819 json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors.
ferencd@0 1820 json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`.
ferencd@0 1821 json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character.
ferencd@0 1822 json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences.
ferencd@0 1823 json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number.
ferencd@0 1824 json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.
ferencd@0 1825 json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.
ferencd@0 1826 json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.
ferencd@0 1827 json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet).
ferencd@0 1828
ferencd@0 1829 @note For an input with n bytes, 1 is the index of the first character and n+1
ferencd@0 1830 is the index of the terminating null byte or the end of file. This also
ferencd@0 1831 holds true when reading a byte vector (CBOR or MessagePack).
ferencd@0 1832
ferencd@0 1833 @liveexample{The following code shows how a `parse_error` exception can be
ferencd@0 1834 caught.,parse_error}
ferencd@0 1835
ferencd@0 1836 @sa - @ref exception for the base class of the library exceptions
ferencd@0 1837 @sa - @ref invalid_iterator for exceptions indicating errors with iterators
ferencd@0 1838 @sa - @ref type_error for exceptions indicating executing a member function with
ferencd@0 1839 a wrong type
ferencd@0 1840 @sa - @ref out_of_range for exceptions indicating access out of the defined range
ferencd@0 1841 @sa - @ref other_error for exceptions indicating other library errors
ferencd@0 1842
ferencd@0 1843 @since version 3.0.0
ferencd@0 1844 */
ferencd@0 1845 class parse_error : public exception
ferencd@0 1846 {
ferencd@0 1847 public:
ferencd@0 1848 /*!
ferencd@0 1849 @brief create a parse error exception
ferencd@0 1850 @param[in] id_ the id of the exception
ferencd@0 1851 @param[in] pos the position where the error occurred (or with
ferencd@0 1852 chars_read_total=0 if the position cannot be
ferencd@0 1853 determined)
ferencd@0 1854 @param[in] what_arg the explanatory string
ferencd@0 1855 @return parse_error object
ferencd@0 1856 */
ferencd@0 1857 static parse_error create(int id_, const position_t& pos, const std::string& what_arg)
ferencd@0 1858 {
ferencd@0 1859 std::string w = exception::name("parse_error", id_) + "parse error" +
ferencd@0 1860 position_string(pos) + ": " + what_arg;
ferencd@0 1861 return parse_error(id_, pos.chars_read_total, w.c_str());
ferencd@0 1862 }
ferencd@0 1863
ferencd@0 1864 static parse_error create(int id_, std::size_t byte_, const std::string& what_arg)
ferencd@0 1865 {
ferencd@0 1866 std::string w = exception::name("parse_error", id_) + "parse error" +
ferencd@0 1867 (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") +
ferencd@0 1868 ": " + what_arg;
ferencd@0 1869 return parse_error(id_, byte_, w.c_str());
ferencd@0 1870 }
ferencd@0 1871
ferencd@0 1872 /*!
ferencd@0 1873 @brief byte index of the parse error
ferencd@0 1874
ferencd@0 1875 The byte index of the last read character in the input file.
ferencd@0 1876
ferencd@0 1877 @note For an input with n bytes, 1 is the index of the first character and
ferencd@0 1878 n+1 is the index of the terminating null byte or the end of file.
ferencd@0 1879 This also holds true when reading a byte vector (CBOR or MessagePack).
ferencd@0 1880 */
ferencd@0 1881 const std::size_t byte;
ferencd@0 1882
ferencd@0 1883 private:
ferencd@0 1884 parse_error(int id_, std::size_t byte_, const char* what_arg)
ferencd@0 1885 : exception(id_, what_arg), byte(byte_) {}
ferencd@0 1886
ferencd@0 1887 static std::string position_string(const position_t& pos)
ferencd@0 1888 {
ferencd@0 1889 return " at line " + std::to_string(pos.lines_read + 1) +
ferencd@0 1890 ", column " + std::to_string(pos.chars_read_current_line);
ferencd@0 1891 }
ferencd@0 1892 };
ferencd@0 1893
ferencd@0 1894 /*!
ferencd@0 1895 @brief exception indicating errors with iterators
ferencd@0 1896
ferencd@0 1897 This exception is thrown if iterators passed to a library function do not match
ferencd@0 1898 the expected semantics.
ferencd@0 1899
ferencd@0 1900 Exceptions have ids 2xx.
ferencd@0 1901
ferencd@0 1902 name / id | example message | description
ferencd@0 1903 ----------------------------------- | --------------- | -------------------------
ferencd@0 1904 json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.
ferencd@0 1905 json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion.
ferencd@0 1906 json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from.
ferencd@0 1907 json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid.
ferencd@0 1908 json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid.
ferencd@0 1909 json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range.
ferencd@0 1910 json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key.
ferencd@0 1911 json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.
ferencd@0 1912 json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.
ferencd@0 1913 json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.
ferencd@0 1914 json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to.
ferencd@0 1915 json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container.
ferencd@0 1916 json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered.
ferencd@0 1917 json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin().
ferencd@0 1918
ferencd@0 1919 @liveexample{The following code shows how an `invalid_iterator` exception can be
ferencd@0 1920 caught.,invalid_iterator}
ferencd@0 1921
ferencd@0 1922 @sa - @ref exception for the base class of the library exceptions
ferencd@0 1923 @sa - @ref parse_error for exceptions indicating a parse error
ferencd@0 1924 @sa - @ref type_error for exceptions indicating executing a member function with
ferencd@0 1925 a wrong type
ferencd@0 1926 @sa - @ref out_of_range for exceptions indicating access out of the defined range
ferencd@0 1927 @sa - @ref other_error for exceptions indicating other library errors
ferencd@0 1928
ferencd@0 1929 @since version 3.0.0
ferencd@0 1930 */
ferencd@0 1931 class invalid_iterator : public exception
ferencd@0 1932 {
ferencd@0 1933 public:
ferencd@0 1934 static invalid_iterator create(int id_, const std::string& what_arg)
ferencd@0 1935 {
ferencd@0 1936 std::string w = exception::name("invalid_iterator", id_) + what_arg;
ferencd@0 1937 return invalid_iterator(id_, w.c_str());
ferencd@0 1938 }
ferencd@0 1939
ferencd@0 1940 private:
ferencd@0 1941 JSON_HEDLEY_NON_NULL(3)
ferencd@0 1942 invalid_iterator(int id_, const char* what_arg)
ferencd@0 1943 : exception(id_, what_arg) {}
ferencd@0 1944 };
ferencd@0 1945
ferencd@0 1946 /*!
ferencd@0 1947 @brief exception indicating executing a member function with a wrong type
ferencd@0 1948
ferencd@0 1949 This exception is thrown in case of a type error; that is, a library function is
ferencd@0 1950 executed on a JSON value whose type does not match the expected semantics.
ferencd@0 1951
ferencd@0 1952 Exceptions have ids 3xx.
ferencd@0 1953
ferencd@0 1954 name / id | example message | description
ferencd@0 1955 ----------------------------- | --------------- | -------------------------
ferencd@0 1956 json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead.
ferencd@0 1957 json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types.
ferencd@0 1958 json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &.
ferencd@0 1959 json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types.
ferencd@0 1960 json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types.
ferencd@0 1961 json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types.
ferencd@0 1962 json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types.
ferencd@0 1963 json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types.
ferencd@0 1964 json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types.
ferencd@0 1965 json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types.
ferencd@0 1966 json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types.
ferencd@0 1967 json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types.
ferencd@0 1968 json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined.
ferencd@0 1969 json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers.
ferencd@0 1970 json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive.
ferencd@0 1971 json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. |
ferencd@0 1972 json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) |
ferencd@0 1973
ferencd@0 1974 @liveexample{The following code shows how a `type_error` exception can be
ferencd@0 1975 caught.,type_error}
ferencd@0 1976
ferencd@0 1977 @sa - @ref exception for the base class of the library exceptions
ferencd@0 1978 @sa - @ref parse_error for exceptions indicating a parse error
ferencd@0 1979 @sa - @ref invalid_iterator for exceptions indicating errors with iterators
ferencd@0 1980 @sa - @ref out_of_range for exceptions indicating access out of the defined range
ferencd@0 1981 @sa - @ref other_error for exceptions indicating other library errors
ferencd@0 1982
ferencd@0 1983 @since version 3.0.0
ferencd@0 1984 */
ferencd@0 1985 class type_error : public exception
ferencd@0 1986 {
ferencd@0 1987 public:
ferencd@0 1988 static type_error create(int id_, const std::string& what_arg)
ferencd@0 1989 {
ferencd@0 1990 std::string w = exception::name("type_error", id_) + what_arg;
ferencd@0 1991 return type_error(id_, w.c_str());
ferencd@0 1992 }
ferencd@0 1993
ferencd@0 1994 private:
ferencd@0 1995 JSON_HEDLEY_NON_NULL(3)
ferencd@0 1996 type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
ferencd@0 1997 };
ferencd@0 1998
ferencd@0 1999 /*!
ferencd@0 2000 @brief exception indicating access out of the defined range
ferencd@0 2001
ferencd@0 2002 This exception is thrown in case a library function is called on an input
ferencd@0 2003 parameter that exceeds the expected range, for instance in case of array
ferencd@0 2004 indices or nonexisting object keys.
ferencd@0 2005
ferencd@0 2006 Exceptions have ids 4xx.
ferencd@0 2007
ferencd@0 2008 name / id | example message | description
ferencd@0 2009 ------------------------------- | --------------- | -------------------------
ferencd@0 2010 json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1.
ferencd@0 2011 json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it.
ferencd@0 2012 json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object.
ferencd@0 2013 json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved.
ferencd@0 2014 json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.
ferencd@0 2015 json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.
ferencd@0 2016 json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. |
ferencd@0 2017 json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. |
ferencd@0 2018 json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string |
ferencd@0 2019
ferencd@0 2020 @liveexample{The following code shows how an `out_of_range` exception can be
ferencd@0 2021 caught.,out_of_range}
ferencd@0 2022
ferencd@0 2023 @sa - @ref exception for the base class of the library exceptions
ferencd@0 2024 @sa - @ref parse_error for exceptions indicating a parse error
ferencd@0 2025 @sa - @ref invalid_iterator for exceptions indicating errors with iterators
ferencd@0 2026 @sa - @ref type_error for exceptions indicating executing a member function with
ferencd@0 2027 a wrong type
ferencd@0 2028 @sa - @ref other_error for exceptions indicating other library errors
ferencd@0 2029
ferencd@0 2030 @since version 3.0.0
ferencd@0 2031 */
ferencd@0 2032 class out_of_range : public exception
ferencd@0 2033 {
ferencd@0 2034 public:
ferencd@0 2035 static out_of_range create(int id_, const std::string& what_arg)
ferencd@0 2036 {
ferencd@0 2037 std::string w = exception::name("out_of_range", id_) + what_arg;
ferencd@0 2038 return out_of_range(id_, w.c_str());
ferencd@0 2039 }
ferencd@0 2040
ferencd@0 2041 private:
ferencd@0 2042 JSON_HEDLEY_NON_NULL(3)
ferencd@0 2043 out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
ferencd@0 2044 };
ferencd@0 2045
ferencd@0 2046 /*!
ferencd@0 2047 @brief exception indicating other library errors
ferencd@0 2048
ferencd@0 2049 This exception is thrown in case of errors that cannot be classified with the
ferencd@0 2050 other exception types.
ferencd@0 2051
ferencd@0 2052 Exceptions have ids 5xx.
ferencd@0 2053
ferencd@0 2054 name / id | example message | description
ferencd@0 2055 ------------------------------ | --------------- | -------------------------
ferencd@0 2056 json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.
ferencd@0 2057
ferencd@0 2058 @sa - @ref exception for the base class of the library exceptions
ferencd@0 2059 @sa - @ref parse_error for exceptions indicating a parse error
ferencd@0 2060 @sa - @ref invalid_iterator for exceptions indicating errors with iterators
ferencd@0 2061 @sa - @ref type_error for exceptions indicating executing a member function with
ferencd@0 2062 a wrong type
ferencd@0 2063 @sa - @ref out_of_range for exceptions indicating access out of the defined range
ferencd@0 2064
ferencd@0 2065 @liveexample{The following code shows how an `other_error` exception can be
ferencd@0 2066 caught.,other_error}
ferencd@0 2067
ferencd@0 2068 @since version 3.0.0
ferencd@0 2069 */
ferencd@0 2070 class other_error : public exception
ferencd@0 2071 {
ferencd@0 2072 public:
ferencd@0 2073 static other_error create(int id_, const std::string& what_arg)
ferencd@0 2074 {
ferencd@0 2075 std::string w = exception::name("other_error", id_) + what_arg;
ferencd@0 2076 return other_error(id_, w.c_str());
ferencd@0 2077 }
ferencd@0 2078
ferencd@0 2079 private:
ferencd@0 2080 JSON_HEDLEY_NON_NULL(3)
ferencd@0 2081 other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
ferencd@0 2082 };
ferencd@0 2083 } // namespace detail
ferencd@0 2084 } // namespace nlohmann
ferencd@0 2085
ferencd@0 2086 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 2087
ferencd@0 2088 // #include <nlohmann/detail/meta/cpp_future.hpp>
ferencd@0 2089
ferencd@0 2090
ferencd@0 2091 #include <ciso646> // not
ferencd@0 2092 #include <cstddef> // size_t
ferencd@0 2093 #include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
ferencd@0 2094
ferencd@0 2095 namespace nlohmann
ferencd@0 2096 {
ferencd@0 2097 namespace detail
ferencd@0 2098 {
ferencd@0 2099 // alias templates to reduce boilerplate
ferencd@0 2100 template<bool B, typename T = void>
ferencd@0 2101 using enable_if_t = typename std::enable_if<B, T>::type;
ferencd@0 2102
ferencd@0 2103 template<typename T>
ferencd@0 2104 using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
ferencd@0 2105
ferencd@0 2106 // implementation of C++14 index_sequence and affiliates
ferencd@0 2107 // source: https://stackoverflow.com/a/32223343
ferencd@0 2108 template<std::size_t... Ints>
ferencd@0 2109 struct index_sequence
ferencd@0 2110 {
ferencd@0 2111 using type = index_sequence;
ferencd@0 2112 using value_type = std::size_t;
ferencd@0 2113 static constexpr std::size_t size() noexcept
ferencd@0 2114 {
ferencd@0 2115 return sizeof...(Ints);
ferencd@0 2116 }
ferencd@0 2117 };
ferencd@0 2118
ferencd@0 2119 template<class Sequence1, class Sequence2>
ferencd@0 2120 struct merge_and_renumber;
ferencd@0 2121
ferencd@0 2122 template<std::size_t... I1, std::size_t... I2>
ferencd@0 2123 struct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
ferencd@0 2124 : index_sequence < I1..., (sizeof...(I1) + I2)... > {};
ferencd@0 2125
ferencd@0 2126 template<std::size_t N>
ferencd@0 2127 struct make_index_sequence
ferencd@0 2128 : merge_and_renumber < typename make_index_sequence < N / 2 >::type,
ferencd@0 2129 typename make_index_sequence < N - N / 2 >::type > {};
ferencd@0 2130
ferencd@0 2131 template<> struct make_index_sequence<0> : index_sequence<> {};
ferencd@0 2132 template<> struct make_index_sequence<1> : index_sequence<0> {};
ferencd@0 2133
ferencd@0 2134 template<typename... Ts>
ferencd@0 2135 using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
ferencd@0 2136
ferencd@0 2137 // dispatch utility (taken from ranges-v3)
ferencd@0 2138 template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
ferencd@0 2139 template<> struct priority_tag<0> {};
ferencd@0 2140
ferencd@0 2141 // taken from ranges-v3
ferencd@0 2142 template<typename T>
ferencd@0 2143 struct static_const
ferencd@0 2144 {
ferencd@0 2145 static constexpr T value{};
ferencd@0 2146 };
ferencd@0 2147
ferencd@0 2148 template<typename T>
ferencd@0 2149 constexpr T static_const<T>::value;
ferencd@0 2150 } // namespace detail
ferencd@0 2151 } // namespace nlohmann
ferencd@0 2152
ferencd@0 2153 // #include <nlohmann/detail/meta/type_traits.hpp>
ferencd@0 2154
ferencd@0 2155
ferencd@0 2156 #include <ciso646> // not
ferencd@0 2157 #include <limits> // numeric_limits
ferencd@0 2158 #include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
ferencd@0 2159 #include <utility> // declval
ferencd@0 2160
ferencd@0 2161 // #include <nlohmann/detail/iterators/iterator_traits.hpp>
ferencd@0 2162
ferencd@0 2163
ferencd@0 2164 #include <iterator> // random_access_iterator_tag
ferencd@0 2165
ferencd@0 2166 // #include <nlohmann/detail/meta/void_t.hpp>
ferencd@0 2167
ferencd@0 2168
ferencd@0 2169 namespace nlohmann
ferencd@0 2170 {
ferencd@0 2171 namespace detail
ferencd@0 2172 {
ferencd@0 2173 template <typename ...Ts> struct make_void
ferencd@0 2174 {
ferencd@0 2175 using type = void;
ferencd@0 2176 };
ferencd@0 2177 template <typename ...Ts> using void_t = typename make_void<Ts...>::type;
ferencd@0 2178 } // namespace detail
ferencd@0 2179 } // namespace nlohmann
ferencd@0 2180
ferencd@0 2181 // #include <nlohmann/detail/meta/cpp_future.hpp>
ferencd@0 2182
ferencd@0 2183
ferencd@0 2184 namespace nlohmann
ferencd@0 2185 {
ferencd@0 2186 namespace detail
ferencd@0 2187 {
ferencd@0 2188 template <typename It, typename = void>
ferencd@0 2189 struct iterator_types {};
ferencd@0 2190
ferencd@0 2191 template <typename It>
ferencd@0 2192 struct iterator_types <
ferencd@0 2193 It,
ferencd@0 2194 void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
ferencd@0 2195 typename It::reference, typename It::iterator_category >>
ferencd@0 2196 {
ferencd@0 2197 using difference_type = typename It::difference_type;
ferencd@0 2198 using value_type = typename It::value_type;
ferencd@0 2199 using pointer = typename It::pointer;
ferencd@0 2200 using reference = typename It::reference;
ferencd@0 2201 using iterator_category = typename It::iterator_category;
ferencd@0 2202 };
ferencd@0 2203
ferencd@0 2204 // This is required as some compilers implement std::iterator_traits in a way that
ferencd@0 2205 // doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.
ferencd@0 2206 template <typename T, typename = void>
ferencd@0 2207 struct iterator_traits
ferencd@0 2208 {
ferencd@0 2209 };
ferencd@0 2210
ferencd@0 2211 template <typename T>
ferencd@0 2212 struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>
ferencd@0 2213 : iterator_types<T>
ferencd@0 2214 {
ferencd@0 2215 };
ferencd@0 2216
ferencd@0 2217 template <typename T>
ferencd@0 2218 struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>
ferencd@0 2219 {
ferencd@0 2220 using iterator_category = std::random_access_iterator_tag;
ferencd@0 2221 using value_type = T;
ferencd@0 2222 using difference_type = ptrdiff_t;
ferencd@0 2223 using pointer = T*;
ferencd@0 2224 using reference = T&;
ferencd@0 2225 };
ferencd@0 2226 } // namespace detail
ferencd@0 2227 } // namespace nlohmann
ferencd@0 2228
ferencd@0 2229 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 2230
ferencd@0 2231 // #include <nlohmann/detail/meta/cpp_future.hpp>
ferencd@0 2232
ferencd@0 2233 // #include <nlohmann/detail/meta/detected.hpp>
ferencd@0 2234
ferencd@0 2235
ferencd@0 2236 #include <type_traits>
ferencd@0 2237
ferencd@0 2238 // #include <nlohmann/detail/meta/void_t.hpp>
ferencd@0 2239
ferencd@0 2240
ferencd@0 2241 // http://en.cppreference.com/w/cpp/experimental/is_detected
ferencd@0 2242 namespace nlohmann
ferencd@0 2243 {
ferencd@0 2244 namespace detail
ferencd@0 2245 {
ferencd@0 2246 struct nonesuch
ferencd@0 2247 {
ferencd@0 2248 nonesuch() = delete;
ferencd@0 2249 ~nonesuch() = delete;
ferencd@0 2250 nonesuch(nonesuch const&) = delete;
ferencd@0 2251 nonesuch(nonesuch const&&) = delete;
ferencd@0 2252 void operator=(nonesuch const&) = delete;
ferencd@0 2253 void operator=(nonesuch&&) = delete;
ferencd@0 2254 };
ferencd@0 2255
ferencd@0 2256 template <class Default,
ferencd@0 2257 class AlwaysVoid,
ferencd@0 2258 template <class...> class Op,
ferencd@0 2259 class... Args>
ferencd@0 2260 struct detector
ferencd@0 2261 {
ferencd@0 2262 using value_t = std::false_type;
ferencd@0 2263 using type = Default;
ferencd@0 2264 };
ferencd@0 2265
ferencd@0 2266 template <class Default, template <class...> class Op, class... Args>
ferencd@0 2267 struct detector<Default, void_t<Op<Args...>>, Op, Args...>
ferencd@0 2268 {
ferencd@0 2269 using value_t = std::true_type;
ferencd@0 2270 using type = Op<Args...>;
ferencd@0 2271 };
ferencd@0 2272
ferencd@0 2273 template <template <class...> class Op, class... Args>
ferencd@0 2274 using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
ferencd@0 2275
ferencd@0 2276 template <template <class...> class Op, class... Args>
ferencd@0 2277 using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
ferencd@0 2278
ferencd@0 2279 template <class Default, template <class...> class Op, class... Args>
ferencd@0 2280 using detected_or = detector<Default, void, Op, Args...>;
ferencd@0 2281
ferencd@0 2282 template <class Default, template <class...> class Op, class... Args>
ferencd@0 2283 using detected_or_t = typename detected_or<Default, Op, Args...>::type;
ferencd@0 2284
ferencd@0 2285 template <class Expected, template <class...> class Op, class... Args>
ferencd@0 2286 using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
ferencd@0 2287
ferencd@0 2288 template <class To, template <class...> class Op, class... Args>
ferencd@0 2289 using is_detected_convertible =
ferencd@0 2290 std::is_convertible<detected_t<Op, Args...>, To>;
ferencd@0 2291 } // namespace detail
ferencd@0 2292 } // namespace nlohmann
ferencd@0 2293
ferencd@0 2294 // #include <nlohmann/json_fwd.hpp>
ferencd@0 2295 #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
ferencd@0 2296 #define INCLUDE_NLOHMANN_JSON_FWD_HPP_
ferencd@0 2297
ferencd@0 2298 #include <cstdint> // int64_t, uint64_t
ferencd@0 2299 #include <map> // map
ferencd@0 2300 #include <memory> // allocator
ferencd@0 2301 #include <string> // string
ferencd@0 2302 #include <vector> // vector
ferencd@0 2303
ferencd@0 2304 /*!
ferencd@0 2305 @brief namespace for Niels Lohmann
ferencd@0 2306 @see https://github.com/nlohmann
ferencd@0 2307 @since version 1.0.0
ferencd@0 2308 */
ferencd@0 2309 namespace nlohmann
ferencd@0 2310 {
ferencd@0 2311 /*!
ferencd@0 2312 @brief default JSONSerializer template argument
ferencd@0 2313
ferencd@0 2314 This serializer ignores the template arguments and uses ADL
ferencd@0 2315 ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
ferencd@0 2316 for serialization.
ferencd@0 2317 */
ferencd@0 2318 template<typename T = void, typename SFINAE = void>
ferencd@0 2319 struct adl_serializer;
ferencd@0 2320
ferencd@0 2321 template<template<typename U, typename V, typename... Args> class ObjectType =
ferencd@0 2322 std::map,
ferencd@0 2323 template<typename U, typename... Args> class ArrayType = std::vector,
ferencd@0 2324 class StringType = std::string, class BooleanType = bool,
ferencd@0 2325 class NumberIntegerType = std::int64_t,
ferencd@0 2326 class NumberUnsignedType = std::uint64_t,
ferencd@0 2327 class NumberFloatType = double,
ferencd@0 2328 template<typename U> class AllocatorType = std::allocator,
ferencd@0 2329 template<typename T, typename SFINAE = void> class JSONSerializer =
ferencd@0 2330 adl_serializer>
ferencd@0 2331 class basic_json;
ferencd@0 2332
ferencd@0 2333 /*!
ferencd@0 2334 @brief JSON Pointer
ferencd@0 2335
ferencd@0 2336 A JSON pointer defines a string syntax for identifying a specific value
ferencd@0 2337 within a JSON document. It can be used with functions `at` and
ferencd@0 2338 `operator[]`. Furthermore, JSON pointers are the base for JSON patches.
ferencd@0 2339
ferencd@0 2340 @sa [RFC 6901](https://tools.ietf.org/html/rfc6901)
ferencd@0 2341
ferencd@0 2342 @since version 2.0.0
ferencd@0 2343 */
ferencd@0 2344 template<typename BasicJsonType>
ferencd@0 2345 class json_pointer;
ferencd@0 2346
ferencd@0 2347 /*!
ferencd@0 2348 @brief default JSON class
ferencd@0 2349
ferencd@0 2350 This type is the default specialization of the @ref basic_json class which
ferencd@0 2351 uses the standard template types.
ferencd@0 2352
ferencd@0 2353 @since version 1.0.0
ferencd@0 2354 */
ferencd@0 2355 using json = basic_json<>;
ferencd@0 2356 } // namespace nlohmann
ferencd@0 2357
ferencd@0 2358 #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_
ferencd@0 2359
ferencd@0 2360
ferencd@0 2361 namespace nlohmann
ferencd@0 2362 {
ferencd@0 2363 /*!
ferencd@0 2364 @brief detail namespace with internal helper functions
ferencd@0 2365
ferencd@0 2366 This namespace collects functions that should not be exposed,
ferencd@0 2367 implementations of some @ref basic_json methods, and meta-programming helpers.
ferencd@0 2368
ferencd@0 2369 @since version 2.1.0
ferencd@0 2370 */
ferencd@0 2371 namespace detail
ferencd@0 2372 {
ferencd@0 2373 /////////////
ferencd@0 2374 // helpers //
ferencd@0 2375 /////////////
ferencd@0 2376
ferencd@0 2377 // Note to maintainers:
ferencd@0 2378 //
ferencd@0 2379 // Every trait in this file expects a non CV-qualified type.
ferencd@0 2380 // The only exceptions are in the 'aliases for detected' section
ferencd@0 2381 // (i.e. those of the form: decltype(T::member_function(std::declval<T>())))
ferencd@0 2382 //
ferencd@0 2383 // In this case, T has to be properly CV-qualified to constraint the function arguments
ferencd@0 2384 // (e.g. to_json(BasicJsonType&, const T&))
ferencd@0 2385
ferencd@0 2386 template<typename> struct is_basic_json : std::false_type {};
ferencd@0 2387
ferencd@0 2388 NLOHMANN_BASIC_JSON_TPL_DECLARATION
ferencd@0 2389 struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
ferencd@0 2390
ferencd@0 2391 //////////////////////////
ferencd@0 2392 // aliases for detected //
ferencd@0 2393 //////////////////////////
ferencd@0 2394
ferencd@0 2395 template <typename T>
ferencd@0 2396 using mapped_type_t = typename T::mapped_type;
ferencd@0 2397
ferencd@0 2398 template <typename T>
ferencd@0 2399 using key_type_t = typename T::key_type;
ferencd@0 2400
ferencd@0 2401 template <typename T>
ferencd@0 2402 using value_type_t = typename T::value_type;
ferencd@0 2403
ferencd@0 2404 template <typename T>
ferencd@0 2405 using difference_type_t = typename T::difference_type;
ferencd@0 2406
ferencd@0 2407 template <typename T>
ferencd@0 2408 using pointer_t = typename T::pointer;
ferencd@0 2409
ferencd@0 2410 template <typename T>
ferencd@0 2411 using reference_t = typename T::reference;
ferencd@0 2412
ferencd@0 2413 template <typename T>
ferencd@0 2414 using iterator_category_t = typename T::iterator_category;
ferencd@0 2415
ferencd@0 2416 template <typename T>
ferencd@0 2417 using iterator_t = typename T::iterator;
ferencd@0 2418
ferencd@0 2419 template <typename T, typename... Args>
ferencd@0 2420 using to_json_function = decltype(T::to_json(std::declval<Args>()...));
ferencd@0 2421
ferencd@0 2422 template <typename T, typename... Args>
ferencd@0 2423 using from_json_function = decltype(T::from_json(std::declval<Args>()...));
ferencd@0 2424
ferencd@0 2425 template <typename T, typename U>
ferencd@0 2426 using get_template_function = decltype(std::declval<T>().template get<U>());
ferencd@0 2427
ferencd@0 2428 // trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
ferencd@0 2429 template <typename BasicJsonType, typename T, typename = void>
ferencd@0 2430 struct has_from_json : std::false_type {};
ferencd@0 2431
ferencd@0 2432 template <typename BasicJsonType, typename T>
ferencd@0 2433 struct has_from_json<BasicJsonType, T,
ferencd@0 2434 enable_if_t<not is_basic_json<T>::value>>
ferencd@0 2435 {
ferencd@0 2436 using serializer = typename BasicJsonType::template json_serializer<T, void>;
ferencd@0 2437
ferencd@0 2438 static constexpr bool value =
ferencd@0 2439 is_detected_exact<void, from_json_function, serializer,
ferencd@0 2440 const BasicJsonType&, T&>::value;
ferencd@0 2441 };
ferencd@0 2442
ferencd@0 2443 // This trait checks if JSONSerializer<T>::from_json(json const&) exists
ferencd@0 2444 // this overload is used for non-default-constructible user-defined-types
ferencd@0 2445 template <typename BasicJsonType, typename T, typename = void>
ferencd@0 2446 struct has_non_default_from_json : std::false_type {};
ferencd@0 2447
ferencd@0 2448 template<typename BasicJsonType, typename T>
ferencd@0 2449 struct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>
ferencd@0 2450 {
ferencd@0 2451 using serializer = typename BasicJsonType::template json_serializer<T, void>;
ferencd@0 2452
ferencd@0 2453 static constexpr bool value =
ferencd@0 2454 is_detected_exact<T, from_json_function, serializer,
ferencd@0 2455 const BasicJsonType&>::value;
ferencd@0 2456 };
ferencd@0 2457
ferencd@0 2458 // This trait checks if BasicJsonType::json_serializer<T>::to_json exists
ferencd@0 2459 // Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
ferencd@0 2460 template <typename BasicJsonType, typename T, typename = void>
ferencd@0 2461 struct has_to_json : std::false_type {};
ferencd@0 2462
ferencd@0 2463 template <typename BasicJsonType, typename T>
ferencd@0 2464 struct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>
ferencd@0 2465 {
ferencd@0 2466 using serializer = typename BasicJsonType::template json_serializer<T, void>;
ferencd@0 2467
ferencd@0 2468 static constexpr bool value =
ferencd@0 2469 is_detected_exact<void, to_json_function, serializer, BasicJsonType&,
ferencd@0 2470 T>::value;
ferencd@0 2471 };
ferencd@0 2472
ferencd@0 2473
ferencd@0 2474 ///////////////////
ferencd@0 2475 // is_ functions //
ferencd@0 2476 ///////////////////
ferencd@0 2477
ferencd@0 2478 template <typename T, typename = void>
ferencd@0 2479 struct is_iterator_traits : std::false_type {};
ferencd@0 2480
ferencd@0 2481 template <typename T>
ferencd@0 2482 struct is_iterator_traits<iterator_traits<T>>
ferencd@0 2483 {
ferencd@0 2484 private:
ferencd@0 2485 using traits = iterator_traits<T>;
ferencd@0 2486
ferencd@0 2487 public:
ferencd@0 2488 static constexpr auto value =
ferencd@0 2489 is_detected<value_type_t, traits>::value &&
ferencd@0 2490 is_detected<difference_type_t, traits>::value &&
ferencd@0 2491 is_detected<pointer_t, traits>::value &&
ferencd@0 2492 is_detected<iterator_category_t, traits>::value &&
ferencd@0 2493 is_detected<reference_t, traits>::value;
ferencd@0 2494 };
ferencd@0 2495
ferencd@0 2496 // source: https://stackoverflow.com/a/37193089/4116453
ferencd@0 2497
ferencd@0 2498 template <typename T, typename = void>
ferencd@0 2499 struct is_complete_type : std::false_type {};
ferencd@0 2500
ferencd@0 2501 template <typename T>
ferencd@0 2502 struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
ferencd@0 2503
ferencd@0 2504 template <typename BasicJsonType, typename CompatibleObjectType,
ferencd@0 2505 typename = void>
ferencd@0 2506 struct is_compatible_object_type_impl : std::false_type {};
ferencd@0 2507
ferencd@0 2508 template <typename BasicJsonType, typename CompatibleObjectType>
ferencd@0 2509 struct is_compatible_object_type_impl <
ferencd@0 2510 BasicJsonType, CompatibleObjectType,
ferencd@0 2511 enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and
ferencd@0 2512 is_detected<key_type_t, CompatibleObjectType>::value >>
ferencd@0 2513 {
ferencd@0 2514
ferencd@0 2515 using object_t = typename BasicJsonType::object_t;
ferencd@0 2516
ferencd@0 2517 // macOS's is_constructible does not play well with nonesuch...
ferencd@0 2518 static constexpr bool value =
ferencd@0 2519 std::is_constructible<typename object_t::key_type,
ferencd@0 2520 typename CompatibleObjectType::key_type>::value and
ferencd@0 2521 std::is_constructible<typename object_t::mapped_type,
ferencd@0 2522 typename CompatibleObjectType::mapped_type>::value;
ferencd@0 2523 };
ferencd@0 2524
ferencd@0 2525 template <typename BasicJsonType, typename CompatibleObjectType>
ferencd@0 2526 struct is_compatible_object_type
ferencd@0 2527 : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
ferencd@0 2528
ferencd@0 2529 template <typename BasicJsonType, typename ConstructibleObjectType,
ferencd@0 2530 typename = void>
ferencd@0 2531 struct is_constructible_object_type_impl : std::false_type {};
ferencd@0 2532
ferencd@0 2533 template <typename BasicJsonType, typename ConstructibleObjectType>
ferencd@0 2534 struct is_constructible_object_type_impl <
ferencd@0 2535 BasicJsonType, ConstructibleObjectType,
ferencd@0 2536 enable_if_t<is_detected<mapped_type_t, ConstructibleObjectType>::value and
ferencd@0 2537 is_detected<key_type_t, ConstructibleObjectType>::value >>
ferencd@0 2538 {
ferencd@0 2539 using object_t = typename BasicJsonType::object_t;
ferencd@0 2540
ferencd@0 2541 static constexpr bool value =
ferencd@0 2542 (std::is_default_constructible<ConstructibleObjectType>::value and
ferencd@0 2543 (std::is_move_assignable<ConstructibleObjectType>::value or
ferencd@0 2544 std::is_copy_assignable<ConstructibleObjectType>::value) and
ferencd@0 2545 (std::is_constructible<typename ConstructibleObjectType::key_type,
ferencd@0 2546 typename object_t::key_type>::value and
ferencd@0 2547 std::is_same <
ferencd@0 2548 typename object_t::mapped_type,
ferencd@0 2549 typename ConstructibleObjectType::mapped_type >::value)) or
ferencd@0 2550 (has_from_json<BasicJsonType,
ferencd@0 2551 typename ConstructibleObjectType::mapped_type>::value or
ferencd@0 2552 has_non_default_from_json <
ferencd@0 2553 BasicJsonType,
ferencd@0 2554 typename ConstructibleObjectType::mapped_type >::value);
ferencd@0 2555 };
ferencd@0 2556
ferencd@0 2557 template <typename BasicJsonType, typename ConstructibleObjectType>
ferencd@0 2558 struct is_constructible_object_type
ferencd@0 2559 : is_constructible_object_type_impl<BasicJsonType,
ferencd@0 2560 ConstructibleObjectType> {};
ferencd@0 2561
ferencd@0 2562 template <typename BasicJsonType, typename CompatibleStringType,
ferencd@0 2563 typename = void>
ferencd@0 2564 struct is_compatible_string_type_impl : std::false_type {};
ferencd@0 2565
ferencd@0 2566 template <typename BasicJsonType, typename CompatibleStringType>
ferencd@0 2567 struct is_compatible_string_type_impl <
ferencd@0 2568 BasicJsonType, CompatibleStringType,
ferencd@0 2569 enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,
ferencd@0 2570 value_type_t, CompatibleStringType>::value >>
ferencd@0 2571 {
ferencd@0 2572 static constexpr auto value =
ferencd@0 2573 std::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
ferencd@0 2574 };
ferencd@0 2575
ferencd@0 2576 template <typename BasicJsonType, typename ConstructibleStringType>
ferencd@0 2577 struct is_compatible_string_type
ferencd@0 2578 : is_compatible_string_type_impl<BasicJsonType, ConstructibleStringType> {};
ferencd@0 2579
ferencd@0 2580 template <typename BasicJsonType, typename ConstructibleStringType,
ferencd@0 2581 typename = void>
ferencd@0 2582 struct is_constructible_string_type_impl : std::false_type {};
ferencd@0 2583
ferencd@0 2584 template <typename BasicJsonType, typename ConstructibleStringType>
ferencd@0 2585 struct is_constructible_string_type_impl <
ferencd@0 2586 BasicJsonType, ConstructibleStringType,
ferencd@0 2587 enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,
ferencd@0 2588 value_type_t, ConstructibleStringType>::value >>
ferencd@0 2589 {
ferencd@0 2590 static constexpr auto value =
ferencd@0 2591 std::is_constructible<ConstructibleStringType,
ferencd@0 2592 typename BasicJsonType::string_t>::value;
ferencd@0 2593 };
ferencd@0 2594
ferencd@0 2595 template <typename BasicJsonType, typename ConstructibleStringType>
ferencd@0 2596 struct is_constructible_string_type
ferencd@0 2597 : is_constructible_string_type_impl<BasicJsonType, ConstructibleStringType> {};
ferencd@0 2598
ferencd@0 2599 template <typename BasicJsonType, typename CompatibleArrayType, typename = void>
ferencd@0 2600 struct is_compatible_array_type_impl : std::false_type {};
ferencd@0 2601
ferencd@0 2602 template <typename BasicJsonType, typename CompatibleArrayType>
ferencd@0 2603 struct is_compatible_array_type_impl <
ferencd@0 2604 BasicJsonType, CompatibleArrayType,
ferencd@0 2605 enable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and
ferencd@0 2606 is_detected<iterator_t, CompatibleArrayType>::value and
ferencd@0 2607 // This is needed because json_reverse_iterator has a ::iterator type...
ferencd@0 2608 // Therefore it is detected as a CompatibleArrayType.
ferencd@0 2609 // The real fix would be to have an Iterable concept.
ferencd@0 2610 not is_iterator_traits<
ferencd@0 2611 iterator_traits<CompatibleArrayType>>::value >>
ferencd@0 2612 {
ferencd@0 2613 static constexpr bool value =
ferencd@0 2614 std::is_constructible<BasicJsonType,
ferencd@0 2615 typename CompatibleArrayType::value_type>::value;
ferencd@0 2616 };
ferencd@0 2617
ferencd@0 2618 template <typename BasicJsonType, typename CompatibleArrayType>
ferencd@0 2619 struct is_compatible_array_type
ferencd@0 2620 : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
ferencd@0 2621
ferencd@0 2622 template <typename BasicJsonType, typename ConstructibleArrayType, typename = void>
ferencd@0 2623 struct is_constructible_array_type_impl : std::false_type {};
ferencd@0 2624
ferencd@0 2625 template <typename BasicJsonType, typename ConstructibleArrayType>
ferencd@0 2626 struct is_constructible_array_type_impl <
ferencd@0 2627 BasicJsonType, ConstructibleArrayType,
ferencd@0 2628 enable_if_t<std::is_same<ConstructibleArrayType,
ferencd@0 2629 typename BasicJsonType::value_type>::value >>
ferencd@0 2630 : std::true_type {};
ferencd@0 2631
ferencd@0 2632 template <typename BasicJsonType, typename ConstructibleArrayType>
ferencd@0 2633 struct is_constructible_array_type_impl <
ferencd@0 2634 BasicJsonType, ConstructibleArrayType,
ferencd@0 2635 enable_if_t<not std::is_same<ConstructibleArrayType,
ferencd@0 2636 typename BasicJsonType::value_type>::value and
ferencd@0 2637 std::is_default_constructible<ConstructibleArrayType>::value and
ferencd@0 2638 (std::is_move_assignable<ConstructibleArrayType>::value or
ferencd@0 2639 std::is_copy_assignable<ConstructibleArrayType>::value) and
ferencd@0 2640 is_detected<value_type_t, ConstructibleArrayType>::value and
ferencd@0 2641 is_detected<iterator_t, ConstructibleArrayType>::value and
ferencd@0 2642 is_complete_type<
ferencd@0 2643 detected_t<value_type_t, ConstructibleArrayType>>::value >>
ferencd@0 2644 {
ferencd@0 2645 static constexpr bool value =
ferencd@0 2646 // This is needed because json_reverse_iterator has a ::iterator type,
ferencd@0 2647 // furthermore, std::back_insert_iterator (and other iterators) have a
ferencd@0 2648 // base class `iterator`... Therefore it is detected as a
ferencd@0 2649 // ConstructibleArrayType. The real fix would be to have an Iterable
ferencd@0 2650 // concept.
ferencd@0 2651 not is_iterator_traits<iterator_traits<ConstructibleArrayType>>::value and
ferencd@0 2652
ferencd@0 2653 (std::is_same<typename ConstructibleArrayType::value_type,
ferencd@0 2654 typename BasicJsonType::array_t::value_type>::value or
ferencd@0 2655 has_from_json<BasicJsonType,
ferencd@0 2656 typename ConstructibleArrayType::value_type>::value or
ferencd@0 2657 has_non_default_from_json <
ferencd@0 2658 BasicJsonType, typename ConstructibleArrayType::value_type >::value);
ferencd@0 2659 };
ferencd@0 2660
ferencd@0 2661 template <typename BasicJsonType, typename ConstructibleArrayType>
ferencd@0 2662 struct is_constructible_array_type
ferencd@0 2663 : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};
ferencd@0 2664
ferencd@0 2665 template <typename RealIntegerType, typename CompatibleNumberIntegerType,
ferencd@0 2666 typename = void>
ferencd@0 2667 struct is_compatible_integer_type_impl : std::false_type {};
ferencd@0 2668
ferencd@0 2669 template <typename RealIntegerType, typename CompatibleNumberIntegerType>
ferencd@0 2670 struct is_compatible_integer_type_impl <
ferencd@0 2671 RealIntegerType, CompatibleNumberIntegerType,
ferencd@0 2672 enable_if_t<std::is_integral<RealIntegerType>::value and
ferencd@0 2673 std::is_integral<CompatibleNumberIntegerType>::value and
ferencd@0 2674 not std::is_same<bool, CompatibleNumberIntegerType>::value >>
ferencd@0 2675 {
ferencd@0 2676 // is there an assert somewhere on overflows?
ferencd@0 2677 using RealLimits = std::numeric_limits<RealIntegerType>;
ferencd@0 2678 using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
ferencd@0 2679
ferencd@0 2680 static constexpr auto value =
ferencd@0 2681 std::is_constructible<RealIntegerType,
ferencd@0 2682 CompatibleNumberIntegerType>::value and
ferencd@0 2683 CompatibleLimits::is_integer and
ferencd@0 2684 RealLimits::is_signed == CompatibleLimits::is_signed;
ferencd@0 2685 };
ferencd@0 2686
ferencd@0 2687 template <typename RealIntegerType, typename CompatibleNumberIntegerType>
ferencd@0 2688 struct is_compatible_integer_type
ferencd@0 2689 : is_compatible_integer_type_impl<RealIntegerType,
ferencd@0 2690 CompatibleNumberIntegerType> {};
ferencd@0 2691
ferencd@0 2692 template <typename BasicJsonType, typename CompatibleType, typename = void>
ferencd@0 2693 struct is_compatible_type_impl: std::false_type {};
ferencd@0 2694
ferencd@0 2695 template <typename BasicJsonType, typename CompatibleType>
ferencd@0 2696 struct is_compatible_type_impl <
ferencd@0 2697 BasicJsonType, CompatibleType,
ferencd@0 2698 enable_if_t<is_complete_type<CompatibleType>::value >>
ferencd@0 2699 {
ferencd@0 2700 static constexpr bool value =
ferencd@0 2701 has_to_json<BasicJsonType, CompatibleType>::value;
ferencd@0 2702 };
ferencd@0 2703
ferencd@0 2704 template <typename BasicJsonType, typename CompatibleType>
ferencd@0 2705 struct is_compatible_type
ferencd@0 2706 : is_compatible_type_impl<BasicJsonType, CompatibleType> {};
ferencd@0 2707 } // namespace detail
ferencd@0 2708 } // namespace nlohmann
ferencd@0 2709
ferencd@0 2710 // #include <nlohmann/detail/value_t.hpp>
ferencd@0 2711
ferencd@0 2712
ferencd@0 2713 #include <array> // array
ferencd@0 2714 #include <ciso646> // and
ferencd@0 2715 #include <cstddef> // size_t
ferencd@0 2716 #include <cstdint> // uint8_t
ferencd@0 2717 #include <string> // string
ferencd@0 2718
ferencd@0 2719 namespace nlohmann
ferencd@0 2720 {
ferencd@0 2721 namespace detail
ferencd@0 2722 {
ferencd@0 2723 ///////////////////////////
ferencd@0 2724 // JSON type enumeration //
ferencd@0 2725 ///////////////////////////
ferencd@0 2726
ferencd@0 2727 /*!
ferencd@0 2728 @brief the JSON type enumeration
ferencd@0 2729
ferencd@0 2730 This enumeration collects the different JSON types. It is internally used to
ferencd@0 2731 distinguish the stored values, and the functions @ref basic_json::is_null(),
ferencd@0 2732 @ref basic_json::is_object(), @ref basic_json::is_array(),
ferencd@0 2733 @ref basic_json::is_string(), @ref basic_json::is_boolean(),
ferencd@0 2734 @ref basic_json::is_number() (with @ref basic_json::is_number_integer(),
ferencd@0 2735 @ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),
ferencd@0 2736 @ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and
ferencd@0 2737 @ref basic_json::is_structured() rely on it.
ferencd@0 2738
ferencd@0 2739 @note There are three enumeration entries (number_integer, number_unsigned, and
ferencd@0 2740 number_float), because the library distinguishes these three types for numbers:
ferencd@0 2741 @ref basic_json::number_unsigned_t is used for unsigned integers,
ferencd@0 2742 @ref basic_json::number_integer_t is used for signed integers, and
ferencd@0 2743 @ref basic_json::number_float_t is used for floating-point numbers or to
ferencd@0 2744 approximate integers which do not fit in the limits of their respective type.
ferencd@0 2745
ferencd@0 2746 @sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON
ferencd@0 2747 value with the default value for a given type
ferencd@0 2748
ferencd@0 2749 @since version 1.0.0
ferencd@0 2750 */
ferencd@0 2751 enum class value_t : std::uint8_t
ferencd@0 2752 {
ferencd@0 2753 null, ///< null value
ferencd@0 2754 object, ///< object (unordered set of name/value pairs)
ferencd@0 2755 array, ///< array (ordered collection of values)
ferencd@0 2756 string, ///< string value
ferencd@0 2757 boolean, ///< boolean value
ferencd@0 2758 number_integer, ///< number value (signed integer)
ferencd@0 2759 number_unsigned, ///< number value (unsigned integer)
ferencd@0 2760 number_float, ///< number value (floating-point)
ferencd@0 2761 discarded ///< discarded by the the parser callback function
ferencd@0 2762 };
ferencd@0 2763
ferencd@0 2764 /*!
ferencd@0 2765 @brief comparison operator for JSON types
ferencd@0 2766
ferencd@0 2767 Returns an ordering that is similar to Python:
ferencd@0 2768 - order: null < boolean < number < object < array < string
ferencd@0 2769 - furthermore, each type is not smaller than itself
ferencd@0 2770 - discarded values are not comparable
ferencd@0 2771
ferencd@0 2772 @since version 1.0.0
ferencd@0 2773 */
ferencd@0 2774 inline bool operator<(const value_t lhs, const value_t rhs) noexcept
ferencd@0 2775 {
ferencd@0 2776 static constexpr std::array<std::uint8_t, 8> order = {{
ferencd@0 2777 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,
ferencd@0 2778 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */
ferencd@0 2779 }
ferencd@0 2780 };
ferencd@0 2781
ferencd@0 2782 const auto l_index = static_cast<std::size_t>(lhs);
ferencd@0 2783 const auto r_index = static_cast<std::size_t>(rhs);
ferencd@0 2784 return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index];
ferencd@0 2785 }
ferencd@0 2786 } // namespace detail
ferencd@0 2787 } // namespace nlohmann
ferencd@0 2788
ferencd@0 2789
ferencd@0 2790 namespace nlohmann
ferencd@0 2791 {
ferencd@0 2792 namespace detail
ferencd@0 2793 {
ferencd@0 2794 template<typename BasicJsonType>
ferencd@0 2795 void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
ferencd@0 2796 {
ferencd@0 2797 if (JSON_HEDLEY_UNLIKELY(not j.is_null()))
ferencd@0 2798 {
ferencd@0 2799 JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name())));
ferencd@0 2800 }
ferencd@0 2801 n = nullptr;
ferencd@0 2802 }
ferencd@0 2803
ferencd@0 2804 // overloads for basic_json template parameters
ferencd@0 2805 template<typename BasicJsonType, typename ArithmeticType,
ferencd@0 2806 enable_if_t<std::is_arithmetic<ArithmeticType>::value and
ferencd@0 2807 not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
ferencd@0 2808 int> = 0>
ferencd@0 2809 void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
ferencd@0 2810 {
ferencd@0 2811 switch (static_cast<value_t>(j))
ferencd@0 2812 {
ferencd@0 2813 case value_t::number_unsigned:
ferencd@0 2814 {
ferencd@0 2815 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
ferencd@0 2816 break;
ferencd@0 2817 }
ferencd@0 2818 case value_t::number_integer:
ferencd@0 2819 {
ferencd@0 2820 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
ferencd@0 2821 break;
ferencd@0 2822 }
ferencd@0 2823 case value_t::number_float:
ferencd@0 2824 {
ferencd@0 2825 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
ferencd@0 2826 break;
ferencd@0 2827 }
ferencd@0 2828
ferencd@0 2829 default:
ferencd@0 2830 JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name())));
ferencd@0 2831 }
ferencd@0 2832 }
ferencd@0 2833
ferencd@0 2834 template<typename BasicJsonType>
ferencd@0 2835 void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
ferencd@0 2836 {
ferencd@0 2837 if (JSON_HEDLEY_UNLIKELY(not j.is_boolean()))
ferencd@0 2838 {
ferencd@0 2839 JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name())));
ferencd@0 2840 }
ferencd@0 2841 b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
ferencd@0 2842 }
ferencd@0 2843
ferencd@0 2844 template<typename BasicJsonType>
ferencd@0 2845 void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
ferencd@0 2846 {
ferencd@0 2847 if (JSON_HEDLEY_UNLIKELY(not j.is_string()))
ferencd@0 2848 {
ferencd@0 2849 JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
ferencd@0 2850 }
ferencd@0 2851 s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
ferencd@0 2852 }
ferencd@0 2853
ferencd@0 2854 template <
ferencd@0 2855 typename BasicJsonType, typename ConstructibleStringType,
ferencd@0 2856 enable_if_t <
ferencd@0 2857 is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value and
ferencd@0 2858 not std::is_same<typename BasicJsonType::string_t,
ferencd@0 2859 ConstructibleStringType>::value,
ferencd@0 2860 int > = 0 >
ferencd@0 2861 void from_json(const BasicJsonType& j, ConstructibleStringType& s)
ferencd@0 2862 {
ferencd@0 2863 if (JSON_HEDLEY_UNLIKELY(not j.is_string()))
ferencd@0 2864 {
ferencd@0 2865 JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
ferencd@0 2866 }
ferencd@0 2867
ferencd@0 2868 s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
ferencd@0 2869 }
ferencd@0 2870
ferencd@0 2871 template<typename BasicJsonType>
ferencd@0 2872 void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
ferencd@0 2873 {
ferencd@0 2874 get_arithmetic_value(j, val);
ferencd@0 2875 }
ferencd@0 2876
ferencd@0 2877 template<typename BasicJsonType>
ferencd@0 2878 void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
ferencd@0 2879 {
ferencd@0 2880 get_arithmetic_value(j, val);
ferencd@0 2881 }
ferencd@0 2882
ferencd@0 2883 template<typename BasicJsonType>
ferencd@0 2884 void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
ferencd@0 2885 {
ferencd@0 2886 get_arithmetic_value(j, val);
ferencd@0 2887 }
ferencd@0 2888
ferencd@0 2889 template<typename BasicJsonType, typename EnumType,
ferencd@0 2890 enable_if_t<std::is_enum<EnumType>::value, int> = 0>
ferencd@0 2891 void from_json(const BasicJsonType& j, EnumType& e)
ferencd@0 2892 {
ferencd@0 2893 typename std::underlying_type<EnumType>::type val;
ferencd@0 2894 get_arithmetic_value(j, val);
ferencd@0 2895 e = static_cast<EnumType>(val);
ferencd@0 2896 }
ferencd@0 2897
ferencd@0 2898 // forward_list doesn't have an insert method
ferencd@0 2899 template<typename BasicJsonType, typename T, typename Allocator,
ferencd@0 2900 enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
ferencd@0 2901 void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
ferencd@0 2902 {
ferencd@0 2903 if (JSON_HEDLEY_UNLIKELY(not j.is_array()))
ferencd@0 2904 {
ferencd@0 2905 JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
ferencd@0 2906 }
ferencd@0 2907 l.clear();
ferencd@0 2908 std::transform(j.rbegin(), j.rend(),
ferencd@0 2909 std::front_inserter(l), [](const BasicJsonType & i)
ferencd@0 2910 {
ferencd@0 2911 return i.template get<T>();
ferencd@0 2912 });
ferencd@0 2913 }
ferencd@0 2914
ferencd@0 2915 // valarray doesn't have an insert method
ferencd@0 2916 template<typename BasicJsonType, typename T,
ferencd@0 2917 enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
ferencd@0 2918 void from_json(const BasicJsonType& j, std::valarray<T>& l)
ferencd@0 2919 {
ferencd@0 2920 if (JSON_HEDLEY_UNLIKELY(not j.is_array()))
ferencd@0 2921 {
ferencd@0 2922 JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
ferencd@0 2923 }
ferencd@0 2924 l.resize(j.size());
ferencd@0 2925 std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l));
ferencd@0 2926 }
ferencd@0 2927
ferencd@0 2928 template <typename BasicJsonType, typename T, std::size_t N>
ferencd@0 2929 auto from_json(const BasicJsonType& j, T (&arr)[N])
ferencd@0 2930 -> decltype(j.template get<T>(), void())
ferencd@0 2931 {
ferencd@0 2932 for (std::size_t i = 0; i < N; ++i)
ferencd@0 2933 {
ferencd@0 2934 arr[i] = j.at(i).template get<T>();
ferencd@0 2935 }
ferencd@0 2936 }
ferencd@0 2937
ferencd@0 2938 template<typename BasicJsonType>
ferencd@0 2939 void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
ferencd@0 2940 {
ferencd@0 2941 arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
ferencd@0 2942 }
ferencd@0 2943
ferencd@0 2944 template <typename BasicJsonType, typename T, std::size_t N>
ferencd@0 2945 auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
ferencd@0 2946 priority_tag<2> /*unused*/)
ferencd@0 2947 -> decltype(j.template get<T>(), void())
ferencd@0 2948 {
ferencd@0 2949 for (std::size_t i = 0; i < N; ++i)
ferencd@0 2950 {
ferencd@0 2951 arr[i] = j.at(i).template get<T>();
ferencd@0 2952 }
ferencd@0 2953 }
ferencd@0 2954
ferencd@0 2955 template<typename BasicJsonType, typename ConstructibleArrayType>
ferencd@0 2956 auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
ferencd@0 2957 -> decltype(
ferencd@0 2958 arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),
ferencd@0 2959 j.template get<typename ConstructibleArrayType::value_type>(),
ferencd@0 2960 void())
ferencd@0 2961 {
ferencd@0 2962 using std::end;
ferencd@0 2963
ferencd@0 2964 ConstructibleArrayType ret;
ferencd@0 2965 ret.reserve(j.size());
ferencd@0 2966 std::transform(j.begin(), j.end(),
ferencd@0 2967 std::inserter(ret, end(ret)), [](const BasicJsonType & i)
ferencd@0 2968 {
ferencd@0 2969 // get<BasicJsonType>() returns *this, this won't call a from_json
ferencd@0 2970 // method when value_type is BasicJsonType
ferencd@0 2971 return i.template get<typename ConstructibleArrayType::value_type>();
ferencd@0 2972 });
ferencd@0 2973 arr = std::move(ret);
ferencd@0 2974 }
ferencd@0 2975
ferencd@0 2976 template <typename BasicJsonType, typename ConstructibleArrayType>
ferencd@0 2977 void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
ferencd@0 2978 priority_tag<0> /*unused*/)
ferencd@0 2979 {
ferencd@0 2980 using std::end;
ferencd@0 2981
ferencd@0 2982 ConstructibleArrayType ret;
ferencd@0 2983 std::transform(
ferencd@0 2984 j.begin(), j.end(), std::inserter(ret, end(ret)),
ferencd@0 2985 [](const BasicJsonType & i)
ferencd@0 2986 {
ferencd@0 2987 // get<BasicJsonType>() returns *this, this won't call a from_json
ferencd@0 2988 // method when value_type is BasicJsonType
ferencd@0 2989 return i.template get<typename ConstructibleArrayType::value_type>();
ferencd@0 2990 });
ferencd@0 2991 arr = std::move(ret);
ferencd@0 2992 }
ferencd@0 2993
ferencd@0 2994 template <typename BasicJsonType, typename ConstructibleArrayType,
ferencd@0 2995 enable_if_t <
ferencd@0 2996 is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value and
ferencd@0 2997 not is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value and
ferencd@0 2998 not is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value and
ferencd@0 2999 not is_basic_json<ConstructibleArrayType>::value,
ferencd@0 3000 int > = 0 >
ferencd@0 3001
ferencd@0 3002 auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
ferencd@0 3003 -> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
ferencd@0 3004 j.template get<typename ConstructibleArrayType::value_type>(),
ferencd@0 3005 void())
ferencd@0 3006 {
ferencd@0 3007 if (JSON_HEDLEY_UNLIKELY(not j.is_array()))
ferencd@0 3008 {
ferencd@0 3009 JSON_THROW(type_error::create(302, "type must be array, but is " +
ferencd@0 3010 std::string(j.type_name())));
ferencd@0 3011 }
ferencd@0 3012
ferencd@0 3013 from_json_array_impl(j, arr, priority_tag<3> {});
ferencd@0 3014 }
ferencd@0 3015
ferencd@0 3016 template<typename BasicJsonType, typename ConstructibleObjectType,
ferencd@0 3017 enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
ferencd@0 3018 void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
ferencd@0 3019 {
ferencd@0 3020 if (JSON_HEDLEY_UNLIKELY(not j.is_object()))
ferencd@0 3021 {
ferencd@0 3022 JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name())));
ferencd@0 3023 }
ferencd@0 3024
ferencd@0 3025 ConstructibleObjectType ret;
ferencd@0 3026 auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
ferencd@0 3027 using value_type = typename ConstructibleObjectType::value_type;
ferencd@0 3028 std::transform(
ferencd@0 3029 inner_object->begin(), inner_object->end(),
ferencd@0 3030 std::inserter(ret, ret.begin()),
ferencd@0 3031 [](typename BasicJsonType::object_t::value_type const & p)
ferencd@0 3032 {
ferencd@0 3033 return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());
ferencd@0 3034 });
ferencd@0 3035 obj = std::move(ret);
ferencd@0 3036 }
ferencd@0 3037
ferencd@0 3038 // overload for arithmetic types, not chosen for basic_json template arguments
ferencd@0 3039 // (BooleanType, etc..); note: Is it really necessary to provide explicit
ferencd@0 3040 // overloads for boolean_t etc. in case of a custom BooleanType which is not
ferencd@0 3041 // an arithmetic type?
ferencd@0 3042 template<typename BasicJsonType, typename ArithmeticType,
ferencd@0 3043 enable_if_t <
ferencd@0 3044 std::is_arithmetic<ArithmeticType>::value and
ferencd@0 3045 not std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value and
ferencd@0 3046 not std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value and
ferencd@0 3047 not std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value and
ferencd@0 3048 not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
ferencd@0 3049 int> = 0>
ferencd@0 3050 void from_json(const BasicJsonType& j, ArithmeticType& val)
ferencd@0 3051 {
ferencd@0 3052 switch (static_cast<value_t>(j))
ferencd@0 3053 {
ferencd@0 3054 case value_t::number_unsigned:
ferencd@0 3055 {
ferencd@0 3056 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
ferencd@0 3057 break;
ferencd@0 3058 }
ferencd@0 3059 case value_t::number_integer:
ferencd@0 3060 {
ferencd@0 3061 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
ferencd@0 3062 break;
ferencd@0 3063 }
ferencd@0 3064 case value_t::number_float:
ferencd@0 3065 {
ferencd@0 3066 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
ferencd@0 3067 break;
ferencd@0 3068 }
ferencd@0 3069 case value_t::boolean:
ferencd@0 3070 {
ferencd@0 3071 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
ferencd@0 3072 break;
ferencd@0 3073 }
ferencd@0 3074
ferencd@0 3075 default:
ferencd@0 3076 JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name())));
ferencd@0 3077 }
ferencd@0 3078 }
ferencd@0 3079
ferencd@0 3080 template<typename BasicJsonType, typename A1, typename A2>
ferencd@0 3081 void from_json(const BasicJsonType& j, std::pair<A1, A2>& p)
ferencd@0 3082 {
ferencd@0 3083 p = {j.at(0).template get<A1>(), j.at(1).template get<A2>()};
ferencd@0 3084 }
ferencd@0 3085
ferencd@0 3086 template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
ferencd@0 3087 void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...> /*unused*/)
ferencd@0 3088 {
ferencd@0 3089 t = std::make_tuple(j.at(Idx).template get<typename std::tuple_element<Idx, Tuple>::type>()...);
ferencd@0 3090 }
ferencd@0 3091
ferencd@0 3092 template<typename BasicJsonType, typename... Args>
ferencd@0 3093 void from_json(const BasicJsonType& j, std::tuple<Args...>& t)
ferencd@0 3094 {
ferencd@0 3095 from_json_tuple_impl(j, t, index_sequence_for<Args...> {});
ferencd@0 3096 }
ferencd@0 3097
ferencd@0 3098 template <typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
ferencd@0 3099 typename = enable_if_t<not std::is_constructible<
ferencd@0 3100 typename BasicJsonType::string_t, Key>::value>>
ferencd@0 3101 void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
ferencd@0 3102 {
ferencd@0 3103 if (JSON_HEDLEY_UNLIKELY(not j.is_array()))
ferencd@0 3104 {
ferencd@0 3105 JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
ferencd@0 3106 }
ferencd@0 3107 m.clear();
ferencd@0 3108 for (const auto& p : j)
ferencd@0 3109 {
ferencd@0 3110 if (JSON_HEDLEY_UNLIKELY(not p.is_array()))
ferencd@0 3111 {
ferencd@0 3112 JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
ferencd@0 3113 }
ferencd@0 3114 m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
ferencd@0 3115 }
ferencd@0 3116 }
ferencd@0 3117
ferencd@0 3118 template <typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
ferencd@0 3119 typename = enable_if_t<not std::is_constructible<
ferencd@0 3120 typename BasicJsonType::string_t, Key>::value>>
ferencd@0 3121 void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
ferencd@0 3122 {
ferencd@0 3123 if (JSON_HEDLEY_UNLIKELY(not j.is_array()))
ferencd@0 3124 {
ferencd@0 3125 JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
ferencd@0 3126 }
ferencd@0 3127 m.clear();
ferencd@0 3128 for (const auto& p : j)
ferencd@0 3129 {
ferencd@0 3130 if (JSON_HEDLEY_UNLIKELY(not p.is_array()))
ferencd@0 3131 {
ferencd@0 3132 JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
ferencd@0 3133 }
ferencd@0 3134 m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
ferencd@0 3135 }
ferencd@0 3136 }
ferencd@0 3137
ferencd@0 3138 struct from_json_fn
ferencd@0 3139 {
ferencd@0 3140 template<typename BasicJsonType, typename T>
ferencd@0 3141 auto operator()(const BasicJsonType& j, T& val) const
ferencd@0 3142 noexcept(noexcept(from_json(j, val)))
ferencd@0 3143 -> decltype(from_json(j, val), void())
ferencd@0 3144 {
ferencd@0 3145 return from_json(j, val);
ferencd@0 3146 }
ferencd@0 3147 };
ferencd@0 3148 } // namespace detail
ferencd@0 3149
ferencd@0 3150 /// namespace to hold default `from_json` function
ferencd@0 3151 /// to see why this is required:
ferencd@0 3152 /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
ferencd@0 3153 namespace
ferencd@0 3154 {
ferencd@0 3155 constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;
ferencd@0 3156 } // namespace
ferencd@0 3157 } // namespace nlohmann
ferencd@0 3158
ferencd@0 3159 // #include <nlohmann/detail/conversions/to_json.hpp>
ferencd@0 3160
ferencd@0 3161
ferencd@0 3162 #include <algorithm> // copy
ferencd@0 3163 #include <ciso646> // or, and, not
ferencd@0 3164 #include <iterator> // begin, end
ferencd@0 3165 #include <string> // string
ferencd@0 3166 #include <tuple> // tuple, get
ferencd@0 3167 #include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
ferencd@0 3168 #include <utility> // move, forward, declval, pair
ferencd@0 3169 #include <valarray> // valarray
ferencd@0 3170 #include <vector> // vector
ferencd@0 3171
ferencd@0 3172 // #include <nlohmann/detail/iterators/iteration_proxy.hpp>
ferencd@0 3173
ferencd@0 3174
ferencd@0 3175 #include <cstddef> // size_t
ferencd@0 3176 #include <iterator> // input_iterator_tag
ferencd@0 3177 #include <string> // string, to_string
ferencd@0 3178 #include <tuple> // tuple_size, get, tuple_element
ferencd@0 3179
ferencd@0 3180 // #include <nlohmann/detail/meta/type_traits.hpp>
ferencd@0 3181
ferencd@0 3182 // #include <nlohmann/detail/value_t.hpp>
ferencd@0 3183
ferencd@0 3184
ferencd@0 3185 namespace nlohmann
ferencd@0 3186 {
ferencd@0 3187 namespace detail
ferencd@0 3188 {
ferencd@0 3189 template <typename IteratorType> class iteration_proxy_value
ferencd@0 3190 {
ferencd@0 3191 public:
ferencd@0 3192 using difference_type = std::ptrdiff_t;
ferencd@0 3193 using value_type = iteration_proxy_value;
ferencd@0 3194 using pointer = value_type * ;
ferencd@0 3195 using reference = value_type & ;
ferencd@0 3196 using iterator_category = std::input_iterator_tag;
ferencd@0 3197
ferencd@0 3198 private:
ferencd@0 3199 /// the iterator
ferencd@0 3200 IteratorType anchor;
ferencd@0 3201 /// an index for arrays (used to create key names)
ferencd@0 3202 std::size_t array_index = 0;
ferencd@0 3203 /// last stringified array index
ferencd@0 3204 mutable std::size_t array_index_last = 0;
ferencd@0 3205 /// a string representation of the array index
ferencd@0 3206 mutable std::string array_index_str = "0";
ferencd@0 3207 /// an empty string (to return a reference for primitive values)
ferencd@0 3208 const std::string empty_str = "";
ferencd@0 3209
ferencd@0 3210 public:
ferencd@0 3211 explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {}
ferencd@0 3212
ferencd@0 3213 /// dereference operator (needed for range-based for)
ferencd@0 3214 iteration_proxy_value& operator*()
ferencd@0 3215 {
ferencd@0 3216 return *this;
ferencd@0 3217 }
ferencd@0 3218
ferencd@0 3219 /// increment operator (needed for range-based for)
ferencd@0 3220 iteration_proxy_value& operator++()
ferencd@0 3221 {
ferencd@0 3222 ++anchor;
ferencd@0 3223 ++array_index;
ferencd@0 3224
ferencd@0 3225 return *this;
ferencd@0 3226 }
ferencd@0 3227
ferencd@0 3228 /// equality operator (needed for InputIterator)
ferencd@0 3229 bool operator==(const iteration_proxy_value& o) const
ferencd@0 3230 {
ferencd@0 3231 return anchor == o.anchor;
ferencd@0 3232 }
ferencd@0 3233
ferencd@0 3234 /// inequality operator (needed for range-based for)
ferencd@0 3235 bool operator!=(const iteration_proxy_value& o) const
ferencd@0 3236 {
ferencd@0 3237 return anchor != o.anchor;
ferencd@0 3238 }
ferencd@0 3239
ferencd@0 3240 /// return key of the iterator
ferencd@0 3241 const std::string& key() const
ferencd@0 3242 {
ferencd@0 3243 assert(anchor.m_object != nullptr);
ferencd@0 3244
ferencd@0 3245 switch (anchor.m_object->type())
ferencd@0 3246 {
ferencd@0 3247 // use integer array index as key
ferencd@0 3248 case value_t::array:
ferencd@0 3249 {
ferencd@0 3250 if (array_index != array_index_last)
ferencd@0 3251 {
ferencd@0 3252 array_index_str = std::to_string(array_index);
ferencd@0 3253 array_index_last = array_index;
ferencd@0 3254 }
ferencd@0 3255 return array_index_str;
ferencd@0 3256 }
ferencd@0 3257
ferencd@0 3258 // use key from the object
ferencd@0 3259 case value_t::object:
ferencd@0 3260 return anchor.key();
ferencd@0 3261
ferencd@0 3262 // use an empty key for all primitive types
ferencd@0 3263 default:
ferencd@0 3264 return empty_str;
ferencd@0 3265 }
ferencd@0 3266 }
ferencd@0 3267
ferencd@0 3268 /// return value of the iterator
ferencd@0 3269 typename IteratorType::reference value() const
ferencd@0 3270 {
ferencd@0 3271 return anchor.value();
ferencd@0 3272 }
ferencd@0 3273 };
ferencd@0 3274
ferencd@0 3275 /// proxy class for the items() function
ferencd@0 3276 template<typename IteratorType> class iteration_proxy
ferencd@0 3277 {
ferencd@0 3278 private:
ferencd@0 3279 /// the container to iterate
ferencd@0 3280 typename IteratorType::reference container;
ferencd@0 3281
ferencd@0 3282 public:
ferencd@0 3283 /// construct iteration proxy from a container
ferencd@0 3284 explicit iteration_proxy(typename IteratorType::reference cont) noexcept
ferencd@0 3285 : container(cont) {}
ferencd@0 3286
ferencd@0 3287 /// return iterator begin (needed for range-based for)
ferencd@0 3288 iteration_proxy_value<IteratorType> begin() noexcept
ferencd@0 3289 {
ferencd@0 3290 return iteration_proxy_value<IteratorType>(container.begin());
ferencd@0 3291 }
ferencd@0 3292
ferencd@0 3293 /// return iterator end (needed for range-based for)
ferencd@0 3294 iteration_proxy_value<IteratorType> end() noexcept
ferencd@0 3295 {
ferencd@0 3296 return iteration_proxy_value<IteratorType>(container.end());
ferencd@0 3297 }
ferencd@0 3298 };
ferencd@0 3299 // Structured Bindings Support
ferencd@0 3300 // For further reference see https://blog.tartanllama.xyz/structured-bindings/
ferencd@0 3301 // And see https://github.com/nlohmann/json/pull/1391
ferencd@0 3302 template <std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
ferencd@0 3303 auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())
ferencd@0 3304 {
ferencd@0 3305 return i.key();
ferencd@0 3306 }
ferencd@0 3307 // Structured Bindings Support
ferencd@0 3308 // For further reference see https://blog.tartanllama.xyz/structured-bindings/
ferencd@0 3309 // And see https://github.com/nlohmann/json/pull/1391
ferencd@0 3310 template <std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
ferencd@0 3311 auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())
ferencd@0 3312 {
ferencd@0 3313 return i.value();
ferencd@0 3314 }
ferencd@0 3315 } // namespace detail
ferencd@0 3316 } // namespace nlohmann
ferencd@0 3317
ferencd@0 3318 // The Addition to the STD Namespace is required to add
ferencd@0 3319 // Structured Bindings Support to the iteration_proxy_value class
ferencd@0 3320 // For further reference see https://blog.tartanllama.xyz/structured-bindings/
ferencd@0 3321 // And see https://github.com/nlohmann/json/pull/1391
ferencd@0 3322 namespace std
ferencd@0 3323 {
ferencd@0 3324 #if defined(__clang__)
ferencd@0 3325 // Fix: https://github.com/nlohmann/json/issues/1401
ferencd@0 3326 #pragma clang diagnostic push
ferencd@0 3327 #pragma clang diagnostic ignored "-Wmismatched-tags"
ferencd@0 3328 #endif
ferencd@0 3329 template <typename IteratorType>
ferencd@0 3330 class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>
ferencd@0 3331 : public std::integral_constant<std::size_t, 2> {};
ferencd@0 3332
ferencd@0 3333 template <std::size_t N, typename IteratorType>
ferencd@0 3334 class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
ferencd@0 3335 {
ferencd@0 3336 public:
ferencd@0 3337 using type = decltype(
ferencd@0 3338 get<N>(std::declval <
ferencd@0 3339 ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
ferencd@0 3340 };
ferencd@0 3341 #if defined(__clang__)
ferencd@0 3342 #pragma clang diagnostic pop
ferencd@0 3343 #endif
ferencd@0 3344 } // namespace std
ferencd@0 3345
ferencd@0 3346 // #include <nlohmann/detail/meta/cpp_future.hpp>
ferencd@0 3347
ferencd@0 3348 // #include <nlohmann/detail/meta/type_traits.hpp>
ferencd@0 3349
ferencd@0 3350 // #include <nlohmann/detail/value_t.hpp>
ferencd@0 3351
ferencd@0 3352
ferencd@0 3353 namespace nlohmann
ferencd@0 3354 {
ferencd@0 3355 namespace detail
ferencd@0 3356 {
ferencd@0 3357 //////////////////
ferencd@0 3358 // constructors //
ferencd@0 3359 //////////////////
ferencd@0 3360
ferencd@0 3361 template<value_t> struct external_constructor;
ferencd@0 3362
ferencd@0 3363 template<>
ferencd@0 3364 struct external_constructor<value_t::boolean>
ferencd@0 3365 {
ferencd@0 3366 template<typename BasicJsonType>
ferencd@0 3367 static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
ferencd@0 3368 {
ferencd@0 3369 j.m_type = value_t::boolean;
ferencd@0 3370 j.m_value = b;
ferencd@0 3371 j.assert_invariant();
ferencd@0 3372 }
ferencd@0 3373 };
ferencd@0 3374
ferencd@0 3375 template<>
ferencd@0 3376 struct external_constructor<value_t::string>
ferencd@0 3377 {
ferencd@0 3378 template<typename BasicJsonType>
ferencd@0 3379 static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
ferencd@0 3380 {
ferencd@0 3381 j.m_type = value_t::string;
ferencd@0 3382 j.m_value = s;
ferencd@0 3383 j.assert_invariant();
ferencd@0 3384 }
ferencd@0 3385
ferencd@0 3386 template<typename BasicJsonType>
ferencd@0 3387 static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
ferencd@0 3388 {
ferencd@0 3389 j.m_type = value_t::string;
ferencd@0 3390 j.m_value = std::move(s);
ferencd@0 3391 j.assert_invariant();
ferencd@0 3392 }
ferencd@0 3393
ferencd@0 3394 template<typename BasicJsonType, typename CompatibleStringType,
ferencd@0 3395 enable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
ferencd@0 3396 int> = 0>
ferencd@0 3397 static void construct(BasicJsonType& j, const CompatibleStringType& str)
ferencd@0 3398 {
ferencd@0 3399 j.m_type = value_t::string;
ferencd@0 3400 j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
ferencd@0 3401 j.assert_invariant();
ferencd@0 3402 }
ferencd@0 3403 };
ferencd@0 3404
ferencd@0 3405 template<>
ferencd@0 3406 struct external_constructor<value_t::number_float>
ferencd@0 3407 {
ferencd@0 3408 template<typename BasicJsonType>
ferencd@0 3409 static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
ferencd@0 3410 {
ferencd@0 3411 j.m_type = value_t::number_float;
ferencd@0 3412 j.m_value = val;
ferencd@0 3413 j.assert_invariant();
ferencd@0 3414 }
ferencd@0 3415 };
ferencd@0 3416
ferencd@0 3417 template<>
ferencd@0 3418 struct external_constructor<value_t::number_unsigned>
ferencd@0 3419 {
ferencd@0 3420 template<typename BasicJsonType>
ferencd@0 3421 static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
ferencd@0 3422 {
ferencd@0 3423 j.m_type = value_t::number_unsigned;
ferencd@0 3424 j.m_value = val;
ferencd@0 3425 j.assert_invariant();
ferencd@0 3426 }
ferencd@0 3427 };
ferencd@0 3428
ferencd@0 3429 template<>
ferencd@0 3430 struct external_constructor<value_t::number_integer>
ferencd@0 3431 {
ferencd@0 3432 template<typename BasicJsonType>
ferencd@0 3433 static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
ferencd@0 3434 {
ferencd@0 3435 j.m_type = value_t::number_integer;
ferencd@0 3436 j.m_value = val;
ferencd@0 3437 j.assert_invariant();
ferencd@0 3438 }
ferencd@0 3439 };
ferencd@0 3440
ferencd@0 3441 template<>
ferencd@0 3442 struct external_constructor<value_t::array>
ferencd@0 3443 {
ferencd@0 3444 template<typename BasicJsonType>
ferencd@0 3445 static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
ferencd@0 3446 {
ferencd@0 3447 j.m_type = value_t::array;
ferencd@0 3448 j.m_value = arr;
ferencd@0 3449 j.assert_invariant();
ferencd@0 3450 }
ferencd@0 3451
ferencd@0 3452 template<typename BasicJsonType>
ferencd@0 3453 static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
ferencd@0 3454 {
ferencd@0 3455 j.m_type = value_t::array;
ferencd@0 3456 j.m_value = std::move(arr);
ferencd@0 3457 j.assert_invariant();
ferencd@0 3458 }
ferencd@0 3459
ferencd@0 3460 template<typename BasicJsonType, typename CompatibleArrayType,
ferencd@0 3461 enable_if_t<not std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
ferencd@0 3462 int> = 0>
ferencd@0 3463 static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
ferencd@0 3464 {
ferencd@0 3465 using std::begin;
ferencd@0 3466 using std::end;
ferencd@0 3467 j.m_type = value_t::array;
ferencd@0 3468 j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
ferencd@0 3469 j.assert_invariant();
ferencd@0 3470 }
ferencd@0 3471
ferencd@0 3472 template<typename BasicJsonType>
ferencd@0 3473 static void construct(BasicJsonType& j, const std::vector<bool>& arr)
ferencd@0 3474 {
ferencd@0 3475 j.m_type = value_t::array;
ferencd@0 3476 j.m_value = value_t::array;
ferencd@0 3477 j.m_value.array->reserve(arr.size());
ferencd@0 3478 for (const bool x : arr)
ferencd@0 3479 {
ferencd@0 3480 j.m_value.array->push_back(x);
ferencd@0 3481 }
ferencd@0 3482 j.assert_invariant();
ferencd@0 3483 }
ferencd@0 3484
ferencd@0 3485 template<typename BasicJsonType, typename T,
ferencd@0 3486 enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
ferencd@0 3487 static void construct(BasicJsonType& j, const std::valarray<T>& arr)
ferencd@0 3488 {
ferencd@0 3489 j.m_type = value_t::array;
ferencd@0 3490 j.m_value = value_t::array;
ferencd@0 3491 j.m_value.array->resize(arr.size());
ferencd@0 3492 std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());
ferencd@0 3493 j.assert_invariant();
ferencd@0 3494 }
ferencd@0 3495 };
ferencd@0 3496
ferencd@0 3497 template<>
ferencd@0 3498 struct external_constructor<value_t::object>
ferencd@0 3499 {
ferencd@0 3500 template<typename BasicJsonType>
ferencd@0 3501 static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
ferencd@0 3502 {
ferencd@0 3503 j.m_type = value_t::object;
ferencd@0 3504 j.m_value = obj;
ferencd@0 3505 j.assert_invariant();
ferencd@0 3506 }
ferencd@0 3507
ferencd@0 3508 template<typename BasicJsonType>
ferencd@0 3509 static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
ferencd@0 3510 {
ferencd@0 3511 j.m_type = value_t::object;
ferencd@0 3512 j.m_value = std::move(obj);
ferencd@0 3513 j.assert_invariant();
ferencd@0 3514 }
ferencd@0 3515
ferencd@0 3516 template<typename BasicJsonType, typename CompatibleObjectType,
ferencd@0 3517 enable_if_t<not std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int> = 0>
ferencd@0 3518 static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
ferencd@0 3519 {
ferencd@0 3520 using std::begin;
ferencd@0 3521 using std::end;
ferencd@0 3522
ferencd@0 3523 j.m_type = value_t::object;
ferencd@0 3524 j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
ferencd@0 3525 j.assert_invariant();
ferencd@0 3526 }
ferencd@0 3527 };
ferencd@0 3528
ferencd@0 3529 /////////////
ferencd@0 3530 // to_json //
ferencd@0 3531 /////////////
ferencd@0 3532
ferencd@0 3533 template<typename BasicJsonType, typename T,
ferencd@0 3534 enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>
ferencd@0 3535 void to_json(BasicJsonType& j, T b) noexcept
ferencd@0 3536 {
ferencd@0 3537 external_constructor<value_t::boolean>::construct(j, b);
ferencd@0 3538 }
ferencd@0 3539
ferencd@0 3540 template<typename BasicJsonType, typename CompatibleString,
ferencd@0 3541 enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>
ferencd@0 3542 void to_json(BasicJsonType& j, const CompatibleString& s)
ferencd@0 3543 {
ferencd@0 3544 external_constructor<value_t::string>::construct(j, s);
ferencd@0 3545 }
ferencd@0 3546
ferencd@0 3547 template<typename BasicJsonType>
ferencd@0 3548 void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)
ferencd@0 3549 {
ferencd@0 3550 external_constructor<value_t::string>::construct(j, std::move(s));
ferencd@0 3551 }
ferencd@0 3552
ferencd@0 3553 template<typename BasicJsonType, typename FloatType,
ferencd@0 3554 enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
ferencd@0 3555 void to_json(BasicJsonType& j, FloatType val) noexcept
ferencd@0 3556 {
ferencd@0 3557 external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
ferencd@0 3558 }
ferencd@0 3559
ferencd@0 3560 template<typename BasicJsonType, typename CompatibleNumberUnsignedType,
ferencd@0 3561 enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>
ferencd@0 3562 void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
ferencd@0 3563 {
ferencd@0 3564 external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
ferencd@0 3565 }
ferencd@0 3566
ferencd@0 3567 template<typename BasicJsonType, typename CompatibleNumberIntegerType,
ferencd@0 3568 enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>
ferencd@0 3569 void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
ferencd@0 3570 {
ferencd@0 3571 external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
ferencd@0 3572 }
ferencd@0 3573
ferencd@0 3574 template<typename BasicJsonType, typename EnumType,
ferencd@0 3575 enable_if_t<std::is_enum<EnumType>::value, int> = 0>
ferencd@0 3576 void to_json(BasicJsonType& j, EnumType e) noexcept
ferencd@0 3577 {
ferencd@0 3578 using underlying_type = typename std::underlying_type<EnumType>::type;
ferencd@0 3579 external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));
ferencd@0 3580 }
ferencd@0 3581
ferencd@0 3582 template<typename BasicJsonType>
ferencd@0 3583 void to_json(BasicJsonType& j, const std::vector<bool>& e)
ferencd@0 3584 {
ferencd@0 3585 external_constructor<value_t::array>::construct(j, e);
ferencd@0 3586 }
ferencd@0 3587
ferencd@0 3588 template <typename BasicJsonType, typename CompatibleArrayType,
ferencd@0 3589 enable_if_t<is_compatible_array_type<BasicJsonType,
ferencd@0 3590 CompatibleArrayType>::value and
ferencd@0 3591 not is_compatible_object_type<
ferencd@0 3592 BasicJsonType, CompatibleArrayType>::value and
ferencd@0 3593 not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and
ferencd@0 3594 not is_basic_json<CompatibleArrayType>::value,
ferencd@0 3595 int> = 0>
ferencd@0 3596 void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
ferencd@0 3597 {
ferencd@0 3598 external_constructor<value_t::array>::construct(j, arr);
ferencd@0 3599 }
ferencd@0 3600
ferencd@0 3601 template<typename BasicJsonType, typename T,
ferencd@0 3602 enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
ferencd@0 3603 void to_json(BasicJsonType& j, const std::valarray<T>& arr)
ferencd@0 3604 {
ferencd@0 3605 external_constructor<value_t::array>::construct(j, std::move(arr));
ferencd@0 3606 }
ferencd@0 3607
ferencd@0 3608 template<typename BasicJsonType>
ferencd@0 3609 void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
ferencd@0 3610 {
ferencd@0 3611 external_constructor<value_t::array>::construct(j, std::move(arr));
ferencd@0 3612 }
ferencd@0 3613
ferencd@0 3614 template<typename BasicJsonType, typename CompatibleObjectType,
ferencd@0 3615 enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0>
ferencd@0 3616 void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
ferencd@0 3617 {
ferencd@0 3618 external_constructor<value_t::object>::construct(j, obj);
ferencd@0 3619 }
ferencd@0 3620
ferencd@0 3621 template<typename BasicJsonType>
ferencd@0 3622 void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
ferencd@0 3623 {
ferencd@0 3624 external_constructor<value_t::object>::construct(j, std::move(obj));
ferencd@0 3625 }
ferencd@0 3626
ferencd@0 3627 template <
ferencd@0 3628 typename BasicJsonType, typename T, std::size_t N,
ferencd@0 3629 enable_if_t<not std::is_constructible<typename BasicJsonType::string_t,
ferencd@0 3630 const T(&)[N]>::value,
ferencd@0 3631 int> = 0 >
ferencd@0 3632 void to_json(BasicJsonType& j, const T(&arr)[N])
ferencd@0 3633 {
ferencd@0 3634 external_constructor<value_t::array>::construct(j, arr);
ferencd@0 3635 }
ferencd@0 3636
ferencd@0 3637 template<typename BasicJsonType, typename... Args>
ferencd@0 3638 void to_json(BasicJsonType& j, const std::pair<Args...>& p)
ferencd@0 3639 {
ferencd@0 3640 j = { p.first, p.second };
ferencd@0 3641 }
ferencd@0 3642
ferencd@0 3643 // for https://github.com/nlohmann/json/pull/1134
ferencd@0 3644 template < typename BasicJsonType, typename T,
ferencd@0 3645 enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
ferencd@0 3646 void to_json(BasicJsonType& j, const T& b)
ferencd@0 3647 {
ferencd@0 3648 j = { {b.key(), b.value()} };
ferencd@0 3649 }
ferencd@0 3650
ferencd@0 3651 template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
ferencd@0 3652 void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)
ferencd@0 3653 {
ferencd@0 3654 j = { std::get<Idx>(t)... };
ferencd@0 3655 }
ferencd@0 3656
ferencd@0 3657 template<typename BasicJsonType, typename... Args>
ferencd@0 3658 void to_json(BasicJsonType& j, const std::tuple<Args...>& t)
ferencd@0 3659 {
ferencd@0 3660 to_json_tuple_impl(j, t, index_sequence_for<Args...> {});
ferencd@0 3661 }
ferencd@0 3662
ferencd@0 3663 struct to_json_fn
ferencd@0 3664 {
ferencd@0 3665 template<typename BasicJsonType, typename T>
ferencd@0 3666 auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
ferencd@0 3667 -> decltype(to_json(j, std::forward<T>(val)), void())
ferencd@0 3668 {
ferencd@0 3669 return to_json(j, std::forward<T>(val));
ferencd@0 3670 }
ferencd@0 3671 };
ferencd@0 3672 } // namespace detail
ferencd@0 3673
ferencd@0 3674 /// namespace to hold default `to_json` function
ferencd@0 3675 namespace
ferencd@0 3676 {
ferencd@0 3677 constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;
ferencd@0 3678 } // namespace
ferencd@0 3679 } // namespace nlohmann
ferencd@0 3680
ferencd@0 3681
ferencd@0 3682 namespace nlohmann
ferencd@0 3683 {
ferencd@0 3684
ferencd@0 3685 template<typename, typename>
ferencd@0 3686 struct adl_serializer
ferencd@0 3687 {
ferencd@0 3688 /*!
ferencd@0 3689 @brief convert a JSON value to any value type
ferencd@0 3690
ferencd@0 3691 This function is usually called by the `get()` function of the
ferencd@0 3692 @ref basic_json class (either explicit or via conversion operators).
ferencd@0 3693
ferencd@0 3694 @param[in] j JSON value to read from
ferencd@0 3695 @param[in,out] val value to write to
ferencd@0 3696 */
ferencd@0 3697 template<typename BasicJsonType, typename ValueType>
ferencd@0 3698 static auto from_json(BasicJsonType&& j, ValueType& val) noexcept(
ferencd@0 3699 noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))
ferencd@0 3700 -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void())
ferencd@0 3701 {
ferencd@0 3702 ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
ferencd@0 3703 }
ferencd@0 3704
ferencd@0 3705 /*!
ferencd@0 3706 @brief convert any value type to a JSON value
ferencd@0 3707
ferencd@0 3708 This function is usually called by the constructors of the @ref basic_json
ferencd@0 3709 class.
ferencd@0 3710
ferencd@0 3711 @param[in,out] j JSON value to write to
ferencd@0 3712 @param[in] val value to read from
ferencd@0 3713 */
ferencd@0 3714 template <typename BasicJsonType, typename ValueType>
ferencd@0 3715 static auto to_json(BasicJsonType& j, ValueType&& val) noexcept(
ferencd@0 3716 noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val))))
ferencd@0 3717 -> decltype(::nlohmann::to_json(j, std::forward<ValueType>(val)), void())
ferencd@0 3718 {
ferencd@0 3719 ::nlohmann::to_json(j, std::forward<ValueType>(val));
ferencd@0 3720 }
ferencd@0 3721 };
ferencd@0 3722
ferencd@0 3723 } // namespace nlohmann
ferencd@0 3724
ferencd@0 3725 // #include <nlohmann/detail/conversions/from_json.hpp>
ferencd@0 3726
ferencd@0 3727 // #include <nlohmann/detail/conversions/to_json.hpp>
ferencd@0 3728
ferencd@0 3729 // #include <nlohmann/detail/exceptions.hpp>
ferencd@0 3730
ferencd@0 3731 // #include <nlohmann/detail/input/binary_reader.hpp>
ferencd@0 3732
ferencd@0 3733
ferencd@0 3734 #include <algorithm> // generate_n
ferencd@0 3735 #include <array> // array
ferencd@0 3736 #include <cassert> // assert
ferencd@0 3737 #include <cmath> // ldexp
ferencd@0 3738 #include <cstddef> // size_t
ferencd@0 3739 #include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
ferencd@0 3740 #include <cstdio> // snprintf
ferencd@0 3741 #include <cstring> // memcpy
ferencd@0 3742 #include <iterator> // back_inserter
ferencd@0 3743 #include <limits> // numeric_limits
ferencd@0 3744 #include <string> // char_traits, string
ferencd@0 3745 #include <utility> // make_pair, move
ferencd@0 3746
ferencd@0 3747 // #include <nlohmann/detail/exceptions.hpp>
ferencd@0 3748
ferencd@0 3749 // #include <nlohmann/detail/input/input_adapters.hpp>
ferencd@0 3750
ferencd@0 3751
ferencd@0 3752 #include <array> // array
ferencd@0 3753 #include <cassert> // assert
ferencd@0 3754 #include <cstddef> // size_t
ferencd@0 3755 #include <cstdio> //FILE *
ferencd@0 3756 #include <cstring> // strlen
ferencd@0 3757 #include <istream> // istream
ferencd@0 3758 #include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
ferencd@0 3759 #include <memory> // shared_ptr, make_shared, addressof
ferencd@0 3760 #include <numeric> // accumulate
ferencd@0 3761 #include <string> // string, char_traits
ferencd@0 3762 #include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
ferencd@0 3763 #include <utility> // pair, declval
ferencd@0 3764
ferencd@0 3765 // #include <nlohmann/detail/iterators/iterator_traits.hpp>
ferencd@0 3766
ferencd@0 3767 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 3768
ferencd@0 3769
ferencd@0 3770 namespace nlohmann
ferencd@0 3771 {
ferencd@0 3772 namespace detail
ferencd@0 3773 {
ferencd@0 3774 /// the supported input formats
ferencd@0 3775 enum class input_format_t { json, cbor, msgpack, ubjson, bson };
ferencd@0 3776
ferencd@0 3777 ////////////////////
ferencd@0 3778 // input adapters //
ferencd@0 3779 ////////////////////
ferencd@0 3780
ferencd@0 3781 /*!
ferencd@0 3782 @brief abstract input adapter interface
ferencd@0 3783
ferencd@0 3784 Produces a stream of std::char_traits<char>::int_type characters from a
ferencd@0 3785 std::istream, a buffer, or some other input type. Accepts the return of
ferencd@0 3786 exactly one non-EOF character for future input. The int_type characters
ferencd@0 3787 returned consist of all valid char values as positive values (typically
ferencd@0 3788 unsigned char), plus an EOF value outside that range, specified by the value
ferencd@0 3789 of the function std::char_traits<char>::eof(). This value is typically -1, but
ferencd@0 3790 could be any arbitrary value which is not a valid char value.
ferencd@0 3791 */
ferencd@0 3792 struct input_adapter_protocol
ferencd@0 3793 {
ferencd@0 3794 /// get a character [0,255] or std::char_traits<char>::eof().
ferencd@0 3795 virtual std::char_traits<char>::int_type get_character() = 0;
ferencd@0 3796 virtual ~input_adapter_protocol() = default;
ferencd@0 3797 };
ferencd@0 3798
ferencd@0 3799 /// a type to simplify interfaces
ferencd@0 3800 using input_adapter_t = std::shared_ptr<input_adapter_protocol>;
ferencd@0 3801
ferencd@0 3802 /*!
ferencd@0 3803 Input adapter for stdio file access. This adapter read only 1 byte and do not use any
ferencd@0 3804 buffer. This adapter is a very low level adapter.
ferencd@0 3805 */
ferencd@0 3806 class file_input_adapter : public input_adapter_protocol
ferencd@0 3807 {
ferencd@0 3808 public:
ferencd@0 3809 JSON_HEDLEY_NON_NULL(2)
ferencd@0 3810 explicit file_input_adapter(std::FILE* f) noexcept
ferencd@0 3811 : m_file(f)
ferencd@0 3812 {}
ferencd@0 3813
ferencd@0 3814 // make class move-only
ferencd@0 3815 file_input_adapter(const file_input_adapter&) = delete;
ferencd@0 3816 file_input_adapter(file_input_adapter&&) = default;
ferencd@0 3817 file_input_adapter& operator=(const file_input_adapter&) = delete;
ferencd@0 3818 file_input_adapter& operator=(file_input_adapter&&) = default;
ferencd@0 3819 ~file_input_adapter() override = default;
ferencd@0 3820
ferencd@0 3821 std::char_traits<char>::int_type get_character() noexcept override
ferencd@0 3822 {
ferencd@0 3823 return std::fgetc(m_file);
ferencd@0 3824 }
ferencd@0 3825
ferencd@0 3826 private:
ferencd@0 3827 /// the file pointer to read from
ferencd@0 3828 std::FILE* m_file;
ferencd@0 3829 };
ferencd@0 3830
ferencd@0 3831
ferencd@0 3832 /*!
ferencd@0 3833 Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at
ferencd@0 3834 beginning of input. Does not support changing the underlying std::streambuf
ferencd@0 3835 in mid-input. Maintains underlying std::istream and std::streambuf to support
ferencd@0 3836 subsequent use of standard std::istream operations to process any input
ferencd@0 3837 characters following those used in parsing the JSON input. Clears the
ferencd@0 3838 std::istream flags; any input errors (e.g., EOF) will be detected by the first
ferencd@0 3839 subsequent call for input from the std::istream.
ferencd@0 3840 */
ferencd@0 3841 class input_stream_adapter : public input_adapter_protocol
ferencd@0 3842 {
ferencd@0 3843 public:
ferencd@0 3844 ~input_stream_adapter() override
ferencd@0 3845 {
ferencd@0 3846 // clear stream flags; we use underlying streambuf I/O, do not
ferencd@0 3847 // maintain ifstream flags, except eof
ferencd@0 3848 is.clear(is.rdstate() & std::ios::eofbit);
ferencd@0 3849 }
ferencd@0 3850
ferencd@0 3851 explicit input_stream_adapter(std::istream& i)
ferencd@0 3852 : is(i), sb(*i.rdbuf())
ferencd@0 3853 {}
ferencd@0 3854
ferencd@0 3855 // delete because of pointer members
ferencd@0 3856 input_stream_adapter(const input_stream_adapter&) = delete;
ferencd@0 3857 input_stream_adapter& operator=(input_stream_adapter&) = delete;
ferencd@0 3858 input_stream_adapter(input_stream_adapter&&) = delete;
ferencd@0 3859 input_stream_adapter& operator=(input_stream_adapter&&) = delete;
ferencd@0 3860
ferencd@0 3861 // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
ferencd@0 3862 // ensure that std::char_traits<char>::eof() and the character 0xFF do not
ferencd@0 3863 // end up as the same value, eg. 0xFFFFFFFF.
ferencd@0 3864 std::char_traits<char>::int_type get_character() override
ferencd@0 3865 {
ferencd@0 3866 auto res = sb.sbumpc();
ferencd@0 3867 // set eof manually, as we don't use the istream interface.
ferencd@0 3868 if (res == EOF)
ferencd@0 3869 {
ferencd@0 3870 is.clear(is.rdstate() | std::ios::eofbit);
ferencd@0 3871 }
ferencd@0 3872 return res;
ferencd@0 3873 }
ferencd@0 3874
ferencd@0 3875 private:
ferencd@0 3876 /// the associated input stream
ferencd@0 3877 std::istream& is;
ferencd@0 3878 std::streambuf& sb;
ferencd@0 3879 };
ferencd@0 3880
ferencd@0 3881 /// input adapter for buffer input
ferencd@0 3882 class input_buffer_adapter : public input_adapter_protocol
ferencd@0 3883 {
ferencd@0 3884 public:
ferencd@0 3885 JSON_HEDLEY_NON_NULL(2)
ferencd@0 3886 input_buffer_adapter(const char* b, const std::size_t l) noexcept
ferencd@0 3887 : cursor(b), limit(b + l)
ferencd@0 3888 {}
ferencd@0 3889
ferencd@0 3890 // delete because of pointer members
ferencd@0 3891 input_buffer_adapter(const input_buffer_adapter&) = delete;
ferencd@0 3892 input_buffer_adapter& operator=(input_buffer_adapter&) = delete;
ferencd@0 3893 input_buffer_adapter(input_buffer_adapter&&) = delete;
ferencd@0 3894 input_buffer_adapter& operator=(input_buffer_adapter&&) = delete;
ferencd@0 3895 ~input_buffer_adapter() override = default;
ferencd@0 3896
ferencd@0 3897 std::char_traits<char>::int_type get_character() noexcept override
ferencd@0 3898 {
ferencd@0 3899 if (JSON_HEDLEY_LIKELY(cursor < limit))
ferencd@0 3900 {
ferencd@0 3901 return std::char_traits<char>::to_int_type(*(cursor++));
ferencd@0 3902 }
ferencd@0 3903
ferencd@0 3904 return std::char_traits<char>::eof();
ferencd@0 3905 }
ferencd@0 3906
ferencd@0 3907 private:
ferencd@0 3908 /// pointer to the current character
ferencd@0 3909 const char* cursor;
ferencd@0 3910 /// pointer past the last character
ferencd@0 3911 const char* const limit;
ferencd@0 3912 };
ferencd@0 3913
ferencd@0 3914 template<typename WideStringType, size_t T>
ferencd@0 3915 struct wide_string_input_helper
ferencd@0 3916 {
ferencd@0 3917 // UTF-32
ferencd@0 3918 static void fill_buffer(const WideStringType& str,
ferencd@0 3919 size_t& current_wchar,
ferencd@0 3920 std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
ferencd@0 3921 size_t& utf8_bytes_index,
ferencd@0 3922 size_t& utf8_bytes_filled)
ferencd@0 3923 {
ferencd@0 3924 utf8_bytes_index = 0;
ferencd@0 3925
ferencd@0 3926 if (current_wchar == str.size())
ferencd@0 3927 {
ferencd@0 3928 utf8_bytes[0] = std::char_traits<char>::eof();
ferencd@0 3929 utf8_bytes_filled = 1;
ferencd@0 3930 }
ferencd@0 3931 else
ferencd@0 3932 {
ferencd@0 3933 // get the current character
ferencd@0 3934 const auto wc = static_cast<unsigned int>(str[current_wchar++]);
ferencd@0 3935
ferencd@0 3936 // UTF-32 to UTF-8 encoding
ferencd@0 3937 if (wc < 0x80)
ferencd@0 3938 {
ferencd@0 3939 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
ferencd@0 3940 utf8_bytes_filled = 1;
ferencd@0 3941 }
ferencd@0 3942 else if (wc <= 0x7FF)
ferencd@0 3943 {
ferencd@0 3944 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((wc >> 6u) & 0x1Fu));
ferencd@0 3945 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
ferencd@0 3946 utf8_bytes_filled = 2;
ferencd@0 3947 }
ferencd@0 3948 else if (wc <= 0xFFFF)
ferencd@0 3949 {
ferencd@0 3950 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((wc >> 12u) & 0x0Fu));
ferencd@0 3951 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));
ferencd@0 3952 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
ferencd@0 3953 utf8_bytes_filled = 3;
ferencd@0 3954 }
ferencd@0 3955 else if (wc <= 0x10FFFF)
ferencd@0 3956 {
ferencd@0 3957 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((wc >> 18u) & 0x07u));
ferencd@0 3958 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 12u) & 0x3Fu));
ferencd@0 3959 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));
ferencd@0 3960 utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
ferencd@0 3961 utf8_bytes_filled = 4;
ferencd@0 3962 }
ferencd@0 3963 else
ferencd@0 3964 {
ferencd@0 3965 // unknown character
ferencd@0 3966 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
ferencd@0 3967 utf8_bytes_filled = 1;
ferencd@0 3968 }
ferencd@0 3969 }
ferencd@0 3970 }
ferencd@0 3971 };
ferencd@0 3972
ferencd@0 3973 template<typename WideStringType>
ferencd@0 3974 struct wide_string_input_helper<WideStringType, 2>
ferencd@0 3975 {
ferencd@0 3976 // UTF-16
ferencd@0 3977 static void fill_buffer(const WideStringType& str,
ferencd@0 3978 size_t& current_wchar,
ferencd@0 3979 std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
ferencd@0 3980 size_t& utf8_bytes_index,
ferencd@0 3981 size_t& utf8_bytes_filled)
ferencd@0 3982 {
ferencd@0 3983 utf8_bytes_index = 0;
ferencd@0 3984
ferencd@0 3985 if (current_wchar == str.size())
ferencd@0 3986 {
ferencd@0 3987 utf8_bytes[0] = std::char_traits<char>::eof();
ferencd@0 3988 utf8_bytes_filled = 1;
ferencd@0 3989 }
ferencd@0 3990 else
ferencd@0 3991 {
ferencd@0 3992 // get the current character
ferencd@0 3993 const auto wc = static_cast<unsigned int>(str[current_wchar++]);
ferencd@0 3994
ferencd@0 3995 // UTF-16 to UTF-8 encoding
ferencd@0 3996 if (wc < 0x80)
ferencd@0 3997 {
ferencd@0 3998 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
ferencd@0 3999 utf8_bytes_filled = 1;
ferencd@0 4000 }
ferencd@0 4001 else if (wc <= 0x7FF)
ferencd@0 4002 {
ferencd@0 4003 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((wc >> 6u)));
ferencd@0 4004 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
ferencd@0 4005 utf8_bytes_filled = 2;
ferencd@0 4006 }
ferencd@0 4007 else if (0xD800 > wc or wc >= 0xE000)
ferencd@0 4008 {
ferencd@0 4009 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((wc >> 12u)));
ferencd@0 4010 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));
ferencd@0 4011 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
ferencd@0 4012 utf8_bytes_filled = 3;
ferencd@0 4013 }
ferencd@0 4014 else
ferencd@0 4015 {
ferencd@0 4016 if (current_wchar < str.size())
ferencd@0 4017 {
ferencd@0 4018 const auto wc2 = static_cast<unsigned int>(str[current_wchar++]);
ferencd@0 4019 const auto charcode = 0x10000u + (((wc & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
ferencd@0 4020 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));
ferencd@0 4021 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));
ferencd@0 4022 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));
ferencd@0 4023 utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));
ferencd@0 4024 utf8_bytes_filled = 4;
ferencd@0 4025 }
ferencd@0 4026 else
ferencd@0 4027 {
ferencd@0 4028 // unknown character
ferencd@0 4029 ++current_wchar;
ferencd@0 4030 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
ferencd@0 4031 utf8_bytes_filled = 1;
ferencd@0 4032 }
ferencd@0 4033 }
ferencd@0 4034 }
ferencd@0 4035 }
ferencd@0 4036 };
ferencd@0 4037
ferencd@0 4038 template<typename WideStringType>
ferencd@0 4039 class wide_string_input_adapter : public input_adapter_protocol
ferencd@0 4040 {
ferencd@0 4041 public:
ferencd@0 4042 explicit wide_string_input_adapter(const WideStringType& w) noexcept
ferencd@0 4043 : str(w)
ferencd@0 4044 {}
ferencd@0 4045
ferencd@0 4046 std::char_traits<char>::int_type get_character() noexcept override
ferencd@0 4047 {
ferencd@0 4048 // check if buffer needs to be filled
ferencd@0 4049 if (utf8_bytes_index == utf8_bytes_filled)
ferencd@0 4050 {
ferencd@0 4051 fill_buffer<sizeof(typename WideStringType::value_type)>();
ferencd@0 4052
ferencd@0 4053 assert(utf8_bytes_filled > 0);
ferencd@0 4054 assert(utf8_bytes_index == 0);
ferencd@0 4055 }
ferencd@0 4056
ferencd@0 4057 // use buffer
ferencd@0 4058 assert(utf8_bytes_filled > 0);
ferencd@0 4059 assert(utf8_bytes_index < utf8_bytes_filled);
ferencd@0 4060 return utf8_bytes[utf8_bytes_index++];
ferencd@0 4061 }
ferencd@0 4062
ferencd@0 4063 private:
ferencd@0 4064 template<size_t T>
ferencd@0 4065 void fill_buffer()
ferencd@0 4066 {
ferencd@0 4067 wide_string_input_helper<WideStringType, T>::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);
ferencd@0 4068 }
ferencd@0 4069
ferencd@0 4070 /// the wstring to process
ferencd@0 4071 const WideStringType& str;
ferencd@0 4072
ferencd@0 4073 /// index of the current wchar in str
ferencd@0 4074 std::size_t current_wchar = 0;
ferencd@0 4075
ferencd@0 4076 /// a buffer for UTF-8 bytes
ferencd@0 4077 std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};
ferencd@0 4078
ferencd@0 4079 /// index to the utf8_codes array for the next valid byte
ferencd@0 4080 std::size_t utf8_bytes_index = 0;
ferencd@0 4081 /// number of valid bytes in the utf8_codes array
ferencd@0 4082 std::size_t utf8_bytes_filled = 0;
ferencd@0 4083 };
ferencd@0 4084
ferencd@0 4085 class input_adapter
ferencd@0 4086 {
ferencd@0 4087 public:
ferencd@0 4088 // native support
ferencd@0 4089 JSON_HEDLEY_NON_NULL(2)
ferencd@0 4090 input_adapter(std::FILE* file)
ferencd@0 4091 : ia(std::make_shared<file_input_adapter>(file)) {}
ferencd@0 4092 /// input adapter for input stream
ferencd@0 4093 input_adapter(std::istream& i)
ferencd@0 4094 : ia(std::make_shared<input_stream_adapter>(i)) {}
ferencd@0 4095
ferencd@0 4096 /// input adapter for input stream
ferencd@0 4097 input_adapter(std::istream&& i)
ferencd@0 4098 : ia(std::make_shared<input_stream_adapter>(i)) {}
ferencd@0 4099
ferencd@0 4100 input_adapter(const std::wstring& ws)
ferencd@0 4101 : ia(std::make_shared<wide_string_input_adapter<std::wstring>>(ws)) {}
ferencd@0 4102
ferencd@0 4103 input_adapter(const std::u16string& ws)
ferencd@0 4104 : ia(std::make_shared<wide_string_input_adapter<std::u16string>>(ws)) {}
ferencd@0 4105
ferencd@0 4106 input_adapter(const std::u32string& ws)
ferencd@0 4107 : ia(std::make_shared<wide_string_input_adapter<std::u32string>>(ws)) {}
ferencd@0 4108
ferencd@0 4109 /// input adapter for buffer
ferencd@0 4110 template<typename CharT,
ferencd@0 4111 typename std::enable_if<
ferencd@0 4112 std::is_pointer<CharT>::value and
ferencd@0 4113 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
ferencd@0 4114 sizeof(typename std::remove_pointer<CharT>::type) == 1,
ferencd@0 4115 int>::type = 0>
ferencd@0 4116 input_adapter(CharT b, std::size_t l)
ferencd@0 4117 : ia(std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(b), l)) {}
ferencd@0 4118
ferencd@0 4119 // derived support
ferencd@0 4120
ferencd@0 4121 /// input adapter for string literal
ferencd@0 4122 template<typename CharT,
ferencd@0 4123 typename std::enable_if<
ferencd@0 4124 std::is_pointer<CharT>::value and
ferencd@0 4125 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
ferencd@0 4126 sizeof(typename std::remove_pointer<CharT>::type) == 1,
ferencd@0 4127 int>::type = 0>
ferencd@0 4128 input_adapter(CharT b)
ferencd@0 4129 : input_adapter(reinterpret_cast<const char*>(b),
ferencd@0 4130 std::strlen(reinterpret_cast<const char*>(b))) {}
ferencd@0 4131
ferencd@0 4132 /// input adapter for iterator range with contiguous storage
ferencd@0 4133 template<class IteratorType,
ferencd@0 4134 typename std::enable_if<
ferencd@0 4135 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
ferencd@0 4136 int>::type = 0>
ferencd@0 4137 input_adapter(IteratorType first, IteratorType last)
ferencd@0 4138 {
ferencd@0 4139 #ifndef NDEBUG
ferencd@0 4140 // assertion to check that the iterator range is indeed contiguous,
ferencd@0 4141 // see http://stackoverflow.com/a/35008842/266378 for more discussion
ferencd@0 4142 const auto is_contiguous = std::accumulate(
ferencd@0 4143 first, last, std::pair<bool, int>(true, 0),
ferencd@0 4144 [&first](std::pair<bool, int> res, decltype(*first) val)
ferencd@0 4145 {
ferencd@0 4146 res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
ferencd@0 4147 return res;
ferencd@0 4148 }).first;
ferencd@0 4149 assert(is_contiguous);
ferencd@0 4150 #endif
ferencd@0 4151
ferencd@0 4152 // assertion to check that each element is 1 byte long
ferencd@0 4153 static_assert(
ferencd@0 4154 sizeof(typename iterator_traits<IteratorType>::value_type) == 1,
ferencd@0 4155 "each element in the iterator range must have the size of 1 byte");
ferencd@0 4156
ferencd@0 4157 const auto len = static_cast<size_t>(std::distance(first, last));
ferencd@0 4158 if (JSON_HEDLEY_LIKELY(len > 0))
ferencd@0 4159 {
ferencd@0 4160 // there is at least one element: use the address of first
ferencd@0 4161 ia = std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(&(*first)), len);
ferencd@0 4162 }
ferencd@0 4163 else
ferencd@0 4164 {
ferencd@0 4165 // the address of first cannot be used: use nullptr
ferencd@0 4166 ia = std::make_shared<input_buffer_adapter>(nullptr, len);
ferencd@0 4167 }
ferencd@0 4168 }
ferencd@0 4169
ferencd@0 4170 /// input adapter for array
ferencd@0 4171 template<class T, std::size_t N>
ferencd@0 4172 input_adapter(T (&array)[N])
ferencd@0 4173 : input_adapter(std::begin(array), std::end(array)) {}
ferencd@0 4174
ferencd@0 4175 /// input adapter for contiguous container
ferencd@0 4176 template<class ContiguousContainer, typename
ferencd@0 4177 std::enable_if<not std::is_pointer<ContiguousContainer>::value and
ferencd@0 4178 std::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,
ferencd@0 4179 int>::type = 0>
ferencd@0 4180 input_adapter(const ContiguousContainer& c)
ferencd@0 4181 : input_adapter(std::begin(c), std::end(c)) {}
ferencd@0 4182
ferencd@0 4183 operator input_adapter_t()
ferencd@0 4184 {
ferencd@0 4185 return ia;
ferencd@0 4186 }
ferencd@0 4187
ferencd@0 4188 private:
ferencd@0 4189 /// the actual adapter
ferencd@0 4190 input_adapter_t ia = nullptr;
ferencd@0 4191 };
ferencd@0 4192 } // namespace detail
ferencd@0 4193 } // namespace nlohmann
ferencd@0 4194
ferencd@0 4195 // #include <nlohmann/detail/input/json_sax.hpp>
ferencd@0 4196
ferencd@0 4197
ferencd@0 4198 #include <cassert> // assert
ferencd@0 4199 #include <cstddef>
ferencd@0 4200 #include <string> // string
ferencd@0 4201 #include <utility> // move
ferencd@0 4202 #include <vector> // vector
ferencd@0 4203
ferencd@0 4204 // #include <nlohmann/detail/exceptions.hpp>
ferencd@0 4205
ferencd@0 4206 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 4207
ferencd@0 4208
ferencd@0 4209 namespace nlohmann
ferencd@0 4210 {
ferencd@0 4211
ferencd@0 4212 /*!
ferencd@0 4213 @brief SAX interface
ferencd@0 4214
ferencd@0 4215 This class describes the SAX interface used by @ref nlohmann::json::sax_parse.
ferencd@0 4216 Each function is called in different situations while the input is parsed. The
ferencd@0 4217 boolean return value informs the parser whether to continue processing the
ferencd@0 4218 input.
ferencd@0 4219 */
ferencd@0 4220 template<typename BasicJsonType>
ferencd@0 4221 struct json_sax
ferencd@0 4222 {
ferencd@0 4223 /// type for (signed) integers
ferencd@0 4224 using number_integer_t = typename BasicJsonType::number_integer_t;
ferencd@0 4225 /// type for unsigned integers
ferencd@0 4226 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
ferencd@0 4227 /// type for floating-point numbers
ferencd@0 4228 using number_float_t = typename BasicJsonType::number_float_t;
ferencd@0 4229 /// type for strings
ferencd@0 4230 using string_t = typename BasicJsonType::string_t;
ferencd@0 4231
ferencd@0 4232 /*!
ferencd@0 4233 @brief a null value was read
ferencd@0 4234 @return whether parsing should proceed
ferencd@0 4235 */
ferencd@0 4236 virtual bool null() = 0;
ferencd@0 4237
ferencd@0 4238 /*!
ferencd@0 4239 @brief a boolean value was read
ferencd@0 4240 @param[in] val boolean value
ferencd@0 4241 @return whether parsing should proceed
ferencd@0 4242 */
ferencd@0 4243 virtual bool boolean(bool val) = 0;
ferencd@0 4244
ferencd@0 4245 /*!
ferencd@0 4246 @brief an integer number was read
ferencd@0 4247 @param[in] val integer value
ferencd@0 4248 @return whether parsing should proceed
ferencd@0 4249 */
ferencd@0 4250 virtual bool number_integer(number_integer_t val) = 0;
ferencd@0 4251
ferencd@0 4252 /*!
ferencd@0 4253 @brief an unsigned integer number was read
ferencd@0 4254 @param[in] val unsigned integer value
ferencd@0 4255 @return whether parsing should proceed
ferencd@0 4256 */
ferencd@0 4257 virtual bool number_unsigned(number_unsigned_t val) = 0;
ferencd@0 4258
ferencd@0 4259 /*!
ferencd@0 4260 @brief an floating-point number was read
ferencd@0 4261 @param[in] val floating-point value
ferencd@0 4262 @param[in] s raw token value
ferencd@0 4263 @return whether parsing should proceed
ferencd@0 4264 */
ferencd@0 4265 virtual bool number_float(number_float_t val, const string_t& s) = 0;
ferencd@0 4266
ferencd@0 4267 /*!
ferencd@0 4268 @brief a string was read
ferencd@0 4269 @param[in] val string value
ferencd@0 4270 @return whether parsing should proceed
ferencd@0 4271 @note It is safe to move the passed string.
ferencd@0 4272 */
ferencd@0 4273 virtual bool string(string_t& val) = 0;
ferencd@0 4274
ferencd@0 4275 /*!
ferencd@0 4276 @brief the beginning of an object was read
ferencd@0 4277 @param[in] elements number of object elements or -1 if unknown
ferencd@0 4278 @return whether parsing should proceed
ferencd@0 4279 @note binary formats may report the number of elements
ferencd@0 4280 */
ferencd@0 4281 virtual bool start_object(std::size_t elements) = 0;
ferencd@0 4282
ferencd@0 4283 /*!
ferencd@0 4284 @brief an object key was read
ferencd@0 4285 @param[in] val object key
ferencd@0 4286 @return whether parsing should proceed
ferencd@0 4287 @note It is safe to move the passed string.
ferencd@0 4288 */
ferencd@0 4289 virtual bool key(string_t& val) = 0;
ferencd@0 4290
ferencd@0 4291 /*!
ferencd@0 4292 @brief the end of an object was read
ferencd@0 4293 @return whether parsing should proceed
ferencd@0 4294 */
ferencd@0 4295 virtual bool end_object() = 0;
ferencd@0 4296
ferencd@0 4297 /*!
ferencd@0 4298 @brief the beginning of an array was read
ferencd@0 4299 @param[in] elements number of array elements or -1 if unknown
ferencd@0 4300 @return whether parsing should proceed
ferencd@0 4301 @note binary formats may report the number of elements
ferencd@0 4302 */
ferencd@0 4303 virtual bool start_array(std::size_t elements) = 0;
ferencd@0 4304
ferencd@0 4305 /*!
ferencd@0 4306 @brief the end of an array was read
ferencd@0 4307 @return whether parsing should proceed
ferencd@0 4308 */
ferencd@0 4309 virtual bool end_array() = 0;
ferencd@0 4310
ferencd@0 4311 /*!
ferencd@0 4312 @brief a parse error occurred
ferencd@0 4313 @param[in] position the position in the input where the error occurs
ferencd@0 4314 @param[in] last_token the last read token
ferencd@0 4315 @param[in] ex an exception object describing the error
ferencd@0 4316 @return whether parsing should proceed (must return false)
ferencd@0 4317 */
ferencd@0 4318 virtual bool parse_error(std::size_t position,
ferencd@0 4319 const std::string& last_token,
ferencd@0 4320 const detail::exception& ex) = 0;
ferencd@0 4321
ferencd@0 4322 virtual ~json_sax() = default;
ferencd@0 4323 };
ferencd@0 4324
ferencd@0 4325
ferencd@0 4326 namespace detail
ferencd@0 4327 {
ferencd@0 4328 /*!
ferencd@0 4329 @brief SAX implementation to create a JSON value from SAX events
ferencd@0 4330
ferencd@0 4331 This class implements the @ref json_sax interface and processes the SAX events
ferencd@0 4332 to create a JSON value which makes it basically a DOM parser. The structure or
ferencd@0 4333 hierarchy of the JSON value is managed by the stack `ref_stack` which contains
ferencd@0 4334 a pointer to the respective array or object for each recursion depth.
ferencd@0 4335
ferencd@0 4336 After successful parsing, the value that is passed by reference to the
ferencd@0 4337 constructor contains the parsed value.
ferencd@0 4338
ferencd@0 4339 @tparam BasicJsonType the JSON type
ferencd@0 4340 */
ferencd@0 4341 template<typename BasicJsonType>
ferencd@0 4342 class json_sax_dom_parser
ferencd@0 4343 {
ferencd@0 4344 public:
ferencd@0 4345 using number_integer_t = typename BasicJsonType::number_integer_t;
ferencd@0 4346 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
ferencd@0 4347 using number_float_t = typename BasicJsonType::number_float_t;
ferencd@0 4348 using string_t = typename BasicJsonType::string_t;
ferencd@0 4349
ferencd@0 4350 /*!
ferencd@0 4351 @param[in, out] r reference to a JSON value that is manipulated while
ferencd@0 4352 parsing
ferencd@0 4353 @param[in] allow_exceptions_ whether parse errors yield exceptions
ferencd@0 4354 */
ferencd@0 4355 explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
ferencd@0 4356 : root(r), allow_exceptions(allow_exceptions_)
ferencd@0 4357 {}
ferencd@0 4358
ferencd@0 4359 // make class move-only
ferencd@0 4360 json_sax_dom_parser(const json_sax_dom_parser&) = delete;
ferencd@0 4361 json_sax_dom_parser(json_sax_dom_parser&&) = default;
ferencd@0 4362 json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;
ferencd@0 4363 json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default;
ferencd@0 4364 ~json_sax_dom_parser() = default;
ferencd@0 4365
ferencd@0 4366 bool null()
ferencd@0 4367 {
ferencd@0 4368 handle_value(nullptr);
ferencd@0 4369 return true;
ferencd@0 4370 }
ferencd@0 4371
ferencd@0 4372 bool boolean(bool val)
ferencd@0 4373 {
ferencd@0 4374 handle_value(val);
ferencd@0 4375 return true;
ferencd@0 4376 }
ferencd@0 4377
ferencd@0 4378 bool number_integer(number_integer_t val)
ferencd@0 4379 {
ferencd@0 4380 handle_value(val);
ferencd@0 4381 return true;
ferencd@0 4382 }
ferencd@0 4383
ferencd@0 4384 bool number_unsigned(number_unsigned_t val)
ferencd@0 4385 {
ferencd@0 4386 handle_value(val);
ferencd@0 4387 return true;
ferencd@0 4388 }
ferencd@0 4389
ferencd@0 4390 bool number_float(number_float_t val, const string_t& /*unused*/)
ferencd@0 4391 {
ferencd@0 4392 handle_value(val);
ferencd@0 4393 return true;
ferencd@0 4394 }
ferencd@0 4395
ferencd@0 4396 bool string(string_t& val)
ferencd@0 4397 {
ferencd@0 4398 handle_value(val);
ferencd@0 4399 return true;
ferencd@0 4400 }
ferencd@0 4401
ferencd@0 4402 bool start_object(std::size_t len)
ferencd@0 4403 {
ferencd@0 4404 ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
ferencd@0 4405
ferencd@0 4406 if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
ferencd@0 4407 {
ferencd@0 4408 JSON_THROW(out_of_range::create(408,
ferencd@0 4409 "excessive object size: " + std::to_string(len)));
ferencd@0 4410 }
ferencd@0 4411
ferencd@0 4412 return true;
ferencd@0 4413 }
ferencd@0 4414
ferencd@0 4415 bool key(string_t& val)
ferencd@0 4416 {
ferencd@0 4417 // add null at given key and store the reference for later
ferencd@0 4418 object_element = &(ref_stack.back()->m_value.object->operator[](val));
ferencd@0 4419 return true;
ferencd@0 4420 }
ferencd@0 4421
ferencd@0 4422 bool end_object()
ferencd@0 4423 {
ferencd@0 4424 ref_stack.pop_back();
ferencd@0 4425 return true;
ferencd@0 4426 }
ferencd@0 4427
ferencd@0 4428 bool start_array(std::size_t len)
ferencd@0 4429 {
ferencd@0 4430 ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
ferencd@0 4431
ferencd@0 4432 if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
ferencd@0 4433 {
ferencd@0 4434 JSON_THROW(out_of_range::create(408,
ferencd@0 4435 "excessive array size: " + std::to_string(len)));
ferencd@0 4436 }
ferencd@0 4437
ferencd@0 4438 return true;
ferencd@0 4439 }
ferencd@0 4440
ferencd@0 4441 bool end_array()
ferencd@0 4442 {
ferencd@0 4443 ref_stack.pop_back();
ferencd@0 4444 return true;
ferencd@0 4445 }
ferencd@0 4446
ferencd@0 4447 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
ferencd@0 4448 const detail::exception& ex)
ferencd@0 4449 {
ferencd@0 4450 errored = true;
ferencd@0 4451 if (allow_exceptions)
ferencd@0 4452 {
ferencd@0 4453 // determine the proper exception type from the id
ferencd@0 4454 switch ((ex.id / 100) % 100)
ferencd@0 4455 {
ferencd@0 4456 case 1:
ferencd@0 4457 JSON_THROW(*static_cast<const detail::parse_error*>(&ex));
ferencd@0 4458 case 4:
ferencd@0 4459 JSON_THROW(*static_cast<const detail::out_of_range*>(&ex));
ferencd@0 4460 // LCOV_EXCL_START
ferencd@0 4461 case 2:
ferencd@0 4462 JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));
ferencd@0 4463 case 3:
ferencd@0 4464 JSON_THROW(*static_cast<const detail::type_error*>(&ex));
ferencd@0 4465 case 5:
ferencd@0 4466 JSON_THROW(*static_cast<const detail::other_error*>(&ex));
ferencd@0 4467 default:
ferencd@0 4468 assert(false);
ferencd@0 4469 // LCOV_EXCL_STOP
ferencd@0 4470 }
ferencd@0 4471 }
ferencd@0 4472 return false;
ferencd@0 4473 }
ferencd@0 4474
ferencd@0 4475 constexpr bool is_errored() const
ferencd@0 4476 {
ferencd@0 4477 return errored;
ferencd@0 4478 }
ferencd@0 4479
ferencd@0 4480 private:
ferencd@0 4481 /*!
ferencd@0 4482 @invariant If the ref stack is empty, then the passed value will be the new
ferencd@0 4483 root.
ferencd@0 4484 @invariant If the ref stack contains a value, then it is an array or an
ferencd@0 4485 object to which we can add elements
ferencd@0 4486 */
ferencd@0 4487 template<typename Value>
ferencd@0 4488 JSON_HEDLEY_RETURNS_NON_NULL
ferencd@0 4489 BasicJsonType* handle_value(Value&& v)
ferencd@0 4490 {
ferencd@0 4491 if (ref_stack.empty())
ferencd@0 4492 {
ferencd@0 4493 root = BasicJsonType(std::forward<Value>(v));
ferencd@0 4494 return &root;
ferencd@0 4495 }
ferencd@0 4496
ferencd@0 4497 assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
ferencd@0 4498
ferencd@0 4499 if (ref_stack.back()->is_array())
ferencd@0 4500 {
ferencd@0 4501 ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
ferencd@0 4502 return &(ref_stack.back()->m_value.array->back());
ferencd@0 4503 }
ferencd@0 4504
ferencd@0 4505 assert(ref_stack.back()->is_object());
ferencd@0 4506 assert(object_element);
ferencd@0 4507 *object_element = BasicJsonType(std::forward<Value>(v));
ferencd@0 4508 return object_element;
ferencd@0 4509 }
ferencd@0 4510
ferencd@0 4511 /// the parsed JSON value
ferencd@0 4512 BasicJsonType& root;
ferencd@0 4513 /// stack to model hierarchy of values
ferencd@0 4514 std::vector<BasicJsonType*> ref_stack {};
ferencd@0 4515 /// helper to hold the reference for the next object element
ferencd@0 4516 BasicJsonType* object_element = nullptr;
ferencd@0 4517 /// whether a syntax error occurred
ferencd@0 4518 bool errored = false;
ferencd@0 4519 /// whether to throw exceptions in case of errors
ferencd@0 4520 const bool allow_exceptions = true;
ferencd@0 4521 };
ferencd@0 4522
ferencd@0 4523 template<typename BasicJsonType>
ferencd@0 4524 class json_sax_dom_callback_parser
ferencd@0 4525 {
ferencd@0 4526 public:
ferencd@0 4527 using number_integer_t = typename BasicJsonType::number_integer_t;
ferencd@0 4528 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
ferencd@0 4529 using number_float_t = typename BasicJsonType::number_float_t;
ferencd@0 4530 using string_t = typename BasicJsonType::string_t;
ferencd@0 4531 using parser_callback_t = typename BasicJsonType::parser_callback_t;
ferencd@0 4532 using parse_event_t = typename BasicJsonType::parse_event_t;
ferencd@0 4533
ferencd@0 4534 json_sax_dom_callback_parser(BasicJsonType& r,
ferencd@0 4535 const parser_callback_t cb,
ferencd@0 4536 const bool allow_exceptions_ = true)
ferencd@0 4537 : root(r), callback(cb), allow_exceptions(allow_exceptions_)
ferencd@0 4538 {
ferencd@0 4539 keep_stack.push_back(true);
ferencd@0 4540 }
ferencd@0 4541
ferencd@0 4542 // make class move-only
ferencd@0 4543 json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;
ferencd@0 4544 json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default;
ferencd@0 4545 json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;
ferencd@0 4546 json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default;
ferencd@0 4547 ~json_sax_dom_callback_parser() = default;
ferencd@0 4548
ferencd@0 4549 bool null()
ferencd@0 4550 {
ferencd@0 4551 handle_value(nullptr);
ferencd@0 4552 return true;
ferencd@0 4553 }
ferencd@0 4554
ferencd@0 4555 bool boolean(bool val)
ferencd@0 4556 {
ferencd@0 4557 handle_value(val);
ferencd@0 4558 return true;
ferencd@0 4559 }
ferencd@0 4560
ferencd@0 4561 bool number_integer(number_integer_t val)
ferencd@0 4562 {
ferencd@0 4563 handle_value(val);
ferencd@0 4564 return true;
ferencd@0 4565 }
ferencd@0 4566
ferencd@0 4567 bool number_unsigned(number_unsigned_t val)
ferencd@0 4568 {
ferencd@0 4569 handle_value(val);
ferencd@0 4570 return true;
ferencd@0 4571 }
ferencd@0 4572
ferencd@0 4573 bool number_float(number_float_t val, const string_t& /*unused*/)
ferencd@0 4574 {
ferencd@0 4575 handle_value(val);
ferencd@0 4576 return true;
ferencd@0 4577 }
ferencd@0 4578
ferencd@0 4579 bool string(string_t& val)
ferencd@0 4580 {
ferencd@0 4581 handle_value(val);
ferencd@0 4582 return true;
ferencd@0 4583 }
ferencd@0 4584
ferencd@0 4585 bool start_object(std::size_t len)
ferencd@0 4586 {
ferencd@0 4587 // check callback for object start
ferencd@0 4588 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
ferencd@0 4589 keep_stack.push_back(keep);
ferencd@0 4590
ferencd@0 4591 auto val = handle_value(BasicJsonType::value_t::object, true);
ferencd@0 4592 ref_stack.push_back(val.second);
ferencd@0 4593
ferencd@0 4594 // check object limit
ferencd@0 4595 if (ref_stack.back() and JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
ferencd@0 4596 {
ferencd@0 4597 JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len)));
ferencd@0 4598 }
ferencd@0 4599
ferencd@0 4600 return true;
ferencd@0 4601 }
ferencd@0 4602
ferencd@0 4603 bool key(string_t& val)
ferencd@0 4604 {
ferencd@0 4605 BasicJsonType k = BasicJsonType(val);
ferencd@0 4606
ferencd@0 4607 // check callback for key
ferencd@0 4608 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);
ferencd@0 4609 key_keep_stack.push_back(keep);
ferencd@0 4610
ferencd@0 4611 // add discarded value at given key and store the reference for later
ferencd@0 4612 if (keep and ref_stack.back())
ferencd@0 4613 {
ferencd@0 4614 object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
ferencd@0 4615 }
ferencd@0 4616
ferencd@0 4617 return true;
ferencd@0 4618 }
ferencd@0 4619
ferencd@0 4620 bool end_object()
ferencd@0 4621 {
ferencd@0 4622 if (ref_stack.back() and not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
ferencd@0 4623 {
ferencd@0 4624 // discard object
ferencd@0 4625 *ref_stack.back() = discarded;
ferencd@0 4626 }
ferencd@0 4627
ferencd@0 4628 assert(not ref_stack.empty());
ferencd@0 4629 assert(not keep_stack.empty());
ferencd@0 4630 ref_stack.pop_back();
ferencd@0 4631 keep_stack.pop_back();
ferencd@0 4632
ferencd@0 4633 if (not ref_stack.empty() and ref_stack.back() and ref_stack.back()->is_object())
ferencd@0 4634 {
ferencd@0 4635 // remove discarded value
ferencd@0 4636 for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
ferencd@0 4637 {
ferencd@0 4638 if (it->is_discarded())
ferencd@0 4639 {
ferencd@0 4640 ref_stack.back()->erase(it);
ferencd@0 4641 break;
ferencd@0 4642 }
ferencd@0 4643 }
ferencd@0 4644 }
ferencd@0 4645
ferencd@0 4646 return true;
ferencd@0 4647 }
ferencd@0 4648
ferencd@0 4649 bool start_array(std::size_t len)
ferencd@0 4650 {
ferencd@0 4651 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
ferencd@0 4652 keep_stack.push_back(keep);
ferencd@0 4653
ferencd@0 4654 auto val = handle_value(BasicJsonType::value_t::array, true);
ferencd@0 4655 ref_stack.push_back(val.second);
ferencd@0 4656
ferencd@0 4657 // check array limit
ferencd@0 4658 if (ref_stack.back() and JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
ferencd@0 4659 {
ferencd@0 4660 JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len)));
ferencd@0 4661 }
ferencd@0 4662
ferencd@0 4663 return true;
ferencd@0 4664 }
ferencd@0 4665
ferencd@0 4666 bool end_array()
ferencd@0 4667 {
ferencd@0 4668 bool keep = true;
ferencd@0 4669
ferencd@0 4670 if (ref_stack.back())
ferencd@0 4671 {
ferencd@0 4672 keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
ferencd@0 4673 if (not keep)
ferencd@0 4674 {
ferencd@0 4675 // discard array
ferencd@0 4676 *ref_stack.back() = discarded;
ferencd@0 4677 }
ferencd@0 4678 }
ferencd@0 4679
ferencd@0 4680 assert(not ref_stack.empty());
ferencd@0 4681 assert(not keep_stack.empty());
ferencd@0 4682 ref_stack.pop_back();
ferencd@0 4683 keep_stack.pop_back();
ferencd@0 4684
ferencd@0 4685 // remove discarded value
ferencd@0 4686 if (not keep and not ref_stack.empty() and ref_stack.back()->is_array())
ferencd@0 4687 {
ferencd@0 4688 ref_stack.back()->m_value.array->pop_back();
ferencd@0 4689 }
ferencd@0 4690
ferencd@0 4691 return true;
ferencd@0 4692 }
ferencd@0 4693
ferencd@0 4694 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
ferencd@0 4695 const detail::exception& ex)
ferencd@0 4696 {
ferencd@0 4697 errored = true;
ferencd@0 4698 if (allow_exceptions)
ferencd@0 4699 {
ferencd@0 4700 // determine the proper exception type from the id
ferencd@0 4701 switch ((ex.id / 100) % 100)
ferencd@0 4702 {
ferencd@0 4703 case 1:
ferencd@0 4704 JSON_THROW(*static_cast<const detail::parse_error*>(&ex));
ferencd@0 4705 case 4:
ferencd@0 4706 JSON_THROW(*static_cast<const detail::out_of_range*>(&ex));
ferencd@0 4707 // LCOV_EXCL_START
ferencd@0 4708 case 2:
ferencd@0 4709 JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));
ferencd@0 4710 case 3:
ferencd@0 4711 JSON_THROW(*static_cast<const detail::type_error*>(&ex));
ferencd@0 4712 case 5:
ferencd@0 4713 JSON_THROW(*static_cast<const detail::other_error*>(&ex));
ferencd@0 4714 default:
ferencd@0 4715 assert(false);
ferencd@0 4716 // LCOV_EXCL_STOP
ferencd@0 4717 }
ferencd@0 4718 }
ferencd@0 4719 return false;
ferencd@0 4720 }
ferencd@0 4721
ferencd@0 4722 constexpr bool is_errored() const
ferencd@0 4723 {
ferencd@0 4724 return errored;
ferencd@0 4725 }
ferencd@0 4726
ferencd@0 4727 private:
ferencd@0 4728 /*!
ferencd@0 4729 @param[in] v value to add to the JSON value we build during parsing
ferencd@0 4730 @param[in] skip_callback whether we should skip calling the callback
ferencd@0 4731 function; this is required after start_array() and
ferencd@0 4732 start_object() SAX events, because otherwise we would call the
ferencd@0 4733 callback function with an empty array or object, respectively.
ferencd@0 4734
ferencd@0 4735 @invariant If the ref stack is empty, then the passed value will be the new
ferencd@0 4736 root.
ferencd@0 4737 @invariant If the ref stack contains a value, then it is an array or an
ferencd@0 4738 object to which we can add elements
ferencd@0 4739
ferencd@0 4740 @return pair of boolean (whether value should be kept) and pointer (to the
ferencd@0 4741 passed value in the ref_stack hierarchy; nullptr if not kept)
ferencd@0 4742 */
ferencd@0 4743 template<typename Value>
ferencd@0 4744 std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
ferencd@0 4745 {
ferencd@0 4746 assert(not keep_stack.empty());
ferencd@0 4747
ferencd@0 4748 // do not handle this value if we know it would be added to a discarded
ferencd@0 4749 // container
ferencd@0 4750 if (not keep_stack.back())
ferencd@0 4751 {
ferencd@0 4752 return {false, nullptr};
ferencd@0 4753 }
ferencd@0 4754
ferencd@0 4755 // create value
ferencd@0 4756 auto value = BasicJsonType(std::forward<Value>(v));
ferencd@0 4757
ferencd@0 4758 // check callback
ferencd@0 4759 const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
ferencd@0 4760
ferencd@0 4761 // do not handle this value if we just learnt it shall be discarded
ferencd@0 4762 if (not keep)
ferencd@0 4763 {
ferencd@0 4764 return {false, nullptr};
ferencd@0 4765 }
ferencd@0 4766
ferencd@0 4767 if (ref_stack.empty())
ferencd@0 4768 {
ferencd@0 4769 root = std::move(value);
ferencd@0 4770 return {true, &root};
ferencd@0 4771 }
ferencd@0 4772
ferencd@0 4773 // skip this value if we already decided to skip the parent
ferencd@0 4774 // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
ferencd@0 4775 if (not ref_stack.back())
ferencd@0 4776 {
ferencd@0 4777 return {false, nullptr};
ferencd@0 4778 }
ferencd@0 4779
ferencd@0 4780 // we now only expect arrays and objects
ferencd@0 4781 assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
ferencd@0 4782
ferencd@0 4783 // array
ferencd@0 4784 if (ref_stack.back()->is_array())
ferencd@0 4785 {
ferencd@0 4786 ref_stack.back()->m_value.array->push_back(std::move(value));
ferencd@0 4787 return {true, &(ref_stack.back()->m_value.array->back())};
ferencd@0 4788 }
ferencd@0 4789
ferencd@0 4790 // object
ferencd@0 4791 assert(ref_stack.back()->is_object());
ferencd@0 4792 // check if we should store an element for the current key
ferencd@0 4793 assert(not key_keep_stack.empty());
ferencd@0 4794 const bool store_element = key_keep_stack.back();
ferencd@0 4795 key_keep_stack.pop_back();
ferencd@0 4796
ferencd@0 4797 if (not store_element)
ferencd@0 4798 {
ferencd@0 4799 return {false, nullptr};
ferencd@0 4800 }
ferencd@0 4801
ferencd@0 4802 assert(object_element);
ferencd@0 4803 *object_element = std::move(value);
ferencd@0 4804 return {true, object_element};
ferencd@0 4805 }
ferencd@0 4806
ferencd@0 4807 /// the parsed JSON value
ferencd@0 4808 BasicJsonType& root;
ferencd@0 4809 /// stack to model hierarchy of values
ferencd@0 4810 std::vector<BasicJsonType*> ref_stack {};
ferencd@0 4811 /// stack to manage which values to keep
ferencd@0 4812 std::vector<bool> keep_stack {};
ferencd@0 4813 /// stack to manage which object keys to keep
ferencd@0 4814 std::vector<bool> key_keep_stack {};
ferencd@0 4815 /// helper to hold the reference for the next object element
ferencd@0 4816 BasicJsonType* object_element = nullptr;
ferencd@0 4817 /// whether a syntax error occurred
ferencd@0 4818 bool errored = false;
ferencd@0 4819 /// callback function
ferencd@0 4820 const parser_callback_t callback = nullptr;
ferencd@0 4821 /// whether to throw exceptions in case of errors
ferencd@0 4822 const bool allow_exceptions = true;
ferencd@0 4823 /// a discarded value for the callback
ferencd@0 4824 BasicJsonType discarded = BasicJsonType::value_t::discarded;
ferencd@0 4825 };
ferencd@0 4826
ferencd@0 4827 template<typename BasicJsonType>
ferencd@0 4828 class json_sax_acceptor
ferencd@0 4829 {
ferencd@0 4830 public:
ferencd@0 4831 using number_integer_t = typename BasicJsonType::number_integer_t;
ferencd@0 4832 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
ferencd@0 4833 using number_float_t = typename BasicJsonType::number_float_t;
ferencd@0 4834 using string_t = typename BasicJsonType::string_t;
ferencd@0 4835
ferencd@0 4836 bool null()
ferencd@0 4837 {
ferencd@0 4838 return true;
ferencd@0 4839 }
ferencd@0 4840
ferencd@0 4841 bool boolean(bool /*unused*/)
ferencd@0 4842 {
ferencd@0 4843 return true;
ferencd@0 4844 }
ferencd@0 4845
ferencd@0 4846 bool number_integer(number_integer_t /*unused*/)
ferencd@0 4847 {
ferencd@0 4848 return true;
ferencd@0 4849 }
ferencd@0 4850
ferencd@0 4851 bool number_unsigned(number_unsigned_t /*unused*/)
ferencd@0 4852 {
ferencd@0 4853 return true;
ferencd@0 4854 }
ferencd@0 4855
ferencd@0 4856 bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
ferencd@0 4857 {
ferencd@0 4858 return true;
ferencd@0 4859 }
ferencd@0 4860
ferencd@0 4861 bool string(string_t& /*unused*/)
ferencd@0 4862 {
ferencd@0 4863 return true;
ferencd@0 4864 }
ferencd@0 4865
ferencd@0 4866 bool start_object(std::size_t /*unused*/ = std::size_t(-1))
ferencd@0 4867 {
ferencd@0 4868 return true;
ferencd@0 4869 }
ferencd@0 4870
ferencd@0 4871 bool key(string_t& /*unused*/)
ferencd@0 4872 {
ferencd@0 4873 return true;
ferencd@0 4874 }
ferencd@0 4875
ferencd@0 4876 bool end_object()
ferencd@0 4877 {
ferencd@0 4878 return true;
ferencd@0 4879 }
ferencd@0 4880
ferencd@0 4881 bool start_array(std::size_t /*unused*/ = std::size_t(-1))
ferencd@0 4882 {
ferencd@0 4883 return true;
ferencd@0 4884 }
ferencd@0 4885
ferencd@0 4886 bool end_array()
ferencd@0 4887 {
ferencd@0 4888 return true;
ferencd@0 4889 }
ferencd@0 4890
ferencd@0 4891 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)
ferencd@0 4892 {
ferencd@0 4893 return false;
ferencd@0 4894 }
ferencd@0 4895 };
ferencd@0 4896 } // namespace detail
ferencd@0 4897
ferencd@0 4898 } // namespace nlohmann
ferencd@0 4899
ferencd@0 4900 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 4901
ferencd@0 4902 // #include <nlohmann/detail/meta/is_sax.hpp>
ferencd@0 4903
ferencd@0 4904
ferencd@0 4905 #include <cstdint> // size_t
ferencd@0 4906 #include <utility> // declval
ferencd@0 4907 #include <string> // string
ferencd@0 4908
ferencd@0 4909 // #include <nlohmann/detail/meta/detected.hpp>
ferencd@0 4910
ferencd@0 4911 // #include <nlohmann/detail/meta/type_traits.hpp>
ferencd@0 4912
ferencd@0 4913
ferencd@0 4914 namespace nlohmann
ferencd@0 4915 {
ferencd@0 4916 namespace detail
ferencd@0 4917 {
ferencd@0 4918 template <typename T>
ferencd@0 4919 using null_function_t = decltype(std::declval<T&>().null());
ferencd@0 4920
ferencd@0 4921 template <typename T>
ferencd@0 4922 using boolean_function_t =
ferencd@0 4923 decltype(std::declval<T&>().boolean(std::declval<bool>()));
ferencd@0 4924
ferencd@0 4925 template <typename T, typename Integer>
ferencd@0 4926 using number_integer_function_t =
ferencd@0 4927 decltype(std::declval<T&>().number_integer(std::declval<Integer>()));
ferencd@0 4928
ferencd@0 4929 template <typename T, typename Unsigned>
ferencd@0 4930 using number_unsigned_function_t =
ferencd@0 4931 decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));
ferencd@0 4932
ferencd@0 4933 template <typename T, typename Float, typename String>
ferencd@0 4934 using number_float_function_t = decltype(std::declval<T&>().number_float(
ferencd@0 4935 std::declval<Float>(), std::declval<const String&>()));
ferencd@0 4936
ferencd@0 4937 template <typename T, typename String>
ferencd@0 4938 using string_function_t =
ferencd@0 4939 decltype(std::declval<T&>().string(std::declval<String&>()));
ferencd@0 4940
ferencd@0 4941 template <typename T>
ferencd@0 4942 using start_object_function_t =
ferencd@0 4943 decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));
ferencd@0 4944
ferencd@0 4945 template <typename T, typename String>
ferencd@0 4946 using key_function_t =
ferencd@0 4947 decltype(std::declval<T&>().key(std::declval<String&>()));
ferencd@0 4948
ferencd@0 4949 template <typename T>
ferencd@0 4950 using end_object_function_t = decltype(std::declval<T&>().end_object());
ferencd@0 4951
ferencd@0 4952 template <typename T>
ferencd@0 4953 using start_array_function_t =
ferencd@0 4954 decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));
ferencd@0 4955
ferencd@0 4956 template <typename T>
ferencd@0 4957 using end_array_function_t = decltype(std::declval<T&>().end_array());
ferencd@0 4958
ferencd@0 4959 template <typename T, typename Exception>
ferencd@0 4960 using parse_error_function_t = decltype(std::declval<T&>().parse_error(
ferencd@0 4961 std::declval<std::size_t>(), std::declval<const std::string&>(),
ferencd@0 4962 std::declval<const Exception&>()));
ferencd@0 4963
ferencd@0 4964 template <typename SAX, typename BasicJsonType>
ferencd@0 4965 struct is_sax
ferencd@0 4966 {
ferencd@0 4967 private:
ferencd@0 4968 static_assert(is_basic_json<BasicJsonType>::value,
ferencd@0 4969 "BasicJsonType must be of type basic_json<...>");
ferencd@0 4970
ferencd@0 4971 using number_integer_t = typename BasicJsonType::number_integer_t;
ferencd@0 4972 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
ferencd@0 4973 using number_float_t = typename BasicJsonType::number_float_t;
ferencd@0 4974 using string_t = typename BasicJsonType::string_t;
ferencd@0 4975 using exception_t = typename BasicJsonType::exception;
ferencd@0 4976
ferencd@0 4977 public:
ferencd@0 4978 static constexpr bool value =
ferencd@0 4979 is_detected_exact<bool, null_function_t, SAX>::value &&
ferencd@0 4980 is_detected_exact<bool, boolean_function_t, SAX>::value &&
ferencd@0 4981 is_detected_exact<bool, number_integer_function_t, SAX,
ferencd@0 4982 number_integer_t>::value &&
ferencd@0 4983 is_detected_exact<bool, number_unsigned_function_t, SAX,
ferencd@0 4984 number_unsigned_t>::value &&
ferencd@0 4985 is_detected_exact<bool, number_float_function_t, SAX, number_float_t,
ferencd@0 4986 string_t>::value &&
ferencd@0 4987 is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
ferencd@0 4988 is_detected_exact<bool, start_object_function_t, SAX>::value &&
ferencd@0 4989 is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
ferencd@0 4990 is_detected_exact<bool, end_object_function_t, SAX>::value &&
ferencd@0 4991 is_detected_exact<bool, start_array_function_t, SAX>::value &&
ferencd@0 4992 is_detected_exact<bool, end_array_function_t, SAX>::value &&
ferencd@0 4993 is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
ferencd@0 4994 };
ferencd@0 4995
ferencd@0 4996 template <typename SAX, typename BasicJsonType>
ferencd@0 4997 struct is_sax_static_asserts
ferencd@0 4998 {
ferencd@0 4999 private:
ferencd@0 5000 static_assert(is_basic_json<BasicJsonType>::value,
ferencd@0 5001 "BasicJsonType must be of type basic_json<...>");
ferencd@0 5002
ferencd@0 5003 using number_integer_t = typename BasicJsonType::number_integer_t;
ferencd@0 5004 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
ferencd@0 5005 using number_float_t = typename BasicJsonType::number_float_t;
ferencd@0 5006 using string_t = typename BasicJsonType::string_t;
ferencd@0 5007 using exception_t = typename BasicJsonType::exception;
ferencd@0 5008
ferencd@0 5009 public:
ferencd@0 5010 static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
ferencd@0 5011 "Missing/invalid function: bool null()");
ferencd@0 5012 static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
ferencd@0 5013 "Missing/invalid function: bool boolean(bool)");
ferencd@0 5014 static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
ferencd@0 5015 "Missing/invalid function: bool boolean(bool)");
ferencd@0 5016 static_assert(
ferencd@0 5017 is_detected_exact<bool, number_integer_function_t, SAX,
ferencd@0 5018 number_integer_t>::value,
ferencd@0 5019 "Missing/invalid function: bool number_integer(number_integer_t)");
ferencd@0 5020 static_assert(
ferencd@0 5021 is_detected_exact<bool, number_unsigned_function_t, SAX,
ferencd@0 5022 number_unsigned_t>::value,
ferencd@0 5023 "Missing/invalid function: bool number_unsigned(number_unsigned_t)");
ferencd@0 5024 static_assert(is_detected_exact<bool, number_float_function_t, SAX,
ferencd@0 5025 number_float_t, string_t>::value,
ferencd@0 5026 "Missing/invalid function: bool number_float(number_float_t, const string_t&)");
ferencd@0 5027 static_assert(
ferencd@0 5028 is_detected_exact<bool, string_function_t, SAX, string_t>::value,
ferencd@0 5029 "Missing/invalid function: bool string(string_t&)");
ferencd@0 5030 static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
ferencd@0 5031 "Missing/invalid function: bool start_object(std::size_t)");
ferencd@0 5032 static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,
ferencd@0 5033 "Missing/invalid function: bool key(string_t&)");
ferencd@0 5034 static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
ferencd@0 5035 "Missing/invalid function: bool end_object()");
ferencd@0 5036 static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
ferencd@0 5037 "Missing/invalid function: bool start_array(std::size_t)");
ferencd@0 5038 static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
ferencd@0 5039 "Missing/invalid function: bool end_array()");
ferencd@0 5040 static_assert(
ferencd@0 5041 is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
ferencd@0 5042 "Missing/invalid function: bool parse_error(std::size_t, const "
ferencd@0 5043 "std::string&, const exception&)");
ferencd@0 5044 };
ferencd@0 5045 } // namespace detail
ferencd@0 5046 } // namespace nlohmann
ferencd@0 5047
ferencd@0 5048 // #include <nlohmann/detail/value_t.hpp>
ferencd@0 5049
ferencd@0 5050
ferencd@0 5051 namespace nlohmann
ferencd@0 5052 {
ferencd@0 5053 namespace detail
ferencd@0 5054 {
ferencd@0 5055 ///////////////////
ferencd@0 5056 // binary reader //
ferencd@0 5057 ///////////////////
ferencd@0 5058
ferencd@0 5059 /*!
ferencd@0 5060 @brief deserialization of CBOR, MessagePack, and UBJSON values
ferencd@0 5061 */
ferencd@0 5062 template<typename BasicJsonType, typename SAX = json_sax_dom_parser<BasicJsonType>>
ferencd@0 5063 class binary_reader
ferencd@0 5064 {
ferencd@0 5065 using number_integer_t = typename BasicJsonType::number_integer_t;
ferencd@0 5066 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
ferencd@0 5067 using number_float_t = typename BasicJsonType::number_float_t;
ferencd@0 5068 using string_t = typename BasicJsonType::string_t;
ferencd@0 5069 using json_sax_t = SAX;
ferencd@0 5070
ferencd@0 5071 public:
ferencd@0 5072 /*!
ferencd@0 5073 @brief create a binary reader
ferencd@0 5074
ferencd@0 5075 @param[in] adapter input adapter to read from
ferencd@0 5076 */
ferencd@0 5077 explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter))
ferencd@0 5078 {
ferencd@0 5079 (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
ferencd@0 5080 assert(ia);
ferencd@0 5081 }
ferencd@0 5082
ferencd@0 5083 // make class move-only
ferencd@0 5084 binary_reader(const binary_reader&) = delete;
ferencd@0 5085 binary_reader(binary_reader&&) = default;
ferencd@0 5086 binary_reader& operator=(const binary_reader&) = delete;
ferencd@0 5087 binary_reader& operator=(binary_reader&&) = default;
ferencd@0 5088 ~binary_reader() = default;
ferencd@0 5089
ferencd@0 5090 /*!
ferencd@0 5091 @param[in] format the binary format to parse
ferencd@0 5092 @param[in] sax_ a SAX event processor
ferencd@0 5093 @param[in] strict whether to expect the input to be consumed completed
ferencd@0 5094
ferencd@0 5095 @return
ferencd@0 5096 */
ferencd@0 5097 JSON_HEDLEY_NON_NULL(3)
ferencd@0 5098 bool sax_parse(const input_format_t format,
ferencd@0 5099 json_sax_t* sax_,
ferencd@0 5100 const bool strict = true)
ferencd@0 5101 {
ferencd@0 5102 sax = sax_;
ferencd@0 5103 bool result = false;
ferencd@0 5104
ferencd@0 5105 switch (format)
ferencd@0 5106 {
ferencd@0 5107 case input_format_t::bson:
ferencd@0 5108 result = parse_bson_internal();
ferencd@0 5109 break;
ferencd@0 5110
ferencd@0 5111 case input_format_t::cbor:
ferencd@0 5112 result = parse_cbor_internal();
ferencd@0 5113 break;
ferencd@0 5114
ferencd@0 5115 case input_format_t::msgpack:
ferencd@0 5116 result = parse_msgpack_internal();
ferencd@0 5117 break;
ferencd@0 5118
ferencd@0 5119 case input_format_t::ubjson:
ferencd@0 5120 result = parse_ubjson_internal();
ferencd@0 5121 break;
ferencd@0 5122
ferencd@0 5123 default: // LCOV_EXCL_LINE
ferencd@0 5124 assert(false); // LCOV_EXCL_LINE
ferencd@0 5125 }
ferencd@0 5126
ferencd@0 5127 // strict mode: next byte must be EOF
ferencd@0 5128 if (result and strict)
ferencd@0 5129 {
ferencd@0 5130 if (format == input_format_t::ubjson)
ferencd@0 5131 {
ferencd@0 5132 get_ignore_noop();
ferencd@0 5133 }
ferencd@0 5134 else
ferencd@0 5135 {
ferencd@0 5136 get();
ferencd@0 5137 }
ferencd@0 5138
ferencd@0 5139 if (JSON_HEDLEY_UNLIKELY(current != std::char_traits<char>::eof()))
ferencd@0 5140 {
ferencd@0 5141 return sax->parse_error(chars_read, get_token_string(),
ferencd@0 5142 parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value")));
ferencd@0 5143 }
ferencd@0 5144 }
ferencd@0 5145
ferencd@0 5146 return result;
ferencd@0 5147 }
ferencd@0 5148
ferencd@0 5149 /*!
ferencd@0 5150 @brief determine system byte order
ferencd@0 5151
ferencd@0 5152 @return true if and only if system's byte order is little endian
ferencd@0 5153
ferencd@0 5154 @note from http://stackoverflow.com/a/1001328/266378
ferencd@0 5155 */
ferencd@0 5156 static constexpr bool little_endianess(int num = 1) noexcept
ferencd@0 5157 {
ferencd@0 5158 return *reinterpret_cast<char*>(&num) == 1;
ferencd@0 5159 }
ferencd@0 5160
ferencd@0 5161 private:
ferencd@0 5162 //////////
ferencd@0 5163 // BSON //
ferencd@0 5164 //////////
ferencd@0 5165
ferencd@0 5166 /*!
ferencd@0 5167 @brief Reads in a BSON-object and passes it to the SAX-parser.
ferencd@0 5168 @return whether a valid BSON-value was passed to the SAX parser
ferencd@0 5169 */
ferencd@0 5170 bool parse_bson_internal()
ferencd@0 5171 {
ferencd@0 5172 std::int32_t document_size;
ferencd@0 5173 get_number<std::int32_t, true>(input_format_t::bson, document_size);
ferencd@0 5174
ferencd@0 5175 if (JSON_HEDLEY_UNLIKELY(not sax->start_object(std::size_t(-1))))
ferencd@0 5176 {
ferencd@0 5177 return false;
ferencd@0 5178 }
ferencd@0 5179
ferencd@0 5180 if (JSON_HEDLEY_UNLIKELY(not parse_bson_element_list(/*is_array*/false)))
ferencd@0 5181 {
ferencd@0 5182 return false;
ferencd@0 5183 }
ferencd@0 5184
ferencd@0 5185 return sax->end_object();
ferencd@0 5186 }
ferencd@0 5187
ferencd@0 5188 /*!
ferencd@0 5189 @brief Parses a C-style string from the BSON input.
ferencd@0 5190 @param[in, out] result A reference to the string variable where the read
ferencd@0 5191 string is to be stored.
ferencd@0 5192 @return `true` if the \x00-byte indicating the end of the string was
ferencd@0 5193 encountered before the EOF; false` indicates an unexpected EOF.
ferencd@0 5194 */
ferencd@0 5195 bool get_bson_cstr(string_t& result)
ferencd@0 5196 {
ferencd@0 5197 auto out = std::back_inserter(result);
ferencd@0 5198 while (true)
ferencd@0 5199 {
ferencd@0 5200 get();
ferencd@0 5201 if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::bson, "cstring")))
ferencd@0 5202 {
ferencd@0 5203 return false;
ferencd@0 5204 }
ferencd@0 5205 if (current == 0x00)
ferencd@0 5206 {
ferencd@0 5207 return true;
ferencd@0 5208 }
ferencd@0 5209 *out++ = static_cast<char>(current);
ferencd@0 5210 }
ferencd@0 5211
ferencd@0 5212 return true;
ferencd@0 5213 }
ferencd@0 5214
ferencd@0 5215 /*!
ferencd@0 5216 @brief Parses a zero-terminated string of length @a len from the BSON
ferencd@0 5217 input.
ferencd@0 5218 @param[in] len The length (including the zero-byte at the end) of the
ferencd@0 5219 string to be read.
ferencd@0 5220 @param[in, out] result A reference to the string variable where the read
ferencd@0 5221 string is to be stored.
ferencd@0 5222 @tparam NumberType The type of the length @a len
ferencd@0 5223 @pre len >= 1
ferencd@0 5224 @return `true` if the string was successfully parsed
ferencd@0 5225 */
ferencd@0 5226 template<typename NumberType>
ferencd@0 5227 bool get_bson_string(const NumberType len, string_t& result)
ferencd@0 5228 {
ferencd@0 5229 if (JSON_HEDLEY_UNLIKELY(len < 1))
ferencd@0 5230 {
ferencd@0 5231 auto last_token = get_token_string();
ferencd@0 5232 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string")));
ferencd@0 5233 }
ferencd@0 5234
ferencd@0 5235 return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) and get() != std::char_traits<char>::eof();
ferencd@0 5236 }
ferencd@0 5237
ferencd@0 5238 /*!
ferencd@0 5239 @brief Read a BSON document element of the given @a element_type.
ferencd@0 5240 @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html
ferencd@0 5241 @param[in] element_type_parse_position The position in the input stream,
ferencd@0 5242 where the `element_type` was read.
ferencd@0 5243 @warning Not all BSON element types are supported yet. An unsupported
ferencd@0 5244 @a element_type will give rise to a parse_error.114:
ferencd@0 5245 Unsupported BSON record type 0x...
ferencd@0 5246 @return whether a valid BSON-object/array was passed to the SAX parser
ferencd@0 5247 */
ferencd@0 5248 bool parse_bson_element_internal(const int element_type,
ferencd@0 5249 const std::size_t element_type_parse_position)
ferencd@0 5250 {
ferencd@0 5251 switch (element_type)
ferencd@0 5252 {
ferencd@0 5253 case 0x01: // double
ferencd@0 5254 {
ferencd@0 5255 double number;
ferencd@0 5256 return get_number<double, true>(input_format_t::bson, number) and sax->number_float(static_cast<number_float_t>(number), "");
ferencd@0 5257 }
ferencd@0 5258
ferencd@0 5259 case 0x02: // string
ferencd@0 5260 {
ferencd@0 5261 std::int32_t len;
ferencd@0 5262 string_t value;
ferencd@0 5263 return get_number<std::int32_t, true>(input_format_t::bson, len) and get_bson_string(len, value) and sax->string(value);
ferencd@0 5264 }
ferencd@0 5265
ferencd@0 5266 case 0x03: // object
ferencd@0 5267 {
ferencd@0 5268 return parse_bson_internal();
ferencd@0 5269 }
ferencd@0 5270
ferencd@0 5271 case 0x04: // array
ferencd@0 5272 {
ferencd@0 5273 return parse_bson_array();
ferencd@0 5274 }
ferencd@0 5275
ferencd@0 5276 case 0x08: // boolean
ferencd@0 5277 {
ferencd@0 5278 return sax->boolean(get() != 0);
ferencd@0 5279 }
ferencd@0 5280
ferencd@0 5281 case 0x0A: // null
ferencd@0 5282 {
ferencd@0 5283 return sax->null();
ferencd@0 5284 }
ferencd@0 5285
ferencd@0 5286 case 0x10: // int32
ferencd@0 5287 {
ferencd@0 5288 std::int32_t value;
ferencd@0 5289 return get_number<std::int32_t, true>(input_format_t::bson, value) and sax->number_integer(value);
ferencd@0 5290 }
ferencd@0 5291
ferencd@0 5292 case 0x12: // int64
ferencd@0 5293 {
ferencd@0 5294 std::int64_t value;
ferencd@0 5295 return get_number<std::int64_t, true>(input_format_t::bson, value) and sax->number_integer(value);
ferencd@0 5296 }
ferencd@0 5297
ferencd@0 5298 default: // anything else not supported (yet)
ferencd@0 5299 {
ferencd@0 5300 std::array<char, 3> cr{{}};
ferencd@0 5301 (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type));
ferencd@0 5302 return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data())));
ferencd@0 5303 }
ferencd@0 5304 }
ferencd@0 5305 }
ferencd@0 5306
ferencd@0 5307 /*!
ferencd@0 5308 @brief Read a BSON element list (as specified in the BSON-spec)
ferencd@0 5309
ferencd@0 5310 The same binary layout is used for objects and arrays, hence it must be
ferencd@0 5311 indicated with the argument @a is_array which one is expected
ferencd@0 5312 (true --> array, false --> object).
ferencd@0 5313
ferencd@0 5314 @param[in] is_array Determines if the element list being read is to be
ferencd@0 5315 treated as an object (@a is_array == false), or as an
ferencd@0 5316 array (@a is_array == true).
ferencd@0 5317 @return whether a valid BSON-object/array was passed to the SAX parser
ferencd@0 5318 */
ferencd@0 5319 bool parse_bson_element_list(const bool is_array)
ferencd@0 5320 {
ferencd@0 5321 string_t key;
ferencd@0 5322 while (int element_type = get())
ferencd@0 5323 {
ferencd@0 5324 if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::bson, "element list")))
ferencd@0 5325 {
ferencd@0 5326 return false;
ferencd@0 5327 }
ferencd@0 5328
ferencd@0 5329 const std::size_t element_type_parse_position = chars_read;
ferencd@0 5330 if (JSON_HEDLEY_UNLIKELY(not get_bson_cstr(key)))
ferencd@0 5331 {
ferencd@0 5332 return false;
ferencd@0 5333 }
ferencd@0 5334
ferencd@0 5335 if (not is_array and not sax->key(key))
ferencd@0 5336 {
ferencd@0 5337 return false;
ferencd@0 5338 }
ferencd@0 5339
ferencd@0 5340 if (JSON_HEDLEY_UNLIKELY(not parse_bson_element_internal(element_type, element_type_parse_position)))
ferencd@0 5341 {
ferencd@0 5342 return false;
ferencd@0 5343 }
ferencd@0 5344
ferencd@0 5345 // get_bson_cstr only appends
ferencd@0 5346 key.clear();
ferencd@0 5347 }
ferencd@0 5348
ferencd@0 5349 return true;
ferencd@0 5350 }
ferencd@0 5351
ferencd@0 5352 /*!
ferencd@0 5353 @brief Reads an array from the BSON input and passes it to the SAX-parser.
ferencd@0 5354 @return whether a valid BSON-array was passed to the SAX parser
ferencd@0 5355 */
ferencd@0 5356 bool parse_bson_array()
ferencd@0 5357 {
ferencd@0 5358 std::int32_t document_size;
ferencd@0 5359 get_number<std::int32_t, true>(input_format_t::bson, document_size);
ferencd@0 5360
ferencd@0 5361 if (JSON_HEDLEY_UNLIKELY(not sax->start_array(std::size_t(-1))))
ferencd@0 5362 {
ferencd@0 5363 return false;
ferencd@0 5364 }
ferencd@0 5365
ferencd@0 5366 if (JSON_HEDLEY_UNLIKELY(not parse_bson_element_list(/*is_array*/true)))
ferencd@0 5367 {
ferencd@0 5368 return false;
ferencd@0 5369 }
ferencd@0 5370
ferencd@0 5371 return sax->end_array();
ferencd@0 5372 }
ferencd@0 5373
ferencd@0 5374 //////////
ferencd@0 5375 // CBOR //
ferencd@0 5376 //////////
ferencd@0 5377
ferencd@0 5378 /*!
ferencd@0 5379 @param[in] get_char whether a new character should be retrieved from the
ferencd@0 5380 input (true, default) or whether the last read
ferencd@0 5381 character should be considered instead
ferencd@0 5382
ferencd@0 5383 @return whether a valid CBOR value was passed to the SAX parser
ferencd@0 5384 */
ferencd@0 5385 bool parse_cbor_internal(const bool get_char = true)
ferencd@0 5386 {
ferencd@0 5387 switch (get_char ? get() : current)
ferencd@0 5388 {
ferencd@0 5389 // EOF
ferencd@0 5390 case std::char_traits<char>::eof():
ferencd@0 5391 return unexpect_eof(input_format_t::cbor, "value");
ferencd@0 5392
ferencd@0 5393 // Integer 0x00..0x17 (0..23)
ferencd@0 5394 case 0x00:
ferencd@0 5395 case 0x01:
ferencd@0 5396 case 0x02:
ferencd@0 5397 case 0x03:
ferencd@0 5398 case 0x04:
ferencd@0 5399 case 0x05:
ferencd@0 5400 case 0x06:
ferencd@0 5401 case 0x07:
ferencd@0 5402 case 0x08:
ferencd@0 5403 case 0x09:
ferencd@0 5404 case 0x0A:
ferencd@0 5405 case 0x0B:
ferencd@0 5406 case 0x0C:
ferencd@0 5407 case 0x0D:
ferencd@0 5408 case 0x0E:
ferencd@0 5409 case 0x0F:
ferencd@0 5410 case 0x10:
ferencd@0 5411 case 0x11:
ferencd@0 5412 case 0x12:
ferencd@0 5413 case 0x13:
ferencd@0 5414 case 0x14:
ferencd@0 5415 case 0x15:
ferencd@0 5416 case 0x16:
ferencd@0 5417 case 0x17:
ferencd@0 5418 return sax->number_unsigned(static_cast<number_unsigned_t>(current));
ferencd@0 5419
ferencd@0 5420 case 0x18: // Unsigned integer (one-byte uint8_t follows)
ferencd@0 5421 {
ferencd@0 5422 std::uint8_t number;
ferencd@0 5423 return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
ferencd@0 5424 }
ferencd@0 5425
ferencd@0 5426 case 0x19: // Unsigned integer (two-byte uint16_t follows)
ferencd@0 5427 {
ferencd@0 5428 std::uint16_t number;
ferencd@0 5429 return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
ferencd@0 5430 }
ferencd@0 5431
ferencd@0 5432 case 0x1A: // Unsigned integer (four-byte uint32_t follows)
ferencd@0 5433 {
ferencd@0 5434 std::uint32_t number;
ferencd@0 5435 return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
ferencd@0 5436 }
ferencd@0 5437
ferencd@0 5438 case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
ferencd@0 5439 {
ferencd@0 5440 std::uint64_t number;
ferencd@0 5441 return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
ferencd@0 5442 }
ferencd@0 5443
ferencd@0 5444 // Negative integer -1-0x00..-1-0x17 (-1..-24)
ferencd@0 5445 case 0x20:
ferencd@0 5446 case 0x21:
ferencd@0 5447 case 0x22:
ferencd@0 5448 case 0x23:
ferencd@0 5449 case 0x24:
ferencd@0 5450 case 0x25:
ferencd@0 5451 case 0x26:
ferencd@0 5452 case 0x27:
ferencd@0 5453 case 0x28:
ferencd@0 5454 case 0x29:
ferencd@0 5455 case 0x2A:
ferencd@0 5456 case 0x2B:
ferencd@0 5457 case 0x2C:
ferencd@0 5458 case 0x2D:
ferencd@0 5459 case 0x2E:
ferencd@0 5460 case 0x2F:
ferencd@0 5461 case 0x30:
ferencd@0 5462 case 0x31:
ferencd@0 5463 case 0x32:
ferencd@0 5464 case 0x33:
ferencd@0 5465 case 0x34:
ferencd@0 5466 case 0x35:
ferencd@0 5467 case 0x36:
ferencd@0 5468 case 0x37:
ferencd@0 5469 return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));
ferencd@0 5470
ferencd@0 5471 case 0x38: // Negative integer (one-byte uint8_t follows)
ferencd@0 5472 {
ferencd@0 5473 std::uint8_t number;
ferencd@0 5474 return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
ferencd@0 5475 }
ferencd@0 5476
ferencd@0 5477 case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
ferencd@0 5478 {
ferencd@0 5479 std::uint16_t number;
ferencd@0 5480 return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
ferencd@0 5481 }
ferencd@0 5482
ferencd@0 5483 case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
ferencd@0 5484 {
ferencd@0 5485 std::uint32_t number;
ferencd@0 5486 return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
ferencd@0 5487 }
ferencd@0 5488
ferencd@0 5489 case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
ferencd@0 5490 {
ferencd@0 5491 std::uint64_t number;
ferencd@0 5492 return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1)
ferencd@0 5493 - static_cast<number_integer_t>(number));
ferencd@0 5494 }
ferencd@0 5495
ferencd@0 5496 // UTF-8 string (0x00..0x17 bytes follow)
ferencd@0 5497 case 0x60:
ferencd@0 5498 case 0x61:
ferencd@0 5499 case 0x62:
ferencd@0 5500 case 0x63:
ferencd@0 5501 case 0x64:
ferencd@0 5502 case 0x65:
ferencd@0 5503 case 0x66:
ferencd@0 5504 case 0x67:
ferencd@0 5505 case 0x68:
ferencd@0 5506 case 0x69:
ferencd@0 5507 case 0x6A:
ferencd@0 5508 case 0x6B:
ferencd@0 5509 case 0x6C:
ferencd@0 5510 case 0x6D:
ferencd@0 5511 case 0x6E:
ferencd@0 5512 case 0x6F:
ferencd@0 5513 case 0x70:
ferencd@0 5514 case 0x71:
ferencd@0 5515 case 0x72:
ferencd@0 5516 case 0x73:
ferencd@0 5517 case 0x74:
ferencd@0 5518 case 0x75:
ferencd@0 5519 case 0x76:
ferencd@0 5520 case 0x77:
ferencd@0 5521 case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
ferencd@0 5522 case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
ferencd@0 5523 case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
ferencd@0 5524 case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
ferencd@0 5525 case 0x7F: // UTF-8 string (indefinite length)
ferencd@0 5526 {
ferencd@0 5527 string_t s;
ferencd@0 5528 return get_cbor_string(s) and sax->string(s);
ferencd@0 5529 }
ferencd@0 5530
ferencd@0 5531 // array (0x00..0x17 data items follow)
ferencd@0 5532 case 0x80:
ferencd@0 5533 case 0x81:
ferencd@0 5534 case 0x82:
ferencd@0 5535 case 0x83:
ferencd@0 5536 case 0x84:
ferencd@0 5537 case 0x85:
ferencd@0 5538 case 0x86:
ferencd@0 5539 case 0x87:
ferencd@0 5540 case 0x88:
ferencd@0 5541 case 0x89:
ferencd@0 5542 case 0x8A:
ferencd@0 5543 case 0x8B:
ferencd@0 5544 case 0x8C:
ferencd@0 5545 case 0x8D:
ferencd@0 5546 case 0x8E:
ferencd@0 5547 case 0x8F:
ferencd@0 5548 case 0x90:
ferencd@0 5549 case 0x91:
ferencd@0 5550 case 0x92:
ferencd@0 5551 case 0x93:
ferencd@0 5552 case 0x94:
ferencd@0 5553 case 0x95:
ferencd@0 5554 case 0x96:
ferencd@0 5555 case 0x97:
ferencd@0 5556 return get_cbor_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
ferencd@0 5557
ferencd@0 5558 case 0x98: // array (one-byte uint8_t for n follows)
ferencd@0 5559 {
ferencd@0 5560 std::uint8_t len;
ferencd@0 5561 return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
ferencd@0 5562 }
ferencd@0 5563
ferencd@0 5564 case 0x99: // array (two-byte uint16_t for n follow)
ferencd@0 5565 {
ferencd@0 5566 std::uint16_t len;
ferencd@0 5567 return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
ferencd@0 5568 }
ferencd@0 5569
ferencd@0 5570 case 0x9A: // array (four-byte uint32_t for n follow)
ferencd@0 5571 {
ferencd@0 5572 std::uint32_t len;
ferencd@0 5573 return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
ferencd@0 5574 }
ferencd@0 5575
ferencd@0 5576 case 0x9B: // array (eight-byte uint64_t for n follow)
ferencd@0 5577 {
ferencd@0 5578 std::uint64_t len;
ferencd@0 5579 return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
ferencd@0 5580 }
ferencd@0 5581
ferencd@0 5582 case 0x9F: // array (indefinite length)
ferencd@0 5583 return get_cbor_array(std::size_t(-1));
ferencd@0 5584
ferencd@0 5585 // map (0x00..0x17 pairs of data items follow)
ferencd@0 5586 case 0xA0:
ferencd@0 5587 case 0xA1:
ferencd@0 5588 case 0xA2:
ferencd@0 5589 case 0xA3:
ferencd@0 5590 case 0xA4:
ferencd@0 5591 case 0xA5:
ferencd@0 5592 case 0xA6:
ferencd@0 5593 case 0xA7:
ferencd@0 5594 case 0xA8:
ferencd@0 5595 case 0xA9:
ferencd@0 5596 case 0xAA:
ferencd@0 5597 case 0xAB:
ferencd@0 5598 case 0xAC:
ferencd@0 5599 case 0xAD:
ferencd@0 5600 case 0xAE:
ferencd@0 5601 case 0xAF:
ferencd@0 5602 case 0xB0:
ferencd@0 5603 case 0xB1:
ferencd@0 5604 case 0xB2:
ferencd@0 5605 case 0xB3:
ferencd@0 5606 case 0xB4:
ferencd@0 5607 case 0xB5:
ferencd@0 5608 case 0xB6:
ferencd@0 5609 case 0xB7:
ferencd@0 5610 return get_cbor_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
ferencd@0 5611
ferencd@0 5612 case 0xB8: // map (one-byte uint8_t for n follows)
ferencd@0 5613 {
ferencd@0 5614 std::uint8_t len;
ferencd@0 5615 return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
ferencd@0 5616 }
ferencd@0 5617
ferencd@0 5618 case 0xB9: // map (two-byte uint16_t for n follow)
ferencd@0 5619 {
ferencd@0 5620 std::uint16_t len;
ferencd@0 5621 return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
ferencd@0 5622 }
ferencd@0 5623
ferencd@0 5624 case 0xBA: // map (four-byte uint32_t for n follow)
ferencd@0 5625 {
ferencd@0 5626 std::uint32_t len;
ferencd@0 5627 return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
ferencd@0 5628 }
ferencd@0 5629
ferencd@0 5630 case 0xBB: // map (eight-byte uint64_t for n follow)
ferencd@0 5631 {
ferencd@0 5632 std::uint64_t len;
ferencd@0 5633 return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
ferencd@0 5634 }
ferencd@0 5635
ferencd@0 5636 case 0xBF: // map (indefinite length)
ferencd@0 5637 return get_cbor_object(std::size_t(-1));
ferencd@0 5638
ferencd@0 5639 case 0xF4: // false
ferencd@0 5640 return sax->boolean(false);
ferencd@0 5641
ferencd@0 5642 case 0xF5: // true
ferencd@0 5643 return sax->boolean(true);
ferencd@0 5644
ferencd@0 5645 case 0xF6: // null
ferencd@0 5646 return sax->null();
ferencd@0 5647
ferencd@0 5648 case 0xF9: // Half-Precision Float (two-byte IEEE 754)
ferencd@0 5649 {
ferencd@0 5650 const int byte1_raw = get();
ferencd@0 5651 if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number")))
ferencd@0 5652 {
ferencd@0 5653 return false;
ferencd@0 5654 }
ferencd@0 5655 const int byte2_raw = get();
ferencd@0 5656 if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "number")))
ferencd@0 5657 {
ferencd@0 5658 return false;
ferencd@0 5659 }
ferencd@0 5660
ferencd@0 5661 const auto byte1 = static_cast<unsigned char>(byte1_raw);
ferencd@0 5662 const auto byte2 = static_cast<unsigned char>(byte2_raw);
ferencd@0 5663
ferencd@0 5664 // code from RFC 7049, Appendix D, Figure 3:
ferencd@0 5665 // As half-precision floating-point numbers were only added
ferencd@0 5666 // to IEEE 754 in 2008, today's programming platforms often
ferencd@0 5667 // still only have limited support for them. It is very
ferencd@0 5668 // easy to include at least decoding support for them even
ferencd@0 5669 // without such support. An example of a small decoder for
ferencd@0 5670 // half-precision floating-point numbers in the C language
ferencd@0 5671 // is shown in Fig. 3.
ferencd@0 5672 const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);
ferencd@0 5673 const double val = [&half]
ferencd@0 5674 {
ferencd@0 5675 const int exp = (half >> 10u) & 0x1Fu;
ferencd@0 5676 const unsigned int mant = half & 0x3FFu;
ferencd@0 5677 assert(0 <= exp and exp <= 32);
ferencd@0 5678 assert(0 <= mant and mant <= 1024);
ferencd@0 5679 switch (exp)
ferencd@0 5680 {
ferencd@0 5681 case 0:
ferencd@0 5682 return std::ldexp(mant, -24);
ferencd@0 5683 case 31:
ferencd@0 5684 return (mant == 0)
ferencd@0 5685 ? std::numeric_limits<double>::infinity()
ferencd@0 5686 : std::numeric_limits<double>::quiet_NaN();
ferencd@0 5687 default:
ferencd@0 5688 return std::ldexp(mant + 1024, exp - 25);
ferencd@0 5689 }
ferencd@0 5690 }();
ferencd@0 5691 return sax->number_float((half & 0x8000u) != 0
ferencd@0 5692 ? static_cast<number_float_t>(-val)
ferencd@0 5693 : static_cast<number_float_t>(val), "");
ferencd@0 5694 }
ferencd@0 5695
ferencd@0 5696 case 0xFA: // Single-Precision Float (four-byte IEEE 754)
ferencd@0 5697 {
ferencd@0 5698 float number;
ferencd@0 5699 return get_number(input_format_t::cbor, number) and sax->number_float(static_cast<number_float_t>(number), "");
ferencd@0 5700 }
ferencd@0 5701
ferencd@0 5702 case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
ferencd@0 5703 {
ferencd@0 5704 double number;
ferencd@0 5705 return get_number(input_format_t::cbor, number) and sax->number_float(static_cast<number_float_t>(number), "");
ferencd@0 5706 }
ferencd@0 5707
ferencd@0 5708 default: // anything else (0xFF is handled inside the other types)
ferencd@0 5709 {
ferencd@0 5710 auto last_token = get_token_string();
ferencd@0 5711 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value")));
ferencd@0 5712 }
ferencd@0 5713 }
ferencd@0 5714 }
ferencd@0 5715
ferencd@0 5716 /*!
ferencd@0 5717 @brief reads a CBOR string
ferencd@0 5718
ferencd@0 5719 This function first reads starting bytes to determine the expected
ferencd@0 5720 string length and then copies this number of bytes into a string.
ferencd@0 5721 Additionally, CBOR's strings with indefinite lengths are supported.
ferencd@0 5722
ferencd@0 5723 @param[out] result created string
ferencd@0 5724
ferencd@0 5725 @return whether string creation completed
ferencd@0 5726 */
ferencd@0 5727 bool get_cbor_string(string_t& result)
ferencd@0 5728 {
ferencd@0 5729 if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::cbor, "string")))
ferencd@0 5730 {
ferencd@0 5731 return false;
ferencd@0 5732 }
ferencd@0 5733
ferencd@0 5734 switch (current)
ferencd@0 5735 {
ferencd@0 5736 // UTF-8 string (0x00..0x17 bytes follow)
ferencd@0 5737 case 0x60:
ferencd@0 5738 case 0x61:
ferencd@0 5739 case 0x62:
ferencd@0 5740 case 0x63:
ferencd@0 5741 case 0x64:
ferencd@0 5742 case 0x65:
ferencd@0 5743 case 0x66:
ferencd@0 5744 case 0x67:
ferencd@0 5745 case 0x68:
ferencd@0 5746 case 0x69:
ferencd@0 5747 case 0x6A:
ferencd@0 5748 case 0x6B:
ferencd@0 5749 case 0x6C:
ferencd@0 5750 case 0x6D:
ferencd@0 5751 case 0x6E:
ferencd@0 5752 case 0x6F:
ferencd@0 5753 case 0x70:
ferencd@0 5754 case 0x71:
ferencd@0 5755 case 0x72:
ferencd@0 5756 case 0x73:
ferencd@0 5757 case 0x74:
ferencd@0 5758 case 0x75:
ferencd@0 5759 case 0x76:
ferencd@0 5760 case 0x77:
ferencd@0 5761 {
ferencd@0 5762 return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
ferencd@0 5763 }
ferencd@0 5764
ferencd@0 5765 case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
ferencd@0 5766 {
ferencd@0 5767 std::uint8_t len;
ferencd@0 5768 return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
ferencd@0 5769 }
ferencd@0 5770
ferencd@0 5771 case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
ferencd@0 5772 {
ferencd@0 5773 std::uint16_t len;
ferencd@0 5774 return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
ferencd@0 5775 }
ferencd@0 5776
ferencd@0 5777 case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
ferencd@0 5778 {
ferencd@0 5779 std::uint32_t len;
ferencd@0 5780 return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
ferencd@0 5781 }
ferencd@0 5782
ferencd@0 5783 case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
ferencd@0 5784 {
ferencd@0 5785 std::uint64_t len;
ferencd@0 5786 return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
ferencd@0 5787 }
ferencd@0 5788
ferencd@0 5789 case 0x7F: // UTF-8 string (indefinite length)
ferencd@0 5790 {
ferencd@0 5791 while (get() != 0xFF)
ferencd@0 5792 {
ferencd@0 5793 string_t chunk;
ferencd@0 5794 if (not get_cbor_string(chunk))
ferencd@0 5795 {
ferencd@0 5796 return false;
ferencd@0 5797 }
ferencd@0 5798 result.append(chunk);
ferencd@0 5799 }
ferencd@0 5800 return true;
ferencd@0 5801 }
ferencd@0 5802
ferencd@0 5803 default:
ferencd@0 5804 {
ferencd@0 5805 auto last_token = get_token_string();
ferencd@0 5806 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string")));
ferencd@0 5807 }
ferencd@0 5808 }
ferencd@0 5809 }
ferencd@0 5810
ferencd@0 5811 /*!
ferencd@0 5812 @param[in] len the length of the array or std::size_t(-1) for an
ferencd@0 5813 array of indefinite size
ferencd@0 5814 @return whether array creation completed
ferencd@0 5815 */
ferencd@0 5816 bool get_cbor_array(const std::size_t len)
ferencd@0 5817 {
ferencd@0 5818 if (JSON_HEDLEY_UNLIKELY(not sax->start_array(len)))
ferencd@0 5819 {
ferencd@0 5820 return false;
ferencd@0 5821 }
ferencd@0 5822
ferencd@0 5823 if (len != std::size_t(-1))
ferencd@0 5824 {
ferencd@0 5825 for (std::size_t i = 0; i < len; ++i)
ferencd@0 5826 {
ferencd@0 5827 if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal()))
ferencd@0 5828 {
ferencd@0 5829 return false;
ferencd@0 5830 }
ferencd@0 5831 }
ferencd@0 5832 }
ferencd@0 5833 else
ferencd@0 5834 {
ferencd@0 5835 while (get() != 0xFF)
ferencd@0 5836 {
ferencd@0 5837 if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal(false)))
ferencd@0 5838 {
ferencd@0 5839 return false;
ferencd@0 5840 }
ferencd@0 5841 }
ferencd@0 5842 }
ferencd@0 5843
ferencd@0 5844 return sax->end_array();
ferencd@0 5845 }
ferencd@0 5846
ferencd@0 5847 /*!
ferencd@0 5848 @param[in] len the length of the object or std::size_t(-1) for an
ferencd@0 5849 object of indefinite size
ferencd@0 5850 @return whether object creation completed
ferencd@0 5851 */
ferencd@0 5852 bool get_cbor_object(const std::size_t len)
ferencd@0 5853 {
ferencd@0 5854 if (JSON_HEDLEY_UNLIKELY(not sax->start_object(len)))
ferencd@0 5855 {
ferencd@0 5856 return false;
ferencd@0 5857 }
ferencd@0 5858
ferencd@0 5859 string_t key;
ferencd@0 5860 if (len != std::size_t(-1))
ferencd@0 5861 {
ferencd@0 5862 for (std::size_t i = 0; i < len; ++i)
ferencd@0 5863 {
ferencd@0 5864 get();
ferencd@0 5865 if (JSON_HEDLEY_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))
ferencd@0 5866 {
ferencd@0 5867 return false;
ferencd@0 5868 }
ferencd@0 5869
ferencd@0 5870 if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal()))
ferencd@0 5871 {
ferencd@0 5872 return false;
ferencd@0 5873 }
ferencd@0 5874 key.clear();
ferencd@0 5875 }
ferencd@0 5876 }
ferencd@0 5877 else
ferencd@0 5878 {
ferencd@0 5879 while (get() != 0xFF)
ferencd@0 5880 {
ferencd@0 5881 if (JSON_HEDLEY_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))
ferencd@0 5882 {
ferencd@0 5883 return false;
ferencd@0 5884 }
ferencd@0 5885
ferencd@0 5886 if (JSON_HEDLEY_UNLIKELY(not parse_cbor_internal()))
ferencd@0 5887 {
ferencd@0 5888 return false;
ferencd@0 5889 }
ferencd@0 5890 key.clear();
ferencd@0 5891 }
ferencd@0 5892 }
ferencd@0 5893
ferencd@0 5894 return sax->end_object();
ferencd@0 5895 }
ferencd@0 5896
ferencd@0 5897 /////////////
ferencd@0 5898 // MsgPack //
ferencd@0 5899 /////////////
ferencd@0 5900
ferencd@0 5901 /*!
ferencd@0 5902 @return whether a valid MessagePack value was passed to the SAX parser
ferencd@0 5903 */
ferencd@0 5904 bool parse_msgpack_internal()
ferencd@0 5905 {
ferencd@0 5906 switch (get())
ferencd@0 5907 {
ferencd@0 5908 // EOF
ferencd@0 5909 case std::char_traits<char>::eof():
ferencd@0 5910 return unexpect_eof(input_format_t::msgpack, "value");
ferencd@0 5911
ferencd@0 5912 // positive fixint
ferencd@0 5913 case 0x00:
ferencd@0 5914 case 0x01:
ferencd@0 5915 case 0x02:
ferencd@0 5916 case 0x03:
ferencd@0 5917 case 0x04:
ferencd@0 5918 case 0x05:
ferencd@0 5919 case 0x06:
ferencd@0 5920 case 0x07:
ferencd@0 5921 case 0x08:
ferencd@0 5922 case 0x09:
ferencd@0 5923 case 0x0A:
ferencd@0 5924 case 0x0B:
ferencd@0 5925 case 0x0C:
ferencd@0 5926 case 0x0D:
ferencd@0 5927 case 0x0E:
ferencd@0 5928 case 0x0F:
ferencd@0 5929 case 0x10:
ferencd@0 5930 case 0x11:
ferencd@0 5931 case 0x12:
ferencd@0 5932 case 0x13:
ferencd@0 5933 case 0x14:
ferencd@0 5934 case 0x15:
ferencd@0 5935 case 0x16:
ferencd@0 5936 case 0x17:
ferencd@0 5937 case 0x18:
ferencd@0 5938 case 0x19:
ferencd@0 5939 case 0x1A:
ferencd@0 5940 case 0x1B:
ferencd@0 5941 case 0x1C:
ferencd@0 5942 case 0x1D:
ferencd@0 5943 case 0x1E:
ferencd@0 5944 case 0x1F:
ferencd@0 5945 case 0x20:
ferencd@0 5946 case 0x21:
ferencd@0 5947 case 0x22:
ferencd@0 5948 case 0x23:
ferencd@0 5949 case 0x24:
ferencd@0 5950 case 0x25:
ferencd@0 5951 case 0x26:
ferencd@0 5952 case 0x27:
ferencd@0 5953 case 0x28:
ferencd@0 5954 case 0x29:
ferencd@0 5955 case 0x2A:
ferencd@0 5956 case 0x2B:
ferencd@0 5957 case 0x2C:
ferencd@0 5958 case 0x2D:
ferencd@0 5959 case 0x2E:
ferencd@0 5960 case 0x2F:
ferencd@0 5961 case 0x30:
ferencd@0 5962 case 0x31:
ferencd@0 5963 case 0x32:
ferencd@0 5964 case 0x33:
ferencd@0 5965 case 0x34:
ferencd@0 5966 case 0x35:
ferencd@0 5967 case 0x36:
ferencd@0 5968 case 0x37:
ferencd@0 5969 case 0x38:
ferencd@0 5970 case 0x39:
ferencd@0 5971 case 0x3A:
ferencd@0 5972 case 0x3B:
ferencd@0 5973 case 0x3C:
ferencd@0 5974 case 0x3D:
ferencd@0 5975 case 0x3E:
ferencd@0 5976 case 0x3F:
ferencd@0 5977 case 0x40:
ferencd@0 5978 case 0x41:
ferencd@0 5979 case 0x42:
ferencd@0 5980 case 0x43:
ferencd@0 5981 case 0x44:
ferencd@0 5982 case 0x45:
ferencd@0 5983 case 0x46:
ferencd@0 5984 case 0x47:
ferencd@0 5985 case 0x48:
ferencd@0 5986 case 0x49:
ferencd@0 5987 case 0x4A:
ferencd@0 5988 case 0x4B:
ferencd@0 5989 case 0x4C:
ferencd@0 5990 case 0x4D:
ferencd@0 5991 case 0x4E:
ferencd@0 5992 case 0x4F:
ferencd@0 5993 case 0x50:
ferencd@0 5994 case 0x51:
ferencd@0 5995 case 0x52:
ferencd@0 5996 case 0x53:
ferencd@0 5997 case 0x54:
ferencd@0 5998 case 0x55:
ferencd@0 5999 case 0x56:
ferencd@0 6000 case 0x57:
ferencd@0 6001 case 0x58:
ferencd@0 6002 case 0x59:
ferencd@0 6003 case 0x5A:
ferencd@0 6004 case 0x5B:
ferencd@0 6005 case 0x5C:
ferencd@0 6006 case 0x5D:
ferencd@0 6007 case 0x5E:
ferencd@0 6008 case 0x5F:
ferencd@0 6009 case 0x60:
ferencd@0 6010 case 0x61:
ferencd@0 6011 case 0x62:
ferencd@0 6012 case 0x63:
ferencd@0 6013 case 0x64:
ferencd@0 6014 case 0x65:
ferencd@0 6015 case 0x66:
ferencd@0 6016 case 0x67:
ferencd@0 6017 case 0x68:
ferencd@0 6018 case 0x69:
ferencd@0 6019 case 0x6A:
ferencd@0 6020 case 0x6B:
ferencd@0 6021 case 0x6C:
ferencd@0 6022 case 0x6D:
ferencd@0 6023 case 0x6E:
ferencd@0 6024 case 0x6F:
ferencd@0 6025 case 0x70:
ferencd@0 6026 case 0x71:
ferencd@0 6027 case 0x72:
ferencd@0 6028 case 0x73:
ferencd@0 6029 case 0x74:
ferencd@0 6030 case 0x75:
ferencd@0 6031 case 0x76:
ferencd@0 6032 case 0x77:
ferencd@0 6033 case 0x78:
ferencd@0 6034 case 0x79:
ferencd@0 6035 case 0x7A:
ferencd@0 6036 case 0x7B:
ferencd@0 6037 case 0x7C:
ferencd@0 6038 case 0x7D:
ferencd@0 6039 case 0x7E:
ferencd@0 6040 case 0x7F:
ferencd@0 6041 return sax->number_unsigned(static_cast<number_unsigned_t>(current));
ferencd@0 6042
ferencd@0 6043 // fixmap
ferencd@0 6044 case 0x80:
ferencd@0 6045 case 0x81:
ferencd@0 6046 case 0x82:
ferencd@0 6047 case 0x83:
ferencd@0 6048 case 0x84:
ferencd@0 6049 case 0x85:
ferencd@0 6050 case 0x86:
ferencd@0 6051 case 0x87:
ferencd@0 6052 case 0x88:
ferencd@0 6053 case 0x89:
ferencd@0 6054 case 0x8A:
ferencd@0 6055 case 0x8B:
ferencd@0 6056 case 0x8C:
ferencd@0 6057 case 0x8D:
ferencd@0 6058 case 0x8E:
ferencd@0 6059 case 0x8F:
ferencd@0 6060 return get_msgpack_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
ferencd@0 6061
ferencd@0 6062 // fixarray
ferencd@0 6063 case 0x90:
ferencd@0 6064 case 0x91:
ferencd@0 6065 case 0x92:
ferencd@0 6066 case 0x93:
ferencd@0 6067 case 0x94:
ferencd@0 6068 case 0x95:
ferencd@0 6069 case 0x96:
ferencd@0 6070 case 0x97:
ferencd@0 6071 case 0x98:
ferencd@0 6072 case 0x99:
ferencd@0 6073 case 0x9A:
ferencd@0 6074 case 0x9B:
ferencd@0 6075 case 0x9C:
ferencd@0 6076 case 0x9D:
ferencd@0 6077 case 0x9E:
ferencd@0 6078 case 0x9F:
ferencd@0 6079 return get_msgpack_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
ferencd@0 6080
ferencd@0 6081 // fixstr
ferencd@0 6082 case 0xA0:
ferencd@0 6083 case 0xA1:
ferencd@0 6084 case 0xA2:
ferencd@0 6085 case 0xA3:
ferencd@0 6086 case 0xA4:
ferencd@0 6087 case 0xA5:
ferencd@0 6088 case 0xA6:
ferencd@0 6089 case 0xA7:
ferencd@0 6090 case 0xA8:
ferencd@0 6091 case 0xA9:
ferencd@0 6092 case 0xAA:
ferencd@0 6093 case 0xAB:
ferencd@0 6094 case 0xAC:
ferencd@0 6095 case 0xAD:
ferencd@0 6096 case 0xAE:
ferencd@0 6097 case 0xAF:
ferencd@0 6098 case 0xB0:
ferencd@0 6099 case 0xB1:
ferencd@0 6100 case 0xB2:
ferencd@0 6101 case 0xB3:
ferencd@0 6102 case 0xB4:
ferencd@0 6103 case 0xB5:
ferencd@0 6104 case 0xB6:
ferencd@0 6105 case 0xB7:
ferencd@0 6106 case 0xB8:
ferencd@0 6107 case 0xB9:
ferencd@0 6108 case 0xBA:
ferencd@0 6109 case 0xBB:
ferencd@0 6110 case 0xBC:
ferencd@0 6111 case 0xBD:
ferencd@0 6112 case 0xBE:
ferencd@0 6113 case 0xBF:
ferencd@0 6114 case 0xD9: // str 8
ferencd@0 6115 case 0xDA: // str 16
ferencd@0 6116 case 0xDB: // str 32
ferencd@0 6117 {
ferencd@0 6118 string_t s;
ferencd@0 6119 return get_msgpack_string(s) and sax->string(s);
ferencd@0 6120 }
ferencd@0 6121
ferencd@0 6122 case 0xC0: // nil
ferencd@0 6123 return sax->null();
ferencd@0 6124
ferencd@0 6125 case 0xC2: // false
ferencd@0 6126 return sax->boolean(false);
ferencd@0 6127
ferencd@0 6128 case 0xC3: // true
ferencd@0 6129 return sax->boolean(true);
ferencd@0 6130
ferencd@0 6131 case 0xCA: // float 32
ferencd@0 6132 {
ferencd@0 6133 float number;
ferencd@0 6134 return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast<number_float_t>(number), "");
ferencd@0 6135 }
ferencd@0 6136
ferencd@0 6137 case 0xCB: // float 64
ferencd@0 6138 {
ferencd@0 6139 double number;
ferencd@0 6140 return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast<number_float_t>(number), "");
ferencd@0 6141 }
ferencd@0 6142
ferencd@0 6143 case 0xCC: // uint 8
ferencd@0 6144 {
ferencd@0 6145 std::uint8_t number;
ferencd@0 6146 return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
ferencd@0 6147 }
ferencd@0 6148
ferencd@0 6149 case 0xCD: // uint 16
ferencd@0 6150 {
ferencd@0 6151 std::uint16_t number;
ferencd@0 6152 return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
ferencd@0 6153 }
ferencd@0 6154
ferencd@0 6155 case 0xCE: // uint 32
ferencd@0 6156 {
ferencd@0 6157 std::uint32_t number;
ferencd@0 6158 return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
ferencd@0 6159 }
ferencd@0 6160
ferencd@0 6161 case 0xCF: // uint 64
ferencd@0 6162 {
ferencd@0 6163 std::uint64_t number;
ferencd@0 6164 return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
ferencd@0 6165 }
ferencd@0 6166
ferencd@0 6167 case 0xD0: // int 8
ferencd@0 6168 {
ferencd@0 6169 std::int8_t number;
ferencd@0 6170 return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
ferencd@0 6171 }
ferencd@0 6172
ferencd@0 6173 case 0xD1: // int 16
ferencd@0 6174 {
ferencd@0 6175 std::int16_t number;
ferencd@0 6176 return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
ferencd@0 6177 }
ferencd@0 6178
ferencd@0 6179 case 0xD2: // int 32
ferencd@0 6180 {
ferencd@0 6181 std::int32_t number;
ferencd@0 6182 return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
ferencd@0 6183 }
ferencd@0 6184
ferencd@0 6185 case 0xD3: // int 64
ferencd@0 6186 {
ferencd@0 6187 std::int64_t number;
ferencd@0 6188 return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
ferencd@0 6189 }
ferencd@0 6190
ferencd@0 6191 case 0xDC: // array 16
ferencd@0 6192 {
ferencd@0 6193 std::uint16_t len;
ferencd@0 6194 return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));
ferencd@0 6195 }
ferencd@0 6196
ferencd@0 6197 case 0xDD: // array 32
ferencd@0 6198 {
ferencd@0 6199 std::uint32_t len;
ferencd@0 6200 return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));
ferencd@0 6201 }
ferencd@0 6202
ferencd@0 6203 case 0xDE: // map 16
ferencd@0 6204 {
ferencd@0 6205 std::uint16_t len;
ferencd@0 6206 return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));
ferencd@0 6207 }
ferencd@0 6208
ferencd@0 6209 case 0xDF: // map 32
ferencd@0 6210 {
ferencd@0 6211 std::uint32_t len;
ferencd@0 6212 return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));
ferencd@0 6213 }
ferencd@0 6214
ferencd@0 6215 // negative fixint
ferencd@0 6216 case 0xE0:
ferencd@0 6217 case 0xE1:
ferencd@0 6218 case 0xE2:
ferencd@0 6219 case 0xE3:
ferencd@0 6220 case 0xE4:
ferencd@0 6221 case 0xE5:
ferencd@0 6222 case 0xE6:
ferencd@0 6223 case 0xE7:
ferencd@0 6224 case 0xE8:
ferencd@0 6225 case 0xE9:
ferencd@0 6226 case 0xEA:
ferencd@0 6227 case 0xEB:
ferencd@0 6228 case 0xEC:
ferencd@0 6229 case 0xED:
ferencd@0 6230 case 0xEE:
ferencd@0 6231 case 0xEF:
ferencd@0 6232 case 0xF0:
ferencd@0 6233 case 0xF1:
ferencd@0 6234 case 0xF2:
ferencd@0 6235 case 0xF3:
ferencd@0 6236 case 0xF4:
ferencd@0 6237 case 0xF5:
ferencd@0 6238 case 0xF6:
ferencd@0 6239 case 0xF7:
ferencd@0 6240 case 0xF8:
ferencd@0 6241 case 0xF9:
ferencd@0 6242 case 0xFA:
ferencd@0 6243 case 0xFB:
ferencd@0 6244 case 0xFC:
ferencd@0 6245 case 0xFD:
ferencd@0 6246 case 0xFE:
ferencd@0 6247 case 0xFF:
ferencd@0 6248 return sax->number_integer(static_cast<std::int8_t>(current));
ferencd@0 6249
ferencd@0 6250 default: // anything else
ferencd@0 6251 {
ferencd@0 6252 auto last_token = get_token_string();
ferencd@0 6253 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value")));
ferencd@0 6254 }
ferencd@0 6255 }
ferencd@0 6256 }
ferencd@0 6257
ferencd@0 6258 /*!
ferencd@0 6259 @brief reads a MessagePack string
ferencd@0 6260
ferencd@0 6261 This function first reads starting bytes to determine the expected
ferencd@0 6262 string length and then copies this number of bytes into a string.
ferencd@0 6263
ferencd@0 6264 @param[out] result created string
ferencd@0 6265
ferencd@0 6266 @return whether string creation completed
ferencd@0 6267 */
ferencd@0 6268 bool get_msgpack_string(string_t& result)
ferencd@0 6269 {
ferencd@0 6270 if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::msgpack, "string")))
ferencd@0 6271 {
ferencd@0 6272 return false;
ferencd@0 6273 }
ferencd@0 6274
ferencd@0 6275 switch (current)
ferencd@0 6276 {
ferencd@0 6277 // fixstr
ferencd@0 6278 case 0xA0:
ferencd@0 6279 case 0xA1:
ferencd@0 6280 case 0xA2:
ferencd@0 6281 case 0xA3:
ferencd@0 6282 case 0xA4:
ferencd@0 6283 case 0xA5:
ferencd@0 6284 case 0xA6:
ferencd@0 6285 case 0xA7:
ferencd@0 6286 case 0xA8:
ferencd@0 6287 case 0xA9:
ferencd@0 6288 case 0xAA:
ferencd@0 6289 case 0xAB:
ferencd@0 6290 case 0xAC:
ferencd@0 6291 case 0xAD:
ferencd@0 6292 case 0xAE:
ferencd@0 6293 case 0xAF:
ferencd@0 6294 case 0xB0:
ferencd@0 6295 case 0xB1:
ferencd@0 6296 case 0xB2:
ferencd@0 6297 case 0xB3:
ferencd@0 6298 case 0xB4:
ferencd@0 6299 case 0xB5:
ferencd@0 6300 case 0xB6:
ferencd@0 6301 case 0xB7:
ferencd@0 6302 case 0xB8:
ferencd@0 6303 case 0xB9:
ferencd@0 6304 case 0xBA:
ferencd@0 6305 case 0xBB:
ferencd@0 6306 case 0xBC:
ferencd@0 6307 case 0xBD:
ferencd@0 6308 case 0xBE:
ferencd@0 6309 case 0xBF:
ferencd@0 6310 {
ferencd@0 6311 return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);
ferencd@0 6312 }
ferencd@0 6313
ferencd@0 6314 case 0xD9: // str 8
ferencd@0 6315 {
ferencd@0 6316 std::uint8_t len;
ferencd@0 6317 return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
ferencd@0 6318 }
ferencd@0 6319
ferencd@0 6320 case 0xDA: // str 16
ferencd@0 6321 {
ferencd@0 6322 std::uint16_t len;
ferencd@0 6323 return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
ferencd@0 6324 }
ferencd@0 6325
ferencd@0 6326 case 0xDB: // str 32
ferencd@0 6327 {
ferencd@0 6328 std::uint32_t len;
ferencd@0 6329 return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
ferencd@0 6330 }
ferencd@0 6331
ferencd@0 6332 default:
ferencd@0 6333 {
ferencd@0 6334 auto last_token = get_token_string();
ferencd@0 6335 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string")));
ferencd@0 6336 }
ferencd@0 6337 }
ferencd@0 6338 }
ferencd@0 6339
ferencd@0 6340 /*!
ferencd@0 6341 @param[in] len the length of the array
ferencd@0 6342 @return whether array creation completed
ferencd@0 6343 */
ferencd@0 6344 bool get_msgpack_array(const std::size_t len)
ferencd@0 6345 {
ferencd@0 6346 if (JSON_HEDLEY_UNLIKELY(not sax->start_array(len)))
ferencd@0 6347 {
ferencd@0 6348 return false;
ferencd@0 6349 }
ferencd@0 6350
ferencd@0 6351 for (std::size_t i = 0; i < len; ++i)
ferencd@0 6352 {
ferencd@0 6353 if (JSON_HEDLEY_UNLIKELY(not parse_msgpack_internal()))
ferencd@0 6354 {
ferencd@0 6355 return false;
ferencd@0 6356 }
ferencd@0 6357 }
ferencd@0 6358
ferencd@0 6359 return sax->end_array();
ferencd@0 6360 }
ferencd@0 6361
ferencd@0 6362 /*!
ferencd@0 6363 @param[in] len the length of the object
ferencd@0 6364 @return whether object creation completed
ferencd@0 6365 */
ferencd@0 6366 bool get_msgpack_object(const std::size_t len)
ferencd@0 6367 {
ferencd@0 6368 if (JSON_HEDLEY_UNLIKELY(not sax->start_object(len)))
ferencd@0 6369 {
ferencd@0 6370 return false;
ferencd@0 6371 }
ferencd@0 6372
ferencd@0 6373 string_t key;
ferencd@0 6374 for (std::size_t i = 0; i < len; ++i)
ferencd@0 6375 {
ferencd@0 6376 get();
ferencd@0 6377 if (JSON_HEDLEY_UNLIKELY(not get_msgpack_string(key) or not sax->key(key)))
ferencd@0 6378 {
ferencd@0 6379 return false;
ferencd@0 6380 }
ferencd@0 6381
ferencd@0 6382 if (JSON_HEDLEY_UNLIKELY(not parse_msgpack_internal()))
ferencd@0 6383 {
ferencd@0 6384 return false;
ferencd@0 6385 }
ferencd@0 6386 key.clear();
ferencd@0 6387 }
ferencd@0 6388
ferencd@0 6389 return sax->end_object();
ferencd@0 6390 }
ferencd@0 6391
ferencd@0 6392 ////////////
ferencd@0 6393 // UBJSON //
ferencd@0 6394 ////////////
ferencd@0 6395
ferencd@0 6396 /*!
ferencd@0 6397 @param[in] get_char whether a new character should be retrieved from the
ferencd@0 6398 input (true, default) or whether the last read
ferencd@0 6399 character should be considered instead
ferencd@0 6400
ferencd@0 6401 @return whether a valid UBJSON value was passed to the SAX parser
ferencd@0 6402 */
ferencd@0 6403 bool parse_ubjson_internal(const bool get_char = true)
ferencd@0 6404 {
ferencd@0 6405 return get_ubjson_value(get_char ? get_ignore_noop() : current);
ferencd@0 6406 }
ferencd@0 6407
ferencd@0 6408 /*!
ferencd@0 6409 @brief reads a UBJSON string
ferencd@0 6410
ferencd@0 6411 This function is either called after reading the 'S' byte explicitly
ferencd@0 6412 indicating a string, or in case of an object key where the 'S' byte can be
ferencd@0 6413 left out.
ferencd@0 6414
ferencd@0 6415 @param[out] result created string
ferencd@0 6416 @param[in] get_char whether a new character should be retrieved from the
ferencd@0 6417 input (true, default) or whether the last read
ferencd@0 6418 character should be considered instead
ferencd@0 6419
ferencd@0 6420 @return whether string creation completed
ferencd@0 6421 */
ferencd@0 6422 bool get_ubjson_string(string_t& result, const bool get_char = true)
ferencd@0 6423 {
ferencd@0 6424 if (get_char)
ferencd@0 6425 {
ferencd@0 6426 get(); // TODO(niels): may we ignore N here?
ferencd@0 6427 }
ferencd@0 6428
ferencd@0 6429 if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value")))
ferencd@0 6430 {
ferencd@0 6431 return false;
ferencd@0 6432 }
ferencd@0 6433
ferencd@0 6434 switch (current)
ferencd@0 6435 {
ferencd@0 6436 case 'U':
ferencd@0 6437 {
ferencd@0 6438 std::uint8_t len;
ferencd@0 6439 return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
ferencd@0 6440 }
ferencd@0 6441
ferencd@0 6442 case 'i':
ferencd@0 6443 {
ferencd@0 6444 std::int8_t len;
ferencd@0 6445 return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
ferencd@0 6446 }
ferencd@0 6447
ferencd@0 6448 case 'I':
ferencd@0 6449 {
ferencd@0 6450 std::int16_t len;
ferencd@0 6451 return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
ferencd@0 6452 }
ferencd@0 6453
ferencd@0 6454 case 'l':
ferencd@0 6455 {
ferencd@0 6456 std::int32_t len;
ferencd@0 6457 return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
ferencd@0 6458 }
ferencd@0 6459
ferencd@0 6460 case 'L':
ferencd@0 6461 {
ferencd@0 6462 std::int64_t len;
ferencd@0 6463 return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
ferencd@0 6464 }
ferencd@0 6465
ferencd@0 6466 default:
ferencd@0 6467 auto last_token = get_token_string();
ferencd@0 6468 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string")));
ferencd@0 6469 }
ferencd@0 6470 }
ferencd@0 6471
ferencd@0 6472 /*!
ferencd@0 6473 @param[out] result determined size
ferencd@0 6474 @return whether size determination completed
ferencd@0 6475 */
ferencd@0 6476 bool get_ubjson_size_value(std::size_t& result)
ferencd@0 6477 {
ferencd@0 6478 switch (get_ignore_noop())
ferencd@0 6479 {
ferencd@0 6480 case 'U':
ferencd@0 6481 {
ferencd@0 6482 std::uint8_t number;
ferencd@0 6483 if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
ferencd@0 6484 {
ferencd@0 6485 return false;
ferencd@0 6486 }
ferencd@0 6487 result = static_cast<std::size_t>(number);
ferencd@0 6488 return true;
ferencd@0 6489 }
ferencd@0 6490
ferencd@0 6491 case 'i':
ferencd@0 6492 {
ferencd@0 6493 std::int8_t number;
ferencd@0 6494 if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
ferencd@0 6495 {
ferencd@0 6496 return false;
ferencd@0 6497 }
ferencd@0 6498 result = static_cast<std::size_t>(number);
ferencd@0 6499 return true;
ferencd@0 6500 }
ferencd@0 6501
ferencd@0 6502 case 'I':
ferencd@0 6503 {
ferencd@0 6504 std::int16_t number;
ferencd@0 6505 if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
ferencd@0 6506 {
ferencd@0 6507 return false;
ferencd@0 6508 }
ferencd@0 6509 result = static_cast<std::size_t>(number);
ferencd@0 6510 return true;
ferencd@0 6511 }
ferencd@0 6512
ferencd@0 6513 case 'l':
ferencd@0 6514 {
ferencd@0 6515 std::int32_t number;
ferencd@0 6516 if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
ferencd@0 6517 {
ferencd@0 6518 return false;
ferencd@0 6519 }
ferencd@0 6520 result = static_cast<std::size_t>(number);
ferencd@0 6521 return true;
ferencd@0 6522 }
ferencd@0 6523
ferencd@0 6524 case 'L':
ferencd@0 6525 {
ferencd@0 6526 std::int64_t number;
ferencd@0 6527 if (JSON_HEDLEY_UNLIKELY(not get_number(input_format_t::ubjson, number)))
ferencd@0 6528 {
ferencd@0 6529 return false;
ferencd@0 6530 }
ferencd@0 6531 result = static_cast<std::size_t>(number);
ferencd@0 6532 return true;
ferencd@0 6533 }
ferencd@0 6534
ferencd@0 6535 default:
ferencd@0 6536 {
ferencd@0 6537 auto last_token = get_token_string();
ferencd@0 6538 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size")));
ferencd@0 6539 }
ferencd@0 6540 }
ferencd@0 6541 }
ferencd@0 6542
ferencd@0 6543 /*!
ferencd@0 6544 @brief determine the type and size for a container
ferencd@0 6545
ferencd@0 6546 In the optimized UBJSON format, a type and a size can be provided to allow
ferencd@0 6547 for a more compact representation.
ferencd@0 6548
ferencd@0 6549 @param[out] result pair of the size and the type
ferencd@0 6550
ferencd@0 6551 @return whether pair creation completed
ferencd@0 6552 */
ferencd@0 6553 bool get_ubjson_size_type(std::pair<std::size_t, int>& result)
ferencd@0 6554 {
ferencd@0 6555 result.first = string_t::npos; // size
ferencd@0 6556 result.second = 0; // type
ferencd@0 6557
ferencd@0 6558 get_ignore_noop();
ferencd@0 6559
ferencd@0 6560 if (current == '$')
ferencd@0 6561 {
ferencd@0 6562 result.second = get(); // must not ignore 'N', because 'N' maybe the type
ferencd@0 6563 if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "type")))
ferencd@0 6564 {
ferencd@0 6565 return false;
ferencd@0 6566 }
ferencd@0 6567
ferencd@0 6568 get_ignore_noop();
ferencd@0 6569 if (JSON_HEDLEY_UNLIKELY(current != '#'))
ferencd@0 6570 {
ferencd@0 6571 if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value")))
ferencd@0 6572 {
ferencd@0 6573 return false;
ferencd@0 6574 }
ferencd@0 6575 auto last_token = get_token_string();
ferencd@0 6576 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size")));
ferencd@0 6577 }
ferencd@0 6578
ferencd@0 6579 return get_ubjson_size_value(result.first);
ferencd@0 6580 }
ferencd@0 6581
ferencd@0 6582 if (current == '#')
ferencd@0 6583 {
ferencd@0 6584 return get_ubjson_size_value(result.first);
ferencd@0 6585 }
ferencd@0 6586
ferencd@0 6587 return true;
ferencd@0 6588 }
ferencd@0 6589
ferencd@0 6590 /*!
ferencd@0 6591 @param prefix the previously read or set type prefix
ferencd@0 6592 @return whether value creation completed
ferencd@0 6593 */
ferencd@0 6594 bool get_ubjson_value(const int prefix)
ferencd@0 6595 {
ferencd@0 6596 switch (prefix)
ferencd@0 6597 {
ferencd@0 6598 case std::char_traits<char>::eof(): // EOF
ferencd@0 6599 return unexpect_eof(input_format_t::ubjson, "value");
ferencd@0 6600
ferencd@0 6601 case 'T': // true
ferencd@0 6602 return sax->boolean(true);
ferencd@0 6603 case 'F': // false
ferencd@0 6604 return sax->boolean(false);
ferencd@0 6605
ferencd@0 6606 case 'Z': // null
ferencd@0 6607 return sax->null();
ferencd@0 6608
ferencd@0 6609 case 'U':
ferencd@0 6610 {
ferencd@0 6611 std::uint8_t number;
ferencd@0 6612 return get_number(input_format_t::ubjson, number) and sax->number_unsigned(number);
ferencd@0 6613 }
ferencd@0 6614
ferencd@0 6615 case 'i':
ferencd@0 6616 {
ferencd@0 6617 std::int8_t number;
ferencd@0 6618 return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
ferencd@0 6619 }
ferencd@0 6620
ferencd@0 6621 case 'I':
ferencd@0 6622 {
ferencd@0 6623 std::int16_t number;
ferencd@0 6624 return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
ferencd@0 6625 }
ferencd@0 6626
ferencd@0 6627 case 'l':
ferencd@0 6628 {
ferencd@0 6629 std::int32_t number;
ferencd@0 6630 return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
ferencd@0 6631 }
ferencd@0 6632
ferencd@0 6633 case 'L':
ferencd@0 6634 {
ferencd@0 6635 std::int64_t number;
ferencd@0 6636 return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
ferencd@0 6637 }
ferencd@0 6638
ferencd@0 6639 case 'd':
ferencd@0 6640 {
ferencd@0 6641 float number;
ferencd@0 6642 return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast<number_float_t>(number), "");
ferencd@0 6643 }
ferencd@0 6644
ferencd@0 6645 case 'D':
ferencd@0 6646 {
ferencd@0 6647 double number;
ferencd@0 6648 return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast<number_float_t>(number), "");
ferencd@0 6649 }
ferencd@0 6650
ferencd@0 6651 case 'C': // char
ferencd@0 6652 {
ferencd@0 6653 get();
ferencd@0 6654 if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "char")))
ferencd@0 6655 {
ferencd@0 6656 return false;
ferencd@0 6657 }
ferencd@0 6658 if (JSON_HEDLEY_UNLIKELY(current > 127))
ferencd@0 6659 {
ferencd@0 6660 auto last_token = get_token_string();
ferencd@0 6661 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char")));
ferencd@0 6662 }
ferencd@0 6663 string_t s(1, static_cast<char>(current));
ferencd@0 6664 return sax->string(s);
ferencd@0 6665 }
ferencd@0 6666
ferencd@0 6667 case 'S': // string
ferencd@0 6668 {
ferencd@0 6669 string_t s;
ferencd@0 6670 return get_ubjson_string(s) and sax->string(s);
ferencd@0 6671 }
ferencd@0 6672
ferencd@0 6673 case '[': // array
ferencd@0 6674 return get_ubjson_array();
ferencd@0 6675
ferencd@0 6676 case '{': // object
ferencd@0 6677 return get_ubjson_object();
ferencd@0 6678
ferencd@0 6679 default: // anything else
ferencd@0 6680 {
ferencd@0 6681 auto last_token = get_token_string();
ferencd@0 6682 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value")));
ferencd@0 6683 }
ferencd@0 6684 }
ferencd@0 6685 }
ferencd@0 6686
ferencd@0 6687 /*!
ferencd@0 6688 @return whether array creation completed
ferencd@0 6689 */
ferencd@0 6690 bool get_ubjson_array()
ferencd@0 6691 {
ferencd@0 6692 std::pair<std::size_t, int> size_and_type;
ferencd@0 6693 if (JSON_HEDLEY_UNLIKELY(not get_ubjson_size_type(size_and_type)))
ferencd@0 6694 {
ferencd@0 6695 return false;
ferencd@0 6696 }
ferencd@0 6697
ferencd@0 6698 if (size_and_type.first != string_t::npos)
ferencd@0 6699 {
ferencd@0 6700 if (JSON_HEDLEY_UNLIKELY(not sax->start_array(size_and_type.first)))
ferencd@0 6701 {
ferencd@0 6702 return false;
ferencd@0 6703 }
ferencd@0 6704
ferencd@0 6705 if (size_and_type.second != 0)
ferencd@0 6706 {
ferencd@0 6707 if (size_and_type.second != 'N')
ferencd@0 6708 {
ferencd@0 6709 for (std::size_t i = 0; i < size_and_type.first; ++i)
ferencd@0 6710 {
ferencd@0 6711 if (JSON_HEDLEY_UNLIKELY(not get_ubjson_value(size_and_type.second)))
ferencd@0 6712 {
ferencd@0 6713 return false;
ferencd@0 6714 }
ferencd@0 6715 }
ferencd@0 6716 }
ferencd@0 6717 }
ferencd@0 6718 else
ferencd@0 6719 {
ferencd@0 6720 for (std::size_t i = 0; i < size_and_type.first; ++i)
ferencd@0 6721 {
ferencd@0 6722 if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal()))
ferencd@0 6723 {
ferencd@0 6724 return false;
ferencd@0 6725 }
ferencd@0 6726 }
ferencd@0 6727 }
ferencd@0 6728 }
ferencd@0 6729 else
ferencd@0 6730 {
ferencd@0 6731 if (JSON_HEDLEY_UNLIKELY(not sax->start_array(std::size_t(-1))))
ferencd@0 6732 {
ferencd@0 6733 return false;
ferencd@0 6734 }
ferencd@0 6735
ferencd@0 6736 while (current != ']')
ferencd@0 6737 {
ferencd@0 6738 if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal(false)))
ferencd@0 6739 {
ferencd@0 6740 return false;
ferencd@0 6741 }
ferencd@0 6742 get_ignore_noop();
ferencd@0 6743 }
ferencd@0 6744 }
ferencd@0 6745
ferencd@0 6746 return sax->end_array();
ferencd@0 6747 }
ferencd@0 6748
ferencd@0 6749 /*!
ferencd@0 6750 @return whether object creation completed
ferencd@0 6751 */
ferencd@0 6752 bool get_ubjson_object()
ferencd@0 6753 {
ferencd@0 6754 std::pair<std::size_t, int> size_and_type;
ferencd@0 6755 if (JSON_HEDLEY_UNLIKELY(not get_ubjson_size_type(size_and_type)))
ferencd@0 6756 {
ferencd@0 6757 return false;
ferencd@0 6758 }
ferencd@0 6759
ferencd@0 6760 string_t key;
ferencd@0 6761 if (size_and_type.first != string_t::npos)
ferencd@0 6762 {
ferencd@0 6763 if (JSON_HEDLEY_UNLIKELY(not sax->start_object(size_and_type.first)))
ferencd@0 6764 {
ferencd@0 6765 return false;
ferencd@0 6766 }
ferencd@0 6767
ferencd@0 6768 if (size_and_type.second != 0)
ferencd@0 6769 {
ferencd@0 6770 for (std::size_t i = 0; i < size_and_type.first; ++i)
ferencd@0 6771 {
ferencd@0 6772 if (JSON_HEDLEY_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))
ferencd@0 6773 {
ferencd@0 6774 return false;
ferencd@0 6775 }
ferencd@0 6776 if (JSON_HEDLEY_UNLIKELY(not get_ubjson_value(size_and_type.second)))
ferencd@0 6777 {
ferencd@0 6778 return false;
ferencd@0 6779 }
ferencd@0 6780 key.clear();
ferencd@0 6781 }
ferencd@0 6782 }
ferencd@0 6783 else
ferencd@0 6784 {
ferencd@0 6785 for (std::size_t i = 0; i < size_and_type.first; ++i)
ferencd@0 6786 {
ferencd@0 6787 if (JSON_HEDLEY_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))
ferencd@0 6788 {
ferencd@0 6789 return false;
ferencd@0 6790 }
ferencd@0 6791 if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal()))
ferencd@0 6792 {
ferencd@0 6793 return false;
ferencd@0 6794 }
ferencd@0 6795 key.clear();
ferencd@0 6796 }
ferencd@0 6797 }
ferencd@0 6798 }
ferencd@0 6799 else
ferencd@0 6800 {
ferencd@0 6801 if (JSON_HEDLEY_UNLIKELY(not sax->start_object(std::size_t(-1))))
ferencd@0 6802 {
ferencd@0 6803 return false;
ferencd@0 6804 }
ferencd@0 6805
ferencd@0 6806 while (current != '}')
ferencd@0 6807 {
ferencd@0 6808 if (JSON_HEDLEY_UNLIKELY(not get_ubjson_string(key, false) or not sax->key(key)))
ferencd@0 6809 {
ferencd@0 6810 return false;
ferencd@0 6811 }
ferencd@0 6812 if (JSON_HEDLEY_UNLIKELY(not parse_ubjson_internal()))
ferencd@0 6813 {
ferencd@0 6814 return false;
ferencd@0 6815 }
ferencd@0 6816 get_ignore_noop();
ferencd@0 6817 key.clear();
ferencd@0 6818 }
ferencd@0 6819 }
ferencd@0 6820
ferencd@0 6821 return sax->end_object();
ferencd@0 6822 }
ferencd@0 6823
ferencd@0 6824 ///////////////////////
ferencd@0 6825 // Utility functions //
ferencd@0 6826 ///////////////////////
ferencd@0 6827
ferencd@0 6828 /*!
ferencd@0 6829 @brief get next character from the input
ferencd@0 6830
ferencd@0 6831 This function provides the interface to the used input adapter. It does
ferencd@0 6832 not throw in case the input reached EOF, but returns a -'ve valued
ferencd@0 6833 `std::char_traits<char>::eof()` in that case.
ferencd@0 6834
ferencd@0 6835 @return character read from the input
ferencd@0 6836 */
ferencd@0 6837 int get()
ferencd@0 6838 {
ferencd@0 6839 ++chars_read;
ferencd@0 6840 return current = ia->get_character();
ferencd@0 6841 }
ferencd@0 6842
ferencd@0 6843 /*!
ferencd@0 6844 @return character read from the input after ignoring all 'N' entries
ferencd@0 6845 */
ferencd@0 6846 int get_ignore_noop()
ferencd@0 6847 {
ferencd@0 6848 do
ferencd@0 6849 {
ferencd@0 6850 get();
ferencd@0 6851 }
ferencd@0 6852 while (current == 'N');
ferencd@0 6853
ferencd@0 6854 return current;
ferencd@0 6855 }
ferencd@0 6856
ferencd@0 6857 /*
ferencd@0 6858 @brief read a number from the input
ferencd@0 6859
ferencd@0 6860 @tparam NumberType the type of the number
ferencd@0 6861 @param[in] format the current format (for diagnostics)
ferencd@0 6862 @param[out] result number of type @a NumberType
ferencd@0 6863
ferencd@0 6864 @return whether conversion completed
ferencd@0 6865
ferencd@0 6866 @note This function needs to respect the system's endianess, because
ferencd@0 6867 bytes in CBOR, MessagePack, and UBJSON are stored in network order
ferencd@0 6868 (big endian) and therefore need reordering on little endian systems.
ferencd@0 6869 */
ferencd@0 6870 template<typename NumberType, bool InputIsLittleEndian = false>
ferencd@0 6871 bool get_number(const input_format_t format, NumberType& result)
ferencd@0 6872 {
ferencd@0 6873 // step 1: read input into array with system's byte order
ferencd@0 6874 std::array<std::uint8_t, sizeof(NumberType)> vec;
ferencd@0 6875 for (std::size_t i = 0; i < sizeof(NumberType); ++i)
ferencd@0 6876 {
ferencd@0 6877 get();
ferencd@0 6878 if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(format, "number")))
ferencd@0 6879 {
ferencd@0 6880 return false;
ferencd@0 6881 }
ferencd@0 6882
ferencd@0 6883 // reverse byte order prior to conversion if necessary
ferencd@0 6884 if (is_little_endian != InputIsLittleEndian)
ferencd@0 6885 {
ferencd@0 6886 vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);
ferencd@0 6887 }
ferencd@0 6888 else
ferencd@0 6889 {
ferencd@0 6890 vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE
ferencd@0 6891 }
ferencd@0 6892 }
ferencd@0 6893
ferencd@0 6894 // step 2: convert array into number of type T and return
ferencd@0 6895 std::memcpy(&result, vec.data(), sizeof(NumberType));
ferencd@0 6896 return true;
ferencd@0 6897 }
ferencd@0 6898
ferencd@0 6899 /*!
ferencd@0 6900 @brief create a string by reading characters from the input
ferencd@0 6901
ferencd@0 6902 @tparam NumberType the type of the number
ferencd@0 6903 @param[in] format the current format (for diagnostics)
ferencd@0 6904 @param[in] len number of characters to read
ferencd@0 6905 @param[out] result string created by reading @a len bytes
ferencd@0 6906
ferencd@0 6907 @return whether string creation completed
ferencd@0 6908
ferencd@0 6909 @note We can not reserve @a len bytes for the result, because @a len
ferencd@0 6910 may be too large. Usually, @ref unexpect_eof() detects the end of
ferencd@0 6911 the input before we run out of string memory.
ferencd@0 6912 */
ferencd@0 6913 template<typename NumberType>
ferencd@0 6914 bool get_string(const input_format_t format,
ferencd@0 6915 const NumberType len,
ferencd@0 6916 string_t& result)
ferencd@0 6917 {
ferencd@0 6918 bool success = true;
ferencd@0 6919 std::generate_n(std::back_inserter(result), len, [this, &success, &format]()
ferencd@0 6920 {
ferencd@0 6921 get();
ferencd@0 6922 if (JSON_HEDLEY_UNLIKELY(not unexpect_eof(format, "string")))
ferencd@0 6923 {
ferencd@0 6924 success = false;
ferencd@0 6925 }
ferencd@0 6926 return static_cast<char>(current);
ferencd@0 6927 });
ferencd@0 6928 return success;
ferencd@0 6929 }
ferencd@0 6930
ferencd@0 6931 /*!
ferencd@0 6932 @param[in] format the current format (for diagnostics)
ferencd@0 6933 @param[in] context further context information (for diagnostics)
ferencd@0 6934 @return whether the last read character is not EOF
ferencd@0 6935 */
ferencd@0 6936 JSON_HEDLEY_NON_NULL(3)
ferencd@0 6937 bool unexpect_eof(const input_format_t format, const char* context) const
ferencd@0 6938 {
ferencd@0 6939 if (JSON_HEDLEY_UNLIKELY(current == std::char_traits<char>::eof()))
ferencd@0 6940 {
ferencd@0 6941 return sax->parse_error(chars_read, "<end of file>",
ferencd@0 6942 parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context)));
ferencd@0 6943 }
ferencd@0 6944 return true;
ferencd@0 6945 }
ferencd@0 6946
ferencd@0 6947 /*!
ferencd@0 6948 @return a string representation of the last read byte
ferencd@0 6949 */
ferencd@0 6950 std::string get_token_string() const
ferencd@0 6951 {
ferencd@0 6952 std::array<char, 3> cr{{}};
ferencd@0 6953 (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current));
ferencd@0 6954 return std::string{cr.data()};
ferencd@0 6955 }
ferencd@0 6956
ferencd@0 6957 /*!
ferencd@0 6958 @param[in] format the current format
ferencd@0 6959 @param[in] detail a detailed error message
ferencd@0 6960 @param[in] context further contect information
ferencd@0 6961 @return a message string to use in the parse_error exceptions
ferencd@0 6962 */
ferencd@0 6963 std::string exception_message(const input_format_t format,
ferencd@0 6964 const std::string& detail,
ferencd@0 6965 const std::string& context) const
ferencd@0 6966 {
ferencd@0 6967 std::string error_msg = "syntax error while parsing ";
ferencd@0 6968
ferencd@0 6969 switch (format)
ferencd@0 6970 {
ferencd@0 6971 case input_format_t::cbor:
ferencd@0 6972 error_msg += "CBOR";
ferencd@0 6973 break;
ferencd@0 6974
ferencd@0 6975 case input_format_t::msgpack:
ferencd@0 6976 error_msg += "MessagePack";
ferencd@0 6977 break;
ferencd@0 6978
ferencd@0 6979 case input_format_t::ubjson:
ferencd@0 6980 error_msg += "UBJSON";
ferencd@0 6981 break;
ferencd@0 6982
ferencd@0 6983 case input_format_t::bson:
ferencd@0 6984 error_msg += "BSON";
ferencd@0 6985 break;
ferencd@0 6986
ferencd@0 6987 default: // LCOV_EXCL_LINE
ferencd@0 6988 assert(false); // LCOV_EXCL_LINE
ferencd@0 6989 }
ferencd@0 6990
ferencd@0 6991 return error_msg + " " + context + ": " + detail;
ferencd@0 6992 }
ferencd@0 6993
ferencd@0 6994 private:
ferencd@0 6995 /// input adapter
ferencd@0 6996 input_adapter_t ia = nullptr;
ferencd@0 6997
ferencd@0 6998 /// the current character
ferencd@0 6999 int current = std::char_traits<char>::eof();
ferencd@0 7000
ferencd@0 7001 /// the number of characters read
ferencd@0 7002 std::size_t chars_read = 0;
ferencd@0 7003
ferencd@0 7004 /// whether we can assume little endianess
ferencd@0 7005 const bool is_little_endian = little_endianess();
ferencd@0 7006
ferencd@0 7007 /// the SAX parser
ferencd@0 7008 json_sax_t* sax = nullptr;
ferencd@0 7009 };
ferencd@0 7010 } // namespace detail
ferencd@0 7011 } // namespace nlohmann
ferencd@0 7012
ferencd@0 7013 // #include <nlohmann/detail/input/input_adapters.hpp>
ferencd@0 7014
ferencd@0 7015 // #include <nlohmann/detail/input/lexer.hpp>
ferencd@0 7016
ferencd@0 7017
ferencd@0 7018 #include <array> // array
ferencd@0 7019 #include <clocale> // localeconv
ferencd@0 7020 #include <cstddef> // size_t
ferencd@0 7021 #include <cstdio> // snprintf
ferencd@0 7022 #include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
ferencd@0 7023 #include <initializer_list> // initializer_list
ferencd@0 7024 #include <string> // char_traits, string
ferencd@0 7025 #include <utility> // move
ferencd@0 7026 #include <vector> // vector
ferencd@0 7027
ferencd@0 7028 // #include <nlohmann/detail/input/input_adapters.hpp>
ferencd@0 7029
ferencd@0 7030 // #include <nlohmann/detail/input/position_t.hpp>
ferencd@0 7031
ferencd@0 7032 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 7033
ferencd@0 7034
ferencd@0 7035 namespace nlohmann
ferencd@0 7036 {
ferencd@0 7037 namespace detail
ferencd@0 7038 {
ferencd@0 7039 ///////////
ferencd@0 7040 // lexer //
ferencd@0 7041 ///////////
ferencd@0 7042
ferencd@0 7043 /*!
ferencd@0 7044 @brief lexical analysis
ferencd@0 7045
ferencd@0 7046 This class organizes the lexical analysis during JSON deserialization.
ferencd@0 7047 */
ferencd@0 7048 template<typename BasicJsonType>
ferencd@0 7049 class lexer
ferencd@0 7050 {
ferencd@0 7051 using number_integer_t = typename BasicJsonType::number_integer_t;
ferencd@0 7052 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
ferencd@0 7053 using number_float_t = typename BasicJsonType::number_float_t;
ferencd@0 7054 using string_t = typename BasicJsonType::string_t;
ferencd@0 7055
ferencd@0 7056 public:
ferencd@0 7057 /// token types for the parser
ferencd@0 7058 enum class token_type
ferencd@0 7059 {
ferencd@0 7060 uninitialized, ///< indicating the scanner is uninitialized
ferencd@0 7061 literal_true, ///< the `true` literal
ferencd@0 7062 literal_false, ///< the `false` literal
ferencd@0 7063 literal_null, ///< the `null` literal
ferencd@0 7064 value_string, ///< a string -- use get_string() for actual value
ferencd@0 7065 value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value
ferencd@0 7066 value_integer, ///< a signed integer -- use get_number_integer() for actual value
ferencd@0 7067 value_float, ///< an floating point number -- use get_number_float() for actual value
ferencd@0 7068 begin_array, ///< the character for array begin `[`
ferencd@0 7069 begin_object, ///< the character for object begin `{`
ferencd@0 7070 end_array, ///< the character for array end `]`
ferencd@0 7071 end_object, ///< the character for object end `}`
ferencd@0 7072 name_separator, ///< the name separator `:`
ferencd@0 7073 value_separator, ///< the value separator `,`
ferencd@0 7074 parse_error, ///< indicating a parse error
ferencd@0 7075 end_of_input, ///< indicating the end of the input buffer
ferencd@0 7076 literal_or_value ///< a literal or the begin of a value (only for diagnostics)
ferencd@0 7077 };
ferencd@0 7078
ferencd@0 7079 /// return name of values of type token_type (only used for errors)
ferencd@0 7080 JSON_HEDLEY_RETURNS_NON_NULL
ferencd@0 7081 JSON_HEDLEY_CONST
ferencd@0 7082 static const char* token_type_name(const token_type t) noexcept
ferencd@0 7083 {
ferencd@0 7084 switch (t)
ferencd@0 7085 {
ferencd@0 7086 case token_type::uninitialized:
ferencd@0 7087 return "<uninitialized>";
ferencd@0 7088 case token_type::literal_true:
ferencd@0 7089 return "true literal";
ferencd@0 7090 case token_type::literal_false:
ferencd@0 7091 return "false literal";
ferencd@0 7092 case token_type::literal_null:
ferencd@0 7093 return "null literal";
ferencd@0 7094 case token_type::value_string:
ferencd@0 7095 return "string literal";
ferencd@0 7096 case lexer::token_type::value_unsigned:
ferencd@0 7097 case lexer::token_type::value_integer:
ferencd@0 7098 case lexer::token_type::value_float:
ferencd@0 7099 return "number literal";
ferencd@0 7100 case token_type::begin_array:
ferencd@0 7101 return "'['";
ferencd@0 7102 case token_type::begin_object:
ferencd@0 7103 return "'{'";
ferencd@0 7104 case token_type::end_array:
ferencd@0 7105 return "']'";
ferencd@0 7106 case token_type::end_object:
ferencd@0 7107 return "'}'";
ferencd@0 7108 case token_type::name_separator:
ferencd@0 7109 return "':'";
ferencd@0 7110 case token_type::value_separator:
ferencd@0 7111 return "','";
ferencd@0 7112 case token_type::parse_error:
ferencd@0 7113 return "<parse error>";
ferencd@0 7114 case token_type::end_of_input:
ferencd@0 7115 return "end of input";
ferencd@0 7116 case token_type::literal_or_value:
ferencd@0 7117 return "'[', '{', or a literal";
ferencd@0 7118 // LCOV_EXCL_START
ferencd@0 7119 default: // catch non-enum values
ferencd@0 7120 return "unknown token";
ferencd@0 7121 // LCOV_EXCL_STOP
ferencd@0 7122 }
ferencd@0 7123 }
ferencd@0 7124
ferencd@0 7125 explicit lexer(detail::input_adapter_t&& adapter)
ferencd@0 7126 : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {}
ferencd@0 7127
ferencd@0 7128 // delete because of pointer members
ferencd@0 7129 lexer(const lexer&) = delete;
ferencd@0 7130 lexer(lexer&&) = delete;
ferencd@0 7131 lexer& operator=(lexer&) = delete;
ferencd@0 7132 lexer& operator=(lexer&&) = delete;
ferencd@0 7133 ~lexer() = default;
ferencd@0 7134
ferencd@0 7135 private:
ferencd@0 7136 /////////////////////
ferencd@0 7137 // locales
ferencd@0 7138 /////////////////////
ferencd@0 7139
ferencd@0 7140 /// return the locale-dependent decimal point
ferencd@0 7141 JSON_HEDLEY_PURE
ferencd@0 7142 static char get_decimal_point() noexcept
ferencd@0 7143 {
ferencd@0 7144 const auto loc = localeconv();
ferencd@0 7145 assert(loc != nullptr);
ferencd@0 7146 return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
ferencd@0 7147 }
ferencd@0 7148
ferencd@0 7149 /////////////////////
ferencd@0 7150 // scan functions
ferencd@0 7151 /////////////////////
ferencd@0 7152
ferencd@0 7153 /*!
ferencd@0 7154 @brief get codepoint from 4 hex characters following `\u`
ferencd@0 7155
ferencd@0 7156 For input "\u c1 c2 c3 c4" the codepoint is:
ferencd@0 7157 (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4
ferencd@0 7158 = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)
ferencd@0 7159
ferencd@0 7160 Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'
ferencd@0 7161 must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The
ferencd@0 7162 conversion is done by subtracting the offset (0x30, 0x37, and 0x57)
ferencd@0 7163 between the ASCII value of the character and the desired integer value.
ferencd@0 7164
ferencd@0 7165 @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or
ferencd@0 7166 non-hex character)
ferencd@0 7167 */
ferencd@0 7168 int get_codepoint()
ferencd@0 7169 {
ferencd@0 7170 // this function only makes sense after reading `\u`
ferencd@0 7171 assert(current == 'u');
ferencd@0 7172 int codepoint = 0;
ferencd@0 7173
ferencd@0 7174 const auto factors = { 12u, 8u, 4u, 0u };
ferencd@0 7175 for (const auto factor : factors)
ferencd@0 7176 {
ferencd@0 7177 get();
ferencd@0 7178
ferencd@0 7179 if (current >= '0' and current <= '9')
ferencd@0 7180 {
ferencd@0 7181 codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);
ferencd@0 7182 }
ferencd@0 7183 else if (current >= 'A' and current <= 'F')
ferencd@0 7184 {
ferencd@0 7185 codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);
ferencd@0 7186 }
ferencd@0 7187 else if (current >= 'a' and current <= 'f')
ferencd@0 7188 {
ferencd@0 7189 codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);
ferencd@0 7190 }
ferencd@0 7191 else
ferencd@0 7192 {
ferencd@0 7193 return -1;
ferencd@0 7194 }
ferencd@0 7195 }
ferencd@0 7196
ferencd@0 7197 assert(0x0000 <= codepoint and codepoint <= 0xFFFF);
ferencd@0 7198 return codepoint;
ferencd@0 7199 }
ferencd@0 7200
ferencd@0 7201 /*!
ferencd@0 7202 @brief check if the next byte(s) are inside a given range
ferencd@0 7203
ferencd@0 7204 Adds the current byte and, for each passed range, reads a new byte and
ferencd@0 7205 checks if it is inside the range. If a violation was detected, set up an
ferencd@0 7206 error message and return false. Otherwise, return true.
ferencd@0 7207
ferencd@0 7208 @param[in] ranges list of integers; interpreted as list of pairs of
ferencd@0 7209 inclusive lower and upper bound, respectively
ferencd@0 7210
ferencd@0 7211 @pre The passed list @a ranges must have 2, 4, or 6 elements; that is,
ferencd@0 7212 1, 2, or 3 pairs. This precondition is enforced by an assertion.
ferencd@0 7213
ferencd@0 7214 @return true if and only if no range violation was detected
ferencd@0 7215 */
ferencd@0 7216 bool next_byte_in_range(std::initializer_list<int> ranges)
ferencd@0 7217 {
ferencd@0 7218 assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6);
ferencd@0 7219 add(current);
ferencd@0 7220
ferencd@0 7221 for (auto range = ranges.begin(); range != ranges.end(); ++range)
ferencd@0 7222 {
ferencd@0 7223 get();
ferencd@0 7224 if (JSON_HEDLEY_LIKELY(*range <= current and current <= *(++range)))
ferencd@0 7225 {
ferencd@0 7226 add(current);
ferencd@0 7227 }
ferencd@0 7228 else
ferencd@0 7229 {
ferencd@0 7230 error_message = "invalid string: ill-formed UTF-8 byte";
ferencd@0 7231 return false;
ferencd@0 7232 }
ferencd@0 7233 }
ferencd@0 7234
ferencd@0 7235 return true;
ferencd@0 7236 }
ferencd@0 7237
ferencd@0 7238 /*!
ferencd@0 7239 @brief scan a string literal
ferencd@0 7240
ferencd@0 7241 This function scans a string according to Sect. 7 of RFC 7159. While
ferencd@0 7242 scanning, bytes are escaped and copied into buffer token_buffer. Then the
ferencd@0 7243 function returns successfully, token_buffer is *not* null-terminated (as it
ferencd@0 7244 may contain \0 bytes), and token_buffer.size() is the number of bytes in the
ferencd@0 7245 string.
ferencd@0 7246
ferencd@0 7247 @return token_type::value_string if string could be successfully scanned,
ferencd@0 7248 token_type::parse_error otherwise
ferencd@0 7249
ferencd@0 7250 @note In case of errors, variable error_message contains a textual
ferencd@0 7251 description.
ferencd@0 7252 */
ferencd@0 7253 token_type scan_string()
ferencd@0 7254 {
ferencd@0 7255 // reset token_buffer (ignore opening quote)
ferencd@0 7256 reset();
ferencd@0 7257
ferencd@0 7258 // we entered the function by reading an open quote
ferencd@0 7259 assert(current == '\"');
ferencd@0 7260
ferencd@0 7261 while (true)
ferencd@0 7262 {
ferencd@0 7263 // get next character
ferencd@0 7264 switch (get())
ferencd@0 7265 {
ferencd@0 7266 // end of file while parsing string
ferencd@0 7267 case std::char_traits<char>::eof():
ferencd@0 7268 {
ferencd@0 7269 error_message = "invalid string: missing closing quote";
ferencd@0 7270 return token_type::parse_error;
ferencd@0 7271 }
ferencd@0 7272
ferencd@0 7273 // closing quote
ferencd@0 7274 case '\"':
ferencd@0 7275 {
ferencd@0 7276 return token_type::value_string;
ferencd@0 7277 }
ferencd@0 7278
ferencd@0 7279 // escapes
ferencd@0 7280 case '\\':
ferencd@0 7281 {
ferencd@0 7282 switch (get())
ferencd@0 7283 {
ferencd@0 7284 // quotation mark
ferencd@0 7285 case '\"':
ferencd@0 7286 add('\"');
ferencd@0 7287 break;
ferencd@0 7288 // reverse solidus
ferencd@0 7289 case '\\':
ferencd@0 7290 add('\\');
ferencd@0 7291 break;
ferencd@0 7292 // solidus
ferencd@0 7293 case '/':
ferencd@0 7294 add('/');
ferencd@0 7295 break;
ferencd@0 7296 // backspace
ferencd@0 7297 case 'b':
ferencd@0 7298 add('\b');
ferencd@0 7299 break;
ferencd@0 7300 // form feed
ferencd@0 7301 case 'f':
ferencd@0 7302 add('\f');
ferencd@0 7303 break;
ferencd@0 7304 // line feed
ferencd@0 7305 case 'n':
ferencd@0 7306 add('\n');
ferencd@0 7307 break;
ferencd@0 7308 // carriage return
ferencd@0 7309 case 'r':
ferencd@0 7310 add('\r');
ferencd@0 7311 break;
ferencd@0 7312 // tab
ferencd@0 7313 case 't':
ferencd@0 7314 add('\t');
ferencd@0 7315 break;
ferencd@0 7316
ferencd@0 7317 // unicode escapes
ferencd@0 7318 case 'u':
ferencd@0 7319 {
ferencd@0 7320 const int codepoint1 = get_codepoint();
ferencd@0 7321 int codepoint = codepoint1; // start with codepoint1
ferencd@0 7322
ferencd@0 7323 if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1))
ferencd@0 7324 {
ferencd@0 7325 error_message = "invalid string: '\\u' must be followed by 4 hex digits";
ferencd@0 7326 return token_type::parse_error;
ferencd@0 7327 }
ferencd@0 7328
ferencd@0 7329 // check if code point is a high surrogate
ferencd@0 7330 if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF)
ferencd@0 7331 {
ferencd@0 7332 // expect next \uxxxx entry
ferencd@0 7333 if (JSON_HEDLEY_LIKELY(get() == '\\' and get() == 'u'))
ferencd@0 7334 {
ferencd@0 7335 const int codepoint2 = get_codepoint();
ferencd@0 7336
ferencd@0 7337 if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1))
ferencd@0 7338 {
ferencd@0 7339 error_message = "invalid string: '\\u' must be followed by 4 hex digits";
ferencd@0 7340 return token_type::parse_error;
ferencd@0 7341 }
ferencd@0 7342
ferencd@0 7343 // check if codepoint2 is a low surrogate
ferencd@0 7344 if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF))
ferencd@0 7345 {
ferencd@0 7346 // overwrite codepoint
ferencd@0 7347 codepoint = static_cast<int>(
ferencd@0 7348 // high surrogate occupies the most significant 22 bits
ferencd@0 7349 (static_cast<unsigned int>(codepoint1) << 10u)
ferencd@0 7350 // low surrogate occupies the least significant 15 bits
ferencd@0 7351 + static_cast<unsigned int>(codepoint2)
ferencd@0 7352 // there is still the 0xD800, 0xDC00 and 0x10000 noise
ferencd@0 7353 // in the result so we have to subtract with:
ferencd@0 7354 // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
ferencd@0 7355 - 0x35FDC00u);
ferencd@0 7356 }
ferencd@0 7357 else
ferencd@0 7358 {
ferencd@0 7359 error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
ferencd@0 7360 return token_type::parse_error;
ferencd@0 7361 }
ferencd@0 7362 }
ferencd@0 7363 else
ferencd@0 7364 {
ferencd@0 7365 error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF";
ferencd@0 7366 return token_type::parse_error;
ferencd@0 7367 }
ferencd@0 7368 }
ferencd@0 7369 else
ferencd@0 7370 {
ferencd@0 7371 if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF))
ferencd@0 7372 {
ferencd@0 7373 error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
ferencd@0 7374 return token_type::parse_error;
ferencd@0 7375 }
ferencd@0 7376 }
ferencd@0 7377
ferencd@0 7378 // result of the above calculation yields a proper codepoint
ferencd@0 7379 assert(0x00 <= codepoint and codepoint <= 0x10FFFF);
ferencd@0 7380
ferencd@0 7381 // translate codepoint into bytes
ferencd@0 7382 if (codepoint < 0x80)
ferencd@0 7383 {
ferencd@0 7384 // 1-byte characters: 0xxxxxxx (ASCII)
ferencd@0 7385 add(codepoint);
ferencd@0 7386 }
ferencd@0 7387 else if (codepoint <= 0x7FF)
ferencd@0 7388 {
ferencd@0 7389 // 2-byte characters: 110xxxxx 10xxxxxx
ferencd@0 7390 add(static_cast<int>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u)));
ferencd@0 7391 add(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
ferencd@0 7392 }
ferencd@0 7393 else if (codepoint <= 0xFFFF)
ferencd@0 7394 {
ferencd@0 7395 // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
ferencd@0 7396 add(static_cast<int>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u)));
ferencd@0 7397 add(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
ferencd@0 7398 add(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
ferencd@0 7399 }
ferencd@0 7400 else
ferencd@0 7401 {
ferencd@0 7402 // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
ferencd@0 7403 add(static_cast<int>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u)));
ferencd@0 7404 add(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu)));
ferencd@0 7405 add(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
ferencd@0 7406 add(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
ferencd@0 7407 }
ferencd@0 7408
ferencd@0 7409 break;
ferencd@0 7410 }
ferencd@0 7411
ferencd@0 7412 // other characters after escape
ferencd@0 7413 default:
ferencd@0 7414 error_message = "invalid string: forbidden character after backslash";
ferencd@0 7415 return token_type::parse_error;
ferencd@0 7416 }
ferencd@0 7417
ferencd@0 7418 break;
ferencd@0 7419 }
ferencd@0 7420
ferencd@0 7421 // invalid control characters
ferencd@0 7422 case 0x00:
ferencd@0 7423 {
ferencd@0 7424 error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000";
ferencd@0 7425 return token_type::parse_error;
ferencd@0 7426 }
ferencd@0 7427
ferencd@0 7428 case 0x01:
ferencd@0 7429 {
ferencd@0 7430 error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001";
ferencd@0 7431 return token_type::parse_error;
ferencd@0 7432 }
ferencd@0 7433
ferencd@0 7434 case 0x02:
ferencd@0 7435 {
ferencd@0 7436 error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002";
ferencd@0 7437 return token_type::parse_error;
ferencd@0 7438 }
ferencd@0 7439
ferencd@0 7440 case 0x03:
ferencd@0 7441 {
ferencd@0 7442 error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003";
ferencd@0 7443 return token_type::parse_error;
ferencd@0 7444 }
ferencd@0 7445
ferencd@0 7446 case 0x04:
ferencd@0 7447 {
ferencd@0 7448 error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004";
ferencd@0 7449 return token_type::parse_error;
ferencd@0 7450 }
ferencd@0 7451
ferencd@0 7452 case 0x05:
ferencd@0 7453 {
ferencd@0 7454 error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005";
ferencd@0 7455 return token_type::parse_error;
ferencd@0 7456 }
ferencd@0 7457
ferencd@0 7458 case 0x06:
ferencd@0 7459 {
ferencd@0 7460 error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006";
ferencd@0 7461 return token_type::parse_error;
ferencd@0 7462 }
ferencd@0 7463
ferencd@0 7464 case 0x07:
ferencd@0 7465 {
ferencd@0 7466 error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007";
ferencd@0 7467 return token_type::parse_error;
ferencd@0 7468 }
ferencd@0 7469
ferencd@0 7470 case 0x08:
ferencd@0 7471 {
ferencd@0 7472 error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b";
ferencd@0 7473 return token_type::parse_error;
ferencd@0 7474 }
ferencd@0 7475
ferencd@0 7476 case 0x09:
ferencd@0 7477 {
ferencd@0 7478 error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t";
ferencd@0 7479 return token_type::parse_error;
ferencd@0 7480 }
ferencd@0 7481
ferencd@0 7482 case 0x0A:
ferencd@0 7483 {
ferencd@0 7484 error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n";
ferencd@0 7485 return token_type::parse_error;
ferencd@0 7486 }
ferencd@0 7487
ferencd@0 7488 case 0x0B:
ferencd@0 7489 {
ferencd@0 7490 error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B";
ferencd@0 7491 return token_type::parse_error;
ferencd@0 7492 }
ferencd@0 7493
ferencd@0 7494 case 0x0C:
ferencd@0 7495 {
ferencd@0 7496 error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f";
ferencd@0 7497 return token_type::parse_error;
ferencd@0 7498 }
ferencd@0 7499
ferencd@0 7500 case 0x0D:
ferencd@0 7501 {
ferencd@0 7502 error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r";
ferencd@0 7503 return token_type::parse_error;
ferencd@0 7504 }
ferencd@0 7505
ferencd@0 7506 case 0x0E:
ferencd@0 7507 {
ferencd@0 7508 error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E";
ferencd@0 7509 return token_type::parse_error;
ferencd@0 7510 }
ferencd@0 7511
ferencd@0 7512 case 0x0F:
ferencd@0 7513 {
ferencd@0 7514 error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F";
ferencd@0 7515 return token_type::parse_error;
ferencd@0 7516 }
ferencd@0 7517
ferencd@0 7518 case 0x10:
ferencd@0 7519 {
ferencd@0 7520 error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010";
ferencd@0 7521 return token_type::parse_error;
ferencd@0 7522 }
ferencd@0 7523
ferencd@0 7524 case 0x11:
ferencd@0 7525 {
ferencd@0 7526 error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011";
ferencd@0 7527 return token_type::parse_error;
ferencd@0 7528 }
ferencd@0 7529
ferencd@0 7530 case 0x12:
ferencd@0 7531 {
ferencd@0 7532 error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012";
ferencd@0 7533 return token_type::parse_error;
ferencd@0 7534 }
ferencd@0 7535
ferencd@0 7536 case 0x13:
ferencd@0 7537 {
ferencd@0 7538 error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013";
ferencd@0 7539 return token_type::parse_error;
ferencd@0 7540 }
ferencd@0 7541
ferencd@0 7542 case 0x14:
ferencd@0 7543 {
ferencd@0 7544 error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014";
ferencd@0 7545 return token_type::parse_error;
ferencd@0 7546 }
ferencd@0 7547
ferencd@0 7548 case 0x15:
ferencd@0 7549 {
ferencd@0 7550 error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015";
ferencd@0 7551 return token_type::parse_error;
ferencd@0 7552 }
ferencd@0 7553
ferencd@0 7554 case 0x16:
ferencd@0 7555 {
ferencd@0 7556 error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016";
ferencd@0 7557 return token_type::parse_error;
ferencd@0 7558 }
ferencd@0 7559
ferencd@0 7560 case 0x17:
ferencd@0 7561 {
ferencd@0 7562 error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017";
ferencd@0 7563 return token_type::parse_error;
ferencd@0 7564 }
ferencd@0 7565
ferencd@0 7566 case 0x18:
ferencd@0 7567 {
ferencd@0 7568 error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018";
ferencd@0 7569 return token_type::parse_error;
ferencd@0 7570 }
ferencd@0 7571
ferencd@0 7572 case 0x19:
ferencd@0 7573 {
ferencd@0 7574 error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019";
ferencd@0 7575 return token_type::parse_error;
ferencd@0 7576 }
ferencd@0 7577
ferencd@0 7578 case 0x1A:
ferencd@0 7579 {
ferencd@0 7580 error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A";
ferencd@0 7581 return token_type::parse_error;
ferencd@0 7582 }
ferencd@0 7583
ferencd@0 7584 case 0x1B:
ferencd@0 7585 {
ferencd@0 7586 error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B";
ferencd@0 7587 return token_type::parse_error;
ferencd@0 7588 }
ferencd@0 7589
ferencd@0 7590 case 0x1C:
ferencd@0 7591 {
ferencd@0 7592 error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C";
ferencd@0 7593 return token_type::parse_error;
ferencd@0 7594 }
ferencd@0 7595
ferencd@0 7596 case 0x1D:
ferencd@0 7597 {
ferencd@0 7598 error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D";
ferencd@0 7599 return token_type::parse_error;
ferencd@0 7600 }
ferencd@0 7601
ferencd@0 7602 case 0x1E:
ferencd@0 7603 {
ferencd@0 7604 error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E";
ferencd@0 7605 return token_type::parse_error;
ferencd@0 7606 }
ferencd@0 7607
ferencd@0 7608 case 0x1F:
ferencd@0 7609 {
ferencd@0 7610 error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F";
ferencd@0 7611 return token_type::parse_error;
ferencd@0 7612 }
ferencd@0 7613
ferencd@0 7614 // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))
ferencd@0 7615 case 0x20:
ferencd@0 7616 case 0x21:
ferencd@0 7617 case 0x23:
ferencd@0 7618 case 0x24:
ferencd@0 7619 case 0x25:
ferencd@0 7620 case 0x26:
ferencd@0 7621 case 0x27:
ferencd@0 7622 case 0x28:
ferencd@0 7623 case 0x29:
ferencd@0 7624 case 0x2A:
ferencd@0 7625 case 0x2B:
ferencd@0 7626 case 0x2C:
ferencd@0 7627 case 0x2D:
ferencd@0 7628 case 0x2E:
ferencd@0 7629 case 0x2F:
ferencd@0 7630 case 0x30:
ferencd@0 7631 case 0x31:
ferencd@0 7632 case 0x32:
ferencd@0 7633 case 0x33:
ferencd@0 7634 case 0x34:
ferencd@0 7635 case 0x35:
ferencd@0 7636 case 0x36:
ferencd@0 7637 case 0x37:
ferencd@0 7638 case 0x38:
ferencd@0 7639 case 0x39:
ferencd@0 7640 case 0x3A:
ferencd@0 7641 case 0x3B:
ferencd@0 7642 case 0x3C:
ferencd@0 7643 case 0x3D:
ferencd@0 7644 case 0x3E:
ferencd@0 7645 case 0x3F:
ferencd@0 7646 case 0x40:
ferencd@0 7647 case 0x41:
ferencd@0 7648 case 0x42:
ferencd@0 7649 case 0x43:
ferencd@0 7650 case 0x44:
ferencd@0 7651 case 0x45:
ferencd@0 7652 case 0x46:
ferencd@0 7653 case 0x47:
ferencd@0 7654 case 0x48:
ferencd@0 7655 case 0x49:
ferencd@0 7656 case 0x4A:
ferencd@0 7657 case 0x4B:
ferencd@0 7658 case 0x4C:
ferencd@0 7659 case 0x4D:
ferencd@0 7660 case 0x4E:
ferencd@0 7661 case 0x4F:
ferencd@0 7662 case 0x50:
ferencd@0 7663 case 0x51:
ferencd@0 7664 case 0x52:
ferencd@0 7665 case 0x53:
ferencd@0 7666 case 0x54:
ferencd@0 7667 case 0x55:
ferencd@0 7668 case 0x56:
ferencd@0 7669 case 0x57:
ferencd@0 7670 case 0x58:
ferencd@0 7671 case 0x59:
ferencd@0 7672 case 0x5A:
ferencd@0 7673 case 0x5B:
ferencd@0 7674 case 0x5D:
ferencd@0 7675 case 0x5E:
ferencd@0 7676 case 0x5F:
ferencd@0 7677 case 0x60:
ferencd@0 7678 case 0x61:
ferencd@0 7679 case 0x62:
ferencd@0 7680 case 0x63:
ferencd@0 7681 case 0x64:
ferencd@0 7682 case 0x65:
ferencd@0 7683 case 0x66:
ferencd@0 7684 case 0x67:
ferencd@0 7685 case 0x68:
ferencd@0 7686 case 0x69:
ferencd@0 7687 case 0x6A:
ferencd@0 7688 case 0x6B:
ferencd@0 7689 case 0x6C:
ferencd@0 7690 case 0x6D:
ferencd@0 7691 case 0x6E:
ferencd@0 7692 case 0x6F:
ferencd@0 7693 case 0x70:
ferencd@0 7694 case 0x71:
ferencd@0 7695 case 0x72:
ferencd@0 7696 case 0x73:
ferencd@0 7697 case 0x74:
ferencd@0 7698 case 0x75:
ferencd@0 7699 case 0x76:
ferencd@0 7700 case 0x77:
ferencd@0 7701 case 0x78:
ferencd@0 7702 case 0x79:
ferencd@0 7703 case 0x7A:
ferencd@0 7704 case 0x7B:
ferencd@0 7705 case 0x7C:
ferencd@0 7706 case 0x7D:
ferencd@0 7707 case 0x7E:
ferencd@0 7708 case 0x7F:
ferencd@0 7709 {
ferencd@0 7710 add(current);
ferencd@0 7711 break;
ferencd@0 7712 }
ferencd@0 7713
ferencd@0 7714 // U+0080..U+07FF: bytes C2..DF 80..BF
ferencd@0 7715 case 0xC2:
ferencd@0 7716 case 0xC3:
ferencd@0 7717 case 0xC4:
ferencd@0 7718 case 0xC5:
ferencd@0 7719 case 0xC6:
ferencd@0 7720 case 0xC7:
ferencd@0 7721 case 0xC8:
ferencd@0 7722 case 0xC9:
ferencd@0 7723 case 0xCA:
ferencd@0 7724 case 0xCB:
ferencd@0 7725 case 0xCC:
ferencd@0 7726 case 0xCD:
ferencd@0 7727 case 0xCE:
ferencd@0 7728 case 0xCF:
ferencd@0 7729 case 0xD0:
ferencd@0 7730 case 0xD1:
ferencd@0 7731 case 0xD2:
ferencd@0 7732 case 0xD3:
ferencd@0 7733 case 0xD4:
ferencd@0 7734 case 0xD5:
ferencd@0 7735 case 0xD6:
ferencd@0 7736 case 0xD7:
ferencd@0 7737 case 0xD8:
ferencd@0 7738 case 0xD9:
ferencd@0 7739 case 0xDA:
ferencd@0 7740 case 0xDB:
ferencd@0 7741 case 0xDC:
ferencd@0 7742 case 0xDD:
ferencd@0 7743 case 0xDE:
ferencd@0 7744 case 0xDF:
ferencd@0 7745 {
ferencd@0 7746 if (JSON_HEDLEY_UNLIKELY(not next_byte_in_range({0x80, 0xBF})))
ferencd@0 7747 {
ferencd@0 7748 return token_type::parse_error;
ferencd@0 7749 }
ferencd@0 7750 break;
ferencd@0 7751 }
ferencd@0 7752
ferencd@0 7753 // U+0800..U+0FFF: bytes E0 A0..BF 80..BF
ferencd@0 7754 case 0xE0:
ferencd@0 7755 {
ferencd@0 7756 if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
ferencd@0 7757 {
ferencd@0 7758 return token_type::parse_error;
ferencd@0 7759 }
ferencd@0 7760 break;
ferencd@0 7761 }
ferencd@0 7762
ferencd@0 7763 // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF
ferencd@0 7764 // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF
ferencd@0 7765 case 0xE1:
ferencd@0 7766 case 0xE2:
ferencd@0 7767 case 0xE3:
ferencd@0 7768 case 0xE4:
ferencd@0 7769 case 0xE5:
ferencd@0 7770 case 0xE6:
ferencd@0 7771 case 0xE7:
ferencd@0 7772 case 0xE8:
ferencd@0 7773 case 0xE9:
ferencd@0 7774 case 0xEA:
ferencd@0 7775 case 0xEB:
ferencd@0 7776 case 0xEC:
ferencd@0 7777 case 0xEE:
ferencd@0 7778 case 0xEF:
ferencd@0 7779 {
ferencd@0 7780 if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
ferencd@0 7781 {
ferencd@0 7782 return token_type::parse_error;
ferencd@0 7783 }
ferencd@0 7784 break;
ferencd@0 7785 }
ferencd@0 7786
ferencd@0 7787 // U+D000..U+D7FF: bytes ED 80..9F 80..BF
ferencd@0 7788 case 0xED:
ferencd@0 7789 {
ferencd@0 7790 if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
ferencd@0 7791 {
ferencd@0 7792 return token_type::parse_error;
ferencd@0 7793 }
ferencd@0 7794 break;
ferencd@0 7795 }
ferencd@0 7796
ferencd@0 7797 // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
ferencd@0 7798 case 0xF0:
ferencd@0 7799 {
ferencd@0 7800 if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
ferencd@0 7801 {
ferencd@0 7802 return token_type::parse_error;
ferencd@0 7803 }
ferencd@0 7804 break;
ferencd@0 7805 }
ferencd@0 7806
ferencd@0 7807 // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
ferencd@0 7808 case 0xF1:
ferencd@0 7809 case 0xF2:
ferencd@0 7810 case 0xF3:
ferencd@0 7811 {
ferencd@0 7812 if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
ferencd@0 7813 {
ferencd@0 7814 return token_type::parse_error;
ferencd@0 7815 }
ferencd@0 7816 break;
ferencd@0 7817 }
ferencd@0 7818
ferencd@0 7819 // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
ferencd@0 7820 case 0xF4:
ferencd@0 7821 {
ferencd@0 7822 if (JSON_HEDLEY_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
ferencd@0 7823 {
ferencd@0 7824 return token_type::parse_error;
ferencd@0 7825 }
ferencd@0 7826 break;
ferencd@0 7827 }
ferencd@0 7828
ferencd@0 7829 // remaining bytes (80..C1 and F5..FF) are ill-formed
ferencd@0 7830 default:
ferencd@0 7831 {
ferencd@0 7832 error_message = "invalid string: ill-formed UTF-8 byte";
ferencd@0 7833 return token_type::parse_error;
ferencd@0 7834 }
ferencd@0 7835 }
ferencd@0 7836 }
ferencd@0 7837 }
ferencd@0 7838
ferencd@0 7839 JSON_HEDLEY_NON_NULL(2)
ferencd@0 7840 static void strtof(float& f, const char* str, char** endptr) noexcept
ferencd@0 7841 {
ferencd@0 7842 f = std::strtof(str, endptr);
ferencd@0 7843 }
ferencd@0 7844
ferencd@0 7845 JSON_HEDLEY_NON_NULL(2)
ferencd@0 7846 static void strtof(double& f, const char* str, char** endptr) noexcept
ferencd@0 7847 {
ferencd@0 7848 f = std::strtod(str, endptr);
ferencd@0 7849 }
ferencd@0 7850
ferencd@0 7851 JSON_HEDLEY_NON_NULL(2)
ferencd@0 7852 static void strtof(long double& f, const char* str, char** endptr) noexcept
ferencd@0 7853 {
ferencd@0 7854 f = std::strtold(str, endptr);
ferencd@0 7855 }
ferencd@0 7856
ferencd@0 7857 /*!
ferencd@0 7858 @brief scan a number literal
ferencd@0 7859
ferencd@0 7860 This function scans a string according to Sect. 6 of RFC 7159.
ferencd@0 7861
ferencd@0 7862 The function is realized with a deterministic finite state machine derived
ferencd@0 7863 from the grammar described in RFC 7159. Starting in state "init", the
ferencd@0 7864 input is read and used to determined the next state. Only state "done"
ferencd@0 7865 accepts the number. State "error" is a trap state to model errors. In the
ferencd@0 7866 table below, "anything" means any character but the ones listed before.
ferencd@0 7867
ferencd@0 7868 state | 0 | 1-9 | e E | + | - | . | anything
ferencd@0 7869 ---------|----------|----------|----------|---------|---------|----------|-----------
ferencd@0 7870 init | zero | any1 | [error] | [error] | minus | [error] | [error]
ferencd@0 7871 minus | zero | any1 | [error] | [error] | [error] | [error] | [error]
ferencd@0 7872 zero | done | done | exponent | done | done | decimal1 | done
ferencd@0 7873 any1 | any1 | any1 | exponent | done | done | decimal1 | done
ferencd@0 7874 decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error]
ferencd@0 7875 decimal2 | decimal2 | decimal2 | exponent | done | done | done | done
ferencd@0 7876 exponent | any2 | any2 | [error] | sign | sign | [error] | [error]
ferencd@0 7877 sign | any2 | any2 | [error] | [error] | [error] | [error] | [error]
ferencd@0 7878 any2 | any2 | any2 | done | done | done | done | done
ferencd@0 7879
ferencd@0 7880 The state machine is realized with one label per state (prefixed with
ferencd@0 7881 "scan_number_") and `goto` statements between them. The state machine
ferencd@0 7882 contains cycles, but any cycle can be left when EOF is read. Therefore,
ferencd@0 7883 the function is guaranteed to terminate.
ferencd@0 7884
ferencd@0 7885 During scanning, the read bytes are stored in token_buffer. This string is
ferencd@0 7886 then converted to a signed integer, an unsigned integer, or a
ferencd@0 7887 floating-point number.
ferencd@0 7888
ferencd@0 7889 @return token_type::value_unsigned, token_type::value_integer, or
ferencd@0 7890 token_type::value_float if number could be successfully scanned,
ferencd@0 7891 token_type::parse_error otherwise
ferencd@0 7892
ferencd@0 7893 @note The scanner is independent of the current locale. Internally, the
ferencd@0 7894 locale's decimal point is used instead of `.` to work with the
ferencd@0 7895 locale-dependent converters.
ferencd@0 7896 */
ferencd@0 7897 token_type scan_number() // lgtm [cpp/use-of-goto]
ferencd@0 7898 {
ferencd@0 7899 // reset token_buffer to store the number's bytes
ferencd@0 7900 reset();
ferencd@0 7901
ferencd@0 7902 // the type of the parsed number; initially set to unsigned; will be
ferencd@0 7903 // changed if minus sign, decimal point or exponent is read
ferencd@0 7904 token_type number_type = token_type::value_unsigned;
ferencd@0 7905
ferencd@0 7906 // state (init): we just found out we need to scan a number
ferencd@0 7907 switch (current)
ferencd@0 7908 {
ferencd@0 7909 case '-':
ferencd@0 7910 {
ferencd@0 7911 add(current);
ferencd@0 7912 goto scan_number_minus;
ferencd@0 7913 }
ferencd@0 7914
ferencd@0 7915 case '0':
ferencd@0 7916 {
ferencd@0 7917 add(current);
ferencd@0 7918 goto scan_number_zero;
ferencd@0 7919 }
ferencd@0 7920
ferencd@0 7921 case '1':
ferencd@0 7922 case '2':
ferencd@0 7923 case '3':
ferencd@0 7924 case '4':
ferencd@0 7925 case '5':
ferencd@0 7926 case '6':
ferencd@0 7927 case '7':
ferencd@0 7928 case '8':
ferencd@0 7929 case '9':
ferencd@0 7930 {
ferencd@0 7931 add(current);
ferencd@0 7932 goto scan_number_any1;
ferencd@0 7933 }
ferencd@0 7934
ferencd@0 7935 // all other characters are rejected outside scan_number()
ferencd@0 7936 default: // LCOV_EXCL_LINE
ferencd@0 7937 assert(false); // LCOV_EXCL_LINE
ferencd@0 7938 }
ferencd@0 7939
ferencd@0 7940 scan_number_minus:
ferencd@0 7941 // state: we just parsed a leading minus sign
ferencd@0 7942 number_type = token_type::value_integer;
ferencd@0 7943 switch (get())
ferencd@0 7944 {
ferencd@0 7945 case '0':
ferencd@0 7946 {
ferencd@0 7947 add(current);
ferencd@0 7948 goto scan_number_zero;
ferencd@0 7949 }
ferencd@0 7950
ferencd@0 7951 case '1':
ferencd@0 7952 case '2':
ferencd@0 7953 case '3':
ferencd@0 7954 case '4':
ferencd@0 7955 case '5':
ferencd@0 7956 case '6':
ferencd@0 7957 case '7':
ferencd@0 7958 case '8':
ferencd@0 7959 case '9':
ferencd@0 7960 {
ferencd@0 7961 add(current);
ferencd@0 7962 goto scan_number_any1;
ferencd@0 7963 }
ferencd@0 7964
ferencd@0 7965 default:
ferencd@0 7966 {
ferencd@0 7967 error_message = "invalid number; expected digit after '-'";
ferencd@0 7968 return token_type::parse_error;
ferencd@0 7969 }
ferencd@0 7970 }
ferencd@0 7971
ferencd@0 7972 scan_number_zero:
ferencd@0 7973 // state: we just parse a zero (maybe with a leading minus sign)
ferencd@0 7974 switch (get())
ferencd@0 7975 {
ferencd@0 7976 case '.':
ferencd@0 7977 {
ferencd@0 7978 add(decimal_point_char);
ferencd@0 7979 goto scan_number_decimal1;
ferencd@0 7980 }
ferencd@0 7981
ferencd@0 7982 case 'e':
ferencd@0 7983 case 'E':
ferencd@0 7984 {
ferencd@0 7985 add(current);
ferencd@0 7986 goto scan_number_exponent;
ferencd@0 7987 }
ferencd@0 7988
ferencd@0 7989 default:
ferencd@0 7990 goto scan_number_done;
ferencd@0 7991 }
ferencd@0 7992
ferencd@0 7993 scan_number_any1:
ferencd@0 7994 // state: we just parsed a number 0-9 (maybe with a leading minus sign)
ferencd@0 7995 switch (get())
ferencd@0 7996 {
ferencd@0 7997 case '0':
ferencd@0 7998 case '1':
ferencd@0 7999 case '2':
ferencd@0 8000 case '3':
ferencd@0 8001 case '4':
ferencd@0 8002 case '5':
ferencd@0 8003 case '6':
ferencd@0 8004 case '7':
ferencd@0 8005 case '8':
ferencd@0 8006 case '9':
ferencd@0 8007 {
ferencd@0 8008 add(current);
ferencd@0 8009 goto scan_number_any1;
ferencd@0 8010 }
ferencd@0 8011
ferencd@0 8012 case '.':
ferencd@0 8013 {
ferencd@0 8014 add(decimal_point_char);
ferencd@0 8015 goto scan_number_decimal1;
ferencd@0 8016 }
ferencd@0 8017
ferencd@0 8018 case 'e':
ferencd@0 8019 case 'E':
ferencd@0 8020 {
ferencd@0 8021 add(current);
ferencd@0 8022 goto scan_number_exponent;
ferencd@0 8023 }
ferencd@0 8024
ferencd@0 8025 default:
ferencd@0 8026 goto scan_number_done;
ferencd@0 8027 }
ferencd@0 8028
ferencd@0 8029 scan_number_decimal1:
ferencd@0 8030 // state: we just parsed a decimal point
ferencd@0 8031 number_type = token_type::value_float;
ferencd@0 8032 switch (get())
ferencd@0 8033 {
ferencd@0 8034 case '0':
ferencd@0 8035 case '1':
ferencd@0 8036 case '2':
ferencd@0 8037 case '3':
ferencd@0 8038 case '4':
ferencd@0 8039 case '5':
ferencd@0 8040 case '6':
ferencd@0 8041 case '7':
ferencd@0 8042 case '8':
ferencd@0 8043 case '9':
ferencd@0 8044 {
ferencd@0 8045 add(current);
ferencd@0 8046 goto scan_number_decimal2;
ferencd@0 8047 }
ferencd@0 8048
ferencd@0 8049 default:
ferencd@0 8050 {
ferencd@0 8051 error_message = "invalid number; expected digit after '.'";
ferencd@0 8052 return token_type::parse_error;
ferencd@0 8053 }
ferencd@0 8054 }
ferencd@0 8055
ferencd@0 8056 scan_number_decimal2:
ferencd@0 8057 // we just parsed at least one number after a decimal point
ferencd@0 8058 switch (get())
ferencd@0 8059 {
ferencd@0 8060 case '0':
ferencd@0 8061 case '1':
ferencd@0 8062 case '2':
ferencd@0 8063 case '3':
ferencd@0 8064 case '4':
ferencd@0 8065 case '5':
ferencd@0 8066 case '6':
ferencd@0 8067 case '7':
ferencd@0 8068 case '8':
ferencd@0 8069 case '9':
ferencd@0 8070 {
ferencd@0 8071 add(current);
ferencd@0 8072 goto scan_number_decimal2;
ferencd@0 8073 }
ferencd@0 8074
ferencd@0 8075 case 'e':
ferencd@0 8076 case 'E':
ferencd@0 8077 {
ferencd@0 8078 add(current);
ferencd@0 8079 goto scan_number_exponent;
ferencd@0 8080 }
ferencd@0 8081
ferencd@0 8082 default:
ferencd@0 8083 goto scan_number_done;
ferencd@0 8084 }
ferencd@0 8085
ferencd@0 8086 scan_number_exponent:
ferencd@0 8087 // we just parsed an exponent
ferencd@0 8088 number_type = token_type::value_float;
ferencd@0 8089 switch (get())
ferencd@0 8090 {
ferencd@0 8091 case '+':
ferencd@0 8092 case '-':
ferencd@0 8093 {
ferencd@0 8094 add(current);
ferencd@0 8095 goto scan_number_sign;
ferencd@0 8096 }
ferencd@0 8097
ferencd@0 8098 case '0':
ferencd@0 8099 case '1':
ferencd@0 8100 case '2':
ferencd@0 8101 case '3':
ferencd@0 8102 case '4':
ferencd@0 8103 case '5':
ferencd@0 8104 case '6':
ferencd@0 8105 case '7':
ferencd@0 8106 case '8':
ferencd@0 8107 case '9':
ferencd@0 8108 {
ferencd@0 8109 add(current);
ferencd@0 8110 goto scan_number_any2;
ferencd@0 8111 }
ferencd@0 8112
ferencd@0 8113 default:
ferencd@0 8114 {
ferencd@0 8115 error_message =
ferencd@0 8116 "invalid number; expected '+', '-', or digit after exponent";
ferencd@0 8117 return token_type::parse_error;
ferencd@0 8118 }
ferencd@0 8119 }
ferencd@0 8120
ferencd@0 8121 scan_number_sign:
ferencd@0 8122 // we just parsed an exponent sign
ferencd@0 8123 switch (get())
ferencd@0 8124 {
ferencd@0 8125 case '0':
ferencd@0 8126 case '1':
ferencd@0 8127 case '2':
ferencd@0 8128 case '3':
ferencd@0 8129 case '4':
ferencd@0 8130 case '5':
ferencd@0 8131 case '6':
ferencd@0 8132 case '7':
ferencd@0 8133 case '8':
ferencd@0 8134 case '9':
ferencd@0 8135 {
ferencd@0 8136 add(current);
ferencd@0 8137 goto scan_number_any2;
ferencd@0 8138 }
ferencd@0 8139
ferencd@0 8140 default:
ferencd@0 8141 {
ferencd@0 8142 error_message = "invalid number; expected digit after exponent sign";
ferencd@0 8143 return token_type::parse_error;
ferencd@0 8144 }
ferencd@0 8145 }
ferencd@0 8146
ferencd@0 8147 scan_number_any2:
ferencd@0 8148 // we just parsed a number after the exponent or exponent sign
ferencd@0 8149 switch (get())
ferencd@0 8150 {
ferencd@0 8151 case '0':
ferencd@0 8152 case '1':
ferencd@0 8153 case '2':
ferencd@0 8154 case '3':
ferencd@0 8155 case '4':
ferencd@0 8156 case '5':
ferencd@0 8157 case '6':
ferencd@0 8158 case '7':
ferencd@0 8159 case '8':
ferencd@0 8160 case '9':
ferencd@0 8161 {
ferencd@0 8162 add(current);
ferencd@0 8163 goto scan_number_any2;
ferencd@0 8164 }
ferencd@0 8165
ferencd@0 8166 default:
ferencd@0 8167 goto scan_number_done;
ferencd@0 8168 }
ferencd@0 8169
ferencd@0 8170 scan_number_done:
ferencd@0 8171 // unget the character after the number (we only read it to know that
ferencd@0 8172 // we are done scanning a number)
ferencd@0 8173 unget();
ferencd@0 8174
ferencd@0 8175 char* endptr = nullptr;
ferencd@0 8176 errno = 0;
ferencd@0 8177
ferencd@0 8178 // try to parse integers first and fall back to floats
ferencd@0 8179 if (number_type == token_type::value_unsigned)
ferencd@0 8180 {
ferencd@0 8181 const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
ferencd@0 8182
ferencd@0 8183 // we checked the number format before
ferencd@0 8184 assert(endptr == token_buffer.data() + token_buffer.size());
ferencd@0 8185
ferencd@0 8186 if (errno == 0)
ferencd@0 8187 {
ferencd@0 8188 value_unsigned = static_cast<number_unsigned_t>(x);
ferencd@0 8189 if (value_unsigned == x)
ferencd@0 8190 {
ferencd@0 8191 return token_type::value_unsigned;
ferencd@0 8192 }
ferencd@0 8193 }
ferencd@0 8194 }
ferencd@0 8195 else if (number_type == token_type::value_integer)
ferencd@0 8196 {
ferencd@0 8197 const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
ferencd@0 8198
ferencd@0 8199 // we checked the number format before
ferencd@0 8200 assert(endptr == token_buffer.data() + token_buffer.size());
ferencd@0 8201
ferencd@0 8202 if (errno == 0)
ferencd@0 8203 {
ferencd@0 8204 value_integer = static_cast<number_integer_t>(x);
ferencd@0 8205 if (value_integer == x)
ferencd@0 8206 {
ferencd@0 8207 return token_type::value_integer;
ferencd@0 8208 }
ferencd@0 8209 }
ferencd@0 8210 }
ferencd@0 8211
ferencd@0 8212 // this code is reached if we parse a floating-point number or if an
ferencd@0 8213 // integer conversion above failed
ferencd@0 8214 strtof(value_float, token_buffer.data(), &endptr);
ferencd@0 8215
ferencd@0 8216 // we checked the number format before
ferencd@0 8217 assert(endptr == token_buffer.data() + token_buffer.size());
ferencd@0 8218
ferencd@0 8219 return token_type::value_float;
ferencd@0 8220 }
ferencd@0 8221
ferencd@0 8222 /*!
ferencd@0 8223 @param[in] literal_text the literal text to expect
ferencd@0 8224 @param[in] length the length of the passed literal text
ferencd@0 8225 @param[in] return_type the token type to return on success
ferencd@0 8226 */
ferencd@0 8227 JSON_HEDLEY_NON_NULL(2)
ferencd@0 8228 token_type scan_literal(const char* literal_text, const std::size_t length,
ferencd@0 8229 token_type return_type)
ferencd@0 8230 {
ferencd@0 8231 assert(current == literal_text[0]);
ferencd@0 8232 for (std::size_t i = 1; i < length; ++i)
ferencd@0 8233 {
ferencd@0 8234 if (JSON_HEDLEY_UNLIKELY(get() != literal_text[i]))
ferencd@0 8235 {
ferencd@0 8236 error_message = "invalid literal";
ferencd@0 8237 return token_type::parse_error;
ferencd@0 8238 }
ferencd@0 8239 }
ferencd@0 8240 return return_type;
ferencd@0 8241 }
ferencd@0 8242
ferencd@0 8243 /////////////////////
ferencd@0 8244 // input management
ferencd@0 8245 /////////////////////
ferencd@0 8246
ferencd@0 8247 /// reset token_buffer; current character is beginning of token
ferencd@0 8248 void reset() noexcept
ferencd@0 8249 {
ferencd@0 8250 token_buffer.clear();
ferencd@0 8251 token_string.clear();
ferencd@0 8252 token_string.push_back(std::char_traits<char>::to_char_type(current));
ferencd@0 8253 }
ferencd@0 8254
ferencd@0 8255 /*
ferencd@0 8256 @brief get next character from the input
ferencd@0 8257
ferencd@0 8258 This function provides the interface to the used input adapter. It does
ferencd@0 8259 not throw in case the input reached EOF, but returns a
ferencd@0 8260 `std::char_traits<char>::eof()` in that case. Stores the scanned characters
ferencd@0 8261 for use in error messages.
ferencd@0 8262
ferencd@0 8263 @return character read from the input
ferencd@0 8264 */
ferencd@0 8265 std::char_traits<char>::int_type get()
ferencd@0 8266 {
ferencd@0 8267 ++position.chars_read_total;
ferencd@0 8268 ++position.chars_read_current_line;
ferencd@0 8269
ferencd@0 8270 if (next_unget)
ferencd@0 8271 {
ferencd@0 8272 // just reset the next_unget variable and work with current
ferencd@0 8273 next_unget = false;
ferencd@0 8274 }
ferencd@0 8275 else
ferencd@0 8276 {
ferencd@0 8277 current = ia->get_character();
ferencd@0 8278 }
ferencd@0 8279
ferencd@0 8280 if (JSON_HEDLEY_LIKELY(current != std::char_traits<char>::eof()))
ferencd@0 8281 {
ferencd@0 8282 token_string.push_back(std::char_traits<char>::to_char_type(current));
ferencd@0 8283 }
ferencd@0 8284
ferencd@0 8285 if (current == '\n')
ferencd@0 8286 {
ferencd@0 8287 ++position.lines_read;
ferencd@0 8288 position.chars_read_current_line = 0;
ferencd@0 8289 }
ferencd@0 8290
ferencd@0 8291 return current;
ferencd@0 8292 }
ferencd@0 8293
ferencd@0 8294 /*!
ferencd@0 8295 @brief unget current character (read it again on next get)
ferencd@0 8296
ferencd@0 8297 We implement unget by setting variable next_unget to true. The input is not
ferencd@0 8298 changed - we just simulate ungetting by modifying chars_read_total,
ferencd@0 8299 chars_read_current_line, and token_string. The next call to get() will
ferencd@0 8300 behave as if the unget character is read again.
ferencd@0 8301 */
ferencd@0 8302 void unget()
ferencd@0 8303 {
ferencd@0 8304 next_unget = true;
ferencd@0 8305
ferencd@0 8306 --position.chars_read_total;
ferencd@0 8307
ferencd@0 8308 // in case we "unget" a newline, we have to also decrement the lines_read
ferencd@0 8309 if (position.chars_read_current_line == 0)
ferencd@0 8310 {
ferencd@0 8311 if (position.lines_read > 0)
ferencd@0 8312 {
ferencd@0 8313 --position.lines_read;
ferencd@0 8314 }
ferencd@0 8315 }
ferencd@0 8316 else
ferencd@0 8317 {
ferencd@0 8318 --position.chars_read_current_line;
ferencd@0 8319 }
ferencd@0 8320
ferencd@0 8321 if (JSON_HEDLEY_LIKELY(current != std::char_traits<char>::eof()))
ferencd@0 8322 {
ferencd@0 8323 assert(not token_string.empty());
ferencd@0 8324 token_string.pop_back();
ferencd@0 8325 }
ferencd@0 8326 }
ferencd@0 8327
ferencd@0 8328 /// add a character to token_buffer
ferencd@0 8329 void add(int c)
ferencd@0 8330 {
ferencd@0 8331 token_buffer.push_back(std::char_traits<char>::to_char_type(c));
ferencd@0 8332 }
ferencd@0 8333
ferencd@0 8334 public:
ferencd@0 8335 /////////////////////
ferencd@0 8336 // value getters
ferencd@0 8337 /////////////////////
ferencd@0 8338
ferencd@0 8339 /// return integer value
ferencd@0 8340 constexpr number_integer_t get_number_integer() const noexcept
ferencd@0 8341 {
ferencd@0 8342 return value_integer;
ferencd@0 8343 }
ferencd@0 8344
ferencd@0 8345 /// return unsigned integer value
ferencd@0 8346 constexpr number_unsigned_t get_number_unsigned() const noexcept
ferencd@0 8347 {
ferencd@0 8348 return value_unsigned;
ferencd@0 8349 }
ferencd@0 8350
ferencd@0 8351 /// return floating-point value
ferencd@0 8352 constexpr number_float_t get_number_float() const noexcept
ferencd@0 8353 {
ferencd@0 8354 return value_float;
ferencd@0 8355 }
ferencd@0 8356
ferencd@0 8357 /// return current string value (implicitly resets the token; useful only once)
ferencd@0 8358 string_t& get_string()
ferencd@0 8359 {
ferencd@0 8360 return token_buffer;
ferencd@0 8361 }
ferencd@0 8362
ferencd@0 8363 /////////////////////
ferencd@0 8364 // diagnostics
ferencd@0 8365 /////////////////////
ferencd@0 8366
ferencd@0 8367 /// return position of last read token
ferencd@0 8368 constexpr position_t get_position() const noexcept
ferencd@0 8369 {
ferencd@0 8370 return position;
ferencd@0 8371 }
ferencd@0 8372
ferencd@0 8373 /// return the last read token (for errors only). Will never contain EOF
ferencd@0 8374 /// (an arbitrary value that is not a valid char value, often -1), because
ferencd@0 8375 /// 255 may legitimately occur. May contain NUL, which should be escaped.
ferencd@0 8376 std::string get_token_string() const
ferencd@0 8377 {
ferencd@0 8378 // escape control characters
ferencd@0 8379 std::string result;
ferencd@0 8380 for (const auto c : token_string)
ferencd@0 8381 {
ferencd@0 8382 if ('\x00' <= c and c <= '\x1F')
ferencd@0 8383 {
ferencd@0 8384 // escape control characters
ferencd@0 8385 std::array<char, 9> cs{{}};
ferencd@0 8386 (std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c));
ferencd@0 8387 result += cs.data();
ferencd@0 8388 }
ferencd@0 8389 else
ferencd@0 8390 {
ferencd@0 8391 // add character as is
ferencd@0 8392 result.push_back(c);
ferencd@0 8393 }
ferencd@0 8394 }
ferencd@0 8395
ferencd@0 8396 return result;
ferencd@0 8397 }
ferencd@0 8398
ferencd@0 8399 /// return syntax error message
ferencd@0 8400 JSON_HEDLEY_RETURNS_NON_NULL
ferencd@0 8401 constexpr const char* get_error_message() const noexcept
ferencd@0 8402 {
ferencd@0 8403 return error_message;
ferencd@0 8404 }
ferencd@0 8405
ferencd@0 8406 /////////////////////
ferencd@0 8407 // actual scanner
ferencd@0 8408 /////////////////////
ferencd@0 8409
ferencd@0 8410 /*!
ferencd@0 8411 @brief skip the UTF-8 byte order mark
ferencd@0 8412 @return true iff there is no BOM or the correct BOM has been skipped
ferencd@0 8413 */
ferencd@0 8414 bool skip_bom()
ferencd@0 8415 {
ferencd@0 8416 if (get() == 0xEF)
ferencd@0 8417 {
ferencd@0 8418 // check if we completely parse the BOM
ferencd@0 8419 return get() == 0xBB and get() == 0xBF;
ferencd@0 8420 }
ferencd@0 8421
ferencd@0 8422 // the first character is not the beginning of the BOM; unget it to
ferencd@0 8423 // process is later
ferencd@0 8424 unget();
ferencd@0 8425 return true;
ferencd@0 8426 }
ferencd@0 8427
ferencd@0 8428 token_type scan()
ferencd@0 8429 {
ferencd@0 8430 // initially, skip the BOM
ferencd@0 8431 if (position.chars_read_total == 0 and not skip_bom())
ferencd@0 8432 {
ferencd@0 8433 error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
ferencd@0 8434 return token_type::parse_error;
ferencd@0 8435 }
ferencd@0 8436
ferencd@0 8437 // read next character and ignore whitespace
ferencd@0 8438 do
ferencd@0 8439 {
ferencd@0 8440 get();
ferencd@0 8441 }
ferencd@0 8442 while (current == ' ' or current == '\t' or current == '\n' or current == '\r');
ferencd@0 8443
ferencd@0 8444 switch (current)
ferencd@0 8445 {
ferencd@0 8446 // structural characters
ferencd@0 8447 case '[':
ferencd@0 8448 return token_type::begin_array;
ferencd@0 8449 case ']':
ferencd@0 8450 return token_type::end_array;
ferencd@0 8451 case '{':
ferencd@0 8452 return token_type::begin_object;
ferencd@0 8453 case '}':
ferencd@0 8454 return token_type::end_object;
ferencd@0 8455 case ':':
ferencd@0 8456 return token_type::name_separator;
ferencd@0 8457 case ',':
ferencd@0 8458 return token_type::value_separator;
ferencd@0 8459
ferencd@0 8460 // literals
ferencd@0 8461 case 't':
ferencd@0 8462 return scan_literal("true", 4, token_type::literal_true);
ferencd@0 8463 case 'f':
ferencd@0 8464 return scan_literal("false", 5, token_type::literal_false);
ferencd@0 8465 case 'n':
ferencd@0 8466 return scan_literal("null", 4, token_type::literal_null);
ferencd@0 8467
ferencd@0 8468 // string
ferencd@0 8469 case '\"':
ferencd@0 8470 return scan_string();
ferencd@0 8471
ferencd@0 8472 // number
ferencd@0 8473 case '-':
ferencd@0 8474 case '0':
ferencd@0 8475 case '1':
ferencd@0 8476 case '2':
ferencd@0 8477 case '3':
ferencd@0 8478 case '4':
ferencd@0 8479 case '5':
ferencd@0 8480 case '6':
ferencd@0 8481 case '7':
ferencd@0 8482 case '8':
ferencd@0 8483 case '9':
ferencd@0 8484 return scan_number();
ferencd@0 8485
ferencd@0 8486 // end of input (the null byte is needed when parsing from
ferencd@0 8487 // string literals)
ferencd@0 8488 case '\0':
ferencd@0 8489 case std::char_traits<char>::eof():
ferencd@0 8490 return token_type::end_of_input;
ferencd@0 8491
ferencd@0 8492 // error
ferencd@0 8493 default:
ferencd@0 8494 error_message = "invalid literal";
ferencd@0 8495 return token_type::parse_error;
ferencd@0 8496 }
ferencd@0 8497 }
ferencd@0 8498
ferencd@0 8499 private:
ferencd@0 8500 /// input adapter
ferencd@0 8501 detail::input_adapter_t ia = nullptr;
ferencd@0 8502
ferencd@0 8503 /// the current character
ferencd@0 8504 std::char_traits<char>::int_type current = std::char_traits<char>::eof();
ferencd@0 8505
ferencd@0 8506 /// whether the next get() call should just return current
ferencd@0 8507 bool next_unget = false;
ferencd@0 8508
ferencd@0 8509 /// the start position of the current token
ferencd@0 8510 position_t position {};
ferencd@0 8511
ferencd@0 8512 /// raw input token string (for error messages)
ferencd@0 8513 std::vector<char> token_string {};
ferencd@0 8514
ferencd@0 8515 /// buffer for variable-length tokens (numbers, strings)
ferencd@0 8516 string_t token_buffer {};
ferencd@0 8517
ferencd@0 8518 /// a description of occurred lexer errors
ferencd@0 8519 const char* error_message = "";
ferencd@0 8520
ferencd@0 8521 // number values
ferencd@0 8522 number_integer_t value_integer = 0;
ferencd@0 8523 number_unsigned_t value_unsigned = 0;
ferencd@0 8524 number_float_t value_float = 0;
ferencd@0 8525
ferencd@0 8526 /// the decimal point
ferencd@0 8527 const char decimal_point_char = '.';
ferencd@0 8528 };
ferencd@0 8529 } // namespace detail
ferencd@0 8530 } // namespace nlohmann
ferencd@0 8531
ferencd@0 8532 // #include <nlohmann/detail/input/parser.hpp>
ferencd@0 8533
ferencd@0 8534
ferencd@0 8535 #include <cassert> // assert
ferencd@0 8536 #include <cmath> // isfinite
ferencd@0 8537 #include <cstdint> // uint8_t
ferencd@0 8538 #include <functional> // function
ferencd@0 8539 #include <string> // string
ferencd@0 8540 #include <utility> // move
ferencd@0 8541 #include <vector> // vector
ferencd@0 8542
ferencd@0 8543 // #include <nlohmann/detail/exceptions.hpp>
ferencd@0 8544
ferencd@0 8545 // #include <nlohmann/detail/input/input_adapters.hpp>
ferencd@0 8546
ferencd@0 8547 // #include <nlohmann/detail/input/json_sax.hpp>
ferencd@0 8548
ferencd@0 8549 // #include <nlohmann/detail/input/lexer.hpp>
ferencd@0 8550
ferencd@0 8551 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 8552
ferencd@0 8553 // #include <nlohmann/detail/meta/is_sax.hpp>
ferencd@0 8554
ferencd@0 8555 // #include <nlohmann/detail/value_t.hpp>
ferencd@0 8556
ferencd@0 8557
ferencd@0 8558 namespace nlohmann
ferencd@0 8559 {
ferencd@0 8560 namespace detail
ferencd@0 8561 {
ferencd@0 8562 ////////////
ferencd@0 8563 // parser //
ferencd@0 8564 ////////////
ferencd@0 8565
ferencd@0 8566 /*!
ferencd@0 8567 @brief syntax analysis
ferencd@0 8568
ferencd@0 8569 This class implements a recursive decent parser.
ferencd@0 8570 */
ferencd@0 8571 template<typename BasicJsonType>
ferencd@0 8572 class parser
ferencd@0 8573 {
ferencd@0 8574 using number_integer_t = typename BasicJsonType::number_integer_t;
ferencd@0 8575 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
ferencd@0 8576 using number_float_t = typename BasicJsonType::number_float_t;
ferencd@0 8577 using string_t = typename BasicJsonType::string_t;
ferencd@0 8578 using lexer_t = lexer<BasicJsonType>;
ferencd@0 8579 using token_type = typename lexer_t::token_type;
ferencd@0 8580
ferencd@0 8581 public:
ferencd@0 8582 enum class parse_event_t : uint8_t
ferencd@0 8583 {
ferencd@0 8584 /// the parser read `{` and started to process a JSON object
ferencd@0 8585 object_start,
ferencd@0 8586 /// the parser read `}` and finished processing a JSON object
ferencd@0 8587 object_end,
ferencd@0 8588 /// the parser read `[` and started to process a JSON array
ferencd@0 8589 array_start,
ferencd@0 8590 /// the parser read `]` and finished processing a JSON array
ferencd@0 8591 array_end,
ferencd@0 8592 /// the parser read a key of a value in an object
ferencd@0 8593 key,
ferencd@0 8594 /// the parser finished reading a JSON value
ferencd@0 8595 value
ferencd@0 8596 };
ferencd@0 8597
ferencd@0 8598 using parser_callback_t =
ferencd@0 8599 std::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>;
ferencd@0 8600
ferencd@0 8601 /// a parser reading from an input adapter
ferencd@0 8602 explicit parser(detail::input_adapter_t&& adapter,
ferencd@0 8603 const parser_callback_t cb = nullptr,
ferencd@0 8604 const bool allow_exceptions_ = true)
ferencd@0 8605 : callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_)
ferencd@0 8606 {
ferencd@0 8607 // read first token
ferencd@0 8608 get_token();
ferencd@0 8609 }
ferencd@0 8610
ferencd@0 8611 /*!
ferencd@0 8612 @brief public parser interface
ferencd@0 8613
ferencd@0 8614 @param[in] strict whether to expect the last token to be EOF
ferencd@0 8615 @param[in,out] result parsed JSON value
ferencd@0 8616
ferencd@0 8617 @throw parse_error.101 in case of an unexpected token
ferencd@0 8618 @throw parse_error.102 if to_unicode fails or surrogate error
ferencd@0 8619 @throw parse_error.103 if to_unicode fails
ferencd@0 8620 */
ferencd@0 8621 void parse(const bool strict, BasicJsonType& result)
ferencd@0 8622 {
ferencd@0 8623 if (callback)
ferencd@0 8624 {
ferencd@0 8625 json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
ferencd@0 8626 sax_parse_internal(&sdp);
ferencd@0 8627 result.assert_invariant();
ferencd@0 8628
ferencd@0 8629 // in strict mode, input must be completely read
ferencd@0 8630 if (strict and (get_token() != token_type::end_of_input))
ferencd@0 8631 {
ferencd@0 8632 sdp.parse_error(m_lexer.get_position(),
ferencd@0 8633 m_lexer.get_token_string(),
ferencd@0 8634 parse_error::create(101, m_lexer.get_position(),
ferencd@0 8635 exception_message(token_type::end_of_input, "value")));
ferencd@0 8636 }
ferencd@0 8637
ferencd@0 8638 // in case of an error, return discarded value
ferencd@0 8639 if (sdp.is_errored())
ferencd@0 8640 {
ferencd@0 8641 result = value_t::discarded;
ferencd@0 8642 return;
ferencd@0 8643 }
ferencd@0 8644
ferencd@0 8645 // set top-level value to null if it was discarded by the callback
ferencd@0 8646 // function
ferencd@0 8647 if (result.is_discarded())
ferencd@0 8648 {
ferencd@0 8649 result = nullptr;
ferencd@0 8650 }
ferencd@0 8651 }
ferencd@0 8652 else
ferencd@0 8653 {
ferencd@0 8654 json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
ferencd@0 8655 sax_parse_internal(&sdp);
ferencd@0 8656 result.assert_invariant();
ferencd@0 8657
ferencd@0 8658 // in strict mode, input must be completely read
ferencd@0 8659 if (strict and (get_token() != token_type::end_of_input))
ferencd@0 8660 {
ferencd@0 8661 sdp.parse_error(m_lexer.get_position(),
ferencd@0 8662 m_lexer.get_token_string(),
ferencd@0 8663 parse_error::create(101, m_lexer.get_position(),
ferencd@0 8664 exception_message(token_type::end_of_input, "value")));
ferencd@0 8665 }
ferencd@0 8666
ferencd@0 8667 // in case of an error, return discarded value
ferencd@0 8668 if (sdp.is_errored())
ferencd@0 8669 {
ferencd@0 8670 result = value_t::discarded;
ferencd@0 8671 return;
ferencd@0 8672 }
ferencd@0 8673 }
ferencd@0 8674 }
ferencd@0 8675
ferencd@0 8676 /*!
ferencd@0 8677 @brief public accept interface
ferencd@0 8678
ferencd@0 8679 @param[in] strict whether to expect the last token to be EOF
ferencd@0 8680 @return whether the input is a proper JSON text
ferencd@0 8681 */
ferencd@0 8682 bool accept(const bool strict = true)
ferencd@0 8683 {
ferencd@0 8684 json_sax_acceptor<BasicJsonType> sax_acceptor;
ferencd@0 8685 return sax_parse(&sax_acceptor, strict);
ferencd@0 8686 }
ferencd@0 8687
ferencd@0 8688 template <typename SAX>
ferencd@0 8689 JSON_HEDLEY_NON_NULL(2)
ferencd@0 8690 bool sax_parse(SAX* sax, const bool strict = true)
ferencd@0 8691 {
ferencd@0 8692 (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
ferencd@0 8693 const bool result = sax_parse_internal(sax);
ferencd@0 8694
ferencd@0 8695 // strict mode: next byte must be EOF
ferencd@0 8696 if (result and strict and (get_token() != token_type::end_of_input))
ferencd@0 8697 {
ferencd@0 8698 return sax->parse_error(m_lexer.get_position(),
ferencd@0 8699 m_lexer.get_token_string(),
ferencd@0 8700 parse_error::create(101, m_lexer.get_position(),
ferencd@0 8701 exception_message(token_type::end_of_input, "value")));
ferencd@0 8702 }
ferencd@0 8703
ferencd@0 8704 return result;
ferencd@0 8705 }
ferencd@0 8706
ferencd@0 8707 private:
ferencd@0 8708 template <typename SAX>
ferencd@0 8709 JSON_HEDLEY_NON_NULL(2)
ferencd@0 8710 bool sax_parse_internal(SAX* sax)
ferencd@0 8711 {
ferencd@0 8712 // stack to remember the hierarchy of structured values we are parsing
ferencd@0 8713 // true = array; false = object
ferencd@0 8714 std::vector<bool> states;
ferencd@0 8715 // value to avoid a goto (see comment where set to true)
ferencd@0 8716 bool skip_to_state_evaluation = false;
ferencd@0 8717
ferencd@0 8718 while (true)
ferencd@0 8719 {
ferencd@0 8720 if (not skip_to_state_evaluation)
ferencd@0 8721 {
ferencd@0 8722 // invariant: get_token() was called before each iteration
ferencd@0 8723 switch (last_token)
ferencd@0 8724 {
ferencd@0 8725 case token_type::begin_object:
ferencd@0 8726 {
ferencd@0 8727 if (JSON_HEDLEY_UNLIKELY(not sax->start_object(std::size_t(-1))))
ferencd@0 8728 {
ferencd@0 8729 return false;
ferencd@0 8730 }
ferencd@0 8731
ferencd@0 8732 // closing } -> we are done
ferencd@0 8733 if (get_token() == token_type::end_object)
ferencd@0 8734 {
ferencd@0 8735 if (JSON_HEDLEY_UNLIKELY(not sax->end_object()))
ferencd@0 8736 {
ferencd@0 8737 return false;
ferencd@0 8738 }
ferencd@0 8739 break;
ferencd@0 8740 }
ferencd@0 8741
ferencd@0 8742 // parse key
ferencd@0 8743 if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
ferencd@0 8744 {
ferencd@0 8745 return sax->parse_error(m_lexer.get_position(),
ferencd@0 8746 m_lexer.get_token_string(),
ferencd@0 8747 parse_error::create(101, m_lexer.get_position(),
ferencd@0 8748 exception_message(token_type::value_string, "object key")));
ferencd@0 8749 }
ferencd@0 8750 if (JSON_HEDLEY_UNLIKELY(not sax->key(m_lexer.get_string())))
ferencd@0 8751 {
ferencd@0 8752 return false;
ferencd@0 8753 }
ferencd@0 8754
ferencd@0 8755 // parse separator (:)
ferencd@0 8756 if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
ferencd@0 8757 {
ferencd@0 8758 return sax->parse_error(m_lexer.get_position(),
ferencd@0 8759 m_lexer.get_token_string(),
ferencd@0 8760 parse_error::create(101, m_lexer.get_position(),
ferencd@0 8761 exception_message(token_type::name_separator, "object separator")));
ferencd@0 8762 }
ferencd@0 8763
ferencd@0 8764 // remember we are now inside an object
ferencd@0 8765 states.push_back(false);
ferencd@0 8766
ferencd@0 8767 // parse values
ferencd@0 8768 get_token();
ferencd@0 8769 continue;
ferencd@0 8770 }
ferencd@0 8771
ferencd@0 8772 case token_type::begin_array:
ferencd@0 8773 {
ferencd@0 8774 if (JSON_HEDLEY_UNLIKELY(not sax->start_array(std::size_t(-1))))
ferencd@0 8775 {
ferencd@0 8776 return false;
ferencd@0 8777 }
ferencd@0 8778
ferencd@0 8779 // closing ] -> we are done
ferencd@0 8780 if (get_token() == token_type::end_array)
ferencd@0 8781 {
ferencd@0 8782 if (JSON_HEDLEY_UNLIKELY(not sax->end_array()))
ferencd@0 8783 {
ferencd@0 8784 return false;
ferencd@0 8785 }
ferencd@0 8786 break;
ferencd@0 8787 }
ferencd@0 8788
ferencd@0 8789 // remember we are now inside an array
ferencd@0 8790 states.push_back(true);
ferencd@0 8791
ferencd@0 8792 // parse values (no need to call get_token)
ferencd@0 8793 continue;
ferencd@0 8794 }
ferencd@0 8795
ferencd@0 8796 case token_type::value_float:
ferencd@0 8797 {
ferencd@0 8798 const auto res = m_lexer.get_number_float();
ferencd@0 8799
ferencd@0 8800 if (JSON_HEDLEY_UNLIKELY(not std::isfinite(res)))
ferencd@0 8801 {
ferencd@0 8802 return sax->parse_error(m_lexer.get_position(),
ferencd@0 8803 m_lexer.get_token_string(),
ferencd@0 8804 out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'"));
ferencd@0 8805 }
ferencd@0 8806
ferencd@0 8807 if (JSON_HEDLEY_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))
ferencd@0 8808 {
ferencd@0 8809 return false;
ferencd@0 8810 }
ferencd@0 8811
ferencd@0 8812 break;
ferencd@0 8813 }
ferencd@0 8814
ferencd@0 8815 case token_type::literal_false:
ferencd@0 8816 {
ferencd@0 8817 if (JSON_HEDLEY_UNLIKELY(not sax->boolean(false)))
ferencd@0 8818 {
ferencd@0 8819 return false;
ferencd@0 8820 }
ferencd@0 8821 break;
ferencd@0 8822 }
ferencd@0 8823
ferencd@0 8824 case token_type::literal_null:
ferencd@0 8825 {
ferencd@0 8826 if (JSON_HEDLEY_UNLIKELY(not sax->null()))
ferencd@0 8827 {
ferencd@0 8828 return false;
ferencd@0 8829 }
ferencd@0 8830 break;
ferencd@0 8831 }
ferencd@0 8832
ferencd@0 8833 case token_type::literal_true:
ferencd@0 8834 {
ferencd@0 8835 if (JSON_HEDLEY_UNLIKELY(not sax->boolean(true)))
ferencd@0 8836 {
ferencd@0 8837 return false;
ferencd@0 8838 }
ferencd@0 8839 break;
ferencd@0 8840 }
ferencd@0 8841
ferencd@0 8842 case token_type::value_integer:
ferencd@0 8843 {
ferencd@0 8844 if (JSON_HEDLEY_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))
ferencd@0 8845 {
ferencd@0 8846 return false;
ferencd@0 8847 }
ferencd@0 8848 break;
ferencd@0 8849 }
ferencd@0 8850
ferencd@0 8851 case token_type::value_string:
ferencd@0 8852 {
ferencd@0 8853 if (JSON_HEDLEY_UNLIKELY(not sax->string(m_lexer.get_string())))
ferencd@0 8854 {
ferencd@0 8855 return false;
ferencd@0 8856 }
ferencd@0 8857 break;
ferencd@0 8858 }
ferencd@0 8859
ferencd@0 8860 case token_type::value_unsigned:
ferencd@0 8861 {
ferencd@0 8862 if (JSON_HEDLEY_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))
ferencd@0 8863 {
ferencd@0 8864 return false;
ferencd@0 8865 }
ferencd@0 8866 break;
ferencd@0 8867 }
ferencd@0 8868
ferencd@0 8869 case token_type::parse_error:
ferencd@0 8870 {
ferencd@0 8871 // using "uninitialized" to avoid "expected" message
ferencd@0 8872 return sax->parse_error(m_lexer.get_position(),
ferencd@0 8873 m_lexer.get_token_string(),
ferencd@0 8874 parse_error::create(101, m_lexer.get_position(),
ferencd@0 8875 exception_message(token_type::uninitialized, "value")));
ferencd@0 8876 }
ferencd@0 8877
ferencd@0 8878 default: // the last token was unexpected
ferencd@0 8879 {
ferencd@0 8880 return sax->parse_error(m_lexer.get_position(),
ferencd@0 8881 m_lexer.get_token_string(),
ferencd@0 8882 parse_error::create(101, m_lexer.get_position(),
ferencd@0 8883 exception_message(token_type::literal_or_value, "value")));
ferencd@0 8884 }
ferencd@0 8885 }
ferencd@0 8886 }
ferencd@0 8887 else
ferencd@0 8888 {
ferencd@0 8889 skip_to_state_evaluation = false;
ferencd@0 8890 }
ferencd@0 8891
ferencd@0 8892 // we reached this line after we successfully parsed a value
ferencd@0 8893 if (states.empty())
ferencd@0 8894 {
ferencd@0 8895 // empty stack: we reached the end of the hierarchy: done
ferencd@0 8896 return true;
ferencd@0 8897 }
ferencd@0 8898
ferencd@0 8899 if (states.back()) // array
ferencd@0 8900 {
ferencd@0 8901 // comma -> next value
ferencd@0 8902 if (get_token() == token_type::value_separator)
ferencd@0 8903 {
ferencd@0 8904 // parse a new value
ferencd@0 8905 get_token();
ferencd@0 8906 continue;
ferencd@0 8907 }
ferencd@0 8908
ferencd@0 8909 // closing ]
ferencd@0 8910 if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array))
ferencd@0 8911 {
ferencd@0 8912 if (JSON_HEDLEY_UNLIKELY(not sax->end_array()))
ferencd@0 8913 {
ferencd@0 8914 return false;
ferencd@0 8915 }
ferencd@0 8916
ferencd@0 8917 // We are done with this array. Before we can parse a
ferencd@0 8918 // new value, we need to evaluate the new state first.
ferencd@0 8919 // By setting skip_to_state_evaluation to false, we
ferencd@0 8920 // are effectively jumping to the beginning of this if.
ferencd@0 8921 assert(not states.empty());
ferencd@0 8922 states.pop_back();
ferencd@0 8923 skip_to_state_evaluation = true;
ferencd@0 8924 continue;
ferencd@0 8925 }
ferencd@0 8926
ferencd@0 8927 return sax->parse_error(m_lexer.get_position(),
ferencd@0 8928 m_lexer.get_token_string(),
ferencd@0 8929 parse_error::create(101, m_lexer.get_position(),
ferencd@0 8930 exception_message(token_type::end_array, "array")));
ferencd@0 8931 }
ferencd@0 8932 else // object
ferencd@0 8933 {
ferencd@0 8934 // comma -> next value
ferencd@0 8935 if (get_token() == token_type::value_separator)
ferencd@0 8936 {
ferencd@0 8937 // parse key
ferencd@0 8938 if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))
ferencd@0 8939 {
ferencd@0 8940 return sax->parse_error(m_lexer.get_position(),
ferencd@0 8941 m_lexer.get_token_string(),
ferencd@0 8942 parse_error::create(101, m_lexer.get_position(),
ferencd@0 8943 exception_message(token_type::value_string, "object key")));
ferencd@0 8944 }
ferencd@0 8945
ferencd@0 8946 if (JSON_HEDLEY_UNLIKELY(not sax->key(m_lexer.get_string())))
ferencd@0 8947 {
ferencd@0 8948 return false;
ferencd@0 8949 }
ferencd@0 8950
ferencd@0 8951 // parse separator (:)
ferencd@0 8952 if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
ferencd@0 8953 {
ferencd@0 8954 return sax->parse_error(m_lexer.get_position(),
ferencd@0 8955 m_lexer.get_token_string(),
ferencd@0 8956 parse_error::create(101, m_lexer.get_position(),
ferencd@0 8957 exception_message(token_type::name_separator, "object separator")));
ferencd@0 8958 }
ferencd@0 8959
ferencd@0 8960 // parse values
ferencd@0 8961 get_token();
ferencd@0 8962 continue;
ferencd@0 8963 }
ferencd@0 8964
ferencd@0 8965 // closing }
ferencd@0 8966 if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))
ferencd@0 8967 {
ferencd@0 8968 if (JSON_HEDLEY_UNLIKELY(not sax->end_object()))
ferencd@0 8969 {
ferencd@0 8970 return false;
ferencd@0 8971 }
ferencd@0 8972
ferencd@0 8973 // We are done with this object. Before we can parse a
ferencd@0 8974 // new value, we need to evaluate the new state first.
ferencd@0 8975 // By setting skip_to_state_evaluation to false, we
ferencd@0 8976 // are effectively jumping to the beginning of this if.
ferencd@0 8977 assert(not states.empty());
ferencd@0 8978 states.pop_back();
ferencd@0 8979 skip_to_state_evaluation = true;
ferencd@0 8980 continue;
ferencd@0 8981 }
ferencd@0 8982
ferencd@0 8983 return sax->parse_error(m_lexer.get_position(),
ferencd@0 8984 m_lexer.get_token_string(),
ferencd@0 8985 parse_error::create(101, m_lexer.get_position(),
ferencd@0 8986 exception_message(token_type::end_object, "object")));
ferencd@0 8987 }
ferencd@0 8988 }
ferencd@0 8989 }
ferencd@0 8990
ferencd@0 8991 /// get next token from lexer
ferencd@0 8992 token_type get_token()
ferencd@0 8993 {
ferencd@0 8994 return last_token = m_lexer.scan();
ferencd@0 8995 }
ferencd@0 8996
ferencd@0 8997 std::string exception_message(const token_type expected, const std::string& context)
ferencd@0 8998 {
ferencd@0 8999 std::string error_msg = "syntax error ";
ferencd@0 9000
ferencd@0 9001 if (not context.empty())
ferencd@0 9002 {
ferencd@0 9003 error_msg += "while parsing " + context + " ";
ferencd@0 9004 }
ferencd@0 9005
ferencd@0 9006 error_msg += "- ";
ferencd@0 9007
ferencd@0 9008 if (last_token == token_type::parse_error)
ferencd@0 9009 {
ferencd@0 9010 error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" +
ferencd@0 9011 m_lexer.get_token_string() + "'";
ferencd@0 9012 }
ferencd@0 9013 else
ferencd@0 9014 {
ferencd@0 9015 error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token));
ferencd@0 9016 }
ferencd@0 9017
ferencd@0 9018 if (expected != token_type::uninitialized)
ferencd@0 9019 {
ferencd@0 9020 error_msg += "; expected " + std::string(lexer_t::token_type_name(expected));
ferencd@0 9021 }
ferencd@0 9022
ferencd@0 9023 return error_msg;
ferencd@0 9024 }
ferencd@0 9025
ferencd@0 9026 private:
ferencd@0 9027 /// callback function
ferencd@0 9028 const parser_callback_t callback = nullptr;
ferencd@0 9029 /// the type of the last read token
ferencd@0 9030 token_type last_token = token_type::uninitialized;
ferencd@0 9031 /// the lexer
ferencd@0 9032 lexer_t m_lexer;
ferencd@0 9033 /// whether to throw exceptions in case of errors
ferencd@0 9034 const bool allow_exceptions = true;
ferencd@0 9035 };
ferencd@0 9036 } // namespace detail
ferencd@0 9037 } // namespace nlohmann
ferencd@0 9038
ferencd@0 9039 // #include <nlohmann/detail/iterators/internal_iterator.hpp>
ferencd@0 9040
ferencd@0 9041
ferencd@0 9042 // #include <nlohmann/detail/iterators/primitive_iterator.hpp>
ferencd@0 9043
ferencd@0 9044
ferencd@0 9045 #include <cstddef> // ptrdiff_t
ferencd@0 9046 #include <limits> // numeric_limits
ferencd@0 9047
ferencd@0 9048 namespace nlohmann
ferencd@0 9049 {
ferencd@0 9050 namespace detail
ferencd@0 9051 {
ferencd@0 9052 /*
ferencd@0 9053 @brief an iterator for primitive JSON types
ferencd@0 9054
ferencd@0 9055 This class models an iterator for primitive JSON types (boolean, number,
ferencd@0 9056 string). It's only purpose is to allow the iterator/const_iterator classes
ferencd@0 9057 to "iterate" over primitive values. Internally, the iterator is modeled by
ferencd@0 9058 a `difference_type` variable. Value begin_value (`0`) models the begin,
ferencd@0 9059 end_value (`1`) models past the end.
ferencd@0 9060 */
ferencd@0 9061 class primitive_iterator_t
ferencd@0 9062 {
ferencd@0 9063 private:
ferencd@0 9064 using difference_type = std::ptrdiff_t;
ferencd@0 9065 static constexpr difference_type begin_value = 0;
ferencd@0 9066 static constexpr difference_type end_value = begin_value + 1;
ferencd@0 9067
ferencd@0 9068 /// iterator as signed integer type
ferencd@0 9069 difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();
ferencd@0 9070
ferencd@0 9071 public:
ferencd@0 9072 constexpr difference_type get_value() const noexcept
ferencd@0 9073 {
ferencd@0 9074 return m_it;
ferencd@0 9075 }
ferencd@0 9076
ferencd@0 9077 /// set iterator to a defined beginning
ferencd@0 9078 void set_begin() noexcept
ferencd@0 9079 {
ferencd@0 9080 m_it = begin_value;
ferencd@0 9081 }
ferencd@0 9082
ferencd@0 9083 /// set iterator to a defined past the end
ferencd@0 9084 void set_end() noexcept
ferencd@0 9085 {
ferencd@0 9086 m_it = end_value;
ferencd@0 9087 }
ferencd@0 9088
ferencd@0 9089 /// return whether the iterator can be dereferenced
ferencd@0 9090 constexpr bool is_begin() const noexcept
ferencd@0 9091 {
ferencd@0 9092 return m_it == begin_value;
ferencd@0 9093 }
ferencd@0 9094
ferencd@0 9095 /// return whether the iterator is at end
ferencd@0 9096 constexpr bool is_end() const noexcept
ferencd@0 9097 {
ferencd@0 9098 return m_it == end_value;
ferencd@0 9099 }
ferencd@0 9100
ferencd@0 9101 friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
ferencd@0 9102 {
ferencd@0 9103 return lhs.m_it == rhs.m_it;
ferencd@0 9104 }
ferencd@0 9105
ferencd@0 9106 friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
ferencd@0 9107 {
ferencd@0 9108 return lhs.m_it < rhs.m_it;
ferencd@0 9109 }
ferencd@0 9110
ferencd@0 9111 primitive_iterator_t operator+(difference_type n) noexcept
ferencd@0 9112 {
ferencd@0 9113 auto result = *this;
ferencd@0 9114 result += n;
ferencd@0 9115 return result;
ferencd@0 9116 }
ferencd@0 9117
ferencd@0 9118 friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
ferencd@0 9119 {
ferencd@0 9120 return lhs.m_it - rhs.m_it;
ferencd@0 9121 }
ferencd@0 9122
ferencd@0 9123 primitive_iterator_t& operator++() noexcept
ferencd@0 9124 {
ferencd@0 9125 ++m_it;
ferencd@0 9126 return *this;
ferencd@0 9127 }
ferencd@0 9128
ferencd@0 9129 primitive_iterator_t const operator++(int) noexcept
ferencd@0 9130 {
ferencd@0 9131 auto result = *this;
ferencd@0 9132 ++m_it;
ferencd@0 9133 return result;
ferencd@0 9134 }
ferencd@0 9135
ferencd@0 9136 primitive_iterator_t& operator--() noexcept
ferencd@0 9137 {
ferencd@0 9138 --m_it;
ferencd@0 9139 return *this;
ferencd@0 9140 }
ferencd@0 9141
ferencd@0 9142 primitive_iterator_t const operator--(int) noexcept
ferencd@0 9143 {
ferencd@0 9144 auto result = *this;
ferencd@0 9145 --m_it;
ferencd@0 9146 return result;
ferencd@0 9147 }
ferencd@0 9148
ferencd@0 9149 primitive_iterator_t& operator+=(difference_type n) noexcept
ferencd@0 9150 {
ferencd@0 9151 m_it += n;
ferencd@0 9152 return *this;
ferencd@0 9153 }
ferencd@0 9154
ferencd@0 9155 primitive_iterator_t& operator-=(difference_type n) noexcept
ferencd@0 9156 {
ferencd@0 9157 m_it -= n;
ferencd@0 9158 return *this;
ferencd@0 9159 }
ferencd@0 9160 };
ferencd@0 9161 } // namespace detail
ferencd@0 9162 } // namespace nlohmann
ferencd@0 9163
ferencd@0 9164
ferencd@0 9165 namespace nlohmann
ferencd@0 9166 {
ferencd@0 9167 namespace detail
ferencd@0 9168 {
ferencd@0 9169 /*!
ferencd@0 9170 @brief an iterator value
ferencd@0 9171
ferencd@0 9172 @note This structure could easily be a union, but MSVC currently does not allow
ferencd@0 9173 unions members with complex constructors, see https://github.com/nlohmann/json/pull/105.
ferencd@0 9174 */
ferencd@0 9175 template<typename BasicJsonType> struct internal_iterator
ferencd@0 9176 {
ferencd@0 9177 /// iterator for JSON objects
ferencd@0 9178 typename BasicJsonType::object_t::iterator object_iterator {};
ferencd@0 9179 /// iterator for JSON arrays
ferencd@0 9180 typename BasicJsonType::array_t::iterator array_iterator {};
ferencd@0 9181 /// generic iterator for all other types
ferencd@0 9182 primitive_iterator_t primitive_iterator {};
ferencd@0 9183 };
ferencd@0 9184 } // namespace detail
ferencd@0 9185 } // namespace nlohmann
ferencd@0 9186
ferencd@0 9187 // #include <nlohmann/detail/iterators/iter_impl.hpp>
ferencd@0 9188
ferencd@0 9189
ferencd@0 9190 #include <ciso646> // not
ferencd@0 9191 #include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
ferencd@0 9192 #include <type_traits> // conditional, is_const, remove_const
ferencd@0 9193
ferencd@0 9194 // #include <nlohmann/detail/exceptions.hpp>
ferencd@0 9195
ferencd@0 9196 // #include <nlohmann/detail/iterators/internal_iterator.hpp>
ferencd@0 9197
ferencd@0 9198 // #include <nlohmann/detail/iterators/primitive_iterator.hpp>
ferencd@0 9199
ferencd@0 9200 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 9201
ferencd@0 9202 // #include <nlohmann/detail/meta/cpp_future.hpp>
ferencd@0 9203
ferencd@0 9204 // #include <nlohmann/detail/meta/type_traits.hpp>
ferencd@0 9205
ferencd@0 9206 // #include <nlohmann/detail/value_t.hpp>
ferencd@0 9207
ferencd@0 9208
ferencd@0 9209 namespace nlohmann
ferencd@0 9210 {
ferencd@0 9211 namespace detail
ferencd@0 9212 {
ferencd@0 9213 // forward declare, to be able to friend it later on
ferencd@0 9214 template<typename IteratorType> class iteration_proxy;
ferencd@0 9215 template<typename IteratorType> class iteration_proxy_value;
ferencd@0 9216
ferencd@0 9217 /*!
ferencd@0 9218 @brief a template for a bidirectional iterator for the @ref basic_json class
ferencd@0 9219 This class implements a both iterators (iterator and const_iterator) for the
ferencd@0 9220 @ref basic_json class.
ferencd@0 9221 @note An iterator is called *initialized* when a pointer to a JSON value has
ferencd@0 9222 been set (e.g., by a constructor or a copy assignment). If the iterator is
ferencd@0 9223 default-constructed, it is *uninitialized* and most methods are undefined.
ferencd@0 9224 **The library uses assertions to detect calls on uninitialized iterators.**
ferencd@0 9225 @requirement The class satisfies the following concept requirements:
ferencd@0 9226 -
ferencd@0 9227 [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
ferencd@0 9228 The iterator that can be moved can be moved in both directions (i.e.
ferencd@0 9229 incremented and decremented).
ferencd@0 9230 @since version 1.0.0, simplified in version 2.0.9, change to bidirectional
ferencd@0 9231 iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
ferencd@0 9232 */
ferencd@0 9233 template<typename BasicJsonType>
ferencd@0 9234 class iter_impl
ferencd@0 9235 {
ferencd@0 9236 /// allow basic_json to access private members
ferencd@0 9237 friend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
ferencd@0 9238 friend BasicJsonType;
ferencd@0 9239 friend iteration_proxy<iter_impl>;
ferencd@0 9240 friend iteration_proxy_value<iter_impl>;
ferencd@0 9241
ferencd@0 9242 using object_t = typename BasicJsonType::object_t;
ferencd@0 9243 using array_t = typename BasicJsonType::array_t;
ferencd@0 9244 // make sure BasicJsonType is basic_json or const basic_json
ferencd@0 9245 static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
ferencd@0 9246 "iter_impl only accepts (const) basic_json");
ferencd@0 9247
ferencd@0 9248 public:
ferencd@0 9249
ferencd@0 9250 /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
ferencd@0 9251 /// The C++ Standard has never required user-defined iterators to derive from std::iterator.
ferencd@0 9252 /// A user-defined iterator should provide publicly accessible typedefs named
ferencd@0 9253 /// iterator_category, value_type, difference_type, pointer, and reference.
ferencd@0 9254 /// Note that value_type is required to be non-const, even for constant iterators.
ferencd@0 9255 using iterator_category = std::bidirectional_iterator_tag;
ferencd@0 9256
ferencd@0 9257 /// the type of the values when the iterator is dereferenced
ferencd@0 9258 using value_type = typename BasicJsonType::value_type;
ferencd@0 9259 /// a type to represent differences between iterators
ferencd@0 9260 using difference_type = typename BasicJsonType::difference_type;
ferencd@0 9261 /// defines a pointer to the type iterated over (value_type)
ferencd@0 9262 using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
ferencd@0 9263 typename BasicJsonType::const_pointer,
ferencd@0 9264 typename BasicJsonType::pointer>::type;
ferencd@0 9265 /// defines a reference to the type iterated over (value_type)
ferencd@0 9266 using reference =
ferencd@0 9267 typename std::conditional<std::is_const<BasicJsonType>::value,
ferencd@0 9268 typename BasicJsonType::const_reference,
ferencd@0 9269 typename BasicJsonType::reference>::type;
ferencd@0 9270
ferencd@0 9271 /// default constructor
ferencd@0 9272 iter_impl() = default;
ferencd@0 9273
ferencd@0 9274 /*!
ferencd@0 9275 @brief constructor for a given JSON instance
ferencd@0 9276 @param[in] object pointer to a JSON object for this iterator
ferencd@0 9277 @pre object != nullptr
ferencd@0 9278 @post The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9279 */
ferencd@0 9280 explicit iter_impl(pointer object) noexcept : m_object(object)
ferencd@0 9281 {
ferencd@0 9282 assert(m_object != nullptr);
ferencd@0 9283
ferencd@0 9284 switch (m_object->m_type)
ferencd@0 9285 {
ferencd@0 9286 case value_t::object:
ferencd@0 9287 {
ferencd@0 9288 m_it.object_iterator = typename object_t::iterator();
ferencd@0 9289 break;
ferencd@0 9290 }
ferencd@0 9291
ferencd@0 9292 case value_t::array:
ferencd@0 9293 {
ferencd@0 9294 m_it.array_iterator = typename array_t::iterator();
ferencd@0 9295 break;
ferencd@0 9296 }
ferencd@0 9297
ferencd@0 9298 default:
ferencd@0 9299 {
ferencd@0 9300 m_it.primitive_iterator = primitive_iterator_t();
ferencd@0 9301 break;
ferencd@0 9302 }
ferencd@0 9303 }
ferencd@0 9304 }
ferencd@0 9305
ferencd@0 9306 /*!
ferencd@0 9307 @note The conventional copy constructor and copy assignment are implicitly
ferencd@0 9308 defined. Combined with the following converting constructor and
ferencd@0 9309 assignment, they support: (1) copy from iterator to iterator, (2)
ferencd@0 9310 copy from const iterator to const iterator, and (3) conversion from
ferencd@0 9311 iterator to const iterator. However conversion from const iterator
ferencd@0 9312 to iterator is not defined.
ferencd@0 9313 */
ferencd@0 9314
ferencd@0 9315 /*!
ferencd@0 9316 @brief const copy constructor
ferencd@0 9317 @param[in] other const iterator to copy from
ferencd@0 9318 @note This copy constuctor had to be defined explicitely to circumvent a bug
ferencd@0 9319 occuring on msvc v19.0 compiler (VS 2015) debug build. For more
ferencd@0 9320 information refer to: https://github.com/nlohmann/json/issues/1608
ferencd@0 9321 */
ferencd@0 9322 iter_impl(const iter_impl<const BasicJsonType>& other) noexcept
ferencd@0 9323 : m_object(other.m_object), m_it(other.m_it)
ferencd@0 9324 {}
ferencd@0 9325
ferencd@0 9326 /*!
ferencd@0 9327 @brief converting assignment
ferencd@0 9328 @param[in] other const iterator to copy from
ferencd@0 9329 @return const/non-const iterator
ferencd@0 9330 @note It is not checked whether @a other is initialized.
ferencd@0 9331 */
ferencd@0 9332 iter_impl& operator=(const iter_impl<const BasicJsonType>& other) noexcept
ferencd@0 9333 {
ferencd@0 9334 m_object = other.m_object;
ferencd@0 9335 m_it = other.m_it;
ferencd@0 9336 return *this;
ferencd@0 9337 }
ferencd@0 9338
ferencd@0 9339 /*!
ferencd@0 9340 @brief converting constructor
ferencd@0 9341 @param[in] other non-const iterator to copy from
ferencd@0 9342 @note It is not checked whether @a other is initialized.
ferencd@0 9343 */
ferencd@0 9344 iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
ferencd@0 9345 : m_object(other.m_object), m_it(other.m_it)
ferencd@0 9346 {}
ferencd@0 9347
ferencd@0 9348 /*!
ferencd@0 9349 @brief converting assignment
ferencd@0 9350 @param[in] other non-const iterator to copy from
ferencd@0 9351 @return const/non-const iterator
ferencd@0 9352 @note It is not checked whether @a other is initialized.
ferencd@0 9353 */
ferencd@0 9354 iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
ferencd@0 9355 {
ferencd@0 9356 m_object = other.m_object;
ferencd@0 9357 m_it = other.m_it;
ferencd@0 9358 return *this;
ferencd@0 9359 }
ferencd@0 9360
ferencd@0 9361 private:
ferencd@0 9362 /*!
ferencd@0 9363 @brief set the iterator to the first value
ferencd@0 9364 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9365 */
ferencd@0 9366 void set_begin() noexcept
ferencd@0 9367 {
ferencd@0 9368 assert(m_object != nullptr);
ferencd@0 9369
ferencd@0 9370 switch (m_object->m_type)
ferencd@0 9371 {
ferencd@0 9372 case value_t::object:
ferencd@0 9373 {
ferencd@0 9374 m_it.object_iterator = m_object->m_value.object->begin();
ferencd@0 9375 break;
ferencd@0 9376 }
ferencd@0 9377
ferencd@0 9378 case value_t::array:
ferencd@0 9379 {
ferencd@0 9380 m_it.array_iterator = m_object->m_value.array->begin();
ferencd@0 9381 break;
ferencd@0 9382 }
ferencd@0 9383
ferencd@0 9384 case value_t::null:
ferencd@0 9385 {
ferencd@0 9386 // set to end so begin()==end() is true: null is empty
ferencd@0 9387 m_it.primitive_iterator.set_end();
ferencd@0 9388 break;
ferencd@0 9389 }
ferencd@0 9390
ferencd@0 9391 default:
ferencd@0 9392 {
ferencd@0 9393 m_it.primitive_iterator.set_begin();
ferencd@0 9394 break;
ferencd@0 9395 }
ferencd@0 9396 }
ferencd@0 9397 }
ferencd@0 9398
ferencd@0 9399 /*!
ferencd@0 9400 @brief set the iterator past the last value
ferencd@0 9401 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9402 */
ferencd@0 9403 void set_end() noexcept
ferencd@0 9404 {
ferencd@0 9405 assert(m_object != nullptr);
ferencd@0 9406
ferencd@0 9407 switch (m_object->m_type)
ferencd@0 9408 {
ferencd@0 9409 case value_t::object:
ferencd@0 9410 {
ferencd@0 9411 m_it.object_iterator = m_object->m_value.object->end();
ferencd@0 9412 break;
ferencd@0 9413 }
ferencd@0 9414
ferencd@0 9415 case value_t::array:
ferencd@0 9416 {
ferencd@0 9417 m_it.array_iterator = m_object->m_value.array->end();
ferencd@0 9418 break;
ferencd@0 9419 }
ferencd@0 9420
ferencd@0 9421 default:
ferencd@0 9422 {
ferencd@0 9423 m_it.primitive_iterator.set_end();
ferencd@0 9424 break;
ferencd@0 9425 }
ferencd@0 9426 }
ferencd@0 9427 }
ferencd@0 9428
ferencd@0 9429 public:
ferencd@0 9430 /*!
ferencd@0 9431 @brief return a reference to the value pointed to by the iterator
ferencd@0 9432 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9433 */
ferencd@0 9434 reference operator*() const
ferencd@0 9435 {
ferencd@0 9436 assert(m_object != nullptr);
ferencd@0 9437
ferencd@0 9438 switch (m_object->m_type)
ferencd@0 9439 {
ferencd@0 9440 case value_t::object:
ferencd@0 9441 {
ferencd@0 9442 assert(m_it.object_iterator != m_object->m_value.object->end());
ferencd@0 9443 return m_it.object_iterator->second;
ferencd@0 9444 }
ferencd@0 9445
ferencd@0 9446 case value_t::array:
ferencd@0 9447 {
ferencd@0 9448 assert(m_it.array_iterator != m_object->m_value.array->end());
ferencd@0 9449 return *m_it.array_iterator;
ferencd@0 9450 }
ferencd@0 9451
ferencd@0 9452 case value_t::null:
ferencd@0 9453 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
ferencd@0 9454
ferencd@0 9455 default:
ferencd@0 9456 {
ferencd@0 9457 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
ferencd@0 9458 {
ferencd@0 9459 return *m_object;
ferencd@0 9460 }
ferencd@0 9461
ferencd@0 9462 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
ferencd@0 9463 }
ferencd@0 9464 }
ferencd@0 9465 }
ferencd@0 9466
ferencd@0 9467 /*!
ferencd@0 9468 @brief dereference the iterator
ferencd@0 9469 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9470 */
ferencd@0 9471 pointer operator->() const
ferencd@0 9472 {
ferencd@0 9473 assert(m_object != nullptr);
ferencd@0 9474
ferencd@0 9475 switch (m_object->m_type)
ferencd@0 9476 {
ferencd@0 9477 case value_t::object:
ferencd@0 9478 {
ferencd@0 9479 assert(m_it.object_iterator != m_object->m_value.object->end());
ferencd@0 9480 return &(m_it.object_iterator->second);
ferencd@0 9481 }
ferencd@0 9482
ferencd@0 9483 case value_t::array:
ferencd@0 9484 {
ferencd@0 9485 assert(m_it.array_iterator != m_object->m_value.array->end());
ferencd@0 9486 return &*m_it.array_iterator;
ferencd@0 9487 }
ferencd@0 9488
ferencd@0 9489 default:
ferencd@0 9490 {
ferencd@0 9491 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
ferencd@0 9492 {
ferencd@0 9493 return m_object;
ferencd@0 9494 }
ferencd@0 9495
ferencd@0 9496 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
ferencd@0 9497 }
ferencd@0 9498 }
ferencd@0 9499 }
ferencd@0 9500
ferencd@0 9501 /*!
ferencd@0 9502 @brief post-increment (it++)
ferencd@0 9503 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9504 */
ferencd@0 9505 iter_impl const operator++(int)
ferencd@0 9506 {
ferencd@0 9507 auto result = *this;
ferencd@0 9508 ++(*this);
ferencd@0 9509 return result;
ferencd@0 9510 }
ferencd@0 9511
ferencd@0 9512 /*!
ferencd@0 9513 @brief pre-increment (++it)
ferencd@0 9514 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9515 */
ferencd@0 9516 iter_impl& operator++()
ferencd@0 9517 {
ferencd@0 9518 assert(m_object != nullptr);
ferencd@0 9519
ferencd@0 9520 switch (m_object->m_type)
ferencd@0 9521 {
ferencd@0 9522 case value_t::object:
ferencd@0 9523 {
ferencd@0 9524 std::advance(m_it.object_iterator, 1);
ferencd@0 9525 break;
ferencd@0 9526 }
ferencd@0 9527
ferencd@0 9528 case value_t::array:
ferencd@0 9529 {
ferencd@0 9530 std::advance(m_it.array_iterator, 1);
ferencd@0 9531 break;
ferencd@0 9532 }
ferencd@0 9533
ferencd@0 9534 default:
ferencd@0 9535 {
ferencd@0 9536 ++m_it.primitive_iterator;
ferencd@0 9537 break;
ferencd@0 9538 }
ferencd@0 9539 }
ferencd@0 9540
ferencd@0 9541 return *this;
ferencd@0 9542 }
ferencd@0 9543
ferencd@0 9544 /*!
ferencd@0 9545 @brief post-decrement (it--)
ferencd@0 9546 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9547 */
ferencd@0 9548 iter_impl const operator--(int)
ferencd@0 9549 {
ferencd@0 9550 auto result = *this;
ferencd@0 9551 --(*this);
ferencd@0 9552 return result;
ferencd@0 9553 }
ferencd@0 9554
ferencd@0 9555 /*!
ferencd@0 9556 @brief pre-decrement (--it)
ferencd@0 9557 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9558 */
ferencd@0 9559 iter_impl& operator--()
ferencd@0 9560 {
ferencd@0 9561 assert(m_object != nullptr);
ferencd@0 9562
ferencd@0 9563 switch (m_object->m_type)
ferencd@0 9564 {
ferencd@0 9565 case value_t::object:
ferencd@0 9566 {
ferencd@0 9567 std::advance(m_it.object_iterator, -1);
ferencd@0 9568 break;
ferencd@0 9569 }
ferencd@0 9570
ferencd@0 9571 case value_t::array:
ferencd@0 9572 {
ferencd@0 9573 std::advance(m_it.array_iterator, -1);
ferencd@0 9574 break;
ferencd@0 9575 }
ferencd@0 9576
ferencd@0 9577 default:
ferencd@0 9578 {
ferencd@0 9579 --m_it.primitive_iterator;
ferencd@0 9580 break;
ferencd@0 9581 }
ferencd@0 9582 }
ferencd@0 9583
ferencd@0 9584 return *this;
ferencd@0 9585 }
ferencd@0 9586
ferencd@0 9587 /*!
ferencd@0 9588 @brief comparison: equal
ferencd@0 9589 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9590 */
ferencd@0 9591 bool operator==(const iter_impl& other) const
ferencd@0 9592 {
ferencd@0 9593 // if objects are not the same, the comparison is undefined
ferencd@0 9594 if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
ferencd@0 9595 {
ferencd@0 9596 JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
ferencd@0 9597 }
ferencd@0 9598
ferencd@0 9599 assert(m_object != nullptr);
ferencd@0 9600
ferencd@0 9601 switch (m_object->m_type)
ferencd@0 9602 {
ferencd@0 9603 case value_t::object:
ferencd@0 9604 return (m_it.object_iterator == other.m_it.object_iterator);
ferencd@0 9605
ferencd@0 9606 case value_t::array:
ferencd@0 9607 return (m_it.array_iterator == other.m_it.array_iterator);
ferencd@0 9608
ferencd@0 9609 default:
ferencd@0 9610 return (m_it.primitive_iterator == other.m_it.primitive_iterator);
ferencd@0 9611 }
ferencd@0 9612 }
ferencd@0 9613
ferencd@0 9614 /*!
ferencd@0 9615 @brief comparison: not equal
ferencd@0 9616 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9617 */
ferencd@0 9618 bool operator!=(const iter_impl& other) const
ferencd@0 9619 {
ferencd@0 9620 return not operator==(other);
ferencd@0 9621 }
ferencd@0 9622
ferencd@0 9623 /*!
ferencd@0 9624 @brief comparison: smaller
ferencd@0 9625 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9626 */
ferencd@0 9627 bool operator<(const iter_impl& other) const
ferencd@0 9628 {
ferencd@0 9629 // if objects are not the same, the comparison is undefined
ferencd@0 9630 if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
ferencd@0 9631 {
ferencd@0 9632 JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers"));
ferencd@0 9633 }
ferencd@0 9634
ferencd@0 9635 assert(m_object != nullptr);
ferencd@0 9636
ferencd@0 9637 switch (m_object->m_type)
ferencd@0 9638 {
ferencd@0 9639 case value_t::object:
ferencd@0 9640 JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators"));
ferencd@0 9641
ferencd@0 9642 case value_t::array:
ferencd@0 9643 return (m_it.array_iterator < other.m_it.array_iterator);
ferencd@0 9644
ferencd@0 9645 default:
ferencd@0 9646 return (m_it.primitive_iterator < other.m_it.primitive_iterator);
ferencd@0 9647 }
ferencd@0 9648 }
ferencd@0 9649
ferencd@0 9650 /*!
ferencd@0 9651 @brief comparison: less than or equal
ferencd@0 9652 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9653 */
ferencd@0 9654 bool operator<=(const iter_impl& other) const
ferencd@0 9655 {
ferencd@0 9656 return not other.operator < (*this);
ferencd@0 9657 }
ferencd@0 9658
ferencd@0 9659 /*!
ferencd@0 9660 @brief comparison: greater than
ferencd@0 9661 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9662 */
ferencd@0 9663 bool operator>(const iter_impl& other) const
ferencd@0 9664 {
ferencd@0 9665 return not operator<=(other);
ferencd@0 9666 }
ferencd@0 9667
ferencd@0 9668 /*!
ferencd@0 9669 @brief comparison: greater than or equal
ferencd@0 9670 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9671 */
ferencd@0 9672 bool operator>=(const iter_impl& other) const
ferencd@0 9673 {
ferencd@0 9674 return not operator<(other);
ferencd@0 9675 }
ferencd@0 9676
ferencd@0 9677 /*!
ferencd@0 9678 @brief add to iterator
ferencd@0 9679 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9680 */
ferencd@0 9681 iter_impl& operator+=(difference_type i)
ferencd@0 9682 {
ferencd@0 9683 assert(m_object != nullptr);
ferencd@0 9684
ferencd@0 9685 switch (m_object->m_type)
ferencd@0 9686 {
ferencd@0 9687 case value_t::object:
ferencd@0 9688 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
ferencd@0 9689
ferencd@0 9690 case value_t::array:
ferencd@0 9691 {
ferencd@0 9692 std::advance(m_it.array_iterator, i);
ferencd@0 9693 break;
ferencd@0 9694 }
ferencd@0 9695
ferencd@0 9696 default:
ferencd@0 9697 {
ferencd@0 9698 m_it.primitive_iterator += i;
ferencd@0 9699 break;
ferencd@0 9700 }
ferencd@0 9701 }
ferencd@0 9702
ferencd@0 9703 return *this;
ferencd@0 9704 }
ferencd@0 9705
ferencd@0 9706 /*!
ferencd@0 9707 @brief subtract from iterator
ferencd@0 9708 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9709 */
ferencd@0 9710 iter_impl& operator-=(difference_type i)
ferencd@0 9711 {
ferencd@0 9712 return operator+=(-i);
ferencd@0 9713 }
ferencd@0 9714
ferencd@0 9715 /*!
ferencd@0 9716 @brief add to iterator
ferencd@0 9717 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9718 */
ferencd@0 9719 iter_impl operator+(difference_type i) const
ferencd@0 9720 {
ferencd@0 9721 auto result = *this;
ferencd@0 9722 result += i;
ferencd@0 9723 return result;
ferencd@0 9724 }
ferencd@0 9725
ferencd@0 9726 /*!
ferencd@0 9727 @brief addition of distance and iterator
ferencd@0 9728 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9729 */
ferencd@0 9730 friend iter_impl operator+(difference_type i, const iter_impl& it)
ferencd@0 9731 {
ferencd@0 9732 auto result = it;
ferencd@0 9733 result += i;
ferencd@0 9734 return result;
ferencd@0 9735 }
ferencd@0 9736
ferencd@0 9737 /*!
ferencd@0 9738 @brief subtract from iterator
ferencd@0 9739 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9740 */
ferencd@0 9741 iter_impl operator-(difference_type i) const
ferencd@0 9742 {
ferencd@0 9743 auto result = *this;
ferencd@0 9744 result -= i;
ferencd@0 9745 return result;
ferencd@0 9746 }
ferencd@0 9747
ferencd@0 9748 /*!
ferencd@0 9749 @brief return difference
ferencd@0 9750 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9751 */
ferencd@0 9752 difference_type operator-(const iter_impl& other) const
ferencd@0 9753 {
ferencd@0 9754 assert(m_object != nullptr);
ferencd@0 9755
ferencd@0 9756 switch (m_object->m_type)
ferencd@0 9757 {
ferencd@0 9758 case value_t::object:
ferencd@0 9759 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators"));
ferencd@0 9760
ferencd@0 9761 case value_t::array:
ferencd@0 9762 return m_it.array_iterator - other.m_it.array_iterator;
ferencd@0 9763
ferencd@0 9764 default:
ferencd@0 9765 return m_it.primitive_iterator - other.m_it.primitive_iterator;
ferencd@0 9766 }
ferencd@0 9767 }
ferencd@0 9768
ferencd@0 9769 /*!
ferencd@0 9770 @brief access to successor
ferencd@0 9771 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9772 */
ferencd@0 9773 reference operator[](difference_type n) const
ferencd@0 9774 {
ferencd@0 9775 assert(m_object != nullptr);
ferencd@0 9776
ferencd@0 9777 switch (m_object->m_type)
ferencd@0 9778 {
ferencd@0 9779 case value_t::object:
ferencd@0 9780 JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators"));
ferencd@0 9781
ferencd@0 9782 case value_t::array:
ferencd@0 9783 return *std::next(m_it.array_iterator, n);
ferencd@0 9784
ferencd@0 9785 case value_t::null:
ferencd@0 9786 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
ferencd@0 9787
ferencd@0 9788 default:
ferencd@0 9789 {
ferencd@0 9790 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n))
ferencd@0 9791 {
ferencd@0 9792 return *m_object;
ferencd@0 9793 }
ferencd@0 9794
ferencd@0 9795 JSON_THROW(invalid_iterator::create(214, "cannot get value"));
ferencd@0 9796 }
ferencd@0 9797 }
ferencd@0 9798 }
ferencd@0 9799
ferencd@0 9800 /*!
ferencd@0 9801 @brief return the key of an object iterator
ferencd@0 9802 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9803 */
ferencd@0 9804 const typename object_t::key_type& key() const
ferencd@0 9805 {
ferencd@0 9806 assert(m_object != nullptr);
ferencd@0 9807
ferencd@0 9808 if (JSON_HEDLEY_LIKELY(m_object->is_object()))
ferencd@0 9809 {
ferencd@0 9810 return m_it.object_iterator->first;
ferencd@0 9811 }
ferencd@0 9812
ferencd@0 9813 JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators"));
ferencd@0 9814 }
ferencd@0 9815
ferencd@0 9816 /*!
ferencd@0 9817 @brief return the value of an iterator
ferencd@0 9818 @pre The iterator is initialized; i.e. `m_object != nullptr`.
ferencd@0 9819 */
ferencd@0 9820 reference value() const
ferencd@0 9821 {
ferencd@0 9822 return operator*();
ferencd@0 9823 }
ferencd@0 9824
ferencd@0 9825 private:
ferencd@0 9826 /// associated JSON instance
ferencd@0 9827 pointer m_object = nullptr;
ferencd@0 9828 /// the actual iterator of the associated instance
ferencd@0 9829 internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {};
ferencd@0 9830 };
ferencd@0 9831 } // namespace detail
ferencd@0 9832 } // namespace nlohmann
ferencd@0 9833
ferencd@0 9834 // #include <nlohmann/detail/iterators/iteration_proxy.hpp>
ferencd@0 9835
ferencd@0 9836 // #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
ferencd@0 9837
ferencd@0 9838
ferencd@0 9839 #include <cstddef> // ptrdiff_t
ferencd@0 9840 #include <iterator> // reverse_iterator
ferencd@0 9841 #include <utility> // declval
ferencd@0 9842
ferencd@0 9843 namespace nlohmann
ferencd@0 9844 {
ferencd@0 9845 namespace detail
ferencd@0 9846 {
ferencd@0 9847 //////////////////////
ferencd@0 9848 // reverse_iterator //
ferencd@0 9849 //////////////////////
ferencd@0 9850
ferencd@0 9851 /*!
ferencd@0 9852 @brief a template for a reverse iterator class
ferencd@0 9853
ferencd@0 9854 @tparam Base the base iterator type to reverse. Valid types are @ref
ferencd@0 9855 iterator (to create @ref reverse_iterator) and @ref const_iterator (to
ferencd@0 9856 create @ref const_reverse_iterator).
ferencd@0 9857
ferencd@0 9858 @requirement The class satisfies the following concept requirements:
ferencd@0 9859 -
ferencd@0 9860 [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
ferencd@0 9861 The iterator that can be moved can be moved in both directions (i.e.
ferencd@0 9862 incremented and decremented).
ferencd@0 9863 - [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):
ferencd@0 9864 It is possible to write to the pointed-to element (only if @a Base is
ferencd@0 9865 @ref iterator).
ferencd@0 9866
ferencd@0 9867 @since version 1.0.0
ferencd@0 9868 */
ferencd@0 9869 template<typename Base>
ferencd@0 9870 class json_reverse_iterator : public std::reverse_iterator<Base>
ferencd@0 9871 {
ferencd@0 9872 public:
ferencd@0 9873 using difference_type = std::ptrdiff_t;
ferencd@0 9874 /// shortcut to the reverse iterator adapter
ferencd@0 9875 using base_iterator = std::reverse_iterator<Base>;
ferencd@0 9876 /// the reference type for the pointed-to element
ferencd@0 9877 using reference = typename Base::reference;
ferencd@0 9878
ferencd@0 9879 /// create reverse iterator from iterator
ferencd@0 9880 explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
ferencd@0 9881 : base_iterator(it) {}
ferencd@0 9882
ferencd@0 9883 /// create reverse iterator from base class
ferencd@0 9884 explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}
ferencd@0 9885
ferencd@0 9886 /// post-increment (it++)
ferencd@0 9887 json_reverse_iterator const operator++(int)
ferencd@0 9888 {
ferencd@0 9889 return static_cast<json_reverse_iterator>(base_iterator::operator++(1));
ferencd@0 9890 }
ferencd@0 9891
ferencd@0 9892 /// pre-increment (++it)
ferencd@0 9893 json_reverse_iterator& operator++()
ferencd@0 9894 {
ferencd@0 9895 return static_cast<json_reverse_iterator&>(base_iterator::operator++());
ferencd@0 9896 }
ferencd@0 9897
ferencd@0 9898 /// post-decrement (it--)
ferencd@0 9899 json_reverse_iterator const operator--(int)
ferencd@0 9900 {
ferencd@0 9901 return static_cast<json_reverse_iterator>(base_iterator::operator--(1));
ferencd@0 9902 }
ferencd@0 9903
ferencd@0 9904 /// pre-decrement (--it)
ferencd@0 9905 json_reverse_iterator& operator--()
ferencd@0 9906 {
ferencd@0 9907 return static_cast<json_reverse_iterator&>(base_iterator::operator--());
ferencd@0 9908 }
ferencd@0 9909
ferencd@0 9910 /// add to iterator
ferencd@0 9911 json_reverse_iterator& operator+=(difference_type i)
ferencd@0 9912 {
ferencd@0 9913 return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));
ferencd@0 9914 }
ferencd@0 9915
ferencd@0 9916 /// add to iterator
ferencd@0 9917 json_reverse_iterator operator+(difference_type i) const
ferencd@0 9918 {
ferencd@0 9919 return static_cast<json_reverse_iterator>(base_iterator::operator+(i));
ferencd@0 9920 }
ferencd@0 9921
ferencd@0 9922 /// subtract from iterator
ferencd@0 9923 json_reverse_iterator operator-(difference_type i) const
ferencd@0 9924 {
ferencd@0 9925 return static_cast<json_reverse_iterator>(base_iterator::operator-(i));
ferencd@0 9926 }
ferencd@0 9927
ferencd@0 9928 /// return difference
ferencd@0 9929 difference_type operator-(const json_reverse_iterator& other) const
ferencd@0 9930 {
ferencd@0 9931 return base_iterator(*this) - base_iterator(other);
ferencd@0 9932 }
ferencd@0 9933
ferencd@0 9934 /// access to successor
ferencd@0 9935 reference operator[](difference_type n) const
ferencd@0 9936 {
ferencd@0 9937 return *(this->operator+(n));
ferencd@0 9938 }
ferencd@0 9939
ferencd@0 9940 /// return the key of an object iterator
ferencd@0 9941 auto key() const -> decltype(std::declval<Base>().key())
ferencd@0 9942 {
ferencd@0 9943 auto it = --this->base();
ferencd@0 9944 return it.key();
ferencd@0 9945 }
ferencd@0 9946
ferencd@0 9947 /// return the value of an iterator
ferencd@0 9948 reference value() const
ferencd@0 9949 {
ferencd@0 9950 auto it = --this->base();
ferencd@0 9951 return it.operator * ();
ferencd@0 9952 }
ferencd@0 9953 };
ferencd@0 9954 } // namespace detail
ferencd@0 9955 } // namespace nlohmann
ferencd@0 9956
ferencd@0 9957 // #include <nlohmann/detail/iterators/primitive_iterator.hpp>
ferencd@0 9958
ferencd@0 9959 // #include <nlohmann/detail/json_pointer.hpp>
ferencd@0 9960
ferencd@0 9961
ferencd@0 9962 #include <algorithm> // all_of
ferencd@0 9963 #include <cassert> // assert
ferencd@0 9964 #include <cctype> // isdigit
ferencd@0 9965 #include <numeric> // accumulate
ferencd@0 9966 #include <string> // string
ferencd@0 9967 #include <utility> // move
ferencd@0 9968 #include <vector> // vector
ferencd@0 9969
ferencd@0 9970 // #include <nlohmann/detail/exceptions.hpp>
ferencd@0 9971
ferencd@0 9972 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 9973
ferencd@0 9974 // #include <nlohmann/detail/value_t.hpp>
ferencd@0 9975
ferencd@0 9976
ferencd@0 9977 namespace nlohmann
ferencd@0 9978 {
ferencd@0 9979 template<typename BasicJsonType>
ferencd@0 9980 class json_pointer
ferencd@0 9981 {
ferencd@0 9982 // allow basic_json to access private members
ferencd@0 9983 NLOHMANN_BASIC_JSON_TPL_DECLARATION
ferencd@0 9984 friend class basic_json;
ferencd@0 9985
ferencd@0 9986 public:
ferencd@0 9987 /*!
ferencd@0 9988 @brief create JSON pointer
ferencd@0 9989
ferencd@0 9990 Create a JSON pointer according to the syntax described in
ferencd@0 9991 [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).
ferencd@0 9992
ferencd@0 9993 @param[in] s string representing the JSON pointer; if omitted, the empty
ferencd@0 9994 string is assumed which references the whole JSON value
ferencd@0 9995
ferencd@0 9996 @throw parse_error.107 if the given JSON pointer @a s is nonempty and does
ferencd@0 9997 not begin with a slash (`/`); see example below
ferencd@0 9998
ferencd@0 9999 @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is
ferencd@0 10000 not followed by `0` (representing `~`) or `1` (representing `/`); see
ferencd@0 10001 example below
ferencd@0 10002
ferencd@0 10003 @liveexample{The example shows the construction several valid JSON pointers
ferencd@0 10004 as well as the exceptional behavior.,json_pointer}
ferencd@0 10005
ferencd@0 10006 @since version 2.0.0
ferencd@0 10007 */
ferencd@0 10008 explicit json_pointer(const std::string& s = "")
ferencd@0 10009 : reference_tokens(split(s))
ferencd@0 10010 {}
ferencd@0 10011
ferencd@0 10012 /*!
ferencd@0 10013 @brief return a string representation of the JSON pointer
ferencd@0 10014
ferencd@0 10015 @invariant For each JSON pointer `ptr`, it holds:
ferencd@0 10016 @code {.cpp}
ferencd@0 10017 ptr == json_pointer(ptr.to_string());
ferencd@0 10018 @endcode
ferencd@0 10019
ferencd@0 10020 @return a string representation of the JSON pointer
ferencd@0 10021
ferencd@0 10022 @liveexample{The example shows the result of `to_string`.,json_pointer__to_string}
ferencd@0 10023
ferencd@0 10024 @since version 2.0.0
ferencd@0 10025 */
ferencd@0 10026 std::string to_string() const
ferencd@0 10027 {
ferencd@0 10028 return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
ferencd@0 10029 std::string{},
ferencd@0 10030 [](const std::string & a, const std::string & b)
ferencd@0 10031 {
ferencd@0 10032 return a + "/" + escape(b);
ferencd@0 10033 });
ferencd@0 10034 }
ferencd@0 10035
ferencd@0 10036 /// @copydoc to_string()
ferencd@0 10037 operator std::string() const
ferencd@0 10038 {
ferencd@0 10039 return to_string();
ferencd@0 10040 }
ferencd@0 10041
ferencd@0 10042 /*!
ferencd@0 10043 @brief append another JSON pointer at the end of this JSON pointer
ferencd@0 10044
ferencd@0 10045 @param[in] ptr JSON pointer to append
ferencd@0 10046 @return JSON pointer with @a ptr appended
ferencd@0 10047
ferencd@0 10048 @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}
ferencd@0 10049
ferencd@0 10050 @complexity Linear in the length of @a ptr.
ferencd@0 10051
ferencd@0 10052 @sa @ref operator/=(std::string) to append a reference token
ferencd@0 10053 @sa @ref operator/=(std::size_t) to append an array index
ferencd@0 10054 @sa @ref operator/(const json_pointer&, const json_pointer&) for a binary operator
ferencd@0 10055
ferencd@0 10056 @since version 3.6.0
ferencd@0 10057 */
ferencd@0 10058 json_pointer& operator/=(const json_pointer& ptr)
ferencd@0 10059 {
ferencd@0 10060 reference_tokens.insert(reference_tokens.end(),
ferencd@0 10061 ptr.reference_tokens.begin(),
ferencd@0 10062 ptr.reference_tokens.end());
ferencd@0 10063 return *this;
ferencd@0 10064 }
ferencd@0 10065
ferencd@0 10066 /*!
ferencd@0 10067 @brief append an unescaped reference token at the end of this JSON pointer
ferencd@0 10068
ferencd@0 10069 @param[in] token reference token to append
ferencd@0 10070 @return JSON pointer with @a token appended without escaping @a token
ferencd@0 10071
ferencd@0 10072 @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}
ferencd@0 10073
ferencd@0 10074 @complexity Amortized constant.
ferencd@0 10075
ferencd@0 10076 @sa @ref operator/=(const json_pointer&) to append a JSON pointer
ferencd@0 10077 @sa @ref operator/=(std::size_t) to append an array index
ferencd@0 10078 @sa @ref operator/(const json_pointer&, std::size_t) for a binary operator
ferencd@0 10079
ferencd@0 10080 @since version 3.6.0
ferencd@0 10081 */
ferencd@0 10082 json_pointer& operator/=(std::string token)
ferencd@0 10083 {
ferencd@0 10084 push_back(std::move(token));
ferencd@0 10085 return *this;
ferencd@0 10086 }
ferencd@0 10087
ferencd@0 10088 /*!
ferencd@0 10089 @brief append an array index at the end of this JSON pointer
ferencd@0 10090
ferencd@0 10091 @param[in] array_index array index ot append
ferencd@0 10092 @return JSON pointer with @a array_index appended
ferencd@0 10093
ferencd@0 10094 @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add}
ferencd@0 10095
ferencd@0 10096 @complexity Amortized constant.
ferencd@0 10097
ferencd@0 10098 @sa @ref operator/=(const json_pointer&) to append a JSON pointer
ferencd@0 10099 @sa @ref operator/=(std::string) to append a reference token
ferencd@0 10100 @sa @ref operator/(const json_pointer&, std::string) for a binary operator
ferencd@0 10101
ferencd@0 10102 @since version 3.6.0
ferencd@0 10103 */
ferencd@0 10104 json_pointer& operator/=(std::size_t array_index)
ferencd@0 10105 {
ferencd@0 10106 return *this /= std::to_string(array_index);
ferencd@0 10107 }
ferencd@0 10108
ferencd@0 10109 /*!
ferencd@0 10110 @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
ferencd@0 10111
ferencd@0 10112 @param[in] lhs JSON pointer
ferencd@0 10113 @param[in] rhs JSON pointer
ferencd@0 10114 @return a new JSON pointer with @a rhs appended to @a lhs
ferencd@0 10115
ferencd@0 10116 @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}
ferencd@0 10117
ferencd@0 10118 @complexity Linear in the length of @a lhs and @a rhs.
ferencd@0 10119
ferencd@0 10120 @sa @ref operator/=(const json_pointer&) to append a JSON pointer
ferencd@0 10121
ferencd@0 10122 @since version 3.6.0
ferencd@0 10123 */
ferencd@0 10124 friend json_pointer operator/(const json_pointer& lhs,
ferencd@0 10125 const json_pointer& rhs)
ferencd@0 10126 {
ferencd@0 10127 return json_pointer(lhs) /= rhs;
ferencd@0 10128 }
ferencd@0 10129
ferencd@0 10130 /*!
ferencd@0 10131 @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
ferencd@0 10132
ferencd@0 10133 @param[in] ptr JSON pointer
ferencd@0 10134 @param[in] token reference token
ferencd@0 10135 @return a new JSON pointer with unescaped @a token appended to @a ptr
ferencd@0 10136
ferencd@0 10137 @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}
ferencd@0 10138
ferencd@0 10139 @complexity Linear in the length of @a ptr.
ferencd@0 10140
ferencd@0 10141 @sa @ref operator/=(std::string) to append a reference token
ferencd@0 10142
ferencd@0 10143 @since version 3.6.0
ferencd@0 10144 */
ferencd@0 10145 friend json_pointer operator/(const json_pointer& ptr, std::string token)
ferencd@0 10146 {
ferencd@0 10147 return json_pointer(ptr) /= std::move(token);
ferencd@0 10148 }
ferencd@0 10149
ferencd@0 10150 /*!
ferencd@0 10151 @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
ferencd@0 10152
ferencd@0 10153 @param[in] ptr JSON pointer
ferencd@0 10154 @param[in] array_index array index
ferencd@0 10155 @return a new JSON pointer with @a array_index appended to @a ptr
ferencd@0 10156
ferencd@0 10157 @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary}
ferencd@0 10158
ferencd@0 10159 @complexity Linear in the length of @a ptr.
ferencd@0 10160
ferencd@0 10161 @sa @ref operator/=(std::size_t) to append an array index
ferencd@0 10162
ferencd@0 10163 @since version 3.6.0
ferencd@0 10164 */
ferencd@0 10165 friend json_pointer operator/(const json_pointer& ptr, std::size_t array_index)
ferencd@0 10166 {
ferencd@0 10167 return json_pointer(ptr) /= array_index;
ferencd@0 10168 }
ferencd@0 10169
ferencd@0 10170 /*!
ferencd@0 10171 @brief returns the parent of this JSON pointer
ferencd@0 10172
ferencd@0 10173 @return parent of this JSON pointer; in case this JSON pointer is the root,
ferencd@0 10174 the root itself is returned
ferencd@0 10175
ferencd@0 10176 @complexity Linear in the length of the JSON pointer.
ferencd@0 10177
ferencd@0 10178 @liveexample{The example shows the result of `parent_pointer` for different
ferencd@0 10179 JSON Pointers.,json_pointer__parent_pointer}
ferencd@0 10180
ferencd@0 10181 @since version 3.6.0
ferencd@0 10182 */
ferencd@0 10183 json_pointer parent_pointer() const
ferencd@0 10184 {
ferencd@0 10185 if (empty())
ferencd@0 10186 {
ferencd@0 10187 return *this;
ferencd@0 10188 }
ferencd@0 10189
ferencd@0 10190 json_pointer res = *this;
ferencd@0 10191 res.pop_back();
ferencd@0 10192 return res;
ferencd@0 10193 }
ferencd@0 10194
ferencd@0 10195 /*!
ferencd@0 10196 @brief remove last reference token
ferencd@0 10197
ferencd@0 10198 @pre not `empty()`
ferencd@0 10199
ferencd@0 10200 @liveexample{The example shows the usage of `pop_back`.,json_pointer__pop_back}
ferencd@0 10201
ferencd@0 10202 @complexity Constant.
ferencd@0 10203
ferencd@0 10204 @throw out_of_range.405 if JSON pointer has no parent
ferencd@0 10205
ferencd@0 10206 @since version 3.6.0
ferencd@0 10207 */
ferencd@0 10208 void pop_back()
ferencd@0 10209 {
ferencd@0 10210 if (JSON_HEDLEY_UNLIKELY(empty()))
ferencd@0 10211 {
ferencd@0 10212 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
ferencd@0 10213 }
ferencd@0 10214
ferencd@0 10215 reference_tokens.pop_back();
ferencd@0 10216 }
ferencd@0 10217
ferencd@0 10218 /*!
ferencd@0 10219 @brief return last reference token
ferencd@0 10220
ferencd@0 10221 @pre not `empty()`
ferencd@0 10222 @return last reference token
ferencd@0 10223
ferencd@0 10224 @liveexample{The example shows the usage of `back`.,json_pointer__back}
ferencd@0 10225
ferencd@0 10226 @complexity Constant.
ferencd@0 10227
ferencd@0 10228 @throw out_of_range.405 if JSON pointer has no parent
ferencd@0 10229
ferencd@0 10230 @since version 3.6.0
ferencd@0 10231 */
ferencd@0 10232 const std::string& back()
ferencd@0 10233 {
ferencd@0 10234 if (JSON_HEDLEY_UNLIKELY(empty()))
ferencd@0 10235 {
ferencd@0 10236 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
ferencd@0 10237 }
ferencd@0 10238
ferencd@0 10239 return reference_tokens.back();
ferencd@0 10240 }
ferencd@0 10241
ferencd@0 10242 /*!
ferencd@0 10243 @brief append an unescaped token at the end of the reference pointer
ferencd@0 10244
ferencd@0 10245 @param[in] token token to add
ferencd@0 10246
ferencd@0 10247 @complexity Amortized constant.
ferencd@0 10248
ferencd@0 10249 @liveexample{The example shows the result of `push_back` for different
ferencd@0 10250 JSON Pointers.,json_pointer__push_back}
ferencd@0 10251
ferencd@0 10252 @since version 3.6.0
ferencd@0 10253 */
ferencd@0 10254 void push_back(const std::string& token)
ferencd@0 10255 {
ferencd@0 10256 reference_tokens.push_back(token);
ferencd@0 10257 }
ferencd@0 10258
ferencd@0 10259 /// @copydoc push_back(const std::string&)
ferencd@0 10260 void push_back(std::string&& token)
ferencd@0 10261 {
ferencd@0 10262 reference_tokens.push_back(std::move(token));
ferencd@0 10263 }
ferencd@0 10264
ferencd@0 10265 /*!
ferencd@0 10266 @brief return whether pointer points to the root document
ferencd@0 10267
ferencd@0 10268 @return true iff the JSON pointer points to the root document
ferencd@0 10269
ferencd@0 10270 @complexity Constant.
ferencd@0 10271
ferencd@0 10272 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 10273
ferencd@0 10274 @liveexample{The example shows the result of `empty` for different JSON
ferencd@0 10275 Pointers.,json_pointer__empty}
ferencd@0 10276
ferencd@0 10277 @since version 3.6.0
ferencd@0 10278 */
ferencd@0 10279 bool empty() const noexcept
ferencd@0 10280 {
ferencd@0 10281 return reference_tokens.empty();
ferencd@0 10282 }
ferencd@0 10283
ferencd@0 10284 private:
ferencd@0 10285 /*!
ferencd@0 10286 @param[in] s reference token to be converted into an array index
ferencd@0 10287
ferencd@0 10288 @return integer representation of @a s
ferencd@0 10289
ferencd@0 10290 @throw out_of_range.404 if string @a s could not be converted to an integer
ferencd@0 10291 */
ferencd@0 10292 static int array_index(const std::string& s)
ferencd@0 10293 {
ferencd@0 10294 std::size_t processed_chars = 0;
ferencd@0 10295 const int res = std::stoi(s, &processed_chars);
ferencd@0 10296
ferencd@0 10297 // check if the string was completely read
ferencd@0 10298 if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size()))
ferencd@0 10299 {
ferencd@0 10300 JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'"));
ferencd@0 10301 }
ferencd@0 10302
ferencd@0 10303 return res;
ferencd@0 10304 }
ferencd@0 10305
ferencd@0 10306 json_pointer top() const
ferencd@0 10307 {
ferencd@0 10308 if (JSON_HEDLEY_UNLIKELY(empty()))
ferencd@0 10309 {
ferencd@0 10310 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
ferencd@0 10311 }
ferencd@0 10312
ferencd@0 10313 json_pointer result = *this;
ferencd@0 10314 result.reference_tokens = {reference_tokens[0]};
ferencd@0 10315 return result;
ferencd@0 10316 }
ferencd@0 10317
ferencd@0 10318 /*!
ferencd@0 10319 @brief create and return a reference to the pointed to value
ferencd@0 10320
ferencd@0 10321 @complexity Linear in the number of reference tokens.
ferencd@0 10322
ferencd@0 10323 @throw parse_error.109 if array index is not a number
ferencd@0 10324 @throw type_error.313 if value cannot be unflattened
ferencd@0 10325 */
ferencd@0 10326 BasicJsonType& get_and_create(BasicJsonType& j) const
ferencd@0 10327 {
ferencd@0 10328 using size_type = typename BasicJsonType::size_type;
ferencd@0 10329 auto result = &j;
ferencd@0 10330
ferencd@0 10331 // in case no reference tokens exist, return a reference to the JSON value
ferencd@0 10332 // j which will be overwritten by a primitive value
ferencd@0 10333 for (const auto& reference_token : reference_tokens)
ferencd@0 10334 {
ferencd@0 10335 switch (result->type())
ferencd@0 10336 {
ferencd@0 10337 case detail::value_t::null:
ferencd@0 10338 {
ferencd@0 10339 if (reference_token == "0")
ferencd@0 10340 {
ferencd@0 10341 // start a new array if reference token is 0
ferencd@0 10342 result = &result->operator[](0);
ferencd@0 10343 }
ferencd@0 10344 else
ferencd@0 10345 {
ferencd@0 10346 // start a new object otherwise
ferencd@0 10347 result = &result->operator[](reference_token);
ferencd@0 10348 }
ferencd@0 10349 break;
ferencd@0 10350 }
ferencd@0 10351
ferencd@0 10352 case detail::value_t::object:
ferencd@0 10353 {
ferencd@0 10354 // create an entry in the object
ferencd@0 10355 result = &result->operator[](reference_token);
ferencd@0 10356 break;
ferencd@0 10357 }
ferencd@0 10358
ferencd@0 10359 case detail::value_t::array:
ferencd@0 10360 {
ferencd@0 10361 // create an entry in the array
ferencd@0 10362 JSON_TRY
ferencd@0 10363 {
ferencd@0 10364 result = &result->operator[](static_cast<size_type>(array_index(reference_token)));
ferencd@0 10365 }
ferencd@0 10366 JSON_CATCH(std::invalid_argument&)
ferencd@0 10367 {
ferencd@0 10368 JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
ferencd@0 10369 }
ferencd@0 10370 break;
ferencd@0 10371 }
ferencd@0 10372
ferencd@0 10373 /*
ferencd@0 10374 The following code is only reached if there exists a reference
ferencd@0 10375 token _and_ the current value is primitive. In this case, we have
ferencd@0 10376 an error situation, because primitive values may only occur as
ferencd@0 10377 single value; that is, with an empty list of reference tokens.
ferencd@0 10378 */
ferencd@0 10379 default:
ferencd@0 10380 JSON_THROW(detail::type_error::create(313, "invalid value to unflatten"));
ferencd@0 10381 }
ferencd@0 10382 }
ferencd@0 10383
ferencd@0 10384 return *result;
ferencd@0 10385 }
ferencd@0 10386
ferencd@0 10387 /*!
ferencd@0 10388 @brief return a reference to the pointed to value
ferencd@0 10389
ferencd@0 10390 @note This version does not throw if a value is not present, but tries to
ferencd@0 10391 create nested values instead. For instance, calling this function
ferencd@0 10392 with pointer `"/this/that"` on a null value is equivalent to calling
ferencd@0 10393 `operator[]("this").operator[]("that")` on that value, effectively
ferencd@0 10394 changing the null value to an object.
ferencd@0 10395
ferencd@0 10396 @param[in] ptr a JSON value
ferencd@0 10397
ferencd@0 10398 @return reference to the JSON value pointed to by the JSON pointer
ferencd@0 10399
ferencd@0 10400 @complexity Linear in the length of the JSON pointer.
ferencd@0 10401
ferencd@0 10402 @throw parse_error.106 if an array index begins with '0'
ferencd@0 10403 @throw parse_error.109 if an array index was not a number
ferencd@0 10404 @throw out_of_range.404 if the JSON pointer can not be resolved
ferencd@0 10405 */
ferencd@0 10406 BasicJsonType& get_unchecked(BasicJsonType* ptr) const
ferencd@0 10407 {
ferencd@0 10408 using size_type = typename BasicJsonType::size_type;
ferencd@0 10409 for (const auto& reference_token : reference_tokens)
ferencd@0 10410 {
ferencd@0 10411 // convert null values to arrays or objects before continuing
ferencd@0 10412 if (ptr->is_null())
ferencd@0 10413 {
ferencd@0 10414 // check if reference token is a number
ferencd@0 10415 const bool nums =
ferencd@0 10416 std::all_of(reference_token.begin(), reference_token.end(),
ferencd@0 10417 [](const unsigned char x)
ferencd@0 10418 {
ferencd@0 10419 return std::isdigit(x);
ferencd@0 10420 });
ferencd@0 10421
ferencd@0 10422 // change value to array for numbers or "-" or to object otherwise
ferencd@0 10423 *ptr = (nums or reference_token == "-")
ferencd@0 10424 ? detail::value_t::array
ferencd@0 10425 : detail::value_t::object;
ferencd@0 10426 }
ferencd@0 10427
ferencd@0 10428 switch (ptr->type())
ferencd@0 10429 {
ferencd@0 10430 case detail::value_t::object:
ferencd@0 10431 {
ferencd@0 10432 // use unchecked object access
ferencd@0 10433 ptr = &ptr->operator[](reference_token);
ferencd@0 10434 break;
ferencd@0 10435 }
ferencd@0 10436
ferencd@0 10437 case detail::value_t::array:
ferencd@0 10438 {
ferencd@0 10439 // error condition (cf. RFC 6901, Sect. 4)
ferencd@0 10440 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
ferencd@0 10441 {
ferencd@0 10442 JSON_THROW(detail::parse_error::create(106, 0,
ferencd@0 10443 "array index '" + reference_token +
ferencd@0 10444 "' must not begin with '0'"));
ferencd@0 10445 }
ferencd@0 10446
ferencd@0 10447 if (reference_token == "-")
ferencd@0 10448 {
ferencd@0 10449 // explicitly treat "-" as index beyond the end
ferencd@0 10450 ptr = &ptr->operator[](ptr->m_value.array->size());
ferencd@0 10451 }
ferencd@0 10452 else
ferencd@0 10453 {
ferencd@0 10454 // convert array index to number; unchecked access
ferencd@0 10455 JSON_TRY
ferencd@0 10456 {
ferencd@0 10457 ptr = &ptr->operator[](
ferencd@0 10458 static_cast<size_type>(array_index(reference_token)));
ferencd@0 10459 }
ferencd@0 10460 JSON_CATCH(std::invalid_argument&)
ferencd@0 10461 {
ferencd@0 10462 JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
ferencd@0 10463 }
ferencd@0 10464 }
ferencd@0 10465 break;
ferencd@0 10466 }
ferencd@0 10467
ferencd@0 10468 default:
ferencd@0 10469 JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
ferencd@0 10470 }
ferencd@0 10471 }
ferencd@0 10472
ferencd@0 10473 return *ptr;
ferencd@0 10474 }
ferencd@0 10475
ferencd@0 10476 /*!
ferencd@0 10477 @throw parse_error.106 if an array index begins with '0'
ferencd@0 10478 @throw parse_error.109 if an array index was not a number
ferencd@0 10479 @throw out_of_range.402 if the array index '-' is used
ferencd@0 10480 @throw out_of_range.404 if the JSON pointer can not be resolved
ferencd@0 10481 */
ferencd@0 10482 BasicJsonType& get_checked(BasicJsonType* ptr) const
ferencd@0 10483 {
ferencd@0 10484 using size_type = typename BasicJsonType::size_type;
ferencd@0 10485 for (const auto& reference_token : reference_tokens)
ferencd@0 10486 {
ferencd@0 10487 switch (ptr->type())
ferencd@0 10488 {
ferencd@0 10489 case detail::value_t::object:
ferencd@0 10490 {
ferencd@0 10491 // note: at performs range check
ferencd@0 10492 ptr = &ptr->at(reference_token);
ferencd@0 10493 break;
ferencd@0 10494 }
ferencd@0 10495
ferencd@0 10496 case detail::value_t::array:
ferencd@0 10497 {
ferencd@0 10498 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
ferencd@0 10499 {
ferencd@0 10500 // "-" always fails the range check
ferencd@0 10501 JSON_THROW(detail::out_of_range::create(402,
ferencd@0 10502 "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
ferencd@0 10503 ") is out of range"));
ferencd@0 10504 }
ferencd@0 10505
ferencd@0 10506 // error condition (cf. RFC 6901, Sect. 4)
ferencd@0 10507 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
ferencd@0 10508 {
ferencd@0 10509 JSON_THROW(detail::parse_error::create(106, 0,
ferencd@0 10510 "array index '" + reference_token +
ferencd@0 10511 "' must not begin with '0'"));
ferencd@0 10512 }
ferencd@0 10513
ferencd@0 10514 // note: at performs range check
ferencd@0 10515 JSON_TRY
ferencd@0 10516 {
ferencd@0 10517 ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));
ferencd@0 10518 }
ferencd@0 10519 JSON_CATCH(std::invalid_argument&)
ferencd@0 10520 {
ferencd@0 10521 JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
ferencd@0 10522 }
ferencd@0 10523 break;
ferencd@0 10524 }
ferencd@0 10525
ferencd@0 10526 default:
ferencd@0 10527 JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
ferencd@0 10528 }
ferencd@0 10529 }
ferencd@0 10530
ferencd@0 10531 return *ptr;
ferencd@0 10532 }
ferencd@0 10533
ferencd@0 10534 /*!
ferencd@0 10535 @brief return a const reference to the pointed to value
ferencd@0 10536
ferencd@0 10537 @param[in] ptr a JSON value
ferencd@0 10538
ferencd@0 10539 @return const reference to the JSON value pointed to by the JSON
ferencd@0 10540 pointer
ferencd@0 10541
ferencd@0 10542 @throw parse_error.106 if an array index begins with '0'
ferencd@0 10543 @throw parse_error.109 if an array index was not a number
ferencd@0 10544 @throw out_of_range.402 if the array index '-' is used
ferencd@0 10545 @throw out_of_range.404 if the JSON pointer can not be resolved
ferencd@0 10546 */
ferencd@0 10547 const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
ferencd@0 10548 {
ferencd@0 10549 using size_type = typename BasicJsonType::size_type;
ferencd@0 10550 for (const auto& reference_token : reference_tokens)
ferencd@0 10551 {
ferencd@0 10552 switch (ptr->type())
ferencd@0 10553 {
ferencd@0 10554 case detail::value_t::object:
ferencd@0 10555 {
ferencd@0 10556 // use unchecked object access
ferencd@0 10557 ptr = &ptr->operator[](reference_token);
ferencd@0 10558 break;
ferencd@0 10559 }
ferencd@0 10560
ferencd@0 10561 case detail::value_t::array:
ferencd@0 10562 {
ferencd@0 10563 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
ferencd@0 10564 {
ferencd@0 10565 // "-" cannot be used for const access
ferencd@0 10566 JSON_THROW(detail::out_of_range::create(402,
ferencd@0 10567 "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
ferencd@0 10568 ") is out of range"));
ferencd@0 10569 }
ferencd@0 10570
ferencd@0 10571 // error condition (cf. RFC 6901, Sect. 4)
ferencd@0 10572 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
ferencd@0 10573 {
ferencd@0 10574 JSON_THROW(detail::parse_error::create(106, 0,
ferencd@0 10575 "array index '" + reference_token +
ferencd@0 10576 "' must not begin with '0'"));
ferencd@0 10577 }
ferencd@0 10578
ferencd@0 10579 // use unchecked array access
ferencd@0 10580 JSON_TRY
ferencd@0 10581 {
ferencd@0 10582 ptr = &ptr->operator[](
ferencd@0 10583 static_cast<size_type>(array_index(reference_token)));
ferencd@0 10584 }
ferencd@0 10585 JSON_CATCH(std::invalid_argument&)
ferencd@0 10586 {
ferencd@0 10587 JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
ferencd@0 10588 }
ferencd@0 10589 break;
ferencd@0 10590 }
ferencd@0 10591
ferencd@0 10592 default:
ferencd@0 10593 JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
ferencd@0 10594 }
ferencd@0 10595 }
ferencd@0 10596
ferencd@0 10597 return *ptr;
ferencd@0 10598 }
ferencd@0 10599
ferencd@0 10600 /*!
ferencd@0 10601 @throw parse_error.106 if an array index begins with '0'
ferencd@0 10602 @throw parse_error.109 if an array index was not a number
ferencd@0 10603 @throw out_of_range.402 if the array index '-' is used
ferencd@0 10604 @throw out_of_range.404 if the JSON pointer can not be resolved
ferencd@0 10605 */
ferencd@0 10606 const BasicJsonType& get_checked(const BasicJsonType* ptr) const
ferencd@0 10607 {
ferencd@0 10608 using size_type = typename BasicJsonType::size_type;
ferencd@0 10609 for (const auto& reference_token : reference_tokens)
ferencd@0 10610 {
ferencd@0 10611 switch (ptr->type())
ferencd@0 10612 {
ferencd@0 10613 case detail::value_t::object:
ferencd@0 10614 {
ferencd@0 10615 // note: at performs range check
ferencd@0 10616 ptr = &ptr->at(reference_token);
ferencd@0 10617 break;
ferencd@0 10618 }
ferencd@0 10619
ferencd@0 10620 case detail::value_t::array:
ferencd@0 10621 {
ferencd@0 10622 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
ferencd@0 10623 {
ferencd@0 10624 // "-" always fails the range check
ferencd@0 10625 JSON_THROW(detail::out_of_range::create(402,
ferencd@0 10626 "array index '-' (" + std::to_string(ptr->m_value.array->size()) +
ferencd@0 10627 ") is out of range"));
ferencd@0 10628 }
ferencd@0 10629
ferencd@0 10630 // error condition (cf. RFC 6901, Sect. 4)
ferencd@0 10631 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
ferencd@0 10632 {
ferencd@0 10633 JSON_THROW(detail::parse_error::create(106, 0,
ferencd@0 10634 "array index '" + reference_token +
ferencd@0 10635 "' must not begin with '0'"));
ferencd@0 10636 }
ferencd@0 10637
ferencd@0 10638 // note: at performs range check
ferencd@0 10639 JSON_TRY
ferencd@0 10640 {
ferencd@0 10641 ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));
ferencd@0 10642 }
ferencd@0 10643 JSON_CATCH(std::invalid_argument&)
ferencd@0 10644 {
ferencd@0 10645 JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
ferencd@0 10646 }
ferencd@0 10647 break;
ferencd@0 10648 }
ferencd@0 10649
ferencd@0 10650 default:
ferencd@0 10651 JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'"));
ferencd@0 10652 }
ferencd@0 10653 }
ferencd@0 10654
ferencd@0 10655 return *ptr;
ferencd@0 10656 }
ferencd@0 10657
ferencd@0 10658 /*!
ferencd@0 10659 @throw parse_error.106 if an array index begins with '0'
ferencd@0 10660 @throw parse_error.109 if an array index was not a number
ferencd@0 10661 */
ferencd@0 10662 bool contains(const BasicJsonType* ptr) const
ferencd@0 10663 {
ferencd@0 10664 using size_type = typename BasicJsonType::size_type;
ferencd@0 10665 for (const auto& reference_token : reference_tokens)
ferencd@0 10666 {
ferencd@0 10667 switch (ptr->type())
ferencd@0 10668 {
ferencd@0 10669 case detail::value_t::object:
ferencd@0 10670 {
ferencd@0 10671 if (not ptr->contains(reference_token))
ferencd@0 10672 {
ferencd@0 10673 // we did not find the key in the object
ferencd@0 10674 return false;
ferencd@0 10675 }
ferencd@0 10676
ferencd@0 10677 ptr = &ptr->operator[](reference_token);
ferencd@0 10678 break;
ferencd@0 10679 }
ferencd@0 10680
ferencd@0 10681 case detail::value_t::array:
ferencd@0 10682 {
ferencd@0 10683 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
ferencd@0 10684 {
ferencd@0 10685 // "-" always fails the range check
ferencd@0 10686 return false;
ferencd@0 10687 }
ferencd@0 10688
ferencd@0 10689 // error condition (cf. RFC 6901, Sect. 4)
ferencd@0 10690 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))
ferencd@0 10691 {
ferencd@0 10692 JSON_THROW(detail::parse_error::create(106, 0,
ferencd@0 10693 "array index '" + reference_token +
ferencd@0 10694 "' must not begin with '0'"));
ferencd@0 10695 }
ferencd@0 10696
ferencd@0 10697 JSON_TRY
ferencd@0 10698 {
ferencd@0 10699 const auto idx = static_cast<size_type>(array_index(reference_token));
ferencd@0 10700 if (idx >= ptr->size())
ferencd@0 10701 {
ferencd@0 10702 // index out of range
ferencd@0 10703 return false;
ferencd@0 10704 }
ferencd@0 10705
ferencd@0 10706 ptr = &ptr->operator[](idx);
ferencd@0 10707 break;
ferencd@0 10708 }
ferencd@0 10709 JSON_CATCH(std::invalid_argument&)
ferencd@0 10710 {
ferencd@0 10711 JSON_THROW(detail::parse_error::create(109, 0, "array index '" + reference_token + "' is not a number"));
ferencd@0 10712 }
ferencd@0 10713 break;
ferencd@0 10714 }
ferencd@0 10715
ferencd@0 10716 default:
ferencd@0 10717 {
ferencd@0 10718 // we do not expect primitive values if there is still a
ferencd@0 10719 // reference token to process
ferencd@0 10720 return false;
ferencd@0 10721 }
ferencd@0 10722 }
ferencd@0 10723 }
ferencd@0 10724
ferencd@0 10725 // no reference token left means we found a primitive value
ferencd@0 10726 return true;
ferencd@0 10727 }
ferencd@0 10728
ferencd@0 10729 /*!
ferencd@0 10730 @brief split the string input to reference tokens
ferencd@0 10731
ferencd@0 10732 @note This function is only called by the json_pointer constructor.
ferencd@0 10733 All exceptions below are documented there.
ferencd@0 10734
ferencd@0 10735 @throw parse_error.107 if the pointer is not empty or begins with '/'
ferencd@0 10736 @throw parse_error.108 if character '~' is not followed by '0' or '1'
ferencd@0 10737 */
ferencd@0 10738 static std::vector<std::string> split(const std::string& reference_string)
ferencd@0 10739 {
ferencd@0 10740 std::vector<std::string> result;
ferencd@0 10741
ferencd@0 10742 // special case: empty reference string -> no reference tokens
ferencd@0 10743 if (reference_string.empty())
ferencd@0 10744 {
ferencd@0 10745 return result;
ferencd@0 10746 }
ferencd@0 10747
ferencd@0 10748 // check if nonempty reference string begins with slash
ferencd@0 10749 if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
ferencd@0 10750 {
ferencd@0 10751 JSON_THROW(detail::parse_error::create(107, 1,
ferencd@0 10752 "JSON pointer must be empty or begin with '/' - was: '" +
ferencd@0 10753 reference_string + "'"));
ferencd@0 10754 }
ferencd@0 10755
ferencd@0 10756 // extract the reference tokens:
ferencd@0 10757 // - slash: position of the last read slash (or end of string)
ferencd@0 10758 // - start: position after the previous slash
ferencd@0 10759 for (
ferencd@0 10760 // search for the first slash after the first character
ferencd@0 10761 std::size_t slash = reference_string.find_first_of('/', 1),
ferencd@0 10762 // set the beginning of the first reference token
ferencd@0 10763 start = 1;
ferencd@0 10764 // we can stop if start == 0 (if slash == std::string::npos)
ferencd@0 10765 start != 0;
ferencd@0 10766 // set the beginning of the next reference token
ferencd@0 10767 // (will eventually be 0 if slash == std::string::npos)
ferencd@0 10768 start = (slash == std::string::npos) ? 0 : slash + 1,
ferencd@0 10769 // find next slash
ferencd@0 10770 slash = reference_string.find_first_of('/', start))
ferencd@0 10771 {
ferencd@0 10772 // use the text between the beginning of the reference token
ferencd@0 10773 // (start) and the last slash (slash).
ferencd@0 10774 auto reference_token = reference_string.substr(start, slash - start);
ferencd@0 10775
ferencd@0 10776 // check reference tokens are properly escaped
ferencd@0 10777 for (std::size_t pos = reference_token.find_first_of('~');
ferencd@0 10778 pos != std::string::npos;
ferencd@0 10779 pos = reference_token.find_first_of('~', pos + 1))
ferencd@0 10780 {
ferencd@0 10781 assert(reference_token[pos] == '~');
ferencd@0 10782
ferencd@0 10783 // ~ must be followed by 0 or 1
ferencd@0 10784 if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 or
ferencd@0 10785 (reference_token[pos + 1] != '0' and
ferencd@0 10786 reference_token[pos + 1] != '1')))
ferencd@0 10787 {
ferencd@0 10788 JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'"));
ferencd@0 10789 }
ferencd@0 10790 }
ferencd@0 10791
ferencd@0 10792 // finally, store the reference token
ferencd@0 10793 unescape(reference_token);
ferencd@0 10794 result.push_back(reference_token);
ferencd@0 10795 }
ferencd@0 10796
ferencd@0 10797 return result;
ferencd@0 10798 }
ferencd@0 10799
ferencd@0 10800 /*!
ferencd@0 10801 @brief replace all occurrences of a substring by another string
ferencd@0 10802
ferencd@0 10803 @param[in,out] s the string to manipulate; changed so that all
ferencd@0 10804 occurrences of @a f are replaced with @a t
ferencd@0 10805 @param[in] f the substring to replace with @a t
ferencd@0 10806 @param[in] t the string to replace @a f
ferencd@0 10807
ferencd@0 10808 @pre The search string @a f must not be empty. **This precondition is
ferencd@0 10809 enforced with an assertion.**
ferencd@0 10810
ferencd@0 10811 @since version 2.0.0
ferencd@0 10812 */
ferencd@0 10813 static void replace_substring(std::string& s, const std::string& f,
ferencd@0 10814 const std::string& t)
ferencd@0 10815 {
ferencd@0 10816 assert(not f.empty());
ferencd@0 10817 for (auto pos = s.find(f); // find first occurrence of f
ferencd@0 10818 pos != std::string::npos; // make sure f was found
ferencd@0 10819 s.replace(pos, f.size(), t), // replace with t, and
ferencd@0 10820 pos = s.find(f, pos + t.size())) // find next occurrence of f
ferencd@0 10821 {}
ferencd@0 10822 }
ferencd@0 10823
ferencd@0 10824 /// escape "~" to "~0" and "/" to "~1"
ferencd@0 10825 static std::string escape(std::string s)
ferencd@0 10826 {
ferencd@0 10827 replace_substring(s, "~", "~0");
ferencd@0 10828 replace_substring(s, "/", "~1");
ferencd@0 10829 return s;
ferencd@0 10830 }
ferencd@0 10831
ferencd@0 10832 /// unescape "~1" to tilde and "~0" to slash (order is important!)
ferencd@0 10833 static void unescape(std::string& s)
ferencd@0 10834 {
ferencd@0 10835 replace_substring(s, "~1", "/");
ferencd@0 10836 replace_substring(s, "~0", "~");
ferencd@0 10837 }
ferencd@0 10838
ferencd@0 10839 /*!
ferencd@0 10840 @param[in] reference_string the reference string to the current value
ferencd@0 10841 @param[in] value the value to consider
ferencd@0 10842 @param[in,out] result the result object to insert values to
ferencd@0 10843
ferencd@0 10844 @note Empty objects or arrays are flattened to `null`.
ferencd@0 10845 */
ferencd@0 10846 static void flatten(const std::string& reference_string,
ferencd@0 10847 const BasicJsonType& value,
ferencd@0 10848 BasicJsonType& result)
ferencd@0 10849 {
ferencd@0 10850 switch (value.type())
ferencd@0 10851 {
ferencd@0 10852 case detail::value_t::array:
ferencd@0 10853 {
ferencd@0 10854 if (value.m_value.array->empty())
ferencd@0 10855 {
ferencd@0 10856 // flatten empty array as null
ferencd@0 10857 result[reference_string] = nullptr;
ferencd@0 10858 }
ferencd@0 10859 else
ferencd@0 10860 {
ferencd@0 10861 // iterate array and use index as reference string
ferencd@0 10862 for (std::size_t i = 0; i < value.m_value.array->size(); ++i)
ferencd@0 10863 {
ferencd@0 10864 flatten(reference_string + "/" + std::to_string(i),
ferencd@0 10865 value.m_value.array->operator[](i), result);
ferencd@0 10866 }
ferencd@0 10867 }
ferencd@0 10868 break;
ferencd@0 10869 }
ferencd@0 10870
ferencd@0 10871 case detail::value_t::object:
ferencd@0 10872 {
ferencd@0 10873 if (value.m_value.object->empty())
ferencd@0 10874 {
ferencd@0 10875 // flatten empty object as null
ferencd@0 10876 result[reference_string] = nullptr;
ferencd@0 10877 }
ferencd@0 10878 else
ferencd@0 10879 {
ferencd@0 10880 // iterate object and use keys as reference string
ferencd@0 10881 for (const auto& element : *value.m_value.object)
ferencd@0 10882 {
ferencd@0 10883 flatten(reference_string + "/" + escape(element.first), element.second, result);
ferencd@0 10884 }
ferencd@0 10885 }
ferencd@0 10886 break;
ferencd@0 10887 }
ferencd@0 10888
ferencd@0 10889 default:
ferencd@0 10890 {
ferencd@0 10891 // add primitive value with its reference string
ferencd@0 10892 result[reference_string] = value;
ferencd@0 10893 break;
ferencd@0 10894 }
ferencd@0 10895 }
ferencd@0 10896 }
ferencd@0 10897
ferencd@0 10898 /*!
ferencd@0 10899 @param[in] value flattened JSON
ferencd@0 10900
ferencd@0 10901 @return unflattened JSON
ferencd@0 10902
ferencd@0 10903 @throw parse_error.109 if array index is not a number
ferencd@0 10904 @throw type_error.314 if value is not an object
ferencd@0 10905 @throw type_error.315 if object values are not primitive
ferencd@0 10906 @throw type_error.313 if value cannot be unflattened
ferencd@0 10907 */
ferencd@0 10908 static BasicJsonType
ferencd@0 10909 unflatten(const BasicJsonType& value)
ferencd@0 10910 {
ferencd@0 10911 if (JSON_HEDLEY_UNLIKELY(not value.is_object()))
ferencd@0 10912 {
ferencd@0 10913 JSON_THROW(detail::type_error::create(314, "only objects can be unflattened"));
ferencd@0 10914 }
ferencd@0 10915
ferencd@0 10916 BasicJsonType result;
ferencd@0 10917
ferencd@0 10918 // iterate the JSON object values
ferencd@0 10919 for (const auto& element : *value.m_value.object)
ferencd@0 10920 {
ferencd@0 10921 if (JSON_HEDLEY_UNLIKELY(not element.second.is_primitive()))
ferencd@0 10922 {
ferencd@0 10923 JSON_THROW(detail::type_error::create(315, "values in object must be primitive"));
ferencd@0 10924 }
ferencd@0 10925
ferencd@0 10926 // assign value to reference pointed to by JSON pointer; Note that if
ferencd@0 10927 // the JSON pointer is "" (i.e., points to the whole value), function
ferencd@0 10928 // get_and_create returns a reference to result itself. An assignment
ferencd@0 10929 // will then create a primitive value.
ferencd@0 10930 json_pointer(element.first).get_and_create(result) = element.second;
ferencd@0 10931 }
ferencd@0 10932
ferencd@0 10933 return result;
ferencd@0 10934 }
ferencd@0 10935
ferencd@0 10936 /*!
ferencd@0 10937 @brief compares two JSON pointers for equality
ferencd@0 10938
ferencd@0 10939 @param[in] lhs JSON pointer to compare
ferencd@0 10940 @param[in] rhs JSON pointer to compare
ferencd@0 10941 @return whether @a lhs is equal to @a rhs
ferencd@0 10942
ferencd@0 10943 @complexity Linear in the length of the JSON pointer
ferencd@0 10944
ferencd@0 10945 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 10946 */
ferencd@0 10947 friend bool operator==(json_pointer const& lhs,
ferencd@0 10948 json_pointer const& rhs) noexcept
ferencd@0 10949 {
ferencd@0 10950 return lhs.reference_tokens == rhs.reference_tokens;
ferencd@0 10951 }
ferencd@0 10952
ferencd@0 10953 /*!
ferencd@0 10954 @brief compares two JSON pointers for inequality
ferencd@0 10955
ferencd@0 10956 @param[in] lhs JSON pointer to compare
ferencd@0 10957 @param[in] rhs JSON pointer to compare
ferencd@0 10958 @return whether @a lhs is not equal @a rhs
ferencd@0 10959
ferencd@0 10960 @complexity Linear in the length of the JSON pointer
ferencd@0 10961
ferencd@0 10962 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 10963 */
ferencd@0 10964 friend bool operator!=(json_pointer const& lhs,
ferencd@0 10965 json_pointer const& rhs) noexcept
ferencd@0 10966 {
ferencd@0 10967 return not (lhs == rhs);
ferencd@0 10968 }
ferencd@0 10969
ferencd@0 10970 /// the reference tokens
ferencd@0 10971 std::vector<std::string> reference_tokens;
ferencd@0 10972 };
ferencd@0 10973 } // namespace nlohmann
ferencd@0 10974
ferencd@0 10975 // #include <nlohmann/detail/json_ref.hpp>
ferencd@0 10976
ferencd@0 10977
ferencd@0 10978 #include <initializer_list>
ferencd@0 10979 #include <utility>
ferencd@0 10980
ferencd@0 10981 // #include <nlohmann/detail/meta/type_traits.hpp>
ferencd@0 10982
ferencd@0 10983
ferencd@0 10984 namespace nlohmann
ferencd@0 10985 {
ferencd@0 10986 namespace detail
ferencd@0 10987 {
ferencd@0 10988 template<typename BasicJsonType>
ferencd@0 10989 class json_ref
ferencd@0 10990 {
ferencd@0 10991 public:
ferencd@0 10992 using value_type = BasicJsonType;
ferencd@0 10993
ferencd@0 10994 json_ref(value_type&& value)
ferencd@0 10995 : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true)
ferencd@0 10996 {}
ferencd@0 10997
ferencd@0 10998 json_ref(const value_type& value)
ferencd@0 10999 : value_ref(const_cast<value_type*>(&value)), is_rvalue(false)
ferencd@0 11000 {}
ferencd@0 11001
ferencd@0 11002 json_ref(std::initializer_list<json_ref> init)
ferencd@0 11003 : owned_value(init), value_ref(&owned_value), is_rvalue(true)
ferencd@0 11004 {}
ferencd@0 11005
ferencd@0 11006 template <
ferencd@0 11007 class... Args,
ferencd@0 11008 enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >
ferencd@0 11009 json_ref(Args && ... args)
ferencd@0 11010 : owned_value(std::forward<Args>(args)...), value_ref(&owned_value),
ferencd@0 11011 is_rvalue(true) {}
ferencd@0 11012
ferencd@0 11013 // class should be movable only
ferencd@0 11014 json_ref(json_ref&&) = default;
ferencd@0 11015 json_ref(const json_ref&) = delete;
ferencd@0 11016 json_ref& operator=(const json_ref&) = delete;
ferencd@0 11017 json_ref& operator=(json_ref&&) = delete;
ferencd@0 11018 ~json_ref() = default;
ferencd@0 11019
ferencd@0 11020 value_type moved_or_copied() const
ferencd@0 11021 {
ferencd@0 11022 if (is_rvalue)
ferencd@0 11023 {
ferencd@0 11024 return std::move(*value_ref);
ferencd@0 11025 }
ferencd@0 11026 return *value_ref;
ferencd@0 11027 }
ferencd@0 11028
ferencd@0 11029 value_type const& operator*() const
ferencd@0 11030 {
ferencd@0 11031 return *static_cast<value_type const*>(value_ref);
ferencd@0 11032 }
ferencd@0 11033
ferencd@0 11034 value_type const* operator->() const
ferencd@0 11035 {
ferencd@0 11036 return static_cast<value_type const*>(value_ref);
ferencd@0 11037 }
ferencd@0 11038
ferencd@0 11039 private:
ferencd@0 11040 mutable value_type owned_value = nullptr;
ferencd@0 11041 value_type* value_ref = nullptr;
ferencd@0 11042 const bool is_rvalue;
ferencd@0 11043 };
ferencd@0 11044 } // namespace detail
ferencd@0 11045 } // namespace nlohmann
ferencd@0 11046
ferencd@0 11047 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 11048
ferencd@0 11049 // #include <nlohmann/detail/meta/cpp_future.hpp>
ferencd@0 11050
ferencd@0 11051 // #include <nlohmann/detail/meta/type_traits.hpp>
ferencd@0 11052
ferencd@0 11053 // #include <nlohmann/detail/output/binary_writer.hpp>
ferencd@0 11054
ferencd@0 11055
ferencd@0 11056 #include <algorithm> // reverse
ferencd@0 11057 #include <array> // array
ferencd@0 11058 #include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
ferencd@0 11059 #include <cstring> // memcpy
ferencd@0 11060 #include <limits> // numeric_limits
ferencd@0 11061 #include <string> // string
ferencd@0 11062
ferencd@0 11063 // #include <nlohmann/detail/input/binary_reader.hpp>
ferencd@0 11064
ferencd@0 11065 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 11066
ferencd@0 11067 // #include <nlohmann/detail/output/output_adapters.hpp>
ferencd@0 11068
ferencd@0 11069
ferencd@0 11070 #include <algorithm> // copy
ferencd@0 11071 #include <cstddef> // size_t
ferencd@0 11072 #include <ios> // streamsize
ferencd@0 11073 #include <iterator> // back_inserter
ferencd@0 11074 #include <memory> // shared_ptr, make_shared
ferencd@0 11075 #include <ostream> // basic_ostream
ferencd@0 11076 #include <string> // basic_string
ferencd@0 11077 #include <vector> // vector
ferencd@0 11078 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 11079
ferencd@0 11080
ferencd@0 11081 namespace nlohmann
ferencd@0 11082 {
ferencd@0 11083 namespace detail
ferencd@0 11084 {
ferencd@0 11085 /// abstract output adapter interface
ferencd@0 11086 template<typename CharType> struct output_adapter_protocol
ferencd@0 11087 {
ferencd@0 11088 virtual void write_character(CharType c) = 0;
ferencd@0 11089 virtual void write_characters(const CharType* s, std::size_t length) = 0;
ferencd@0 11090 virtual ~output_adapter_protocol() = default;
ferencd@0 11091 };
ferencd@0 11092
ferencd@0 11093 /// a type to simplify interfaces
ferencd@0 11094 template<typename CharType>
ferencd@0 11095 using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;
ferencd@0 11096
ferencd@0 11097 /// output adapter for byte vectors
ferencd@0 11098 template<typename CharType>
ferencd@0 11099 class output_vector_adapter : public output_adapter_protocol<CharType>
ferencd@0 11100 {
ferencd@0 11101 public:
ferencd@0 11102 explicit output_vector_adapter(std::vector<CharType>& vec) noexcept
ferencd@0 11103 : v(vec)
ferencd@0 11104 {}
ferencd@0 11105
ferencd@0 11106 void write_character(CharType c) override
ferencd@0 11107 {
ferencd@0 11108 v.push_back(c);
ferencd@0 11109 }
ferencd@0 11110
ferencd@0 11111 JSON_HEDLEY_NON_NULL(2)
ferencd@0 11112 void write_characters(const CharType* s, std::size_t length) override
ferencd@0 11113 {
ferencd@0 11114 std::copy(s, s + length, std::back_inserter(v));
ferencd@0 11115 }
ferencd@0 11116
ferencd@0 11117 private:
ferencd@0 11118 std::vector<CharType>& v;
ferencd@0 11119 };
ferencd@0 11120
ferencd@0 11121 /// output adapter for output streams
ferencd@0 11122 template<typename CharType>
ferencd@0 11123 class output_stream_adapter : public output_adapter_protocol<CharType>
ferencd@0 11124 {
ferencd@0 11125 public:
ferencd@0 11126 explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept
ferencd@0 11127 : stream(s)
ferencd@0 11128 {}
ferencd@0 11129
ferencd@0 11130 void write_character(CharType c) override
ferencd@0 11131 {
ferencd@0 11132 stream.put(c);
ferencd@0 11133 }
ferencd@0 11134
ferencd@0 11135 JSON_HEDLEY_NON_NULL(2)
ferencd@0 11136 void write_characters(const CharType* s, std::size_t length) override
ferencd@0 11137 {
ferencd@0 11138 stream.write(s, static_cast<std::streamsize>(length));
ferencd@0 11139 }
ferencd@0 11140
ferencd@0 11141 private:
ferencd@0 11142 std::basic_ostream<CharType>& stream;
ferencd@0 11143 };
ferencd@0 11144
ferencd@0 11145 /// output adapter for basic_string
ferencd@0 11146 template<typename CharType, typename StringType = std::basic_string<CharType>>
ferencd@0 11147 class output_string_adapter : public output_adapter_protocol<CharType>
ferencd@0 11148 {
ferencd@0 11149 public:
ferencd@0 11150 explicit output_string_adapter(StringType& s) noexcept
ferencd@0 11151 : str(s)
ferencd@0 11152 {}
ferencd@0 11153
ferencd@0 11154 void write_character(CharType c) override
ferencd@0 11155 {
ferencd@0 11156 str.push_back(c);
ferencd@0 11157 }
ferencd@0 11158
ferencd@0 11159 JSON_HEDLEY_NON_NULL(2)
ferencd@0 11160 void write_characters(const CharType* s, std::size_t length) override
ferencd@0 11161 {
ferencd@0 11162 str.append(s, length);
ferencd@0 11163 }
ferencd@0 11164
ferencd@0 11165 private:
ferencd@0 11166 StringType& str;
ferencd@0 11167 };
ferencd@0 11168
ferencd@0 11169 template<typename CharType, typename StringType = std::basic_string<CharType>>
ferencd@0 11170 class output_adapter
ferencd@0 11171 {
ferencd@0 11172 public:
ferencd@0 11173 output_adapter(std::vector<CharType>& vec)
ferencd@0 11174 : oa(std::make_shared<output_vector_adapter<CharType>>(vec)) {}
ferencd@0 11175
ferencd@0 11176 output_adapter(std::basic_ostream<CharType>& s)
ferencd@0 11177 : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
ferencd@0 11178
ferencd@0 11179 output_adapter(StringType& s)
ferencd@0 11180 : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}
ferencd@0 11181
ferencd@0 11182 operator output_adapter_t<CharType>()
ferencd@0 11183 {
ferencd@0 11184 return oa;
ferencd@0 11185 }
ferencd@0 11186
ferencd@0 11187 private:
ferencd@0 11188 output_adapter_t<CharType> oa = nullptr;
ferencd@0 11189 };
ferencd@0 11190 } // namespace detail
ferencd@0 11191 } // namespace nlohmann
ferencd@0 11192
ferencd@0 11193
ferencd@0 11194 namespace nlohmann
ferencd@0 11195 {
ferencd@0 11196 namespace detail
ferencd@0 11197 {
ferencd@0 11198 ///////////////////
ferencd@0 11199 // binary writer //
ferencd@0 11200 ///////////////////
ferencd@0 11201
ferencd@0 11202 /*!
ferencd@0 11203 @brief serialization to CBOR and MessagePack values
ferencd@0 11204 */
ferencd@0 11205 template<typename BasicJsonType, typename CharType>
ferencd@0 11206 class binary_writer
ferencd@0 11207 {
ferencd@0 11208 using string_t = typename BasicJsonType::string_t;
ferencd@0 11209
ferencd@0 11210 public:
ferencd@0 11211 /*!
ferencd@0 11212 @brief create a binary writer
ferencd@0 11213
ferencd@0 11214 @param[in] adapter output adapter to write to
ferencd@0 11215 */
ferencd@0 11216 explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)
ferencd@0 11217 {
ferencd@0 11218 assert(oa);
ferencd@0 11219 }
ferencd@0 11220
ferencd@0 11221 /*!
ferencd@0 11222 @param[in] j JSON value to serialize
ferencd@0 11223 @pre j.type() == value_t::object
ferencd@0 11224 */
ferencd@0 11225 void write_bson(const BasicJsonType& j)
ferencd@0 11226 {
ferencd@0 11227 switch (j.type())
ferencd@0 11228 {
ferencd@0 11229 case value_t::object:
ferencd@0 11230 {
ferencd@0 11231 write_bson_object(*j.m_value.object);
ferencd@0 11232 break;
ferencd@0 11233 }
ferencd@0 11234
ferencd@0 11235 default:
ferencd@0 11236 {
ferencd@0 11237 JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name())));
ferencd@0 11238 }
ferencd@0 11239 }
ferencd@0 11240 }
ferencd@0 11241
ferencd@0 11242 /*!
ferencd@0 11243 @param[in] j JSON value to serialize
ferencd@0 11244 */
ferencd@0 11245 void write_cbor(const BasicJsonType& j)
ferencd@0 11246 {
ferencd@0 11247 switch (j.type())
ferencd@0 11248 {
ferencd@0 11249 case value_t::null:
ferencd@0 11250 {
ferencd@0 11251 oa->write_character(to_char_type(0xF6));
ferencd@0 11252 break;
ferencd@0 11253 }
ferencd@0 11254
ferencd@0 11255 case value_t::boolean:
ferencd@0 11256 {
ferencd@0 11257 oa->write_character(j.m_value.boolean
ferencd@0 11258 ? to_char_type(0xF5)
ferencd@0 11259 : to_char_type(0xF4));
ferencd@0 11260 break;
ferencd@0 11261 }
ferencd@0 11262
ferencd@0 11263 case value_t::number_integer:
ferencd@0 11264 {
ferencd@0 11265 if (j.m_value.number_integer >= 0)
ferencd@0 11266 {
ferencd@0 11267 // CBOR does not differentiate between positive signed
ferencd@0 11268 // integers and unsigned integers. Therefore, we used the
ferencd@0 11269 // code from the value_t::number_unsigned case here.
ferencd@0 11270 if (j.m_value.number_integer <= 0x17)
ferencd@0 11271 {
ferencd@0 11272 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
ferencd@0 11273 }
ferencd@0 11274 else if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
ferencd@0 11275 {
ferencd@0 11276 oa->write_character(to_char_type(0x18));
ferencd@0 11277 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
ferencd@0 11278 }
ferencd@0 11279 else if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
ferencd@0 11280 {
ferencd@0 11281 oa->write_character(to_char_type(0x19));
ferencd@0 11282 write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
ferencd@0 11283 }
ferencd@0 11284 else if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
ferencd@0 11285 {
ferencd@0 11286 oa->write_character(to_char_type(0x1A));
ferencd@0 11287 write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
ferencd@0 11288 }
ferencd@0 11289 else
ferencd@0 11290 {
ferencd@0 11291 oa->write_character(to_char_type(0x1B));
ferencd@0 11292 write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
ferencd@0 11293 }
ferencd@0 11294 }
ferencd@0 11295 else
ferencd@0 11296 {
ferencd@0 11297 // The conversions below encode the sign in the first
ferencd@0 11298 // byte, and the value is converted to a positive number.
ferencd@0 11299 const auto positive_number = -1 - j.m_value.number_integer;
ferencd@0 11300 if (j.m_value.number_integer >= -24)
ferencd@0 11301 {
ferencd@0 11302 write_number(static_cast<std::uint8_t>(0x20 + positive_number));
ferencd@0 11303 }
ferencd@0 11304 else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())
ferencd@0 11305 {
ferencd@0 11306 oa->write_character(to_char_type(0x38));
ferencd@0 11307 write_number(static_cast<std::uint8_t>(positive_number));
ferencd@0 11308 }
ferencd@0 11309 else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())
ferencd@0 11310 {
ferencd@0 11311 oa->write_character(to_char_type(0x39));
ferencd@0 11312 write_number(static_cast<std::uint16_t>(positive_number));
ferencd@0 11313 }
ferencd@0 11314 else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())
ferencd@0 11315 {
ferencd@0 11316 oa->write_character(to_char_type(0x3A));
ferencd@0 11317 write_number(static_cast<std::uint32_t>(positive_number));
ferencd@0 11318 }
ferencd@0 11319 else
ferencd@0 11320 {
ferencd@0 11321 oa->write_character(to_char_type(0x3B));
ferencd@0 11322 write_number(static_cast<std::uint64_t>(positive_number));
ferencd@0 11323 }
ferencd@0 11324 }
ferencd@0 11325 break;
ferencd@0 11326 }
ferencd@0 11327
ferencd@0 11328 case value_t::number_unsigned:
ferencd@0 11329 {
ferencd@0 11330 if (j.m_value.number_unsigned <= 0x17)
ferencd@0 11331 {
ferencd@0 11332 write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
ferencd@0 11333 }
ferencd@0 11334 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
ferencd@0 11335 {
ferencd@0 11336 oa->write_character(to_char_type(0x18));
ferencd@0 11337 write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
ferencd@0 11338 }
ferencd@0 11339 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
ferencd@0 11340 {
ferencd@0 11341 oa->write_character(to_char_type(0x19));
ferencd@0 11342 write_number(static_cast<std::uint16_t>(j.m_value.number_unsigned));
ferencd@0 11343 }
ferencd@0 11344 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
ferencd@0 11345 {
ferencd@0 11346 oa->write_character(to_char_type(0x1A));
ferencd@0 11347 write_number(static_cast<std::uint32_t>(j.m_value.number_unsigned));
ferencd@0 11348 }
ferencd@0 11349 else
ferencd@0 11350 {
ferencd@0 11351 oa->write_character(to_char_type(0x1B));
ferencd@0 11352 write_number(static_cast<std::uint64_t>(j.m_value.number_unsigned));
ferencd@0 11353 }
ferencd@0 11354 break;
ferencd@0 11355 }
ferencd@0 11356
ferencd@0 11357 case value_t::number_float:
ferencd@0 11358 {
ferencd@0 11359 oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
ferencd@0 11360 write_number(j.m_value.number_float);
ferencd@0 11361 break;
ferencd@0 11362 }
ferencd@0 11363
ferencd@0 11364 case value_t::string:
ferencd@0 11365 {
ferencd@0 11366 // step 1: write control byte and the string length
ferencd@0 11367 const auto N = j.m_value.string->size();
ferencd@0 11368 if (N <= 0x17)
ferencd@0 11369 {
ferencd@0 11370 write_number(static_cast<std::uint8_t>(0x60 + N));
ferencd@0 11371 }
ferencd@0 11372 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
ferencd@0 11373 {
ferencd@0 11374 oa->write_character(to_char_type(0x78));
ferencd@0 11375 write_number(static_cast<std::uint8_t>(N));
ferencd@0 11376 }
ferencd@0 11377 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
ferencd@0 11378 {
ferencd@0 11379 oa->write_character(to_char_type(0x79));
ferencd@0 11380 write_number(static_cast<std::uint16_t>(N));
ferencd@0 11381 }
ferencd@0 11382 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
ferencd@0 11383 {
ferencd@0 11384 oa->write_character(to_char_type(0x7A));
ferencd@0 11385 write_number(static_cast<std::uint32_t>(N));
ferencd@0 11386 }
ferencd@0 11387 // LCOV_EXCL_START
ferencd@0 11388 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
ferencd@0 11389 {
ferencd@0 11390 oa->write_character(to_char_type(0x7B));
ferencd@0 11391 write_number(static_cast<std::uint64_t>(N));
ferencd@0 11392 }
ferencd@0 11393 // LCOV_EXCL_STOP
ferencd@0 11394
ferencd@0 11395 // step 2: write the string
ferencd@0 11396 oa->write_characters(
ferencd@0 11397 reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
ferencd@0 11398 j.m_value.string->size());
ferencd@0 11399 break;
ferencd@0 11400 }
ferencd@0 11401
ferencd@0 11402 case value_t::array:
ferencd@0 11403 {
ferencd@0 11404 // step 1: write control byte and the array size
ferencd@0 11405 const auto N = j.m_value.array->size();
ferencd@0 11406 if (N <= 0x17)
ferencd@0 11407 {
ferencd@0 11408 write_number(static_cast<std::uint8_t>(0x80 + N));
ferencd@0 11409 }
ferencd@0 11410 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
ferencd@0 11411 {
ferencd@0 11412 oa->write_character(to_char_type(0x98));
ferencd@0 11413 write_number(static_cast<std::uint8_t>(N));
ferencd@0 11414 }
ferencd@0 11415 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
ferencd@0 11416 {
ferencd@0 11417 oa->write_character(to_char_type(0x99));
ferencd@0 11418 write_number(static_cast<std::uint16_t>(N));
ferencd@0 11419 }
ferencd@0 11420 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
ferencd@0 11421 {
ferencd@0 11422 oa->write_character(to_char_type(0x9A));
ferencd@0 11423 write_number(static_cast<std::uint32_t>(N));
ferencd@0 11424 }
ferencd@0 11425 // LCOV_EXCL_START
ferencd@0 11426 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
ferencd@0 11427 {
ferencd@0 11428 oa->write_character(to_char_type(0x9B));
ferencd@0 11429 write_number(static_cast<std::uint64_t>(N));
ferencd@0 11430 }
ferencd@0 11431 // LCOV_EXCL_STOP
ferencd@0 11432
ferencd@0 11433 // step 2: write each element
ferencd@0 11434 for (const auto& el : *j.m_value.array)
ferencd@0 11435 {
ferencd@0 11436 write_cbor(el);
ferencd@0 11437 }
ferencd@0 11438 break;
ferencd@0 11439 }
ferencd@0 11440
ferencd@0 11441 case value_t::object:
ferencd@0 11442 {
ferencd@0 11443 // step 1: write control byte and the object size
ferencd@0 11444 const auto N = j.m_value.object->size();
ferencd@0 11445 if (N <= 0x17)
ferencd@0 11446 {
ferencd@0 11447 write_number(static_cast<std::uint8_t>(0xA0 + N));
ferencd@0 11448 }
ferencd@0 11449 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
ferencd@0 11450 {
ferencd@0 11451 oa->write_character(to_char_type(0xB8));
ferencd@0 11452 write_number(static_cast<std::uint8_t>(N));
ferencd@0 11453 }
ferencd@0 11454 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
ferencd@0 11455 {
ferencd@0 11456 oa->write_character(to_char_type(0xB9));
ferencd@0 11457 write_number(static_cast<std::uint16_t>(N));
ferencd@0 11458 }
ferencd@0 11459 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
ferencd@0 11460 {
ferencd@0 11461 oa->write_character(to_char_type(0xBA));
ferencd@0 11462 write_number(static_cast<std::uint32_t>(N));
ferencd@0 11463 }
ferencd@0 11464 // LCOV_EXCL_START
ferencd@0 11465 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
ferencd@0 11466 {
ferencd@0 11467 oa->write_character(to_char_type(0xBB));
ferencd@0 11468 write_number(static_cast<std::uint64_t>(N));
ferencd@0 11469 }
ferencd@0 11470 // LCOV_EXCL_STOP
ferencd@0 11471
ferencd@0 11472 // step 2: write each element
ferencd@0 11473 for (const auto& el : *j.m_value.object)
ferencd@0 11474 {
ferencd@0 11475 write_cbor(el.first);
ferencd@0 11476 write_cbor(el.second);
ferencd@0 11477 }
ferencd@0 11478 break;
ferencd@0 11479 }
ferencd@0 11480
ferencd@0 11481 default:
ferencd@0 11482 break;
ferencd@0 11483 }
ferencd@0 11484 }
ferencd@0 11485
ferencd@0 11486 /*!
ferencd@0 11487 @param[in] j JSON value to serialize
ferencd@0 11488 */
ferencd@0 11489 void write_msgpack(const BasicJsonType& j)
ferencd@0 11490 {
ferencd@0 11491 switch (j.type())
ferencd@0 11492 {
ferencd@0 11493 case value_t::null: // nil
ferencd@0 11494 {
ferencd@0 11495 oa->write_character(to_char_type(0xC0));
ferencd@0 11496 break;
ferencd@0 11497 }
ferencd@0 11498
ferencd@0 11499 case value_t::boolean: // true and false
ferencd@0 11500 {
ferencd@0 11501 oa->write_character(j.m_value.boolean
ferencd@0 11502 ? to_char_type(0xC3)
ferencd@0 11503 : to_char_type(0xC2));
ferencd@0 11504 break;
ferencd@0 11505 }
ferencd@0 11506
ferencd@0 11507 case value_t::number_integer:
ferencd@0 11508 {
ferencd@0 11509 if (j.m_value.number_integer >= 0)
ferencd@0 11510 {
ferencd@0 11511 // MessagePack does not differentiate between positive
ferencd@0 11512 // signed integers and unsigned integers. Therefore, we used
ferencd@0 11513 // the code from the value_t::number_unsigned case here.
ferencd@0 11514 if (j.m_value.number_unsigned < 128)
ferencd@0 11515 {
ferencd@0 11516 // positive fixnum
ferencd@0 11517 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
ferencd@0 11518 }
ferencd@0 11519 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
ferencd@0 11520 {
ferencd@0 11521 // uint 8
ferencd@0 11522 oa->write_character(to_char_type(0xCC));
ferencd@0 11523 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
ferencd@0 11524 }
ferencd@0 11525 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
ferencd@0 11526 {
ferencd@0 11527 // uint 16
ferencd@0 11528 oa->write_character(to_char_type(0xCD));
ferencd@0 11529 write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
ferencd@0 11530 }
ferencd@0 11531 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
ferencd@0 11532 {
ferencd@0 11533 // uint 32
ferencd@0 11534 oa->write_character(to_char_type(0xCE));
ferencd@0 11535 write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
ferencd@0 11536 }
ferencd@0 11537 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
ferencd@0 11538 {
ferencd@0 11539 // uint 64
ferencd@0 11540 oa->write_character(to_char_type(0xCF));
ferencd@0 11541 write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
ferencd@0 11542 }
ferencd@0 11543 }
ferencd@0 11544 else
ferencd@0 11545 {
ferencd@0 11546 if (j.m_value.number_integer >= -32)
ferencd@0 11547 {
ferencd@0 11548 // negative fixnum
ferencd@0 11549 write_number(static_cast<std::int8_t>(j.m_value.number_integer));
ferencd@0 11550 }
ferencd@0 11551 else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() and
ferencd@0 11552 j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
ferencd@0 11553 {
ferencd@0 11554 // int 8
ferencd@0 11555 oa->write_character(to_char_type(0xD0));
ferencd@0 11556 write_number(static_cast<std::int8_t>(j.m_value.number_integer));
ferencd@0 11557 }
ferencd@0 11558 else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() and
ferencd@0 11559 j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
ferencd@0 11560 {
ferencd@0 11561 // int 16
ferencd@0 11562 oa->write_character(to_char_type(0xD1));
ferencd@0 11563 write_number(static_cast<std::int16_t>(j.m_value.number_integer));
ferencd@0 11564 }
ferencd@0 11565 else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() and
ferencd@0 11566 j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
ferencd@0 11567 {
ferencd@0 11568 // int 32
ferencd@0 11569 oa->write_character(to_char_type(0xD2));
ferencd@0 11570 write_number(static_cast<std::int32_t>(j.m_value.number_integer));
ferencd@0 11571 }
ferencd@0 11572 else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() and
ferencd@0 11573 j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
ferencd@0 11574 {
ferencd@0 11575 // int 64
ferencd@0 11576 oa->write_character(to_char_type(0xD3));
ferencd@0 11577 write_number(static_cast<std::int64_t>(j.m_value.number_integer));
ferencd@0 11578 }
ferencd@0 11579 }
ferencd@0 11580 break;
ferencd@0 11581 }
ferencd@0 11582
ferencd@0 11583 case value_t::number_unsigned:
ferencd@0 11584 {
ferencd@0 11585 if (j.m_value.number_unsigned < 128)
ferencd@0 11586 {
ferencd@0 11587 // positive fixnum
ferencd@0 11588 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
ferencd@0 11589 }
ferencd@0 11590 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
ferencd@0 11591 {
ferencd@0 11592 // uint 8
ferencd@0 11593 oa->write_character(to_char_type(0xCC));
ferencd@0 11594 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
ferencd@0 11595 }
ferencd@0 11596 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
ferencd@0 11597 {
ferencd@0 11598 // uint 16
ferencd@0 11599 oa->write_character(to_char_type(0xCD));
ferencd@0 11600 write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
ferencd@0 11601 }
ferencd@0 11602 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
ferencd@0 11603 {
ferencd@0 11604 // uint 32
ferencd@0 11605 oa->write_character(to_char_type(0xCE));
ferencd@0 11606 write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
ferencd@0 11607 }
ferencd@0 11608 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
ferencd@0 11609 {
ferencd@0 11610 // uint 64
ferencd@0 11611 oa->write_character(to_char_type(0xCF));
ferencd@0 11612 write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
ferencd@0 11613 }
ferencd@0 11614 break;
ferencd@0 11615 }
ferencd@0 11616
ferencd@0 11617 case value_t::number_float:
ferencd@0 11618 {
ferencd@0 11619 oa->write_character(get_msgpack_float_prefix(j.m_value.number_float));
ferencd@0 11620 write_number(j.m_value.number_float);
ferencd@0 11621 break;
ferencd@0 11622 }
ferencd@0 11623
ferencd@0 11624 case value_t::string:
ferencd@0 11625 {
ferencd@0 11626 // step 1: write control byte and the string length
ferencd@0 11627 const auto N = j.m_value.string->size();
ferencd@0 11628 if (N <= 31)
ferencd@0 11629 {
ferencd@0 11630 // fixstr
ferencd@0 11631 write_number(static_cast<std::uint8_t>(0xA0 | N));
ferencd@0 11632 }
ferencd@0 11633 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
ferencd@0 11634 {
ferencd@0 11635 // str 8
ferencd@0 11636 oa->write_character(to_char_type(0xD9));
ferencd@0 11637 write_number(static_cast<std::uint8_t>(N));
ferencd@0 11638 }
ferencd@0 11639 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
ferencd@0 11640 {
ferencd@0 11641 // str 16
ferencd@0 11642 oa->write_character(to_char_type(0xDA));
ferencd@0 11643 write_number(static_cast<std::uint16_t>(N));
ferencd@0 11644 }
ferencd@0 11645 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
ferencd@0 11646 {
ferencd@0 11647 // str 32
ferencd@0 11648 oa->write_character(to_char_type(0xDB));
ferencd@0 11649 write_number(static_cast<std::uint32_t>(N));
ferencd@0 11650 }
ferencd@0 11651
ferencd@0 11652 // step 2: write the string
ferencd@0 11653 oa->write_characters(
ferencd@0 11654 reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
ferencd@0 11655 j.m_value.string->size());
ferencd@0 11656 break;
ferencd@0 11657 }
ferencd@0 11658
ferencd@0 11659 case value_t::array:
ferencd@0 11660 {
ferencd@0 11661 // step 1: write control byte and the array size
ferencd@0 11662 const auto N = j.m_value.array->size();
ferencd@0 11663 if (N <= 15)
ferencd@0 11664 {
ferencd@0 11665 // fixarray
ferencd@0 11666 write_number(static_cast<std::uint8_t>(0x90 | N));
ferencd@0 11667 }
ferencd@0 11668 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
ferencd@0 11669 {
ferencd@0 11670 // array 16
ferencd@0 11671 oa->write_character(to_char_type(0xDC));
ferencd@0 11672 write_number(static_cast<std::uint16_t>(N));
ferencd@0 11673 }
ferencd@0 11674 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
ferencd@0 11675 {
ferencd@0 11676 // array 32
ferencd@0 11677 oa->write_character(to_char_type(0xDD));
ferencd@0 11678 write_number(static_cast<std::uint32_t>(N));
ferencd@0 11679 }
ferencd@0 11680
ferencd@0 11681 // step 2: write each element
ferencd@0 11682 for (const auto& el : *j.m_value.array)
ferencd@0 11683 {
ferencd@0 11684 write_msgpack(el);
ferencd@0 11685 }
ferencd@0 11686 break;
ferencd@0 11687 }
ferencd@0 11688
ferencd@0 11689 case value_t::object:
ferencd@0 11690 {
ferencd@0 11691 // step 1: write control byte and the object size
ferencd@0 11692 const auto N = j.m_value.object->size();
ferencd@0 11693 if (N <= 15)
ferencd@0 11694 {
ferencd@0 11695 // fixmap
ferencd@0 11696 write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));
ferencd@0 11697 }
ferencd@0 11698 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
ferencd@0 11699 {
ferencd@0 11700 // map 16
ferencd@0 11701 oa->write_character(to_char_type(0xDE));
ferencd@0 11702 write_number(static_cast<std::uint16_t>(N));
ferencd@0 11703 }
ferencd@0 11704 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
ferencd@0 11705 {
ferencd@0 11706 // map 32
ferencd@0 11707 oa->write_character(to_char_type(0xDF));
ferencd@0 11708 write_number(static_cast<std::uint32_t>(N));
ferencd@0 11709 }
ferencd@0 11710
ferencd@0 11711 // step 2: write each element
ferencd@0 11712 for (const auto& el : *j.m_value.object)
ferencd@0 11713 {
ferencd@0 11714 write_msgpack(el.first);
ferencd@0 11715 write_msgpack(el.second);
ferencd@0 11716 }
ferencd@0 11717 break;
ferencd@0 11718 }
ferencd@0 11719
ferencd@0 11720 default:
ferencd@0 11721 break;
ferencd@0 11722 }
ferencd@0 11723 }
ferencd@0 11724
ferencd@0 11725 /*!
ferencd@0 11726 @param[in] j JSON value to serialize
ferencd@0 11727 @param[in] use_count whether to use '#' prefixes (optimized format)
ferencd@0 11728 @param[in] use_type whether to use '$' prefixes (optimized format)
ferencd@0 11729 @param[in] add_prefix whether prefixes need to be used for this value
ferencd@0 11730 */
ferencd@0 11731 void write_ubjson(const BasicJsonType& j, const bool use_count,
ferencd@0 11732 const bool use_type, const bool add_prefix = true)
ferencd@0 11733 {
ferencd@0 11734 switch (j.type())
ferencd@0 11735 {
ferencd@0 11736 case value_t::null:
ferencd@0 11737 {
ferencd@0 11738 if (add_prefix)
ferencd@0 11739 {
ferencd@0 11740 oa->write_character(to_char_type('Z'));
ferencd@0 11741 }
ferencd@0 11742 break;
ferencd@0 11743 }
ferencd@0 11744
ferencd@0 11745 case value_t::boolean:
ferencd@0 11746 {
ferencd@0 11747 if (add_prefix)
ferencd@0 11748 {
ferencd@0 11749 oa->write_character(j.m_value.boolean
ferencd@0 11750 ? to_char_type('T')
ferencd@0 11751 : to_char_type('F'));
ferencd@0 11752 }
ferencd@0 11753 break;
ferencd@0 11754 }
ferencd@0 11755
ferencd@0 11756 case value_t::number_integer:
ferencd@0 11757 {
ferencd@0 11758 write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);
ferencd@0 11759 break;
ferencd@0 11760 }
ferencd@0 11761
ferencd@0 11762 case value_t::number_unsigned:
ferencd@0 11763 {
ferencd@0 11764 write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);
ferencd@0 11765 break;
ferencd@0 11766 }
ferencd@0 11767
ferencd@0 11768 case value_t::number_float:
ferencd@0 11769 {
ferencd@0 11770 write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix);
ferencd@0 11771 break;
ferencd@0 11772 }
ferencd@0 11773
ferencd@0 11774 case value_t::string:
ferencd@0 11775 {
ferencd@0 11776 if (add_prefix)
ferencd@0 11777 {
ferencd@0 11778 oa->write_character(to_char_type('S'));
ferencd@0 11779 }
ferencd@0 11780 write_number_with_ubjson_prefix(j.m_value.string->size(), true);
ferencd@0 11781 oa->write_characters(
ferencd@0 11782 reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
ferencd@0 11783 j.m_value.string->size());
ferencd@0 11784 break;
ferencd@0 11785 }
ferencd@0 11786
ferencd@0 11787 case value_t::array:
ferencd@0 11788 {
ferencd@0 11789 if (add_prefix)
ferencd@0 11790 {
ferencd@0 11791 oa->write_character(to_char_type('['));
ferencd@0 11792 }
ferencd@0 11793
ferencd@0 11794 bool prefix_required = true;
ferencd@0 11795 if (use_type and not j.m_value.array->empty())
ferencd@0 11796 {
ferencd@0 11797 assert(use_count);
ferencd@0 11798 const CharType first_prefix = ubjson_prefix(j.front());
ferencd@0 11799 const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
ferencd@0 11800 [this, first_prefix](const BasicJsonType & v)
ferencd@0 11801 {
ferencd@0 11802 return ubjson_prefix(v) == first_prefix;
ferencd@0 11803 });
ferencd@0 11804
ferencd@0 11805 if (same_prefix)
ferencd@0 11806 {
ferencd@0 11807 prefix_required = false;
ferencd@0 11808 oa->write_character(to_char_type('$'));
ferencd@0 11809 oa->write_character(first_prefix);
ferencd@0 11810 }
ferencd@0 11811 }
ferencd@0 11812
ferencd@0 11813 if (use_count)
ferencd@0 11814 {
ferencd@0 11815 oa->write_character(to_char_type('#'));
ferencd@0 11816 write_number_with_ubjson_prefix(j.m_value.array->size(), true);
ferencd@0 11817 }
ferencd@0 11818
ferencd@0 11819 for (const auto& el : *j.m_value.array)
ferencd@0 11820 {
ferencd@0 11821 write_ubjson(el, use_count, use_type, prefix_required);
ferencd@0 11822 }
ferencd@0 11823
ferencd@0 11824 if (not use_count)
ferencd@0 11825 {
ferencd@0 11826 oa->write_character(to_char_type(']'));
ferencd@0 11827 }
ferencd@0 11828
ferencd@0 11829 break;
ferencd@0 11830 }
ferencd@0 11831
ferencd@0 11832 case value_t::object:
ferencd@0 11833 {
ferencd@0 11834 if (add_prefix)
ferencd@0 11835 {
ferencd@0 11836 oa->write_character(to_char_type('{'));
ferencd@0 11837 }
ferencd@0 11838
ferencd@0 11839 bool prefix_required = true;
ferencd@0 11840 if (use_type and not j.m_value.object->empty())
ferencd@0 11841 {
ferencd@0 11842 assert(use_count);
ferencd@0 11843 const CharType first_prefix = ubjson_prefix(j.front());
ferencd@0 11844 const bool same_prefix = std::all_of(j.begin(), j.end(),
ferencd@0 11845 [this, first_prefix](const BasicJsonType & v)
ferencd@0 11846 {
ferencd@0 11847 return ubjson_prefix(v) == first_prefix;
ferencd@0 11848 });
ferencd@0 11849
ferencd@0 11850 if (same_prefix)
ferencd@0 11851 {
ferencd@0 11852 prefix_required = false;
ferencd@0 11853 oa->write_character(to_char_type('$'));
ferencd@0 11854 oa->write_character(first_prefix);
ferencd@0 11855 }
ferencd@0 11856 }
ferencd@0 11857
ferencd@0 11858 if (use_count)
ferencd@0 11859 {
ferencd@0 11860 oa->write_character(to_char_type('#'));
ferencd@0 11861 write_number_with_ubjson_prefix(j.m_value.object->size(), true);
ferencd@0 11862 }
ferencd@0 11863
ferencd@0 11864 for (const auto& el : *j.m_value.object)
ferencd@0 11865 {
ferencd@0 11866 write_number_with_ubjson_prefix(el.first.size(), true);
ferencd@0 11867 oa->write_characters(
ferencd@0 11868 reinterpret_cast<const CharType*>(el.first.c_str()),
ferencd@0 11869 el.first.size());
ferencd@0 11870 write_ubjson(el.second, use_count, use_type, prefix_required);
ferencd@0 11871 }
ferencd@0 11872
ferencd@0 11873 if (not use_count)
ferencd@0 11874 {
ferencd@0 11875 oa->write_character(to_char_type('}'));
ferencd@0 11876 }
ferencd@0 11877
ferencd@0 11878 break;
ferencd@0 11879 }
ferencd@0 11880
ferencd@0 11881 default:
ferencd@0 11882 break;
ferencd@0 11883 }
ferencd@0 11884 }
ferencd@0 11885
ferencd@0 11886 private:
ferencd@0 11887 //////////
ferencd@0 11888 // BSON //
ferencd@0 11889 //////////
ferencd@0 11890
ferencd@0 11891 /*!
ferencd@0 11892 @return The size of a BSON document entry header, including the id marker
ferencd@0 11893 and the entry name size (and its null-terminator).
ferencd@0 11894 */
ferencd@0 11895 static std::size_t calc_bson_entry_header_size(const string_t& name)
ferencd@0 11896 {
ferencd@0 11897 const auto it = name.find(static_cast<typename string_t::value_type>(0));
ferencd@0 11898 if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))
ferencd@0 11899 {
ferencd@0 11900 JSON_THROW(out_of_range::create(409,
ferencd@0 11901 "BSON key cannot contain code point U+0000 (at byte " + std::to_string(it) + ")"));
ferencd@0 11902 }
ferencd@0 11903
ferencd@0 11904 return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;
ferencd@0 11905 }
ferencd@0 11906
ferencd@0 11907 /*!
ferencd@0 11908 @brief Writes the given @a element_type and @a name to the output adapter
ferencd@0 11909 */
ferencd@0 11910 void write_bson_entry_header(const string_t& name,
ferencd@0 11911 const std::uint8_t element_type)
ferencd@0 11912 {
ferencd@0 11913 oa->write_character(to_char_type(element_type)); // boolean
ferencd@0 11914 oa->write_characters(
ferencd@0 11915 reinterpret_cast<const CharType*>(name.c_str()),
ferencd@0 11916 name.size() + 1u);
ferencd@0 11917 }
ferencd@0 11918
ferencd@0 11919 /*!
ferencd@0 11920 @brief Writes a BSON element with key @a name and boolean value @a value
ferencd@0 11921 */
ferencd@0 11922 void write_bson_boolean(const string_t& name,
ferencd@0 11923 const bool value)
ferencd@0 11924 {
ferencd@0 11925 write_bson_entry_header(name, 0x08);
ferencd@0 11926 oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));
ferencd@0 11927 }
ferencd@0 11928
ferencd@0 11929 /*!
ferencd@0 11930 @brief Writes a BSON element with key @a name and double value @a value
ferencd@0 11931 */
ferencd@0 11932 void write_bson_double(const string_t& name,
ferencd@0 11933 const double value)
ferencd@0 11934 {
ferencd@0 11935 write_bson_entry_header(name, 0x01);
ferencd@0 11936 write_number<double, true>(value);
ferencd@0 11937 }
ferencd@0 11938
ferencd@0 11939 /*!
ferencd@0 11940 @return The size of the BSON-encoded string in @a value
ferencd@0 11941 */
ferencd@0 11942 static std::size_t calc_bson_string_size(const string_t& value)
ferencd@0 11943 {
ferencd@0 11944 return sizeof(std::int32_t) + value.size() + 1ul;
ferencd@0 11945 }
ferencd@0 11946
ferencd@0 11947 /*!
ferencd@0 11948 @brief Writes a BSON element with key @a name and string value @a value
ferencd@0 11949 */
ferencd@0 11950 void write_bson_string(const string_t& name,
ferencd@0 11951 const string_t& value)
ferencd@0 11952 {
ferencd@0 11953 write_bson_entry_header(name, 0x02);
ferencd@0 11954
ferencd@0 11955 write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size() + 1ul));
ferencd@0 11956 oa->write_characters(
ferencd@0 11957 reinterpret_cast<const CharType*>(value.c_str()),
ferencd@0 11958 value.size() + 1);
ferencd@0 11959 }
ferencd@0 11960
ferencd@0 11961 /*!
ferencd@0 11962 @brief Writes a BSON element with key @a name and null value
ferencd@0 11963 */
ferencd@0 11964 void write_bson_null(const string_t& name)
ferencd@0 11965 {
ferencd@0 11966 write_bson_entry_header(name, 0x0A);
ferencd@0 11967 }
ferencd@0 11968
ferencd@0 11969 /*!
ferencd@0 11970 @return The size of the BSON-encoded integer @a value
ferencd@0 11971 */
ferencd@0 11972 static std::size_t calc_bson_integer_size(const std::int64_t value)
ferencd@0 11973 {
ferencd@0 11974 return (std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)()
ferencd@0 11975 ? sizeof(std::int32_t)
ferencd@0 11976 : sizeof(std::int64_t);
ferencd@0 11977 }
ferencd@0 11978
ferencd@0 11979 /*!
ferencd@0 11980 @brief Writes a BSON element with key @a name and integer @a value
ferencd@0 11981 */
ferencd@0 11982 void write_bson_integer(const string_t& name,
ferencd@0 11983 const std::int64_t value)
ferencd@0 11984 {
ferencd@0 11985 if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())
ferencd@0 11986 {
ferencd@0 11987 write_bson_entry_header(name, 0x10); // int32
ferencd@0 11988 write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
ferencd@0 11989 }
ferencd@0 11990 else
ferencd@0 11991 {
ferencd@0 11992 write_bson_entry_header(name, 0x12); // int64
ferencd@0 11993 write_number<std::int64_t, true>(static_cast<std::int64_t>(value));
ferencd@0 11994 }
ferencd@0 11995 }
ferencd@0 11996
ferencd@0 11997 /*!
ferencd@0 11998 @return The size of the BSON-encoded unsigned integer in @a j
ferencd@0 11999 */
ferencd@0 12000 static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept
ferencd@0 12001 {
ferencd@0 12002 return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
ferencd@0 12003 ? sizeof(std::int32_t)
ferencd@0 12004 : sizeof(std::int64_t);
ferencd@0 12005 }
ferencd@0 12006
ferencd@0 12007 /*!
ferencd@0 12008 @brief Writes a BSON element with key @a name and unsigned @a value
ferencd@0 12009 */
ferencd@0 12010 void write_bson_unsigned(const string_t& name,
ferencd@0 12011 const std::uint64_t value)
ferencd@0 12012 {
ferencd@0 12013 if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
ferencd@0 12014 {
ferencd@0 12015 write_bson_entry_header(name, 0x10 /* int32 */);
ferencd@0 12016 write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
ferencd@0 12017 }
ferencd@0 12018 else if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
ferencd@0 12019 {
ferencd@0 12020 write_bson_entry_header(name, 0x12 /* int64 */);
ferencd@0 12021 write_number<std::int64_t, true>(static_cast<std::int64_t>(value));
ferencd@0 12022 }
ferencd@0 12023 else
ferencd@0 12024 {
ferencd@0 12025 JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(value) + " cannot be represented by BSON as it does not fit int64"));
ferencd@0 12026 }
ferencd@0 12027 }
ferencd@0 12028
ferencd@0 12029 /*!
ferencd@0 12030 @brief Writes a BSON element with key @a name and object @a value
ferencd@0 12031 */
ferencd@0 12032 void write_bson_object_entry(const string_t& name,
ferencd@0 12033 const typename BasicJsonType::object_t& value)
ferencd@0 12034 {
ferencd@0 12035 write_bson_entry_header(name, 0x03); // object
ferencd@0 12036 write_bson_object(value);
ferencd@0 12037 }
ferencd@0 12038
ferencd@0 12039 /*!
ferencd@0 12040 @return The size of the BSON-encoded array @a value
ferencd@0 12041 */
ferencd@0 12042 static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)
ferencd@0 12043 {
ferencd@0 12044 std::size_t embedded_document_size = 0ul;
ferencd@0 12045 std::size_t array_index = 0ul;
ferencd@0 12046
ferencd@0 12047 for (const auto& el : value)
ferencd@0 12048 {
ferencd@0 12049 embedded_document_size += calc_bson_element_size(std::to_string(array_index++), el);
ferencd@0 12050 }
ferencd@0 12051
ferencd@0 12052 return sizeof(std::int32_t) + embedded_document_size + 1ul;
ferencd@0 12053 }
ferencd@0 12054
ferencd@0 12055 /*!
ferencd@0 12056 @brief Writes a BSON element with key @a name and array @a value
ferencd@0 12057 */
ferencd@0 12058 void write_bson_array(const string_t& name,
ferencd@0 12059 const typename BasicJsonType::array_t& value)
ferencd@0 12060 {
ferencd@0 12061 write_bson_entry_header(name, 0x04); // array
ferencd@0 12062 write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_array_size(value)));
ferencd@0 12063
ferencd@0 12064 std::size_t array_index = 0ul;
ferencd@0 12065
ferencd@0 12066 for (const auto& el : value)
ferencd@0 12067 {
ferencd@0 12068 write_bson_element(std::to_string(array_index++), el);
ferencd@0 12069 }
ferencd@0 12070
ferencd@0 12071 oa->write_character(to_char_type(0x00));
ferencd@0 12072 }
ferencd@0 12073
ferencd@0 12074 /*!
ferencd@0 12075 @brief Calculates the size necessary to serialize the JSON value @a j with its @a name
ferencd@0 12076 @return The calculated size for the BSON document entry for @a j with the given @a name.
ferencd@0 12077 */
ferencd@0 12078 static std::size_t calc_bson_element_size(const string_t& name,
ferencd@0 12079 const BasicJsonType& j)
ferencd@0 12080 {
ferencd@0 12081 const auto header_size = calc_bson_entry_header_size(name);
ferencd@0 12082 switch (j.type())
ferencd@0 12083 {
ferencd@0 12084 case value_t::object:
ferencd@0 12085 return header_size + calc_bson_object_size(*j.m_value.object);
ferencd@0 12086
ferencd@0 12087 case value_t::array:
ferencd@0 12088 return header_size + calc_bson_array_size(*j.m_value.array);
ferencd@0 12089
ferencd@0 12090 case value_t::boolean:
ferencd@0 12091 return header_size + 1ul;
ferencd@0 12092
ferencd@0 12093 case value_t::number_float:
ferencd@0 12094 return header_size + 8ul;
ferencd@0 12095
ferencd@0 12096 case value_t::number_integer:
ferencd@0 12097 return header_size + calc_bson_integer_size(j.m_value.number_integer);
ferencd@0 12098
ferencd@0 12099 case value_t::number_unsigned:
ferencd@0 12100 return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned);
ferencd@0 12101
ferencd@0 12102 case value_t::string:
ferencd@0 12103 return header_size + calc_bson_string_size(*j.m_value.string);
ferencd@0 12104
ferencd@0 12105 case value_t::null:
ferencd@0 12106 return header_size + 0ul;
ferencd@0 12107
ferencd@0 12108 // LCOV_EXCL_START
ferencd@0 12109 default:
ferencd@0 12110 assert(false);
ferencd@0 12111 return 0ul;
ferencd@0 12112 // LCOV_EXCL_STOP
ferencd@0 12113 }
ferencd@0 12114 }
ferencd@0 12115
ferencd@0 12116 /*!
ferencd@0 12117 @brief Serializes the JSON value @a j to BSON and associates it with the
ferencd@0 12118 key @a name.
ferencd@0 12119 @param name The name to associate with the JSON entity @a j within the
ferencd@0 12120 current BSON document
ferencd@0 12121 @return The size of the BSON entry
ferencd@0 12122 */
ferencd@0 12123 void write_bson_element(const string_t& name,
ferencd@0 12124 const BasicJsonType& j)
ferencd@0 12125 {
ferencd@0 12126 switch (j.type())
ferencd@0 12127 {
ferencd@0 12128 case value_t::object:
ferencd@0 12129 return write_bson_object_entry(name, *j.m_value.object);
ferencd@0 12130
ferencd@0 12131 case value_t::array:
ferencd@0 12132 return write_bson_array(name, *j.m_value.array);
ferencd@0 12133
ferencd@0 12134 case value_t::boolean:
ferencd@0 12135 return write_bson_boolean(name, j.m_value.boolean);
ferencd@0 12136
ferencd@0 12137 case value_t::number_float:
ferencd@0 12138 return write_bson_double(name, j.m_value.number_float);
ferencd@0 12139
ferencd@0 12140 case value_t::number_integer:
ferencd@0 12141 return write_bson_integer(name, j.m_value.number_integer);
ferencd@0 12142
ferencd@0 12143 case value_t::number_unsigned:
ferencd@0 12144 return write_bson_unsigned(name, j.m_value.number_unsigned);
ferencd@0 12145
ferencd@0 12146 case value_t::string:
ferencd@0 12147 return write_bson_string(name, *j.m_value.string);
ferencd@0 12148
ferencd@0 12149 case value_t::null:
ferencd@0 12150 return write_bson_null(name);
ferencd@0 12151
ferencd@0 12152 // LCOV_EXCL_START
ferencd@0 12153 default:
ferencd@0 12154 assert(false);
ferencd@0 12155 return;
ferencd@0 12156 // LCOV_EXCL_STOP
ferencd@0 12157 }
ferencd@0 12158 }
ferencd@0 12159
ferencd@0 12160 /*!
ferencd@0 12161 @brief Calculates the size of the BSON serialization of the given
ferencd@0 12162 JSON-object @a j.
ferencd@0 12163 @param[in] j JSON value to serialize
ferencd@0 12164 @pre j.type() == value_t::object
ferencd@0 12165 */
ferencd@0 12166 static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
ferencd@0 12167 {
ferencd@0 12168 std::size_t document_size = std::accumulate(value.begin(), value.end(), 0ul,
ferencd@0 12169 [](size_t result, const typename BasicJsonType::object_t::value_type & el)
ferencd@0 12170 {
ferencd@0 12171 return result += calc_bson_element_size(el.first, el.second);
ferencd@0 12172 });
ferencd@0 12173
ferencd@0 12174 return sizeof(std::int32_t) + document_size + 1ul;
ferencd@0 12175 }
ferencd@0 12176
ferencd@0 12177 /*!
ferencd@0 12178 @param[in] j JSON value to serialize
ferencd@0 12179 @pre j.type() == value_t::object
ferencd@0 12180 */
ferencd@0 12181 void write_bson_object(const typename BasicJsonType::object_t& value)
ferencd@0 12182 {
ferencd@0 12183 write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_object_size(value)));
ferencd@0 12184
ferencd@0 12185 for (const auto& el : value)
ferencd@0 12186 {
ferencd@0 12187 write_bson_element(el.first, el.second);
ferencd@0 12188 }
ferencd@0 12189
ferencd@0 12190 oa->write_character(to_char_type(0x00));
ferencd@0 12191 }
ferencd@0 12192
ferencd@0 12193 //////////
ferencd@0 12194 // CBOR //
ferencd@0 12195 //////////
ferencd@0 12196
ferencd@0 12197 static constexpr CharType get_cbor_float_prefix(float /*unused*/)
ferencd@0 12198 {
ferencd@0 12199 return to_char_type(0xFA); // Single-Precision Float
ferencd@0 12200 }
ferencd@0 12201
ferencd@0 12202 static constexpr CharType get_cbor_float_prefix(double /*unused*/)
ferencd@0 12203 {
ferencd@0 12204 return to_char_type(0xFB); // Double-Precision Float
ferencd@0 12205 }
ferencd@0 12206
ferencd@0 12207 /////////////
ferencd@0 12208 // MsgPack //
ferencd@0 12209 /////////////
ferencd@0 12210
ferencd@0 12211 static constexpr CharType get_msgpack_float_prefix(float /*unused*/)
ferencd@0 12212 {
ferencd@0 12213 return to_char_type(0xCA); // float 32
ferencd@0 12214 }
ferencd@0 12215
ferencd@0 12216 static constexpr CharType get_msgpack_float_prefix(double /*unused*/)
ferencd@0 12217 {
ferencd@0 12218 return to_char_type(0xCB); // float 64
ferencd@0 12219 }
ferencd@0 12220
ferencd@0 12221 ////////////
ferencd@0 12222 // UBJSON //
ferencd@0 12223 ////////////
ferencd@0 12224
ferencd@0 12225 // UBJSON: write number (floating point)
ferencd@0 12226 template<typename NumberType, typename std::enable_if<
ferencd@0 12227 std::is_floating_point<NumberType>::value, int>::type = 0>
ferencd@0 12228 void write_number_with_ubjson_prefix(const NumberType n,
ferencd@0 12229 const bool add_prefix)
ferencd@0 12230 {
ferencd@0 12231 if (add_prefix)
ferencd@0 12232 {
ferencd@0 12233 oa->write_character(get_ubjson_float_prefix(n));
ferencd@0 12234 }
ferencd@0 12235 write_number(n);
ferencd@0 12236 }
ferencd@0 12237
ferencd@0 12238 // UBJSON: write number (unsigned integer)
ferencd@0 12239 template<typename NumberType, typename std::enable_if<
ferencd@0 12240 std::is_unsigned<NumberType>::value, int>::type = 0>
ferencd@0 12241 void write_number_with_ubjson_prefix(const NumberType n,
ferencd@0 12242 const bool add_prefix)
ferencd@0 12243 {
ferencd@0 12244 if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
ferencd@0 12245 {
ferencd@0 12246 if (add_prefix)
ferencd@0 12247 {
ferencd@0 12248 oa->write_character(to_char_type('i')); // int8
ferencd@0 12249 }
ferencd@0 12250 write_number(static_cast<std::uint8_t>(n));
ferencd@0 12251 }
ferencd@0 12252 else if (n <= (std::numeric_limits<std::uint8_t>::max)())
ferencd@0 12253 {
ferencd@0 12254 if (add_prefix)
ferencd@0 12255 {
ferencd@0 12256 oa->write_character(to_char_type('U')); // uint8
ferencd@0 12257 }
ferencd@0 12258 write_number(static_cast<std::uint8_t>(n));
ferencd@0 12259 }
ferencd@0 12260 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
ferencd@0 12261 {
ferencd@0 12262 if (add_prefix)
ferencd@0 12263 {
ferencd@0 12264 oa->write_character(to_char_type('I')); // int16
ferencd@0 12265 }
ferencd@0 12266 write_number(static_cast<std::int16_t>(n));
ferencd@0 12267 }
ferencd@0 12268 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
ferencd@0 12269 {
ferencd@0 12270 if (add_prefix)
ferencd@0 12271 {
ferencd@0 12272 oa->write_character(to_char_type('l')); // int32
ferencd@0 12273 }
ferencd@0 12274 write_number(static_cast<std::int32_t>(n));
ferencd@0 12275 }
ferencd@0 12276 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
ferencd@0 12277 {
ferencd@0 12278 if (add_prefix)
ferencd@0 12279 {
ferencd@0 12280 oa->write_character(to_char_type('L')); // int64
ferencd@0 12281 }
ferencd@0 12282 write_number(static_cast<std::int64_t>(n));
ferencd@0 12283 }
ferencd@0 12284 else
ferencd@0 12285 {
ferencd@0 12286 JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(n) + " cannot be represented by UBJSON as it does not fit int64"));
ferencd@0 12287 }
ferencd@0 12288 }
ferencd@0 12289
ferencd@0 12290 // UBJSON: write number (signed integer)
ferencd@0 12291 template<typename NumberType, typename std::enable_if<
ferencd@0 12292 std::is_signed<NumberType>::value and
ferencd@0 12293 not std::is_floating_point<NumberType>::value, int>::type = 0>
ferencd@0 12294 void write_number_with_ubjson_prefix(const NumberType n,
ferencd@0 12295 const bool add_prefix)
ferencd@0 12296 {
ferencd@0 12297 if ((std::numeric_limits<std::int8_t>::min)() <= n and n <= (std::numeric_limits<std::int8_t>::max)())
ferencd@0 12298 {
ferencd@0 12299 if (add_prefix)
ferencd@0 12300 {
ferencd@0 12301 oa->write_character(to_char_type('i')); // int8
ferencd@0 12302 }
ferencd@0 12303 write_number(static_cast<std::int8_t>(n));
ferencd@0 12304 }
ferencd@0 12305 else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n and n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))
ferencd@0 12306 {
ferencd@0 12307 if (add_prefix)
ferencd@0 12308 {
ferencd@0 12309 oa->write_character(to_char_type('U')); // uint8
ferencd@0 12310 }
ferencd@0 12311 write_number(static_cast<std::uint8_t>(n));
ferencd@0 12312 }
ferencd@0 12313 else if ((std::numeric_limits<std::int16_t>::min)() <= n and n <= (std::numeric_limits<std::int16_t>::max)())
ferencd@0 12314 {
ferencd@0 12315 if (add_prefix)
ferencd@0 12316 {
ferencd@0 12317 oa->write_character(to_char_type('I')); // int16
ferencd@0 12318 }
ferencd@0 12319 write_number(static_cast<std::int16_t>(n));
ferencd@0 12320 }
ferencd@0 12321 else if ((std::numeric_limits<std::int32_t>::min)() <= n and n <= (std::numeric_limits<std::int32_t>::max)())
ferencd@0 12322 {
ferencd@0 12323 if (add_prefix)
ferencd@0 12324 {
ferencd@0 12325 oa->write_character(to_char_type('l')); // int32
ferencd@0 12326 }
ferencd@0 12327 write_number(static_cast<std::int32_t>(n));
ferencd@0 12328 }
ferencd@0 12329 else if ((std::numeric_limits<std::int64_t>::min)() <= n and n <= (std::numeric_limits<std::int64_t>::max)())
ferencd@0 12330 {
ferencd@0 12331 if (add_prefix)
ferencd@0 12332 {
ferencd@0 12333 oa->write_character(to_char_type('L')); // int64
ferencd@0 12334 }
ferencd@0 12335 write_number(static_cast<std::int64_t>(n));
ferencd@0 12336 }
ferencd@0 12337 // LCOV_EXCL_START
ferencd@0 12338 else
ferencd@0 12339 {
ferencd@0 12340 JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(n) + " cannot be represented by UBJSON as it does not fit int64"));
ferencd@0 12341 }
ferencd@0 12342 // LCOV_EXCL_STOP
ferencd@0 12343 }
ferencd@0 12344
ferencd@0 12345 /*!
ferencd@0 12346 @brief determine the type prefix of container values
ferencd@0 12347
ferencd@0 12348 @note This function does not need to be 100% accurate when it comes to
ferencd@0 12349 integer limits. In case a number exceeds the limits of int64_t,
ferencd@0 12350 this will be detected by a later call to function
ferencd@0 12351 write_number_with_ubjson_prefix. Therefore, we return 'L' for any
ferencd@0 12352 value that does not fit the previous limits.
ferencd@0 12353 */
ferencd@0 12354 CharType ubjson_prefix(const BasicJsonType& j) const noexcept
ferencd@0 12355 {
ferencd@0 12356 switch (j.type())
ferencd@0 12357 {
ferencd@0 12358 case value_t::null:
ferencd@0 12359 return 'Z';
ferencd@0 12360
ferencd@0 12361 case value_t::boolean:
ferencd@0 12362 return j.m_value.boolean ? 'T' : 'F';
ferencd@0 12363
ferencd@0 12364 case value_t::number_integer:
ferencd@0 12365 {
ferencd@0 12366 if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
ferencd@0 12367 {
ferencd@0 12368 return 'i';
ferencd@0 12369 }
ferencd@0 12370 if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
ferencd@0 12371 {
ferencd@0 12372 return 'U';
ferencd@0 12373 }
ferencd@0 12374 if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
ferencd@0 12375 {
ferencd@0 12376 return 'I';
ferencd@0 12377 }
ferencd@0 12378 if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
ferencd@0 12379 {
ferencd@0 12380 return 'l';
ferencd@0 12381 }
ferencd@0 12382 // no check and assume int64_t (see note above)
ferencd@0 12383 return 'L';
ferencd@0 12384 }
ferencd@0 12385
ferencd@0 12386 case value_t::number_unsigned:
ferencd@0 12387 {
ferencd@0 12388 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
ferencd@0 12389 {
ferencd@0 12390 return 'i';
ferencd@0 12391 }
ferencd@0 12392 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))
ferencd@0 12393 {
ferencd@0 12394 return 'U';
ferencd@0 12395 }
ferencd@0 12396 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
ferencd@0 12397 {
ferencd@0 12398 return 'I';
ferencd@0 12399 }
ferencd@0 12400 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
ferencd@0 12401 {
ferencd@0 12402 return 'l';
ferencd@0 12403 }
ferencd@0 12404 // no check and assume int64_t (see note above)
ferencd@0 12405 return 'L';
ferencd@0 12406 }
ferencd@0 12407
ferencd@0 12408 case value_t::number_float:
ferencd@0 12409 return get_ubjson_float_prefix(j.m_value.number_float);
ferencd@0 12410
ferencd@0 12411 case value_t::string:
ferencd@0 12412 return 'S';
ferencd@0 12413
ferencd@0 12414 case value_t::array:
ferencd@0 12415 return '[';
ferencd@0 12416
ferencd@0 12417 case value_t::object:
ferencd@0 12418 return '{';
ferencd@0 12419
ferencd@0 12420 default: // discarded values
ferencd@0 12421 return 'N';
ferencd@0 12422 }
ferencd@0 12423 }
ferencd@0 12424
ferencd@0 12425 static constexpr CharType get_ubjson_float_prefix(float /*unused*/)
ferencd@0 12426 {
ferencd@0 12427 return 'd'; // float 32
ferencd@0 12428 }
ferencd@0 12429
ferencd@0 12430 static constexpr CharType get_ubjson_float_prefix(double /*unused*/)
ferencd@0 12431 {
ferencd@0 12432 return 'D'; // float 64
ferencd@0 12433 }
ferencd@0 12434
ferencd@0 12435 ///////////////////////
ferencd@0 12436 // Utility functions //
ferencd@0 12437 ///////////////////////
ferencd@0 12438
ferencd@0 12439 /*
ferencd@0 12440 @brief write a number to output input
ferencd@0 12441 @param[in] n number of type @a NumberType
ferencd@0 12442 @tparam NumberType the type of the number
ferencd@0 12443 @tparam OutputIsLittleEndian Set to true if output data is
ferencd@0 12444 required to be little endian
ferencd@0 12445
ferencd@0 12446 @note This function needs to respect the system's endianess, because bytes
ferencd@0 12447 in CBOR, MessagePack, and UBJSON are stored in network order (big
ferencd@0 12448 endian) and therefore need reordering on little endian systems.
ferencd@0 12449 */
ferencd@0 12450 template<typename NumberType, bool OutputIsLittleEndian = false>
ferencd@0 12451 void write_number(const NumberType n)
ferencd@0 12452 {
ferencd@0 12453 // step 1: write number to array of length NumberType
ferencd@0 12454 std::array<CharType, sizeof(NumberType)> vec;
ferencd@0 12455 std::memcpy(vec.data(), &n, sizeof(NumberType));
ferencd@0 12456
ferencd@0 12457 // step 2: write array to output (with possible reordering)
ferencd@0 12458 if (is_little_endian != OutputIsLittleEndian)
ferencd@0 12459 {
ferencd@0 12460 // reverse byte order prior to conversion if necessary
ferencd@0 12461 std::reverse(vec.begin(), vec.end());
ferencd@0 12462 }
ferencd@0 12463
ferencd@0 12464 oa->write_characters(vec.data(), sizeof(NumberType));
ferencd@0 12465 }
ferencd@0 12466
ferencd@0 12467 public:
ferencd@0 12468 // The following to_char_type functions are implement the conversion
ferencd@0 12469 // between uint8_t and CharType. In case CharType is not unsigned,
ferencd@0 12470 // such a conversion is required to allow values greater than 128.
ferencd@0 12471 // See <https://github.com/nlohmann/json/issues/1286> for a discussion.
ferencd@0 12472 template < typename C = CharType,
ferencd@0 12473 enable_if_t < std::is_signed<C>::value and std::is_signed<char>::value > * = nullptr >
ferencd@0 12474 static constexpr CharType to_char_type(std::uint8_t x) noexcept
ferencd@0 12475 {
ferencd@0 12476 return *reinterpret_cast<char*>(&x);
ferencd@0 12477 }
ferencd@0 12478
ferencd@0 12479 template < typename C = CharType,
ferencd@0 12480 enable_if_t < std::is_signed<C>::value and std::is_unsigned<char>::value > * = nullptr >
ferencd@0 12481 static CharType to_char_type(std::uint8_t x) noexcept
ferencd@0 12482 {
ferencd@0 12483 static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
ferencd@0 12484 static_assert(std::is_pod<CharType>::value, "CharType must be POD");
ferencd@0 12485 CharType result;
ferencd@0 12486 std::memcpy(&result, &x, sizeof(x));
ferencd@0 12487 return result;
ferencd@0 12488 }
ferencd@0 12489
ferencd@0 12490 template<typename C = CharType,
ferencd@0 12491 enable_if_t<std::is_unsigned<C>::value>* = nullptr>
ferencd@0 12492 static constexpr CharType to_char_type(std::uint8_t x) noexcept
ferencd@0 12493 {
ferencd@0 12494 return x;
ferencd@0 12495 }
ferencd@0 12496
ferencd@0 12497 template < typename InputCharType, typename C = CharType,
ferencd@0 12498 enable_if_t <
ferencd@0 12499 std::is_signed<C>::value and
ferencd@0 12500 std::is_signed<char>::value and
ferencd@0 12501 std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
ferencd@0 12502 > * = nullptr >
ferencd@0 12503 static constexpr CharType to_char_type(InputCharType x) noexcept
ferencd@0 12504 {
ferencd@0 12505 return x;
ferencd@0 12506 }
ferencd@0 12507
ferencd@0 12508 private:
ferencd@0 12509 /// whether we can assume little endianess
ferencd@0 12510 const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();
ferencd@0 12511
ferencd@0 12512 /// the output
ferencd@0 12513 output_adapter_t<CharType> oa = nullptr;
ferencd@0 12514 };
ferencd@0 12515 } // namespace detail
ferencd@0 12516 } // namespace nlohmann
ferencd@0 12517
ferencd@0 12518 // #include <nlohmann/detail/output/output_adapters.hpp>
ferencd@0 12519
ferencd@0 12520 // #include <nlohmann/detail/output/serializer.hpp>
ferencd@0 12521
ferencd@0 12522
ferencd@0 12523 #include <algorithm> // reverse, remove, fill, find, none_of
ferencd@0 12524 #include <array> // array
ferencd@0 12525 #include <cassert> // assert
ferencd@0 12526 #include <ciso646> // and, or
ferencd@0 12527 #include <clocale> // localeconv, lconv
ferencd@0 12528 #include <cmath> // labs, isfinite, isnan, signbit
ferencd@0 12529 #include <cstddef> // size_t, ptrdiff_t
ferencd@0 12530 #include <cstdint> // uint8_t
ferencd@0 12531 #include <cstdio> // snprintf
ferencd@0 12532 #include <limits> // numeric_limits
ferencd@0 12533 #include <string> // string
ferencd@0 12534 #include <type_traits> // is_same
ferencd@0 12535 #include <utility> // move
ferencd@0 12536
ferencd@0 12537 // #include <nlohmann/detail/conversions/to_chars.hpp>
ferencd@0 12538
ferencd@0 12539
ferencd@0 12540 #include <array> // array
ferencd@0 12541 #include <cassert> // assert
ferencd@0 12542 #include <ciso646> // or, and, not
ferencd@0 12543 #include <cmath> // signbit, isfinite
ferencd@0 12544 #include <cstdint> // intN_t, uintN_t
ferencd@0 12545 #include <cstring> // memcpy, memmove
ferencd@0 12546 #include <limits> // numeric_limits
ferencd@0 12547 #include <type_traits> // conditional
ferencd@0 12548 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 12549
ferencd@0 12550
ferencd@0 12551 namespace nlohmann
ferencd@0 12552 {
ferencd@0 12553 namespace detail
ferencd@0 12554 {
ferencd@0 12555
ferencd@0 12556 /*!
ferencd@0 12557 @brief implements the Grisu2 algorithm for binary to decimal floating-point
ferencd@0 12558 conversion.
ferencd@0 12559
ferencd@0 12560 This implementation is a slightly modified version of the reference
ferencd@0 12561 implementation which may be obtained from
ferencd@0 12562 http://florian.loitsch.com/publications (bench.tar.gz).
ferencd@0 12563
ferencd@0 12564 The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.
ferencd@0 12565
ferencd@0 12566 For a detailed description of the algorithm see:
ferencd@0 12567
ferencd@0 12568 [1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with
ferencd@0 12569 Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming
ferencd@0 12570 Language Design and Implementation, PLDI 2010
ferencd@0 12571 [2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately",
ferencd@0 12572 Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language
ferencd@0 12573 Design and Implementation, PLDI 1996
ferencd@0 12574 */
ferencd@0 12575 namespace dtoa_impl
ferencd@0 12576 {
ferencd@0 12577
ferencd@0 12578 template <typename Target, typename Source>
ferencd@0 12579 Target reinterpret_bits(const Source source)
ferencd@0 12580 {
ferencd@0 12581 static_assert(sizeof(Target) == sizeof(Source), "size mismatch");
ferencd@0 12582
ferencd@0 12583 Target target;
ferencd@0 12584 std::memcpy(&target, &source, sizeof(Source));
ferencd@0 12585 return target;
ferencd@0 12586 }
ferencd@0 12587
ferencd@0 12588 struct diyfp // f * 2^e
ferencd@0 12589 {
ferencd@0 12590 static constexpr int kPrecision = 64; // = q
ferencd@0 12591
ferencd@0 12592 std::uint64_t f = 0;
ferencd@0 12593 int e = 0;
ferencd@0 12594
ferencd@0 12595 constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {}
ferencd@0 12596
ferencd@0 12597 /*!
ferencd@0 12598 @brief returns x - y
ferencd@0 12599 @pre x.e == y.e and x.f >= y.f
ferencd@0 12600 */
ferencd@0 12601 static diyfp sub(const diyfp& x, const diyfp& y) noexcept
ferencd@0 12602 {
ferencd@0 12603 assert(x.e == y.e);
ferencd@0 12604 assert(x.f >= y.f);
ferencd@0 12605
ferencd@0 12606 return {x.f - y.f, x.e};
ferencd@0 12607 }
ferencd@0 12608
ferencd@0 12609 /*!
ferencd@0 12610 @brief returns x * y
ferencd@0 12611 @note The result is rounded. (Only the upper q bits are returned.)
ferencd@0 12612 */
ferencd@0 12613 static diyfp mul(const diyfp& x, const diyfp& y) noexcept
ferencd@0 12614 {
ferencd@0 12615 static_assert(kPrecision == 64, "internal error");
ferencd@0 12616
ferencd@0 12617 // Computes:
ferencd@0 12618 // f = round((x.f * y.f) / 2^q)
ferencd@0 12619 // e = x.e + y.e + q
ferencd@0 12620
ferencd@0 12621 // Emulate the 64-bit * 64-bit multiplication:
ferencd@0 12622 //
ferencd@0 12623 // p = u * v
ferencd@0 12624 // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)
ferencd@0 12625 // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi )
ferencd@0 12626 // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 )
ferencd@0 12627 // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 )
ferencd@0 12628 // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3)
ferencd@0 12629 // = (p0_lo ) + 2^32 (Q ) + 2^64 (H )
ferencd@0 12630 // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H )
ferencd@0 12631 //
ferencd@0 12632 // (Since Q might be larger than 2^32 - 1)
ferencd@0 12633 //
ferencd@0 12634 // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)
ferencd@0 12635 //
ferencd@0 12636 // (Q_hi + H does not overflow a 64-bit int)
ferencd@0 12637 //
ferencd@0 12638 // = p_lo + 2^64 p_hi
ferencd@0 12639
ferencd@0 12640 const std::uint64_t u_lo = x.f & 0xFFFFFFFFu;
ferencd@0 12641 const std::uint64_t u_hi = x.f >> 32u;
ferencd@0 12642 const std::uint64_t v_lo = y.f & 0xFFFFFFFFu;
ferencd@0 12643 const std::uint64_t v_hi = y.f >> 32u;
ferencd@0 12644
ferencd@0 12645 const std::uint64_t p0 = u_lo * v_lo;
ferencd@0 12646 const std::uint64_t p1 = u_lo * v_hi;
ferencd@0 12647 const std::uint64_t p2 = u_hi * v_lo;
ferencd@0 12648 const std::uint64_t p3 = u_hi * v_hi;
ferencd@0 12649
ferencd@0 12650 const std::uint64_t p0_hi = p0 >> 32u;
ferencd@0 12651 const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu;
ferencd@0 12652 const std::uint64_t p1_hi = p1 >> 32u;
ferencd@0 12653 const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu;
ferencd@0 12654 const std::uint64_t p2_hi = p2 >> 32u;
ferencd@0 12655
ferencd@0 12656 std::uint64_t Q = p0_hi + p1_lo + p2_lo;
ferencd@0 12657
ferencd@0 12658 // The full product might now be computed as
ferencd@0 12659 //
ferencd@0 12660 // p_hi = p3 + p2_hi + p1_hi + (Q >> 32)
ferencd@0 12661 // p_lo = p0_lo + (Q << 32)
ferencd@0 12662 //
ferencd@0 12663 // But in this particular case here, the full p_lo is not required.
ferencd@0 12664 // Effectively we only need to add the highest bit in p_lo to p_hi (and
ferencd@0 12665 // Q_hi + 1 does not overflow).
ferencd@0 12666
ferencd@0 12667 Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up
ferencd@0 12668
ferencd@0 12669 const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u);
ferencd@0 12670
ferencd@0 12671 return {h, x.e + y.e + 64};
ferencd@0 12672 }
ferencd@0 12673
ferencd@0 12674 /*!
ferencd@0 12675 @brief normalize x such that the significand is >= 2^(q-1)
ferencd@0 12676 @pre x.f != 0
ferencd@0 12677 */
ferencd@0 12678 static diyfp normalize(diyfp x) noexcept
ferencd@0 12679 {
ferencd@0 12680 assert(x.f != 0);
ferencd@0 12681
ferencd@0 12682 while ((x.f >> 63u) == 0)
ferencd@0 12683 {
ferencd@0 12684 x.f <<= 1u;
ferencd@0 12685 x.e--;
ferencd@0 12686 }
ferencd@0 12687
ferencd@0 12688 return x;
ferencd@0 12689 }
ferencd@0 12690
ferencd@0 12691 /*!
ferencd@0 12692 @brief normalize x such that the result has the exponent E
ferencd@0 12693 @pre e >= x.e and the upper e - x.e bits of x.f must be zero.
ferencd@0 12694 */
ferencd@0 12695 static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept
ferencd@0 12696 {
ferencd@0 12697 const int delta = x.e - target_exponent;
ferencd@0 12698
ferencd@0 12699 assert(delta >= 0);
ferencd@0 12700 assert(((x.f << delta) >> delta) == x.f);
ferencd@0 12701
ferencd@0 12702 return {x.f << delta, target_exponent};
ferencd@0 12703 }
ferencd@0 12704 };
ferencd@0 12705
ferencd@0 12706 struct boundaries
ferencd@0 12707 {
ferencd@0 12708 diyfp w;
ferencd@0 12709 diyfp minus;
ferencd@0 12710 diyfp plus;
ferencd@0 12711 };
ferencd@0 12712
ferencd@0 12713 /*!
ferencd@0 12714 Compute the (normalized) diyfp representing the input number 'value' and its
ferencd@0 12715 boundaries.
ferencd@0 12716
ferencd@0 12717 @pre value must be finite and positive
ferencd@0 12718 */
ferencd@0 12719 template <typename FloatType>
ferencd@0 12720 boundaries compute_boundaries(FloatType value)
ferencd@0 12721 {
ferencd@0 12722 assert(std::isfinite(value));
ferencd@0 12723 assert(value > 0);
ferencd@0 12724
ferencd@0 12725 // Convert the IEEE representation into a diyfp.
ferencd@0 12726 //
ferencd@0 12727 // If v is denormal:
ferencd@0 12728 // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1))
ferencd@0 12729 // If v is normalized:
ferencd@0 12730 // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))
ferencd@0 12731
ferencd@0 12732 static_assert(std::numeric_limits<FloatType>::is_iec559,
ferencd@0 12733 "internal error: dtoa_short requires an IEEE-754 floating-point implementation");
ferencd@0 12734
ferencd@0 12735 constexpr int kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)
ferencd@0 12736 constexpr int kBias = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);
ferencd@0 12737 constexpr int kMinExp = 1 - kBias;
ferencd@0 12738 constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1)
ferencd@0 12739
ferencd@0 12740 using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type;
ferencd@0 12741
ferencd@0 12742 const std::uint64_t bits = reinterpret_bits<bits_type>(value);
ferencd@0 12743 const std::uint64_t E = bits >> (kPrecision - 1);
ferencd@0 12744 const std::uint64_t F = bits & (kHiddenBit - 1);
ferencd@0 12745
ferencd@0 12746 const bool is_denormal = E == 0;
ferencd@0 12747 const diyfp v = is_denormal
ferencd@0 12748 ? diyfp(F, kMinExp)
ferencd@0 12749 : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
ferencd@0 12750
ferencd@0 12751 // Compute the boundaries m- and m+ of the floating-point value
ferencd@0 12752 // v = f * 2^e.
ferencd@0 12753 //
ferencd@0 12754 // Determine v- and v+, the floating-point predecessor and successor if v,
ferencd@0 12755 // respectively.
ferencd@0 12756 //
ferencd@0 12757 // v- = v - 2^e if f != 2^(p-1) or e == e_min (A)
ferencd@0 12758 // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B)
ferencd@0 12759 //
ferencd@0 12760 // v+ = v + 2^e
ferencd@0 12761 //
ferencd@0 12762 // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_
ferencd@0 12763 // between m- and m+ round to v, regardless of how the input rounding
ferencd@0 12764 // algorithm breaks ties.
ferencd@0 12765 //
ferencd@0 12766 // ---+-------------+-------------+-------------+-------------+--- (A)
ferencd@0 12767 // v- m- v m+ v+
ferencd@0 12768 //
ferencd@0 12769 // -----------------+------+------+-------------+-------------+--- (B)
ferencd@0 12770 // v- m- v m+ v+
ferencd@0 12771
ferencd@0 12772 const bool lower_boundary_is_closer = F == 0 and E > 1;
ferencd@0 12773 const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
ferencd@0 12774 const diyfp m_minus = lower_boundary_is_closer
ferencd@0 12775 ? diyfp(4 * v.f - 1, v.e - 2) // (B)
ferencd@0 12776 : diyfp(2 * v.f - 1, v.e - 1); // (A)
ferencd@0 12777
ferencd@0 12778 // Determine the normalized w+ = m+.
ferencd@0 12779 const diyfp w_plus = diyfp::normalize(m_plus);
ferencd@0 12780
ferencd@0 12781 // Determine w- = m- such that e_(w-) = e_(w+).
ferencd@0 12782 const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);
ferencd@0 12783
ferencd@0 12784 return {diyfp::normalize(v), w_minus, w_plus};
ferencd@0 12785 }
ferencd@0 12786
ferencd@0 12787 // Given normalized diyfp w, Grisu needs to find a (normalized) cached
ferencd@0 12788 // power-of-ten c, such that the exponent of the product c * w = f * 2^e lies
ferencd@0 12789 // within a certain range [alpha, gamma] (Definition 3.2 from [1])
ferencd@0 12790 //
ferencd@0 12791 // alpha <= e = e_c + e_w + q <= gamma
ferencd@0 12792 //
ferencd@0 12793 // or
ferencd@0 12794 //
ferencd@0 12795 // f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q
ferencd@0 12796 // <= f_c * f_w * 2^gamma
ferencd@0 12797 //
ferencd@0 12798 // Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies
ferencd@0 12799 //
ferencd@0 12800 // 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma
ferencd@0 12801 //
ferencd@0 12802 // or
ferencd@0 12803 //
ferencd@0 12804 // 2^(q - 2 + alpha) <= c * w < 2^(q + gamma)
ferencd@0 12805 //
ferencd@0 12806 // The choice of (alpha,gamma) determines the size of the table and the form of
ferencd@0 12807 // the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well
ferencd@0 12808 // in practice:
ferencd@0 12809 //
ferencd@0 12810 // The idea is to cut the number c * w = f * 2^e into two parts, which can be
ferencd@0 12811 // processed independently: An integral part p1, and a fractional part p2:
ferencd@0 12812 //
ferencd@0 12813 // f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e
ferencd@0 12814 // = (f div 2^-e) + (f mod 2^-e) * 2^e
ferencd@0 12815 // = p1 + p2 * 2^e
ferencd@0 12816 //
ferencd@0 12817 // The conversion of p1 into decimal form requires a series of divisions and
ferencd@0 12818 // modulos by (a power of) 10. These operations are faster for 32-bit than for
ferencd@0 12819 // 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be
ferencd@0 12820 // achieved by choosing
ferencd@0 12821 //
ferencd@0 12822 // -e >= 32 or e <= -32 := gamma
ferencd@0 12823 //
ferencd@0 12824 // In order to convert the fractional part
ferencd@0 12825 //
ferencd@0 12826 // p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...
ferencd@0 12827 //
ferencd@0 12828 // into decimal form, the fraction is repeatedly multiplied by 10 and the digits
ferencd@0 12829 // d[-i] are extracted in order:
ferencd@0 12830 //
ferencd@0 12831 // (10 * p2) div 2^-e = d[-1]
ferencd@0 12832 // (10 * p2) mod 2^-e = d[-2] / 10^1 + ...
ferencd@0 12833 //
ferencd@0 12834 // The multiplication by 10 must not overflow. It is sufficient to choose
ferencd@0 12835 //
ferencd@0 12836 // 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.
ferencd@0 12837 //
ferencd@0 12838 // Since p2 = f mod 2^-e < 2^-e,
ferencd@0 12839 //
ferencd@0 12840 // -e <= 60 or e >= -60 := alpha
ferencd@0 12841
ferencd@0 12842 constexpr int kAlpha = -60;
ferencd@0 12843 constexpr int kGamma = -32;
ferencd@0 12844
ferencd@0 12845 struct cached_power // c = f * 2^e ~= 10^k
ferencd@0 12846 {
ferencd@0 12847 std::uint64_t f;
ferencd@0 12848 int e;
ferencd@0 12849 int k;
ferencd@0 12850 };
ferencd@0 12851
ferencd@0 12852 /*!
ferencd@0 12853 For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached
ferencd@0 12854 power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c
ferencd@0 12855 satisfies (Definition 3.2 from [1])
ferencd@0 12856
ferencd@0 12857 alpha <= e_c + e + q <= gamma.
ferencd@0 12858 */
ferencd@0 12859 inline cached_power get_cached_power_for_binary_exponent(int e)
ferencd@0 12860 {
ferencd@0 12861 // Now
ferencd@0 12862 //
ferencd@0 12863 // alpha <= e_c + e + q <= gamma (1)
ferencd@0 12864 // ==> f_c * 2^alpha <= c * 2^e * 2^q
ferencd@0 12865 //
ferencd@0 12866 // and since the c's are normalized, 2^(q-1) <= f_c,
ferencd@0 12867 //
ferencd@0 12868 // ==> 2^(q - 1 + alpha) <= c * 2^(e + q)
ferencd@0 12869 // ==> 2^(alpha - e - 1) <= c
ferencd@0 12870 //
ferencd@0 12871 // If c were an exakt power of ten, i.e. c = 10^k, one may determine k as
ferencd@0 12872 //
ferencd@0 12873 // k = ceil( log_10( 2^(alpha - e - 1) ) )
ferencd@0 12874 // = ceil( (alpha - e - 1) * log_10(2) )
ferencd@0 12875 //
ferencd@0 12876 // From the paper:
ferencd@0 12877 // "In theory the result of the procedure could be wrong since c is rounded,
ferencd@0 12878 // and the computation itself is approximated [...]. In practice, however,
ferencd@0 12879 // this simple function is sufficient."
ferencd@0 12880 //
ferencd@0 12881 // For IEEE double precision floating-point numbers converted into
ferencd@0 12882 // normalized diyfp's w = f * 2^e, with q = 64,
ferencd@0 12883 //
ferencd@0 12884 // e >= -1022 (min IEEE exponent)
ferencd@0 12885 // -52 (p - 1)
ferencd@0 12886 // -52 (p - 1, possibly normalize denormal IEEE numbers)
ferencd@0 12887 // -11 (normalize the diyfp)
ferencd@0 12888 // = -1137
ferencd@0 12889 //
ferencd@0 12890 // and
ferencd@0 12891 //
ferencd@0 12892 // e <= +1023 (max IEEE exponent)
ferencd@0 12893 // -52 (p - 1)
ferencd@0 12894 // -11 (normalize the diyfp)
ferencd@0 12895 // = 960
ferencd@0 12896 //
ferencd@0 12897 // This binary exponent range [-1137,960] results in a decimal exponent
ferencd@0 12898 // range [-307,324]. One does not need to store a cached power for each
ferencd@0 12899 // k in this range. For each such k it suffices to find a cached power
ferencd@0 12900 // such that the exponent of the product lies in [alpha,gamma].
ferencd@0 12901 // This implies that the difference of the decimal exponents of adjacent
ferencd@0 12902 // table entries must be less than or equal to
ferencd@0 12903 //
ferencd@0 12904 // floor( (gamma - alpha) * log_10(2) ) = 8.
ferencd@0 12905 //
ferencd@0 12906 // (A smaller distance gamma-alpha would require a larger table.)
ferencd@0 12907
ferencd@0 12908 // NB:
ferencd@0 12909 // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.
ferencd@0 12910
ferencd@0 12911 constexpr int kCachedPowersMinDecExp = -300;
ferencd@0 12912 constexpr int kCachedPowersDecStep = 8;
ferencd@0 12913
ferencd@0 12914 static constexpr std::array<cached_power, 79> kCachedPowers =
ferencd@0 12915 {
ferencd@0 12916 {
ferencd@0 12917 { 0xAB70FE17C79AC6CA, -1060, -300 },
ferencd@0 12918 { 0xFF77B1FCBEBCDC4F, -1034, -292 },
ferencd@0 12919 { 0xBE5691EF416BD60C, -1007, -284 },
ferencd@0 12920 { 0x8DD01FAD907FFC3C, -980, -276 },
ferencd@0 12921 { 0xD3515C2831559A83, -954, -268 },
ferencd@0 12922 { 0x9D71AC8FADA6C9B5, -927, -260 },
ferencd@0 12923 { 0xEA9C227723EE8BCB, -901, -252 },
ferencd@0 12924 { 0xAECC49914078536D, -874, -244 },
ferencd@0 12925 { 0x823C12795DB6CE57, -847, -236 },
ferencd@0 12926 { 0xC21094364DFB5637, -821, -228 },
ferencd@0 12927 { 0x9096EA6F3848984F, -794, -220 },
ferencd@0 12928 { 0xD77485CB25823AC7, -768, -212 },
ferencd@0 12929 { 0xA086CFCD97BF97F4, -741, -204 },
ferencd@0 12930 { 0xEF340A98172AACE5, -715, -196 },
ferencd@0 12931 { 0xB23867FB2A35B28E, -688, -188 },
ferencd@0 12932 { 0x84C8D4DFD2C63F3B, -661, -180 },
ferencd@0 12933 { 0xC5DD44271AD3CDBA, -635, -172 },
ferencd@0 12934 { 0x936B9FCEBB25C996, -608, -164 },
ferencd@0 12935 { 0xDBAC6C247D62A584, -582, -156 },
ferencd@0 12936 { 0xA3AB66580D5FDAF6, -555, -148 },
ferencd@0 12937 { 0xF3E2F893DEC3F126, -529, -140 },
ferencd@0 12938 { 0xB5B5ADA8AAFF80B8, -502, -132 },
ferencd@0 12939 { 0x87625F056C7C4A8B, -475, -124 },
ferencd@0 12940 { 0xC9BCFF6034C13053, -449, -116 },
ferencd@0 12941 { 0x964E858C91BA2655, -422, -108 },
ferencd@0 12942 { 0xDFF9772470297EBD, -396, -100 },
ferencd@0 12943 { 0xA6DFBD9FB8E5B88F, -369, -92 },
ferencd@0 12944 { 0xF8A95FCF88747D94, -343, -84 },
ferencd@0 12945 { 0xB94470938FA89BCF, -316, -76 },
ferencd@0 12946 { 0x8A08F0F8BF0F156B, -289, -68 },
ferencd@0 12947 { 0xCDB02555653131B6, -263, -60 },
ferencd@0 12948 { 0x993FE2C6D07B7FAC, -236, -52 },
ferencd@0 12949 { 0xE45C10C42A2B3B06, -210, -44 },
ferencd@0 12950 { 0xAA242499697392D3, -183, -36 },
ferencd@0 12951 { 0xFD87B5F28300CA0E, -157, -28 },
ferencd@0 12952 { 0xBCE5086492111AEB, -130, -20 },
ferencd@0 12953 { 0x8CBCCC096F5088CC, -103, -12 },
ferencd@0 12954 { 0xD1B71758E219652C, -77, -4 },
ferencd@0 12955 { 0x9C40000000000000, -50, 4 },
ferencd@0 12956 { 0xE8D4A51000000000, -24, 12 },
ferencd@0 12957 { 0xAD78EBC5AC620000, 3, 20 },
ferencd@0 12958 { 0x813F3978F8940984, 30, 28 },
ferencd@0 12959 { 0xC097CE7BC90715B3, 56, 36 },
ferencd@0 12960 { 0x8F7E32CE7BEA5C70, 83, 44 },
ferencd@0 12961 { 0xD5D238A4ABE98068, 109, 52 },
ferencd@0 12962 { 0x9F4F2726179A2245, 136, 60 },
ferencd@0 12963 { 0xED63A231D4C4FB27, 162, 68 },
ferencd@0 12964 { 0xB0DE65388CC8ADA8, 189, 76 },
ferencd@0 12965 { 0x83C7088E1AAB65DB, 216, 84 },
ferencd@0 12966 { 0xC45D1DF942711D9A, 242, 92 },
ferencd@0 12967 { 0x924D692CA61BE758, 269, 100 },
ferencd@0 12968 { 0xDA01EE641A708DEA, 295, 108 },
ferencd@0 12969 { 0xA26DA3999AEF774A, 322, 116 },
ferencd@0 12970 { 0xF209787BB47D6B85, 348, 124 },
ferencd@0 12971 { 0xB454E4A179DD1877, 375, 132 },
ferencd@0 12972 { 0x865B86925B9BC5C2, 402, 140 },
ferencd@0 12973 { 0xC83553C5C8965D3D, 428, 148 },
ferencd@0 12974 { 0x952AB45CFA97A0B3, 455, 156 },
ferencd@0 12975 { 0xDE469FBD99A05FE3, 481, 164 },
ferencd@0 12976 { 0xA59BC234DB398C25, 508, 172 },
ferencd@0 12977 { 0xF6C69A72A3989F5C, 534, 180 },
ferencd@0 12978 { 0xB7DCBF5354E9BECE, 561, 188 },
ferencd@0 12979 { 0x88FCF317F22241E2, 588, 196 },
ferencd@0 12980 { 0xCC20CE9BD35C78A5, 614, 204 },
ferencd@0 12981 { 0x98165AF37B2153DF, 641, 212 },
ferencd@0 12982 { 0xE2A0B5DC971F303A, 667, 220 },
ferencd@0 12983 { 0xA8D9D1535CE3B396, 694, 228 },
ferencd@0 12984 { 0xFB9B7CD9A4A7443C, 720, 236 },
ferencd@0 12985 { 0xBB764C4CA7A44410, 747, 244 },
ferencd@0 12986 { 0x8BAB8EEFB6409C1A, 774, 252 },
ferencd@0 12987 { 0xD01FEF10A657842C, 800, 260 },
ferencd@0 12988 { 0x9B10A4E5E9913129, 827, 268 },
ferencd@0 12989 { 0xE7109BFBA19C0C9D, 853, 276 },
ferencd@0 12990 { 0xAC2820D9623BF429, 880, 284 },
ferencd@0 12991 { 0x80444B5E7AA7CF85, 907, 292 },
ferencd@0 12992 { 0xBF21E44003ACDD2D, 933, 300 },
ferencd@0 12993 { 0x8E679C2F5E44FF8F, 960, 308 },
ferencd@0 12994 { 0xD433179D9C8CB841, 986, 316 },
ferencd@0 12995 { 0x9E19DB92B4E31BA9, 1013, 324 },
ferencd@0 12996 }
ferencd@0 12997 };
ferencd@0 12998
ferencd@0 12999 // This computation gives exactly the same results for k as
ferencd@0 13000 // k = ceil((kAlpha - e - 1) * 0.30102999566398114)
ferencd@0 13001 // for |e| <= 1500, but doesn't require floating-point operations.
ferencd@0 13002 // NB: log_10(2) ~= 78913 / 2^18
ferencd@0 13003 assert(e >= -1500);
ferencd@0 13004 assert(e <= 1500);
ferencd@0 13005 const int f = kAlpha - e - 1;
ferencd@0 13006 const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);
ferencd@0 13007
ferencd@0 13008 const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
ferencd@0 13009 assert(index >= 0);
ferencd@0 13010 assert(static_cast<std::size_t>(index) < kCachedPowers.size());
ferencd@0 13011
ferencd@0 13012 const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];
ferencd@0 13013 assert(kAlpha <= cached.e + e + 64);
ferencd@0 13014 assert(kGamma >= cached.e + e + 64);
ferencd@0 13015
ferencd@0 13016 return cached;
ferencd@0 13017 }
ferencd@0 13018
ferencd@0 13019 /*!
ferencd@0 13020 For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.
ferencd@0 13021 For n == 0, returns 1 and sets pow10 := 1.
ferencd@0 13022 */
ferencd@0 13023 inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)
ferencd@0 13024 {
ferencd@0 13025 // LCOV_EXCL_START
ferencd@0 13026 if (n >= 1000000000)
ferencd@0 13027 {
ferencd@0 13028 pow10 = 1000000000;
ferencd@0 13029 return 10;
ferencd@0 13030 }
ferencd@0 13031 // LCOV_EXCL_STOP
ferencd@0 13032 else if (n >= 100000000)
ferencd@0 13033 {
ferencd@0 13034 pow10 = 100000000;
ferencd@0 13035 return 9;
ferencd@0 13036 }
ferencd@0 13037 else if (n >= 10000000)
ferencd@0 13038 {
ferencd@0 13039 pow10 = 10000000;
ferencd@0 13040 return 8;
ferencd@0 13041 }
ferencd@0 13042 else if (n >= 1000000)
ferencd@0 13043 {
ferencd@0 13044 pow10 = 1000000;
ferencd@0 13045 return 7;
ferencd@0 13046 }
ferencd@0 13047 else if (n >= 100000)
ferencd@0 13048 {
ferencd@0 13049 pow10 = 100000;
ferencd@0 13050 return 6;
ferencd@0 13051 }
ferencd@0 13052 else if (n >= 10000)
ferencd@0 13053 {
ferencd@0 13054 pow10 = 10000;
ferencd@0 13055 return 5;
ferencd@0 13056 }
ferencd@0 13057 else if (n >= 1000)
ferencd@0 13058 {
ferencd@0 13059 pow10 = 1000;
ferencd@0 13060 return 4;
ferencd@0 13061 }
ferencd@0 13062 else if (n >= 100)
ferencd@0 13063 {
ferencd@0 13064 pow10 = 100;
ferencd@0 13065 return 3;
ferencd@0 13066 }
ferencd@0 13067 else if (n >= 10)
ferencd@0 13068 {
ferencd@0 13069 pow10 = 10;
ferencd@0 13070 return 2;
ferencd@0 13071 }
ferencd@0 13072 else
ferencd@0 13073 {
ferencd@0 13074 pow10 = 1;
ferencd@0 13075 return 1;
ferencd@0 13076 }
ferencd@0 13077 }
ferencd@0 13078
ferencd@0 13079 inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,
ferencd@0 13080 std::uint64_t rest, std::uint64_t ten_k)
ferencd@0 13081 {
ferencd@0 13082 assert(len >= 1);
ferencd@0 13083 assert(dist <= delta);
ferencd@0 13084 assert(rest <= delta);
ferencd@0 13085 assert(ten_k > 0);
ferencd@0 13086
ferencd@0 13087 // <--------------------------- delta ---->
ferencd@0 13088 // <---- dist --------->
ferencd@0 13089 // --------------[------------------+-------------------]--------------
ferencd@0 13090 // M- w M+
ferencd@0 13091 //
ferencd@0 13092 // ten_k
ferencd@0 13093 // <------>
ferencd@0 13094 // <---- rest ---->
ferencd@0 13095 // --------------[------------------+----+--------------]--------------
ferencd@0 13096 // w V
ferencd@0 13097 // = buf * 10^k
ferencd@0 13098 //
ferencd@0 13099 // ten_k represents a unit-in-the-last-place in the decimal representation
ferencd@0 13100 // stored in buf.
ferencd@0 13101 // Decrement buf by ten_k while this takes buf closer to w.
ferencd@0 13102
ferencd@0 13103 // The tests are written in this order to avoid overflow in unsigned
ferencd@0 13104 // integer arithmetic.
ferencd@0 13105
ferencd@0 13106 while (rest < dist
ferencd@0 13107 and delta - rest >= ten_k
ferencd@0 13108 and (rest + ten_k < dist or dist - rest > rest + ten_k - dist))
ferencd@0 13109 {
ferencd@0 13110 assert(buf[len - 1] != '0');
ferencd@0 13111 buf[len - 1]--;
ferencd@0 13112 rest += ten_k;
ferencd@0 13113 }
ferencd@0 13114 }
ferencd@0 13115
ferencd@0 13116 /*!
ferencd@0 13117 Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.
ferencd@0 13118 M- and M+ must be normalized and share the same exponent -60 <= e <= -32.
ferencd@0 13119 */
ferencd@0 13120 inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
ferencd@0 13121 diyfp M_minus, diyfp w, diyfp M_plus)
ferencd@0 13122 {
ferencd@0 13123 static_assert(kAlpha >= -60, "internal error");
ferencd@0 13124 static_assert(kGamma <= -32, "internal error");
ferencd@0 13125
ferencd@0 13126 // Generates the digits (and the exponent) of a decimal floating-point
ferencd@0 13127 // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's
ferencd@0 13128 // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.
ferencd@0 13129 //
ferencd@0 13130 // <--------------------------- delta ---->
ferencd@0 13131 // <---- dist --------->
ferencd@0 13132 // --------------[------------------+-------------------]--------------
ferencd@0 13133 // M- w M+
ferencd@0 13134 //
ferencd@0 13135 // Grisu2 generates the digits of M+ from left to right and stops as soon as
ferencd@0 13136 // V is in [M-,M+].
ferencd@0 13137
ferencd@0 13138 assert(M_plus.e >= kAlpha);
ferencd@0 13139 assert(M_plus.e <= kGamma);
ferencd@0 13140
ferencd@0 13141 std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)
ferencd@0 13142 std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e)
ferencd@0 13143
ferencd@0 13144 // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):
ferencd@0 13145 //
ferencd@0 13146 // M+ = f * 2^e
ferencd@0 13147 // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e
ferencd@0 13148 // = ((p1 ) * 2^-e + (p2 )) * 2^e
ferencd@0 13149 // = p1 + p2 * 2^e
ferencd@0 13150
ferencd@0 13151 const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e);
ferencd@0 13152
ferencd@0 13153 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.)
ferencd@0 13154 std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e
ferencd@0 13155
ferencd@0 13156 // 1)
ferencd@0 13157 //
ferencd@0 13158 // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]
ferencd@0 13159
ferencd@0 13160 assert(p1 > 0);
ferencd@0 13161
ferencd@0 13162 std::uint32_t pow10;
ferencd@0 13163 const int k = find_largest_pow10(p1, pow10);
ferencd@0 13164
ferencd@0 13165 // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)
ferencd@0 13166 //
ferencd@0 13167 // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))
ferencd@0 13168 // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1))
ferencd@0 13169 //
ferencd@0 13170 // M+ = p1 + p2 * 2^e
ferencd@0 13171 // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e
ferencd@0 13172 // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e
ferencd@0 13173 // = d[k-1] * 10^(k-1) + ( rest) * 2^e
ferencd@0 13174 //
ferencd@0 13175 // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)
ferencd@0 13176 //
ferencd@0 13177 // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]
ferencd@0 13178 //
ferencd@0 13179 // but stop as soon as
ferencd@0 13180 //
ferencd@0 13181 // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e
ferencd@0 13182
ferencd@0 13183 int n = k;
ferencd@0 13184 while (n > 0)
ferencd@0 13185 {
ferencd@0 13186 // Invariants:
ferencd@0 13187 // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k)
ferencd@0 13188 // pow10 = 10^(n-1) <= p1 < 10^n
ferencd@0 13189 //
ferencd@0 13190 const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1)
ferencd@0 13191 const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1)
ferencd@0 13192 //
ferencd@0 13193 // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
ferencd@0 13194 // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
ferencd@0 13195 //
ferencd@0 13196 assert(d <= 9);
ferencd@0 13197 buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
ferencd@0 13198 //
ferencd@0 13199 // M+ = buffer * 10^(n-1) + (r + p2 * 2^e)
ferencd@0 13200 //
ferencd@0 13201 p1 = r;
ferencd@0 13202 n--;
ferencd@0 13203 //
ferencd@0 13204 // M+ = buffer * 10^n + (p1 + p2 * 2^e)
ferencd@0 13205 // pow10 = 10^n
ferencd@0 13206 //
ferencd@0 13207
ferencd@0 13208 // Now check if enough digits have been generated.
ferencd@0 13209 // Compute
ferencd@0 13210 //
ferencd@0 13211 // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e
ferencd@0 13212 //
ferencd@0 13213 // Note:
ferencd@0 13214 // Since rest and delta share the same exponent e, it suffices to
ferencd@0 13215 // compare the significands.
ferencd@0 13216 const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2;
ferencd@0 13217 if (rest <= delta)
ferencd@0 13218 {
ferencd@0 13219 // V = buffer * 10^n, with M- <= V <= M+.
ferencd@0 13220
ferencd@0 13221 decimal_exponent += n;
ferencd@0 13222
ferencd@0 13223 // We may now just stop. But instead look if the buffer could be
ferencd@0 13224 // decremented to bring V closer to w.
ferencd@0 13225 //
ferencd@0 13226 // pow10 = 10^n is now 1 ulp in the decimal representation V.
ferencd@0 13227 // The rounding procedure works with diyfp's with an implicit
ferencd@0 13228 // exponent of e.
ferencd@0 13229 //
ferencd@0 13230 // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e
ferencd@0 13231 //
ferencd@0 13232 const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e;
ferencd@0 13233 grisu2_round(buffer, length, dist, delta, rest, ten_n);
ferencd@0 13234
ferencd@0 13235 return;
ferencd@0 13236 }
ferencd@0 13237
ferencd@0 13238 pow10 /= 10;
ferencd@0 13239 //
ferencd@0 13240 // pow10 = 10^(n-1) <= p1 < 10^n
ferencd@0 13241 // Invariants restored.
ferencd@0 13242 }
ferencd@0 13243
ferencd@0 13244 // 2)
ferencd@0 13245 //
ferencd@0 13246 // The digits of the integral part have been generated:
ferencd@0 13247 //
ferencd@0 13248 // M+ = d[k-1]...d[1]d[0] + p2 * 2^e
ferencd@0 13249 // = buffer + p2 * 2^e
ferencd@0 13250 //
ferencd@0 13251 // Now generate the digits of the fractional part p2 * 2^e.
ferencd@0 13252 //
ferencd@0 13253 // Note:
ferencd@0 13254 // No decimal point is generated: the exponent is adjusted instead.
ferencd@0 13255 //
ferencd@0 13256 // p2 actually represents the fraction
ferencd@0 13257 //
ferencd@0 13258 // p2 * 2^e
ferencd@0 13259 // = p2 / 2^-e
ferencd@0 13260 // = d[-1] / 10^1 + d[-2] / 10^2 + ...
ferencd@0 13261 //
ferencd@0 13262 // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)
ferencd@0 13263 //
ferencd@0 13264 // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m
ferencd@0 13265 // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)
ferencd@0 13266 //
ferencd@0 13267 // using
ferencd@0 13268 //
ferencd@0 13269 // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)
ferencd@0 13270 // = ( d) * 2^-e + ( r)
ferencd@0 13271 //
ferencd@0 13272 // or
ferencd@0 13273 // 10^m * p2 * 2^e = d + r * 2^e
ferencd@0 13274 //
ferencd@0 13275 // i.e.
ferencd@0 13276 //
ferencd@0 13277 // M+ = buffer + p2 * 2^e
ferencd@0 13278 // = buffer + 10^-m * (d + r * 2^e)
ferencd@0 13279 // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e
ferencd@0 13280 //
ferencd@0 13281 // and stop as soon as 10^-m * r * 2^e <= delta * 2^e
ferencd@0 13282
ferencd@0 13283 assert(p2 > delta);
ferencd@0 13284
ferencd@0 13285 int m = 0;
ferencd@0 13286 for (;;)
ferencd@0 13287 {
ferencd@0 13288 // Invariant:
ferencd@0 13289 // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e
ferencd@0 13290 // = buffer * 10^-m + 10^-m * (p2 ) * 2^e
ferencd@0 13291 // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e
ferencd@0 13292 // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e
ferencd@0 13293 //
ferencd@0 13294 assert(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);
ferencd@0 13295 p2 *= 10;
ferencd@0 13296 const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e
ferencd@0 13297 const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e
ferencd@0 13298 //
ferencd@0 13299 // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e
ferencd@0 13300 // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
ferencd@0 13301 // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e
ferencd@0 13302 //
ferencd@0 13303 assert(d <= 9);
ferencd@0 13304 buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
ferencd@0 13305 //
ferencd@0 13306 // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e
ferencd@0 13307 //
ferencd@0 13308 p2 = r;
ferencd@0 13309 m++;
ferencd@0 13310 //
ferencd@0 13311 // M+ = buffer * 10^-m + 10^-m * p2 * 2^e
ferencd@0 13312 // Invariant restored.
ferencd@0 13313
ferencd@0 13314 // Check if enough digits have been generated.
ferencd@0 13315 //
ferencd@0 13316 // 10^-m * p2 * 2^e <= delta * 2^e
ferencd@0 13317 // p2 * 2^e <= 10^m * delta * 2^e
ferencd@0 13318 // p2 <= 10^m * delta
ferencd@0 13319 delta *= 10;
ferencd@0 13320 dist *= 10;
ferencd@0 13321 if (p2 <= delta)
ferencd@0 13322 {
ferencd@0 13323 break;
ferencd@0 13324 }
ferencd@0 13325 }
ferencd@0 13326
ferencd@0 13327 // V = buffer * 10^-m, with M- <= V <= M+.
ferencd@0 13328
ferencd@0 13329 decimal_exponent -= m;
ferencd@0 13330
ferencd@0 13331 // 1 ulp in the decimal representation is now 10^-m.
ferencd@0 13332 // Since delta and dist are now scaled by 10^m, we need to do the
ferencd@0 13333 // same with ulp in order to keep the units in sync.
ferencd@0 13334 //
ferencd@0 13335 // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e
ferencd@0 13336 //
ferencd@0 13337 const std::uint64_t ten_m = one.f;
ferencd@0 13338 grisu2_round(buffer, length, dist, delta, p2, ten_m);
ferencd@0 13339
ferencd@0 13340 // By construction this algorithm generates the shortest possible decimal
ferencd@0 13341 // number (Loitsch, Theorem 6.2) which rounds back to w.
ferencd@0 13342 // For an input number of precision p, at least
ferencd@0 13343 //
ferencd@0 13344 // N = 1 + ceil(p * log_10(2))
ferencd@0 13345 //
ferencd@0 13346 // decimal digits are sufficient to identify all binary floating-point
ferencd@0 13347 // numbers (Matula, "In-and-Out conversions").
ferencd@0 13348 // This implies that the algorithm does not produce more than N decimal
ferencd@0 13349 // digits.
ferencd@0 13350 //
ferencd@0 13351 // N = 17 for p = 53 (IEEE double precision)
ferencd@0 13352 // N = 9 for p = 24 (IEEE single precision)
ferencd@0 13353 }
ferencd@0 13354
ferencd@0 13355 /*!
ferencd@0 13356 v = buf * 10^decimal_exponent
ferencd@0 13357 len is the length of the buffer (number of decimal digits)
ferencd@0 13358 The buffer must be large enough, i.e. >= max_digits10.
ferencd@0 13359 */
ferencd@0 13360 JSON_HEDLEY_NON_NULL(1)
ferencd@0 13361 inline void grisu2(char* buf, int& len, int& decimal_exponent,
ferencd@0 13362 diyfp m_minus, diyfp v, diyfp m_plus)
ferencd@0 13363 {
ferencd@0 13364 assert(m_plus.e == m_minus.e);
ferencd@0 13365 assert(m_plus.e == v.e);
ferencd@0 13366
ferencd@0 13367 // --------(-----------------------+-----------------------)-------- (A)
ferencd@0 13368 // m- v m+
ferencd@0 13369 //
ferencd@0 13370 // --------------------(-----------+-----------------------)-------- (B)
ferencd@0 13371 // m- v m+
ferencd@0 13372 //
ferencd@0 13373 // First scale v (and m- and m+) such that the exponent is in the range
ferencd@0 13374 // [alpha, gamma].
ferencd@0 13375
ferencd@0 13376 const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);
ferencd@0 13377
ferencd@0 13378 const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k
ferencd@0 13379
ferencd@0 13380 // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]
ferencd@0 13381 const diyfp w = diyfp::mul(v, c_minus_k);
ferencd@0 13382 const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);
ferencd@0 13383 const diyfp w_plus = diyfp::mul(m_plus, c_minus_k);
ferencd@0 13384
ferencd@0 13385 // ----(---+---)---------------(---+---)---------------(---+---)----
ferencd@0 13386 // w- w w+
ferencd@0 13387 // = c*m- = c*v = c*m+
ferencd@0 13388 //
ferencd@0 13389 // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and
ferencd@0 13390 // w+ are now off by a small amount.
ferencd@0 13391 // In fact:
ferencd@0 13392 //
ferencd@0 13393 // w - v * 10^k < 1 ulp
ferencd@0 13394 //
ferencd@0 13395 // To account for this inaccuracy, add resp. subtract 1 ulp.
ferencd@0 13396 //
ferencd@0 13397 // --------+---[---------------(---+---)---------------]---+--------
ferencd@0 13398 // w- M- w M+ w+
ferencd@0 13399 //
ferencd@0 13400 // Now any number in [M-, M+] (bounds included) will round to w when input,
ferencd@0 13401 // regardless of how the input rounding algorithm breaks ties.
ferencd@0 13402 //
ferencd@0 13403 // And digit_gen generates the shortest possible such number in [M-, M+].
ferencd@0 13404 // Note that this does not mean that Grisu2 always generates the shortest
ferencd@0 13405 // possible number in the interval (m-, m+).
ferencd@0 13406 const diyfp M_minus(w_minus.f + 1, w_minus.e);
ferencd@0 13407 const diyfp M_plus (w_plus.f - 1, w_plus.e );
ferencd@0 13408
ferencd@0 13409 decimal_exponent = -cached.k; // = -(-k) = k
ferencd@0 13410
ferencd@0 13411 grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);
ferencd@0 13412 }
ferencd@0 13413
ferencd@0 13414 /*!
ferencd@0 13415 v = buf * 10^decimal_exponent
ferencd@0 13416 len is the length of the buffer (number of decimal digits)
ferencd@0 13417 The buffer must be large enough, i.e. >= max_digits10.
ferencd@0 13418 */
ferencd@0 13419 template <typename FloatType>
ferencd@0 13420 JSON_HEDLEY_NON_NULL(1)
ferencd@0 13421 void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
ferencd@0 13422 {
ferencd@0 13423 static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,
ferencd@0 13424 "internal error: not enough precision");
ferencd@0 13425
ferencd@0 13426 assert(std::isfinite(value));
ferencd@0 13427 assert(value > 0);
ferencd@0 13428
ferencd@0 13429 // If the neighbors (and boundaries) of 'value' are always computed for double-precision
ferencd@0 13430 // numbers, all float's can be recovered using strtod (and strtof). However, the resulting
ferencd@0 13431 // decimal representations are not exactly "short".
ferencd@0 13432 //
ferencd@0 13433 // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)
ferencd@0 13434 // says "value is converted to a string as if by std::sprintf in the default ("C") locale"
ferencd@0 13435 // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars'
ferencd@0 13436 // does.
ferencd@0 13437 // On the other hand, the documentation for 'std::to_chars' requires that "parsing the
ferencd@0 13438 // representation using the corresponding std::from_chars function recovers value exactly". That
ferencd@0 13439 // indicates that single precision floating-point numbers should be recovered using
ferencd@0 13440 // 'std::strtof'.
ferencd@0 13441 //
ferencd@0 13442 // NB: If the neighbors are computed for single-precision numbers, there is a single float
ferencd@0 13443 // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision
ferencd@0 13444 // value is off by 1 ulp.
ferencd@0 13445 #if 0
ferencd@0 13446 const boundaries w = compute_boundaries(static_cast<double>(value));
ferencd@0 13447 #else
ferencd@0 13448 const boundaries w = compute_boundaries(value);
ferencd@0 13449 #endif
ferencd@0 13450
ferencd@0 13451 grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);
ferencd@0 13452 }
ferencd@0 13453
ferencd@0 13454 /*!
ferencd@0 13455 @brief appends a decimal representation of e to buf
ferencd@0 13456 @return a pointer to the element following the exponent.
ferencd@0 13457 @pre -1000 < e < 1000
ferencd@0 13458 */
ferencd@0 13459 JSON_HEDLEY_NON_NULL(1)
ferencd@0 13460 JSON_HEDLEY_RETURNS_NON_NULL
ferencd@0 13461 inline char* append_exponent(char* buf, int e)
ferencd@0 13462 {
ferencd@0 13463 assert(e > -1000);
ferencd@0 13464 assert(e < 1000);
ferencd@0 13465
ferencd@0 13466 if (e < 0)
ferencd@0 13467 {
ferencd@0 13468 e = -e;
ferencd@0 13469 *buf++ = '-';
ferencd@0 13470 }
ferencd@0 13471 else
ferencd@0 13472 {
ferencd@0 13473 *buf++ = '+';
ferencd@0 13474 }
ferencd@0 13475
ferencd@0 13476 auto k = static_cast<std::uint32_t>(e);
ferencd@0 13477 if (k < 10)
ferencd@0 13478 {
ferencd@0 13479 // Always print at least two digits in the exponent.
ferencd@0 13480 // This is for compatibility with printf("%g").
ferencd@0 13481 *buf++ = '0';
ferencd@0 13482 *buf++ = static_cast<char>('0' + k);
ferencd@0 13483 }
ferencd@0 13484 else if (k < 100)
ferencd@0 13485 {
ferencd@0 13486 *buf++ = static_cast<char>('0' + k / 10);
ferencd@0 13487 k %= 10;
ferencd@0 13488 *buf++ = static_cast<char>('0' + k);
ferencd@0 13489 }
ferencd@0 13490 else
ferencd@0 13491 {
ferencd@0 13492 *buf++ = static_cast<char>('0' + k / 100);
ferencd@0 13493 k %= 100;
ferencd@0 13494 *buf++ = static_cast<char>('0' + k / 10);
ferencd@0 13495 k %= 10;
ferencd@0 13496 *buf++ = static_cast<char>('0' + k);
ferencd@0 13497 }
ferencd@0 13498
ferencd@0 13499 return buf;
ferencd@0 13500 }
ferencd@0 13501
ferencd@0 13502 /*!
ferencd@0 13503 @brief prettify v = buf * 10^decimal_exponent
ferencd@0 13504
ferencd@0 13505 If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point
ferencd@0 13506 notation. Otherwise it will be printed in exponential notation.
ferencd@0 13507
ferencd@0 13508 @pre min_exp < 0
ferencd@0 13509 @pre max_exp > 0
ferencd@0 13510 */
ferencd@0 13511 JSON_HEDLEY_NON_NULL(1)
ferencd@0 13512 JSON_HEDLEY_RETURNS_NON_NULL
ferencd@0 13513 inline char* format_buffer(char* buf, int len, int decimal_exponent,
ferencd@0 13514 int min_exp, int max_exp)
ferencd@0 13515 {
ferencd@0 13516 assert(min_exp < 0);
ferencd@0 13517 assert(max_exp > 0);
ferencd@0 13518
ferencd@0 13519 const int k = len;
ferencd@0 13520 const int n = len + decimal_exponent;
ferencd@0 13521
ferencd@0 13522 // v = buf * 10^(n-k)
ferencd@0 13523 // k is the length of the buffer (number of decimal digits)
ferencd@0 13524 // n is the position of the decimal point relative to the start of the buffer.
ferencd@0 13525
ferencd@0 13526 if (k <= n and n <= max_exp)
ferencd@0 13527 {
ferencd@0 13528 // digits[000]
ferencd@0 13529 // len <= max_exp + 2
ferencd@0 13530
ferencd@0 13531 std::memset(buf + k, '0', static_cast<size_t>(n - k));
ferencd@0 13532 // Make it look like a floating-point number (#362, #378)
ferencd@0 13533 buf[n + 0] = '.';
ferencd@0 13534 buf[n + 1] = '0';
ferencd@0 13535 return buf + (n + 2);
ferencd@0 13536 }
ferencd@0 13537
ferencd@0 13538 if (0 < n and n <= max_exp)
ferencd@0 13539 {
ferencd@0 13540 // dig.its
ferencd@0 13541 // len <= max_digits10 + 1
ferencd@0 13542
ferencd@0 13543 assert(k > n);
ferencd@0 13544
ferencd@0 13545 std::memmove(buf + (n + 1), buf + n, static_cast<size_t>(k - n));
ferencd@0 13546 buf[n] = '.';
ferencd@0 13547 return buf + (k + 1);
ferencd@0 13548 }
ferencd@0 13549
ferencd@0 13550 if (min_exp < n and n <= 0)
ferencd@0 13551 {
ferencd@0 13552 // 0.[000]digits
ferencd@0 13553 // len <= 2 + (-min_exp - 1) + max_digits10
ferencd@0 13554
ferencd@0 13555 std::memmove(buf + (2 + -n), buf, static_cast<size_t>(k));
ferencd@0 13556 buf[0] = '0';
ferencd@0 13557 buf[1] = '.';
ferencd@0 13558 std::memset(buf + 2, '0', static_cast<size_t>(-n));
ferencd@0 13559 return buf + (2 + (-n) + k);
ferencd@0 13560 }
ferencd@0 13561
ferencd@0 13562 if (k == 1)
ferencd@0 13563 {
ferencd@0 13564 // dE+123
ferencd@0 13565 // len <= 1 + 5
ferencd@0 13566
ferencd@0 13567 buf += 1;
ferencd@0 13568 }
ferencd@0 13569 else
ferencd@0 13570 {
ferencd@0 13571 // d.igitsE+123
ferencd@0 13572 // len <= max_digits10 + 1 + 5
ferencd@0 13573
ferencd@0 13574 std::memmove(buf + 2, buf + 1, static_cast<size_t>(k - 1));
ferencd@0 13575 buf[1] = '.';
ferencd@0 13576 buf += 1 + k;
ferencd@0 13577 }
ferencd@0 13578
ferencd@0 13579 *buf++ = 'e';
ferencd@0 13580 return append_exponent(buf, n - 1);
ferencd@0 13581 }
ferencd@0 13582
ferencd@0 13583 } // namespace dtoa_impl
ferencd@0 13584
ferencd@0 13585 /*!
ferencd@0 13586 @brief generates a decimal representation of the floating-point number value in [first, last).
ferencd@0 13587
ferencd@0 13588 The format of the resulting decimal representation is similar to printf's %g
ferencd@0 13589 format. Returns an iterator pointing past-the-end of the decimal representation.
ferencd@0 13590
ferencd@0 13591 @note The input number must be finite, i.e. NaN's and Inf's are not supported.
ferencd@0 13592 @note The buffer must be large enough.
ferencd@0 13593 @note The result is NOT null-terminated.
ferencd@0 13594 */
ferencd@0 13595 template <typename FloatType>
ferencd@0 13596 JSON_HEDLEY_NON_NULL(1, 2)
ferencd@0 13597 JSON_HEDLEY_RETURNS_NON_NULL
ferencd@0 13598 char* to_chars(char* first, const char* last, FloatType value)
ferencd@0 13599 {
ferencd@0 13600 static_cast<void>(last); // maybe unused - fix warning
ferencd@0 13601 assert(std::isfinite(value));
ferencd@0 13602
ferencd@0 13603 // Use signbit(value) instead of (value < 0) since signbit works for -0.
ferencd@0 13604 if (std::signbit(value))
ferencd@0 13605 {
ferencd@0 13606 value = -value;
ferencd@0 13607 *first++ = '-';
ferencd@0 13608 }
ferencd@0 13609
ferencd@0 13610 if (value == 0) // +-0
ferencd@0 13611 {
ferencd@0 13612 *first++ = '0';
ferencd@0 13613 // Make it look like a floating-point number (#362, #378)
ferencd@0 13614 *first++ = '.';
ferencd@0 13615 *first++ = '0';
ferencd@0 13616 return first;
ferencd@0 13617 }
ferencd@0 13618
ferencd@0 13619 assert(last - first >= std::numeric_limits<FloatType>::max_digits10);
ferencd@0 13620
ferencd@0 13621 // Compute v = buffer * 10^decimal_exponent.
ferencd@0 13622 // The decimal digits are stored in the buffer, which needs to be interpreted
ferencd@0 13623 // as an unsigned decimal integer.
ferencd@0 13624 // len is the length of the buffer, i.e. the number of decimal digits.
ferencd@0 13625 int len = 0;
ferencd@0 13626 int decimal_exponent = 0;
ferencd@0 13627 dtoa_impl::grisu2(first, len, decimal_exponent, value);
ferencd@0 13628
ferencd@0 13629 assert(len <= std::numeric_limits<FloatType>::max_digits10);
ferencd@0 13630
ferencd@0 13631 // Format the buffer like printf("%.*g", prec, value)
ferencd@0 13632 constexpr int kMinExp = -4;
ferencd@0 13633 // Use digits10 here to increase compatibility with version 2.
ferencd@0 13634 constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;
ferencd@0 13635
ferencd@0 13636 assert(last - first >= kMaxExp + 2);
ferencd@0 13637 assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
ferencd@0 13638 assert(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
ferencd@0 13639
ferencd@0 13640 return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
ferencd@0 13641 }
ferencd@0 13642
ferencd@0 13643 } // namespace detail
ferencd@0 13644 } // namespace nlohmann
ferencd@0 13645
ferencd@0 13646 // #include <nlohmann/detail/exceptions.hpp>
ferencd@0 13647
ferencd@0 13648 // #include <nlohmann/detail/macro_scope.hpp>
ferencd@0 13649
ferencd@0 13650 // #include <nlohmann/detail/meta/cpp_future.hpp>
ferencd@0 13651
ferencd@0 13652 // #include <nlohmann/detail/output/binary_writer.hpp>
ferencd@0 13653
ferencd@0 13654 // #include <nlohmann/detail/output/output_adapters.hpp>
ferencd@0 13655
ferencd@0 13656 // #include <nlohmann/detail/value_t.hpp>
ferencd@0 13657
ferencd@0 13658
ferencd@0 13659 namespace nlohmann
ferencd@0 13660 {
ferencd@0 13661 namespace detail
ferencd@0 13662 {
ferencd@0 13663 ///////////////////
ferencd@0 13664 // serialization //
ferencd@0 13665 ///////////////////
ferencd@0 13666
ferencd@0 13667 /// how to treat decoding errors
ferencd@0 13668 enum class error_handler_t
ferencd@0 13669 {
ferencd@0 13670 strict, ///< throw a type_error exception in case of invalid UTF-8
ferencd@0 13671 replace, ///< replace invalid UTF-8 sequences with U+FFFD
ferencd@0 13672 ignore ///< ignore invalid UTF-8 sequences
ferencd@0 13673 };
ferencd@0 13674
ferencd@0 13675 template<typename BasicJsonType>
ferencd@0 13676 class serializer
ferencd@0 13677 {
ferencd@0 13678 using string_t = typename BasicJsonType::string_t;
ferencd@0 13679 using number_float_t = typename BasicJsonType::number_float_t;
ferencd@0 13680 using number_integer_t = typename BasicJsonType::number_integer_t;
ferencd@0 13681 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
ferencd@0 13682 static constexpr std::uint8_t UTF8_ACCEPT = 0;
ferencd@0 13683 static constexpr std::uint8_t UTF8_REJECT = 1;
ferencd@0 13684
ferencd@0 13685 public:
ferencd@0 13686 /*!
ferencd@0 13687 @param[in] s output stream to serialize to
ferencd@0 13688 @param[in] ichar indentation character to use
ferencd@0 13689 @param[in] error_handler_ how to react on decoding errors
ferencd@0 13690 */
ferencd@0 13691 serializer(output_adapter_t<char> s, const char ichar,
ferencd@0 13692 error_handler_t error_handler_ = error_handler_t::strict)
ferencd@0 13693 : o(std::move(s))
ferencd@0 13694 , loc(std::localeconv())
ferencd@0 13695 , thousands_sep(loc->thousands_sep == nullptr ? '\0' : * (loc->thousands_sep))
ferencd@0 13696 , decimal_point(loc->decimal_point == nullptr ? '\0' : * (loc->decimal_point))
ferencd@0 13697 , indent_char(ichar)
ferencd@0 13698 , indent_string(512, indent_char)
ferencd@0 13699 , error_handler(error_handler_)
ferencd@0 13700 {}
ferencd@0 13701
ferencd@0 13702 // delete because of pointer members
ferencd@0 13703 serializer(const serializer&) = delete;
ferencd@0 13704 serializer& operator=(const serializer&) = delete;
ferencd@0 13705 serializer(serializer&&) = delete;
ferencd@0 13706 serializer& operator=(serializer&&) = delete;
ferencd@0 13707 ~serializer() = default;
ferencd@0 13708
ferencd@0 13709 /*!
ferencd@0 13710 @brief internal implementation of the serialization function
ferencd@0 13711
ferencd@0 13712 This function is called by the public member function dump and organizes
ferencd@0 13713 the serialization internally. The indentation level is propagated as
ferencd@0 13714 additional parameter. In case of arrays and objects, the function is
ferencd@0 13715 called recursively.
ferencd@0 13716
ferencd@0 13717 - strings and object keys are escaped using `escape_string()`
ferencd@0 13718 - integer numbers are converted implicitly via `operator<<`
ferencd@0 13719 - floating-point numbers are converted to a string using `"%g"` format
ferencd@0 13720
ferencd@0 13721 @param[in] val value to serialize
ferencd@0 13722 @param[in] pretty_print whether the output shall be pretty-printed
ferencd@0 13723 @param[in] indent_step the indent level
ferencd@0 13724 @param[in] current_indent the current indent level (only used internally)
ferencd@0 13725 */
ferencd@0 13726 void dump(const BasicJsonType& val, const bool pretty_print,
ferencd@0 13727 const bool ensure_ascii,
ferencd@0 13728 const unsigned int indent_step,
ferencd@0 13729 const unsigned int current_indent = 0)
ferencd@0 13730 {
ferencd@0 13731 switch (val.m_type)
ferencd@0 13732 {
ferencd@0 13733 case value_t::object:
ferencd@0 13734 {
ferencd@0 13735 if (val.m_value.object->empty())
ferencd@0 13736 {
ferencd@0 13737 o->write_characters("{}", 2);
ferencd@0 13738 return;
ferencd@0 13739 }
ferencd@0 13740
ferencd@0 13741 if (pretty_print)
ferencd@0 13742 {
ferencd@0 13743 o->write_characters("{\n", 2);
ferencd@0 13744
ferencd@0 13745 // variable to hold indentation for recursive calls
ferencd@0 13746 const auto new_indent = current_indent + indent_step;
ferencd@0 13747 if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
ferencd@0 13748 {
ferencd@0 13749 indent_string.resize(indent_string.size() * 2, ' ');
ferencd@0 13750 }
ferencd@0 13751
ferencd@0 13752 // first n-1 elements
ferencd@0 13753 auto i = val.m_value.object->cbegin();
ferencd@0 13754 for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
ferencd@0 13755 {
ferencd@0 13756 o->write_characters(indent_string.c_str(), new_indent);
ferencd@0 13757 o->write_character('\"');
ferencd@0 13758 dump_escaped(i->first, ensure_ascii);
ferencd@0 13759 o->write_characters("\": ", 3);
ferencd@0 13760 dump(i->second, true, ensure_ascii, indent_step, new_indent);
ferencd@0 13761 o->write_characters(",\n", 2);
ferencd@0 13762 }
ferencd@0 13763
ferencd@0 13764 // last element
ferencd@0 13765 assert(i != val.m_value.object->cend());
ferencd@0 13766 assert(std::next(i) == val.m_value.object->cend());
ferencd@0 13767 o->write_characters(indent_string.c_str(), new_indent);
ferencd@0 13768 o->write_character('\"');
ferencd@0 13769 dump_escaped(i->first, ensure_ascii);
ferencd@0 13770 o->write_characters("\": ", 3);
ferencd@0 13771 dump(i->second, true, ensure_ascii, indent_step, new_indent);
ferencd@0 13772
ferencd@0 13773 o->write_character('\n');
ferencd@0 13774 o->write_characters(indent_string.c_str(), current_indent);
ferencd@0 13775 o->write_character('}');
ferencd@0 13776 }
ferencd@0 13777 else
ferencd@0 13778 {
ferencd@0 13779 o->write_character('{');
ferencd@0 13780
ferencd@0 13781 // first n-1 elements
ferencd@0 13782 auto i = val.m_value.object->cbegin();
ferencd@0 13783 for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)
ferencd@0 13784 {
ferencd@0 13785 o->write_character('\"');
ferencd@0 13786 dump_escaped(i->first, ensure_ascii);
ferencd@0 13787 o->write_characters("\":", 2);
ferencd@0 13788 dump(i->second, false, ensure_ascii, indent_step, current_indent);
ferencd@0 13789 o->write_character(',');
ferencd@0 13790 }
ferencd@0 13791
ferencd@0 13792 // last element
ferencd@0 13793 assert(i != val.m_value.object->cend());
ferencd@0 13794 assert(std::next(i) == val.m_value.object->cend());
ferencd@0 13795 o->write_character('\"');
ferencd@0 13796 dump_escaped(i->first, ensure_ascii);
ferencd@0 13797 o->write_characters("\":", 2);
ferencd@0 13798 dump(i->second, false, ensure_ascii, indent_step, current_indent);
ferencd@0 13799
ferencd@0 13800 o->write_character('}');
ferencd@0 13801 }
ferencd@0 13802
ferencd@0 13803 return;
ferencd@0 13804 }
ferencd@0 13805
ferencd@0 13806 case value_t::array:
ferencd@0 13807 {
ferencd@0 13808 if (val.m_value.array->empty())
ferencd@0 13809 {
ferencd@0 13810 o->write_characters("[]", 2);
ferencd@0 13811 return;
ferencd@0 13812 }
ferencd@0 13813
ferencd@0 13814 if (pretty_print)
ferencd@0 13815 {
ferencd@0 13816 o->write_characters("[\n", 2);
ferencd@0 13817
ferencd@0 13818 // variable to hold indentation for recursive calls
ferencd@0 13819 const auto new_indent = current_indent + indent_step;
ferencd@0 13820 if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
ferencd@0 13821 {
ferencd@0 13822 indent_string.resize(indent_string.size() * 2, ' ');
ferencd@0 13823 }
ferencd@0 13824
ferencd@0 13825 // first n-1 elements
ferencd@0 13826 for (auto i = val.m_value.array->cbegin();
ferencd@0 13827 i != val.m_value.array->cend() - 1; ++i)
ferencd@0 13828 {
ferencd@0 13829 o->write_characters(indent_string.c_str(), new_indent);
ferencd@0 13830 dump(*i, true, ensure_ascii, indent_step, new_indent);
ferencd@0 13831 o->write_characters(",\n", 2);
ferencd@0 13832 }
ferencd@0 13833
ferencd@0 13834 // last element
ferencd@0 13835 assert(not val.m_value.array->empty());
ferencd@0 13836 o->write_characters(indent_string.c_str(), new_indent);
ferencd@0 13837 dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
ferencd@0 13838
ferencd@0 13839 o->write_character('\n');
ferencd@0 13840 o->write_characters(indent_string.c_str(), current_indent);
ferencd@0 13841 o->write_character(']');
ferencd@0 13842 }
ferencd@0 13843 else
ferencd@0 13844 {
ferencd@0 13845 o->write_character('[');
ferencd@0 13846
ferencd@0 13847 // first n-1 elements
ferencd@0 13848 for (auto i = val.m_value.array->cbegin();
ferencd@0 13849 i != val.m_value.array->cend() - 1; ++i)
ferencd@0 13850 {
ferencd@0 13851 dump(*i, false, ensure_ascii, indent_step, current_indent);
ferencd@0 13852 o->write_character(',');
ferencd@0 13853 }
ferencd@0 13854
ferencd@0 13855 // last element
ferencd@0 13856 assert(not val.m_value.array->empty());
ferencd@0 13857 dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
ferencd@0 13858
ferencd@0 13859 o->write_character(']');
ferencd@0 13860 }
ferencd@0 13861
ferencd@0 13862 return;
ferencd@0 13863 }
ferencd@0 13864
ferencd@0 13865 case value_t::string:
ferencd@0 13866 {
ferencd@0 13867 o->write_character('\"');
ferencd@0 13868 dump_escaped(*val.m_value.string, ensure_ascii);
ferencd@0 13869 o->write_character('\"');
ferencd@0 13870 return;
ferencd@0 13871 }
ferencd@0 13872
ferencd@0 13873 case value_t::boolean:
ferencd@0 13874 {
ferencd@0 13875 if (val.m_value.boolean)
ferencd@0 13876 {
ferencd@0 13877 o->write_characters("true", 4);
ferencd@0 13878 }
ferencd@0 13879 else
ferencd@0 13880 {
ferencd@0 13881 o->write_characters("false", 5);
ferencd@0 13882 }
ferencd@0 13883 return;
ferencd@0 13884 }
ferencd@0 13885
ferencd@0 13886 case value_t::number_integer:
ferencd@0 13887 {
ferencd@0 13888 dump_integer(val.m_value.number_integer);
ferencd@0 13889 return;
ferencd@0 13890 }
ferencd@0 13891
ferencd@0 13892 case value_t::number_unsigned:
ferencd@0 13893 {
ferencd@0 13894 dump_integer(val.m_value.number_unsigned);
ferencd@0 13895 return;
ferencd@0 13896 }
ferencd@0 13897
ferencd@0 13898 case value_t::number_float:
ferencd@0 13899 {
ferencd@0 13900 dump_float(val.m_value.number_float);
ferencd@0 13901 return;
ferencd@0 13902 }
ferencd@0 13903
ferencd@0 13904 case value_t::discarded:
ferencd@0 13905 {
ferencd@0 13906 o->write_characters("<discarded>", 11);
ferencd@0 13907 return;
ferencd@0 13908 }
ferencd@0 13909
ferencd@0 13910 case value_t::null:
ferencd@0 13911 {
ferencd@0 13912 o->write_characters("null", 4);
ferencd@0 13913 return;
ferencd@0 13914 }
ferencd@0 13915
ferencd@0 13916 default: // LCOV_EXCL_LINE
ferencd@0 13917 assert(false); // LCOV_EXCL_LINE
ferencd@0 13918 }
ferencd@0 13919 }
ferencd@0 13920
ferencd@0 13921 private:
ferencd@0 13922 /*!
ferencd@0 13923 @brief dump escaped string
ferencd@0 13924
ferencd@0 13925 Escape a string by replacing certain special characters by a sequence of an
ferencd@0 13926 escape character (backslash) and another character and other control
ferencd@0 13927 characters by a sequence of "\u" followed by a four-digit hex
ferencd@0 13928 representation. The escaped string is written to output stream @a o.
ferencd@0 13929
ferencd@0 13930 @param[in] s the string to escape
ferencd@0 13931 @param[in] ensure_ascii whether to escape non-ASCII characters with
ferencd@0 13932 \uXXXX sequences
ferencd@0 13933
ferencd@0 13934 @complexity Linear in the length of string @a s.
ferencd@0 13935 */
ferencd@0 13936 void dump_escaped(const string_t& s, const bool ensure_ascii)
ferencd@0 13937 {
ferencd@0 13938 std::uint32_t codepoint;
ferencd@0 13939 std::uint8_t state = UTF8_ACCEPT;
ferencd@0 13940 std::size_t bytes = 0; // number of bytes written to string_buffer
ferencd@0 13941
ferencd@0 13942 // number of bytes written at the point of the last valid byte
ferencd@0 13943 std::size_t bytes_after_last_accept = 0;
ferencd@0 13944 std::size_t undumped_chars = 0;
ferencd@0 13945
ferencd@0 13946 for (std::size_t i = 0; i < s.size(); ++i)
ferencd@0 13947 {
ferencd@0 13948 const auto byte = static_cast<uint8_t>(s[i]);
ferencd@0 13949
ferencd@0 13950 switch (decode(state, codepoint, byte))
ferencd@0 13951 {
ferencd@0 13952 case UTF8_ACCEPT: // decode found a new code point
ferencd@0 13953 {
ferencd@0 13954 switch (codepoint)
ferencd@0 13955 {
ferencd@0 13956 case 0x08: // backspace
ferencd@0 13957 {
ferencd@0 13958 string_buffer[bytes++] = '\\';
ferencd@0 13959 string_buffer[bytes++] = 'b';
ferencd@0 13960 break;
ferencd@0 13961 }
ferencd@0 13962
ferencd@0 13963 case 0x09: // horizontal tab
ferencd@0 13964 {
ferencd@0 13965 string_buffer[bytes++] = '\\';
ferencd@0 13966 string_buffer[bytes++] = 't';
ferencd@0 13967 break;
ferencd@0 13968 }
ferencd@0 13969
ferencd@0 13970 case 0x0A: // newline
ferencd@0 13971 {
ferencd@0 13972 string_buffer[bytes++] = '\\';
ferencd@0 13973 string_buffer[bytes++] = 'n';
ferencd@0 13974 break;
ferencd@0 13975 }
ferencd@0 13976
ferencd@0 13977 case 0x0C: // formfeed
ferencd@0 13978 {
ferencd@0 13979 string_buffer[bytes++] = '\\';
ferencd@0 13980 string_buffer[bytes++] = 'f';
ferencd@0 13981 break;
ferencd@0 13982 }
ferencd@0 13983
ferencd@0 13984 case 0x0D: // carriage return
ferencd@0 13985 {
ferencd@0 13986 string_buffer[bytes++] = '\\';
ferencd@0 13987 string_buffer[bytes++] = 'r';
ferencd@0 13988 break;
ferencd@0 13989 }
ferencd@0 13990
ferencd@0 13991 case 0x22: // quotation mark
ferencd@0 13992 {
ferencd@0 13993 string_buffer[bytes++] = '\\';
ferencd@0 13994 string_buffer[bytes++] = '\"';
ferencd@0 13995 break;
ferencd@0 13996 }
ferencd@0 13997
ferencd@0 13998 case 0x5C: // reverse solidus
ferencd@0 13999 {
ferencd@0 14000 string_buffer[bytes++] = '\\';
ferencd@0 14001 string_buffer[bytes++] = '\\';
ferencd@0 14002 break;
ferencd@0 14003 }
ferencd@0 14004
ferencd@0 14005 default:
ferencd@0 14006 {
ferencd@0 14007 // escape control characters (0x00..0x1F) or, if
ferencd@0 14008 // ensure_ascii parameter is used, non-ASCII characters
ferencd@0 14009 if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F)))
ferencd@0 14010 {
ferencd@0 14011 if (codepoint <= 0xFFFF)
ferencd@0 14012 {
ferencd@0 14013 (std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
ferencd@0 14014 static_cast<std::uint16_t>(codepoint));
ferencd@0 14015 bytes += 6;
ferencd@0 14016 }
ferencd@0 14017 else
ferencd@0 14018 {
ferencd@0 14019 (std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
ferencd@0 14020 static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
ferencd@0 14021 static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));
ferencd@0 14022 bytes += 12;
ferencd@0 14023 }
ferencd@0 14024 }
ferencd@0 14025 else
ferencd@0 14026 {
ferencd@0 14027 // copy byte to buffer (all previous bytes
ferencd@0 14028 // been copied have in default case above)
ferencd@0 14029 string_buffer[bytes++] = s[i];
ferencd@0 14030 }
ferencd@0 14031 break;
ferencd@0 14032 }
ferencd@0 14033 }
ferencd@0 14034
ferencd@0 14035 // write buffer and reset index; there must be 13 bytes
ferencd@0 14036 // left, as this is the maximal number of bytes to be
ferencd@0 14037 // written ("\uxxxx\uxxxx\0") for one code point
ferencd@0 14038 if (string_buffer.size() - bytes < 13)
ferencd@0 14039 {
ferencd@0 14040 o->write_characters(string_buffer.data(), bytes);
ferencd@0 14041 bytes = 0;
ferencd@0 14042 }
ferencd@0 14043
ferencd@0 14044 // remember the byte position of this accept
ferencd@0 14045 bytes_after_last_accept = bytes;
ferencd@0 14046 undumped_chars = 0;
ferencd@0 14047 break;
ferencd@0 14048 }
ferencd@0 14049
ferencd@0 14050 case UTF8_REJECT: // decode found invalid UTF-8 byte
ferencd@0 14051 {
ferencd@0 14052 switch (error_handler)
ferencd@0 14053 {
ferencd@0 14054 case error_handler_t::strict:
ferencd@0 14055 {
ferencd@0 14056 std::string sn(3, '\0');
ferencd@0 14057 (std::snprintf)(&sn[0], sn.size(), "%.2X", byte);
ferencd@0 14058 JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn));
ferencd@0 14059 }
ferencd@0 14060
ferencd@0 14061 case error_handler_t::ignore:
ferencd@0 14062 case error_handler_t::replace:
ferencd@0 14063 {
ferencd@0 14064 // in case we saw this character the first time, we
ferencd@0 14065 // would like to read it again, because the byte
ferencd@0 14066 // may be OK for itself, but just not OK for the
ferencd@0 14067 // previous sequence
ferencd@0 14068 if (undumped_chars > 0)
ferencd@0 14069 {
ferencd@0 14070 --i;
ferencd@0 14071 }
ferencd@0 14072
ferencd@0 14073 // reset length buffer to the last accepted index;
ferencd@0 14074 // thus removing/ignoring the invalid characters
ferencd@0 14075 bytes = bytes_after_last_accept;
ferencd@0 14076
ferencd@0 14077 if (error_handler == error_handler_t::replace)
ferencd@0 14078 {
ferencd@0 14079 // add a replacement character
ferencd@0 14080 if (ensure_ascii)
ferencd@0 14081 {
ferencd@0 14082 string_buffer[bytes++] = '\\';
ferencd@0 14083 string_buffer[bytes++] = 'u';
ferencd@0 14084 string_buffer[bytes++] = 'f';
ferencd@0 14085 string_buffer[bytes++] = 'f';
ferencd@0 14086 string_buffer[bytes++] = 'f';
ferencd@0 14087 string_buffer[bytes++] = 'd';
ferencd@0 14088 }
ferencd@0 14089 else
ferencd@0 14090 {
ferencd@0 14091 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xEF');
ferencd@0 14092 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF');
ferencd@0 14093 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD');
ferencd@0 14094 }
ferencd@0 14095
ferencd@0 14096 // write buffer and reset index; there must be 13 bytes
ferencd@0 14097 // left, as this is the maximal number of bytes to be
ferencd@0 14098 // written ("\uxxxx\uxxxx\0") for one code point
ferencd@0 14099 if (string_buffer.size() - bytes < 13)
ferencd@0 14100 {
ferencd@0 14101 o->write_characters(string_buffer.data(), bytes);
ferencd@0 14102 bytes = 0;
ferencd@0 14103 }
ferencd@0 14104
ferencd@0 14105 bytes_after_last_accept = bytes;
ferencd@0 14106 }
ferencd@0 14107
ferencd@0 14108 undumped_chars = 0;
ferencd@0 14109
ferencd@0 14110 // continue processing the string
ferencd@0 14111 state = UTF8_ACCEPT;
ferencd@0 14112 break;
ferencd@0 14113 }
ferencd@0 14114
ferencd@0 14115 default: // LCOV_EXCL_LINE
ferencd@0 14116 assert(false); // LCOV_EXCL_LINE
ferencd@0 14117 }
ferencd@0 14118 break;
ferencd@0 14119 }
ferencd@0 14120
ferencd@0 14121 default: // decode found yet incomplete multi-byte code point
ferencd@0 14122 {
ferencd@0 14123 if (not ensure_ascii)
ferencd@0 14124 {
ferencd@0 14125 // code point will not be escaped - copy byte to buffer
ferencd@0 14126 string_buffer[bytes++] = s[i];
ferencd@0 14127 }
ferencd@0 14128 ++undumped_chars;
ferencd@0 14129 break;
ferencd@0 14130 }
ferencd@0 14131 }
ferencd@0 14132 }
ferencd@0 14133
ferencd@0 14134 // we finished processing the string
ferencd@0 14135 if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT))
ferencd@0 14136 {
ferencd@0 14137 // write buffer
ferencd@0 14138 if (bytes > 0)
ferencd@0 14139 {
ferencd@0 14140 o->write_characters(string_buffer.data(), bytes);
ferencd@0 14141 }
ferencd@0 14142 }
ferencd@0 14143 else
ferencd@0 14144 {
ferencd@0 14145 // we finish reading, but do not accept: string was incomplete
ferencd@0 14146 switch (error_handler)
ferencd@0 14147 {
ferencd@0 14148 case error_handler_t::strict:
ferencd@0 14149 {
ferencd@0 14150 std::string sn(3, '\0');
ferencd@0 14151 (std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast<std::uint8_t>(s.back()));
ferencd@0 14152 JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn));
ferencd@0 14153 }
ferencd@0 14154
ferencd@0 14155 case error_handler_t::ignore:
ferencd@0 14156 {
ferencd@0 14157 // write all accepted bytes
ferencd@0 14158 o->write_characters(string_buffer.data(), bytes_after_last_accept);
ferencd@0 14159 break;
ferencd@0 14160 }
ferencd@0 14161
ferencd@0 14162 case error_handler_t::replace:
ferencd@0 14163 {
ferencd@0 14164 // write all accepted bytes
ferencd@0 14165 o->write_characters(string_buffer.data(), bytes_after_last_accept);
ferencd@0 14166 // add a replacement character
ferencd@0 14167 if (ensure_ascii)
ferencd@0 14168 {
ferencd@0 14169 o->write_characters("\\ufffd", 6);
ferencd@0 14170 }
ferencd@0 14171 else
ferencd@0 14172 {
ferencd@0 14173 o->write_characters("\xEF\xBF\xBD", 3);
ferencd@0 14174 }
ferencd@0 14175 break;
ferencd@0 14176 }
ferencd@0 14177
ferencd@0 14178 default: // LCOV_EXCL_LINE
ferencd@0 14179 assert(false); // LCOV_EXCL_LINE
ferencd@0 14180 }
ferencd@0 14181 }
ferencd@0 14182 }
ferencd@0 14183
ferencd@0 14184 /*!
ferencd@0 14185 @brief count digits
ferencd@0 14186
ferencd@0 14187 Count the number of decimal (base 10) digits for an input unsigned integer.
ferencd@0 14188
ferencd@0 14189 @param[in] x unsigned integer number to count its digits
ferencd@0 14190 @return number of decimal digits
ferencd@0 14191 */
ferencd@0 14192 inline unsigned int count_digits(number_unsigned_t x) noexcept
ferencd@0 14193 {
ferencd@0 14194 unsigned int n_digits = 1;
ferencd@0 14195 for (;;)
ferencd@0 14196 {
ferencd@0 14197 if (x < 10)
ferencd@0 14198 {
ferencd@0 14199 return n_digits;
ferencd@0 14200 }
ferencd@0 14201 if (x < 100)
ferencd@0 14202 {
ferencd@0 14203 return n_digits + 1;
ferencd@0 14204 }
ferencd@0 14205 if (x < 1000)
ferencd@0 14206 {
ferencd@0 14207 return n_digits + 2;
ferencd@0 14208 }
ferencd@0 14209 if (x < 10000)
ferencd@0 14210 {
ferencd@0 14211 return n_digits + 3;
ferencd@0 14212 }
ferencd@0 14213 x = x / 10000u;
ferencd@0 14214 n_digits += 4;
ferencd@0 14215 }
ferencd@0 14216 }
ferencd@0 14217
ferencd@0 14218 /*!
ferencd@0 14219 @brief dump an integer
ferencd@0 14220
ferencd@0 14221 Dump a given integer to output stream @a o. Works internally with
ferencd@0 14222 @a number_buffer.
ferencd@0 14223
ferencd@0 14224 @param[in] x integer number (signed or unsigned) to dump
ferencd@0 14225 @tparam NumberType either @a number_integer_t or @a number_unsigned_t
ferencd@0 14226 */
ferencd@0 14227 template<typename NumberType, detail::enable_if_t<
ferencd@0 14228 std::is_same<NumberType, number_unsigned_t>::value or
ferencd@0 14229 std::is_same<NumberType, number_integer_t>::value,
ferencd@0 14230 int> = 0>
ferencd@0 14231 void dump_integer(NumberType x)
ferencd@0 14232 {
ferencd@0 14233 static constexpr std::array<std::array<char, 2>, 100> digits_to_99
ferencd@0 14234 {
ferencd@0 14235 {
ferencd@0 14236 {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},
ferencd@0 14237 {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}},
ferencd@0 14238 {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}},
ferencd@0 14239 {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}},
ferencd@0 14240 {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}},
ferencd@0 14241 {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}},
ferencd@0 14242 {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}},
ferencd@0 14243 {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}},
ferencd@0 14244 {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}},
ferencd@0 14245 {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},
ferencd@0 14246 }
ferencd@0 14247 };
ferencd@0 14248
ferencd@0 14249 // special case for "0"
ferencd@0 14250 if (x == 0)
ferencd@0 14251 {
ferencd@0 14252 o->write_character('0');
ferencd@0 14253 return;
ferencd@0 14254 }
ferencd@0 14255
ferencd@0 14256 // use a pointer to fill the buffer
ferencd@0 14257 auto buffer_ptr = number_buffer.begin();
ferencd@0 14258
ferencd@0 14259 const bool is_negative = std::is_same<NumberType, number_integer_t>::value and not(x >= 0); // see issue #755
ferencd@0 14260 number_unsigned_t abs_value;
ferencd@0 14261
ferencd@0 14262 unsigned int n_chars;
ferencd@0 14263
ferencd@0 14264 if (is_negative)
ferencd@0 14265 {
ferencd@0 14266 *buffer_ptr = '-';
ferencd@0 14267 abs_value = static_cast<number_unsigned_t>(std::abs(static_cast<std::intmax_t>(x)));
ferencd@0 14268
ferencd@0 14269 // account one more byte for the minus sign
ferencd@0 14270 n_chars = 1 + count_digits(abs_value);
ferencd@0 14271 }
ferencd@0 14272 else
ferencd@0 14273 {
ferencd@0 14274 abs_value = static_cast<number_unsigned_t>(x);
ferencd@0 14275 n_chars = count_digits(abs_value);
ferencd@0 14276 }
ferencd@0 14277
ferencd@0 14278 // spare 1 byte for '\0'
ferencd@0 14279 assert(n_chars < number_buffer.size() - 1);
ferencd@0 14280
ferencd@0 14281 // jump to the end to generate the string from backward
ferencd@0 14282 // so we later avoid reversing the result
ferencd@0 14283 buffer_ptr += n_chars;
ferencd@0 14284
ferencd@0 14285 // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu
ferencd@0 14286 // See: https://www.youtube.com/watch?v=o4-CwDo2zpg
ferencd@0 14287 while (abs_value >= 100)
ferencd@0 14288 {
ferencd@0 14289 const auto digits_index = static_cast<unsigned>((abs_value % 100));
ferencd@0 14290 abs_value /= 100;
ferencd@0 14291 *(--buffer_ptr) = digits_to_99[digits_index][1];
ferencd@0 14292 *(--buffer_ptr) = digits_to_99[digits_index][0];
ferencd@0 14293 }
ferencd@0 14294
ferencd@0 14295 if (abs_value >= 10)
ferencd@0 14296 {
ferencd@0 14297 const auto digits_index = static_cast<unsigned>(abs_value);
ferencd@0 14298 *(--buffer_ptr) = digits_to_99[digits_index][1];
ferencd@0 14299 *(--buffer_ptr) = digits_to_99[digits_index][0];
ferencd@0 14300 }
ferencd@0 14301 else
ferencd@0 14302 {
ferencd@0 14303 *(--buffer_ptr) = static_cast<char>('0' + abs_value);
ferencd@0 14304 }
ferencd@0 14305
ferencd@0 14306 o->write_characters(number_buffer.data(), n_chars);
ferencd@0 14307 }
ferencd@0 14308
ferencd@0 14309 /*!
ferencd@0 14310 @brief dump a floating-point number
ferencd@0 14311
ferencd@0 14312 Dump a given floating-point number to output stream @a o. Works internally
ferencd@0 14313 with @a number_buffer.
ferencd@0 14314
ferencd@0 14315 @param[in] x floating-point number to dump
ferencd@0 14316 */
ferencd@0 14317 void dump_float(number_float_t x)
ferencd@0 14318 {
ferencd@0 14319 // NaN / inf
ferencd@0 14320 if (not std::isfinite(x))
ferencd@0 14321 {
ferencd@0 14322 o->write_characters("null", 4);
ferencd@0 14323 return;
ferencd@0 14324 }
ferencd@0 14325
ferencd@0 14326 // If number_float_t is an IEEE-754 single or double precision number,
ferencd@0 14327 // use the Grisu2 algorithm to produce short numbers which are
ferencd@0 14328 // guaranteed to round-trip, using strtof and strtod, resp.
ferencd@0 14329 //
ferencd@0 14330 // NB: The test below works if <long double> == <double>.
ferencd@0 14331 static constexpr bool is_ieee_single_or_double
ferencd@0 14332 = (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 24 and std::numeric_limits<number_float_t>::max_exponent == 128) or
ferencd@0 14333 (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 53 and std::numeric_limits<number_float_t>::max_exponent == 1024);
ferencd@0 14334
ferencd@0 14335 dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
ferencd@0 14336 }
ferencd@0 14337
ferencd@0 14338 void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
ferencd@0 14339 {
ferencd@0 14340 char* begin = number_buffer.data();
ferencd@0 14341 char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
ferencd@0 14342
ferencd@0 14343 o->write_characters(begin, static_cast<size_t>(end - begin));
ferencd@0 14344 }
ferencd@0 14345
ferencd@0 14346 void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
ferencd@0 14347 {
ferencd@0 14348 // get number of digits for a float -> text -> float round-trip
ferencd@0 14349 static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;
ferencd@0 14350
ferencd@0 14351 // the actual conversion
ferencd@0 14352 std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
ferencd@0 14353
ferencd@0 14354 // negative value indicates an error
ferencd@0 14355 assert(len > 0);
ferencd@0 14356 // check if buffer was large enough
ferencd@0 14357 assert(static_cast<std::size_t>(len) < number_buffer.size());
ferencd@0 14358
ferencd@0 14359 // erase thousands separator
ferencd@0 14360 if (thousands_sep != '\0')
ferencd@0 14361 {
ferencd@0 14362 const auto end = std::remove(number_buffer.begin(),
ferencd@0 14363 number_buffer.begin() + len, thousands_sep);
ferencd@0 14364 std::fill(end, number_buffer.end(), '\0');
ferencd@0 14365 assert((end - number_buffer.begin()) <= len);
ferencd@0 14366 len = (end - number_buffer.begin());
ferencd@0 14367 }
ferencd@0 14368
ferencd@0 14369 // convert decimal point to '.'
ferencd@0 14370 if (decimal_point != '\0' and decimal_point != '.')
ferencd@0 14371 {
ferencd@0 14372 const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
ferencd@0 14373 if (dec_pos != number_buffer.end())
ferencd@0 14374 {
ferencd@0 14375 *dec_pos = '.';
ferencd@0 14376 }
ferencd@0 14377 }
ferencd@0 14378
ferencd@0 14379 o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));
ferencd@0 14380
ferencd@0 14381 // determine if need to append ".0"
ferencd@0 14382 const bool value_is_int_like =
ferencd@0 14383 std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
ferencd@0 14384 [](char c)
ferencd@0 14385 {
ferencd@0 14386 return c == '.' or c == 'e';
ferencd@0 14387 });
ferencd@0 14388
ferencd@0 14389 if (value_is_int_like)
ferencd@0 14390 {
ferencd@0 14391 o->write_characters(".0", 2);
ferencd@0 14392 }
ferencd@0 14393 }
ferencd@0 14394
ferencd@0 14395 /*!
ferencd@0 14396 @brief check whether a string is UTF-8 encoded
ferencd@0 14397
ferencd@0 14398 The function checks each byte of a string whether it is UTF-8 encoded. The
ferencd@0 14399 result of the check is stored in the @a state parameter. The function must
ferencd@0 14400 be called initially with state 0 (accept). State 1 means the string must
ferencd@0 14401 be rejected, because the current byte is not allowed. If the string is
ferencd@0 14402 completely processed, but the state is non-zero, the string ended
ferencd@0 14403 prematurely; that is, the last byte indicated more bytes should have
ferencd@0 14404 followed.
ferencd@0 14405
ferencd@0 14406 @param[in,out] state the state of the decoding
ferencd@0 14407 @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT)
ferencd@0 14408 @param[in] byte next byte to decode
ferencd@0 14409 @return new state
ferencd@0 14410
ferencd@0 14411 @note The function has been edited: a std::array is used.
ferencd@0 14412
ferencd@0 14413 @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
ferencd@0 14414 @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
ferencd@0 14415 */
ferencd@0 14416 static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept
ferencd@0 14417 {
ferencd@0 14418 static const std::array<std::uint8_t, 400> utf8d =
ferencd@0 14419 {
ferencd@0 14420 {
ferencd@0 14421 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
ferencd@0 14422 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
ferencd@0 14423 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
ferencd@0 14424 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
ferencd@0 14425 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
ferencd@0 14426 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
ferencd@0 14427 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
ferencd@0 14428 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF
ferencd@0 14429 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF
ferencd@0 14430 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
ferencd@0 14431 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
ferencd@0 14432 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
ferencd@0 14433 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
ferencd@0 14434 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
ferencd@0 14435 }
ferencd@0 14436 };
ferencd@0 14437
ferencd@0 14438 const std::uint8_t type = utf8d[byte];
ferencd@0 14439
ferencd@0 14440 codep = (state != UTF8_ACCEPT)
ferencd@0 14441 ? (byte & 0x3fu) | (codep << 6u)
ferencd@0 14442 : (0xFFu >> type) & (byte);
ferencd@0 14443
ferencd@0 14444 state = utf8d[256u + state * 16u + type];
ferencd@0 14445 return state;
ferencd@0 14446 }
ferencd@0 14447
ferencd@0 14448 private:
ferencd@0 14449 /// the output of the serializer
ferencd@0 14450 output_adapter_t<char> o = nullptr;
ferencd@0 14451
ferencd@0 14452 /// a (hopefully) large enough character buffer
ferencd@0 14453 std::array<char, 64> number_buffer{{}};
ferencd@0 14454
ferencd@0 14455 /// the locale
ferencd@0 14456 const std::lconv* loc = nullptr;
ferencd@0 14457 /// the locale's thousand separator character
ferencd@0 14458 const char thousands_sep = '\0';
ferencd@0 14459 /// the locale's decimal point character
ferencd@0 14460 const char decimal_point = '\0';
ferencd@0 14461
ferencd@0 14462 /// string buffer
ferencd@0 14463 std::array<char, 512> string_buffer{{}};
ferencd@0 14464
ferencd@0 14465 /// the indentation character
ferencd@0 14466 const char indent_char;
ferencd@0 14467 /// the indentation string
ferencd@0 14468 string_t indent_string;
ferencd@0 14469
ferencd@0 14470 /// error_handler how to react on decoding errors
ferencd@0 14471 const error_handler_t error_handler;
ferencd@0 14472 };
ferencd@0 14473 } // namespace detail
ferencd@0 14474 } // namespace nlohmann
ferencd@0 14475
ferencd@0 14476 // #include <nlohmann/detail/value_t.hpp>
ferencd@0 14477
ferencd@0 14478 // #include <nlohmann/json_fwd.hpp>
ferencd@0 14479
ferencd@0 14480
ferencd@0 14481 /*!
ferencd@0 14482 @brief namespace for Niels Lohmann
ferencd@0 14483 @see https://github.com/nlohmann
ferencd@0 14484 @since version 1.0.0
ferencd@0 14485 */
ferencd@0 14486 namespace nlohmann
ferencd@0 14487 {
ferencd@0 14488
ferencd@0 14489 /*!
ferencd@0 14490 @brief a class to store JSON values
ferencd@0 14491
ferencd@0 14492 @tparam ObjectType type for JSON objects (`std::map` by default; will be used
ferencd@0 14493 in @ref object_t)
ferencd@0 14494 @tparam ArrayType type for JSON arrays (`std::vector` by default; will be used
ferencd@0 14495 in @ref array_t)
ferencd@0 14496 @tparam StringType type for JSON strings and object keys (`std::string` by
ferencd@0 14497 default; will be used in @ref string_t)
ferencd@0 14498 @tparam BooleanType type for JSON booleans (`bool` by default; will be used
ferencd@0 14499 in @ref boolean_t)
ferencd@0 14500 @tparam NumberIntegerType type for JSON integer numbers (`int64_t` by
ferencd@0 14501 default; will be used in @ref number_integer_t)
ferencd@0 14502 @tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
ferencd@0 14503 `uint64_t` by default; will be used in @ref number_unsigned_t)
ferencd@0 14504 @tparam NumberFloatType type for JSON floating-point numbers (`double` by
ferencd@0 14505 default; will be used in @ref number_float_t)
ferencd@0 14506 @tparam AllocatorType type of the allocator to use (`std::allocator` by
ferencd@0 14507 default)
ferencd@0 14508 @tparam JSONSerializer the serializer to resolve internal calls to `to_json()`
ferencd@0 14509 and `from_json()` (@ref adl_serializer by default)
ferencd@0 14510
ferencd@0 14511 @requirement The class satisfies the following concept requirements:
ferencd@0 14512 - Basic
ferencd@0 14513 - [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible):
ferencd@0 14514 JSON values can be default constructed. The result will be a JSON null
ferencd@0 14515 value.
ferencd@0 14516 - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible):
ferencd@0 14517 A JSON value can be constructed from an rvalue argument.
ferencd@0 14518 - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible):
ferencd@0 14519 A JSON value can be copy-constructed from an lvalue expression.
ferencd@0 14520 - [MoveAssignable](https://en.cppreference.com/w/cpp/named_req/MoveAssignable):
ferencd@0 14521 A JSON value van be assigned from an rvalue argument.
ferencd@0 14522 - [CopyAssignable](https://en.cppreference.com/w/cpp/named_req/CopyAssignable):
ferencd@0 14523 A JSON value can be copy-assigned from an lvalue expression.
ferencd@0 14524 - [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible):
ferencd@0 14525 JSON values can be destructed.
ferencd@0 14526 - Layout
ferencd@0 14527 - [StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType):
ferencd@0 14528 JSON values have
ferencd@0 14529 [standard layout](https://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
ferencd@0 14530 All non-static data members are private and standard layout types, the
ferencd@0 14531 class has no virtual functions or (virtual) base classes.
ferencd@0 14532 - Library-wide
ferencd@0 14533 - [EqualityComparable](https://en.cppreference.com/w/cpp/named_req/EqualityComparable):
ferencd@0 14534 JSON values can be compared with `==`, see @ref
ferencd@0 14535 operator==(const_reference,const_reference).
ferencd@0 14536 - [LessThanComparable](https://en.cppreference.com/w/cpp/named_req/LessThanComparable):
ferencd@0 14537 JSON values can be compared with `<`, see @ref
ferencd@0 14538 operator<(const_reference,const_reference).
ferencd@0 14539 - [Swappable](https://en.cppreference.com/w/cpp/named_req/Swappable):
ferencd@0 14540 Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of
ferencd@0 14541 other compatible types, using unqualified function call @ref swap().
ferencd@0 14542 - [NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer):
ferencd@0 14543 JSON values can be compared against `std::nullptr_t` objects which are used
ferencd@0 14544 to model the `null` value.
ferencd@0 14545 - Container
ferencd@0 14546 - [Container](https://en.cppreference.com/w/cpp/named_req/Container):
ferencd@0 14547 JSON values can be used like STL containers and provide iterator access.
ferencd@0 14548 - [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer);
ferencd@0 14549 JSON values can be used like STL containers and provide reverse iterator
ferencd@0 14550 access.
ferencd@0 14551
ferencd@0 14552 @invariant The member variables @a m_value and @a m_type have the following
ferencd@0 14553 relationship:
ferencd@0 14554 - If `m_type == value_t::object`, then `m_value.object != nullptr`.
ferencd@0 14555 - If `m_type == value_t::array`, then `m_value.array != nullptr`.
ferencd@0 14556 - If `m_type == value_t::string`, then `m_value.string != nullptr`.
ferencd@0 14557 The invariants are checked by member function assert_invariant().
ferencd@0 14558
ferencd@0 14559 @internal
ferencd@0 14560 @note ObjectType trick from http://stackoverflow.com/a/9860911
ferencd@0 14561 @endinternal
ferencd@0 14562
ferencd@0 14563 @see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange
ferencd@0 14564 Format](http://rfc7159.net/rfc7159)
ferencd@0 14565
ferencd@0 14566 @since version 1.0.0
ferencd@0 14567
ferencd@0 14568 @nosubgrouping
ferencd@0 14569 */
ferencd@0 14570 NLOHMANN_BASIC_JSON_TPL_DECLARATION
ferencd@0 14571 class basic_json
ferencd@0 14572 {
ferencd@0 14573 private:
ferencd@0 14574 template<detail::value_t> friend struct detail::external_constructor;
ferencd@0 14575 friend ::nlohmann::json_pointer<basic_json>;
ferencd@0 14576 friend ::nlohmann::detail::parser<basic_json>;
ferencd@0 14577 friend ::nlohmann::detail::serializer<basic_json>;
ferencd@0 14578 template<typename BasicJsonType>
ferencd@0 14579 friend class ::nlohmann::detail::iter_impl;
ferencd@0 14580 template<typename BasicJsonType, typename CharType>
ferencd@0 14581 friend class ::nlohmann::detail::binary_writer;
ferencd@0 14582 template<typename BasicJsonType, typename SAX>
ferencd@0 14583 friend class ::nlohmann::detail::binary_reader;
ferencd@0 14584 template<typename BasicJsonType>
ferencd@0 14585 friend class ::nlohmann::detail::json_sax_dom_parser;
ferencd@0 14586 template<typename BasicJsonType>
ferencd@0 14587 friend class ::nlohmann::detail::json_sax_dom_callback_parser;
ferencd@0 14588
ferencd@0 14589 /// workaround type for MSVC
ferencd@0 14590 using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
ferencd@0 14591
ferencd@0 14592 // convenience aliases for types residing in namespace detail;
ferencd@0 14593 using lexer = ::nlohmann::detail::lexer<basic_json>;
ferencd@0 14594 using parser = ::nlohmann::detail::parser<basic_json>;
ferencd@0 14595
ferencd@0 14596 using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;
ferencd@0 14597 template<typename BasicJsonType>
ferencd@0 14598 using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;
ferencd@0 14599 template<typename BasicJsonType>
ferencd@0 14600 using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;
ferencd@0 14601 template<typename Iterator>
ferencd@0 14602 using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;
ferencd@0 14603 template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;
ferencd@0 14604
ferencd@0 14605 template<typename CharType>
ferencd@0 14606 using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;
ferencd@0 14607
ferencd@0 14608 using binary_reader = ::nlohmann::detail::binary_reader<basic_json>;
ferencd@0 14609 template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;
ferencd@0 14610
ferencd@0 14611 using serializer = ::nlohmann::detail::serializer<basic_json>;
ferencd@0 14612
ferencd@0 14613 public:
ferencd@0 14614 using value_t = detail::value_t;
ferencd@0 14615 /// JSON Pointer, see @ref nlohmann::json_pointer
ferencd@0 14616 using json_pointer = ::nlohmann::json_pointer<basic_json>;
ferencd@0 14617 template<typename T, typename SFINAE>
ferencd@0 14618 using json_serializer = JSONSerializer<T, SFINAE>;
ferencd@0 14619 /// how to treat decoding errors
ferencd@0 14620 using error_handler_t = detail::error_handler_t;
ferencd@0 14621 /// helper type for initializer lists of basic_json values
ferencd@0 14622 using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
ferencd@0 14623
ferencd@0 14624 using input_format_t = detail::input_format_t;
ferencd@0 14625 /// SAX interface type, see @ref nlohmann::json_sax
ferencd@0 14626 using json_sax_t = json_sax<basic_json>;
ferencd@0 14627
ferencd@0 14628 ////////////////
ferencd@0 14629 // exceptions //
ferencd@0 14630 ////////////////
ferencd@0 14631
ferencd@0 14632 /// @name exceptions
ferencd@0 14633 /// Classes to implement user-defined exceptions.
ferencd@0 14634 /// @{
ferencd@0 14635
ferencd@0 14636 /// @copydoc detail::exception
ferencd@0 14637 using exception = detail::exception;
ferencd@0 14638 /// @copydoc detail::parse_error
ferencd@0 14639 using parse_error = detail::parse_error;
ferencd@0 14640 /// @copydoc detail::invalid_iterator
ferencd@0 14641 using invalid_iterator = detail::invalid_iterator;
ferencd@0 14642 /// @copydoc detail::type_error
ferencd@0 14643 using type_error = detail::type_error;
ferencd@0 14644 /// @copydoc detail::out_of_range
ferencd@0 14645 using out_of_range = detail::out_of_range;
ferencd@0 14646 /// @copydoc detail::other_error
ferencd@0 14647 using other_error = detail::other_error;
ferencd@0 14648
ferencd@0 14649 /// @}
ferencd@0 14650
ferencd@0 14651
ferencd@0 14652 /////////////////////
ferencd@0 14653 // container types //
ferencd@0 14654 /////////////////////
ferencd@0 14655
ferencd@0 14656 /// @name container types
ferencd@0 14657 /// The canonic container types to use @ref basic_json like any other STL
ferencd@0 14658 /// container.
ferencd@0 14659 /// @{
ferencd@0 14660
ferencd@0 14661 /// the type of elements in a basic_json container
ferencd@0 14662 using value_type = basic_json;
ferencd@0 14663
ferencd@0 14664 /// the type of an element reference
ferencd@0 14665 using reference = value_type&;
ferencd@0 14666 /// the type of an element const reference
ferencd@0 14667 using const_reference = const value_type&;
ferencd@0 14668
ferencd@0 14669 /// a type to represent differences between iterators
ferencd@0 14670 using difference_type = std::ptrdiff_t;
ferencd@0 14671 /// a type to represent container sizes
ferencd@0 14672 using size_type = std::size_t;
ferencd@0 14673
ferencd@0 14674 /// the allocator type
ferencd@0 14675 using allocator_type = AllocatorType<basic_json>;
ferencd@0 14676
ferencd@0 14677 /// the type of an element pointer
ferencd@0 14678 using pointer = typename std::allocator_traits<allocator_type>::pointer;
ferencd@0 14679 /// the type of an element const pointer
ferencd@0 14680 using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
ferencd@0 14681
ferencd@0 14682 /// an iterator for a basic_json container
ferencd@0 14683 using iterator = iter_impl<basic_json>;
ferencd@0 14684 /// a const iterator for a basic_json container
ferencd@0 14685 using const_iterator = iter_impl<const basic_json>;
ferencd@0 14686 /// a reverse iterator for a basic_json container
ferencd@0 14687 using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
ferencd@0 14688 /// a const reverse iterator for a basic_json container
ferencd@0 14689 using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
ferencd@0 14690
ferencd@0 14691 /// @}
ferencd@0 14692
ferencd@0 14693
ferencd@0 14694 /*!
ferencd@0 14695 @brief returns the allocator associated with the container
ferencd@0 14696 */
ferencd@0 14697 static allocator_type get_allocator()
ferencd@0 14698 {
ferencd@0 14699 return allocator_type();
ferencd@0 14700 }
ferencd@0 14701
ferencd@0 14702 /*!
ferencd@0 14703 @brief returns version information on the library
ferencd@0 14704
ferencd@0 14705 This function returns a JSON object with information about the library,
ferencd@0 14706 including the version number and information on the platform and compiler.
ferencd@0 14707
ferencd@0 14708 @return JSON object holding version information
ferencd@0 14709 key | description
ferencd@0 14710 ----------- | ---------------
ferencd@0 14711 `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version).
ferencd@0 14712 `copyright` | The copyright line for the library as string.
ferencd@0 14713 `name` | The name of the library as string.
ferencd@0 14714 `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`.
ferencd@0 14715 `url` | The URL of the project as string.
ferencd@0 14716 `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string).
ferencd@0 14717
ferencd@0 14718 @liveexample{The following code shows an example output of the `meta()`
ferencd@0 14719 function.,meta}
ferencd@0 14720
ferencd@0 14721 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 14722 changes to any JSON value.
ferencd@0 14723
ferencd@0 14724 @complexity Constant.
ferencd@0 14725
ferencd@0 14726 @since 2.1.0
ferencd@0 14727 */
ferencd@0 14728 JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 14729 static basic_json meta()
ferencd@0 14730 {
ferencd@0 14731 basic_json result;
ferencd@0 14732
ferencd@0 14733 result["copyright"] = "(C) 2013-2017 Niels Lohmann";
ferencd@0 14734 result["name"] = "JSON for Modern C++";
ferencd@0 14735 result["url"] = "https://github.com/nlohmann/json";
ferencd@0 14736 result["version"]["string"] =
ferencd@0 14737 std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." +
ferencd@0 14738 std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." +
ferencd@0 14739 std::to_string(NLOHMANN_JSON_VERSION_PATCH);
ferencd@0 14740 result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR;
ferencd@0 14741 result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR;
ferencd@0 14742 result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH;
ferencd@0 14743
ferencd@0 14744 #ifdef _WIN32
ferencd@0 14745 result["platform"] = "win32";
ferencd@0 14746 #elif defined __linux__
ferencd@0 14747 result["platform"] = "linux";
ferencd@0 14748 #elif defined __APPLE__
ferencd@0 14749 result["platform"] = "apple";
ferencd@0 14750 #elif defined __unix__
ferencd@0 14751 result["platform"] = "unix";
ferencd@0 14752 #else
ferencd@0 14753 result["platform"] = "unknown";
ferencd@0 14754 #endif
ferencd@0 14755
ferencd@0 14756 #if defined(__ICC) || defined(__INTEL_COMPILER)
ferencd@0 14757 result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
ferencd@0 14758 #elif defined(__clang__)
ferencd@0 14759 result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
ferencd@0 14760 #elif defined(__GNUC__) || defined(__GNUG__)
ferencd@0 14761 result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}};
ferencd@0 14762 #elif defined(__HP_cc) || defined(__HP_aCC)
ferencd@0 14763 result["compiler"] = "hp"
ferencd@0 14764 #elif defined(__IBMCPP__)
ferencd@0 14765 result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
ferencd@0 14766 #elif defined(_MSC_VER)
ferencd@0 14767 result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
ferencd@0 14768 #elif defined(__PGI)
ferencd@0 14769 result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
ferencd@0 14770 #elif defined(__SUNPRO_CC)
ferencd@0 14771 result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
ferencd@0 14772 #else
ferencd@0 14773 result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
ferencd@0 14774 #endif
ferencd@0 14775
ferencd@0 14776 #ifdef __cplusplus
ferencd@0 14777 result["compiler"]["c++"] = std::to_string(__cplusplus);
ferencd@0 14778 #else
ferencd@0 14779 result["compiler"]["c++"] = "unknown";
ferencd@0 14780 #endif
ferencd@0 14781 return result;
ferencd@0 14782 }
ferencd@0 14783
ferencd@0 14784
ferencd@0 14785 ///////////////////////////
ferencd@0 14786 // JSON value data types //
ferencd@0 14787 ///////////////////////////
ferencd@0 14788
ferencd@0 14789 /// @name JSON value data types
ferencd@0 14790 /// The data types to store a JSON value. These types are derived from
ferencd@0 14791 /// the template arguments passed to class @ref basic_json.
ferencd@0 14792 /// @{
ferencd@0 14793
ferencd@0 14794 #if defined(JSON_HAS_CPP_14)
ferencd@0 14795 // Use transparent comparator if possible, combined with perfect forwarding
ferencd@0 14796 // on find() and count() calls prevents unnecessary string construction.
ferencd@0 14797 using object_comparator_t = std::less<>;
ferencd@0 14798 #else
ferencd@0 14799 using object_comparator_t = std::less<StringType>;
ferencd@0 14800 #endif
ferencd@0 14801
ferencd@0 14802 /*!
ferencd@0 14803 @brief a type for an object
ferencd@0 14804
ferencd@0 14805 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:
ferencd@0 14806 > An object is an unordered collection of zero or more name/value pairs,
ferencd@0 14807 > where a name is a string and a value is a string, number, boolean, null,
ferencd@0 14808 > object, or array.
ferencd@0 14809
ferencd@0 14810 To store objects in C++, a type is defined by the template parameters
ferencd@0 14811 described below.
ferencd@0 14812
ferencd@0 14813 @tparam ObjectType the container to store objects (e.g., `std::map` or
ferencd@0 14814 `std::unordered_map`)
ferencd@0 14815 @tparam StringType the type of the keys or names (e.g., `std::string`).
ferencd@0 14816 The comparison function `std::less<StringType>` is used to order elements
ferencd@0 14817 inside the container.
ferencd@0 14818 @tparam AllocatorType the allocator to use for objects (e.g.,
ferencd@0 14819 `std::allocator`)
ferencd@0 14820
ferencd@0 14821 #### Default type
ferencd@0 14822
ferencd@0 14823 With the default values for @a ObjectType (`std::map`), @a StringType
ferencd@0 14824 (`std::string`), and @a AllocatorType (`std::allocator`), the default
ferencd@0 14825 value for @a object_t is:
ferencd@0 14826
ferencd@0 14827 @code {.cpp}
ferencd@0 14828 std::map<
ferencd@0 14829 std::string, // key_type
ferencd@0 14830 basic_json, // value_type
ferencd@0 14831 std::less<std::string>, // key_compare
ferencd@0 14832 std::allocator<std::pair<const std::string, basic_json>> // allocator_type
ferencd@0 14833 >
ferencd@0 14834 @endcode
ferencd@0 14835
ferencd@0 14836 #### Behavior
ferencd@0 14837
ferencd@0 14838 The choice of @a object_t influences the behavior of the JSON class. With
ferencd@0 14839 the default type, objects have the following behavior:
ferencd@0 14840
ferencd@0 14841 - When all names are unique, objects will be interoperable in the sense
ferencd@0 14842 that all software implementations receiving that object will agree on
ferencd@0 14843 the name-value mappings.
ferencd@0 14844 - When the names within an object are not unique, it is unspecified which
ferencd@0 14845 one of the values for a given key will be chosen. For instance,
ferencd@0 14846 `{"key": 2, "key": 1}` could be equal to either `{"key": 1}` or
ferencd@0 14847 `{"key": 2}`.
ferencd@0 14848 - Internally, name/value pairs are stored in lexicographical order of the
ferencd@0 14849 names. Objects will also be serialized (see @ref dump) in this order.
ferencd@0 14850 For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored
ferencd@0 14851 and serialized as `{"a": 2, "b": 1}`.
ferencd@0 14852 - When comparing objects, the order of the name/value pairs is irrelevant.
ferencd@0 14853 This makes objects interoperable in the sense that they will not be
ferencd@0 14854 affected by these differences. For instance, `{"b": 1, "a": 2}` and
ferencd@0 14855 `{"a": 2, "b": 1}` will be treated as equal.
ferencd@0 14856
ferencd@0 14857 #### Limits
ferencd@0 14858
ferencd@0 14859 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
ferencd@0 14860 > An implementation may set limits on the maximum depth of nesting.
ferencd@0 14861
ferencd@0 14862 In this class, the object's limit of nesting is not explicitly constrained.
ferencd@0 14863 However, a maximum depth of nesting may be introduced by the compiler or
ferencd@0 14864 runtime environment. A theoretical limit can be queried by calling the
ferencd@0 14865 @ref max_size function of a JSON object.
ferencd@0 14866
ferencd@0 14867 #### Storage
ferencd@0 14868
ferencd@0 14869 Objects are stored as pointers in a @ref basic_json type. That is, for any
ferencd@0 14870 access to object values, a pointer of type `object_t*` must be
ferencd@0 14871 dereferenced.
ferencd@0 14872
ferencd@0 14873 @sa @ref array_t -- type for an array value
ferencd@0 14874
ferencd@0 14875 @since version 1.0.0
ferencd@0 14876
ferencd@0 14877 @note The order name/value pairs are added to the object is *not*
ferencd@0 14878 preserved by the library. Therefore, iterating an object may return
ferencd@0 14879 name/value pairs in a different order than they were originally stored. In
ferencd@0 14880 fact, keys will be traversed in alphabetical order as `std::map` with
ferencd@0 14881 `std::less` is used by default. Please note this behavior conforms to [RFC
ferencd@0 14882 7159](http://rfc7159.net/rfc7159), because any order implements the
ferencd@0 14883 specified "unordered" nature of JSON objects.
ferencd@0 14884 */
ferencd@0 14885 using object_t = ObjectType<StringType,
ferencd@0 14886 basic_json,
ferencd@0 14887 object_comparator_t,
ferencd@0 14888 AllocatorType<std::pair<const StringType,
ferencd@0 14889 basic_json>>>;
ferencd@0 14890
ferencd@0 14891 /*!
ferencd@0 14892 @brief a type for an array
ferencd@0 14893
ferencd@0 14894 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:
ferencd@0 14895 > An array is an ordered sequence of zero or more values.
ferencd@0 14896
ferencd@0 14897 To store objects in C++, a type is defined by the template parameters
ferencd@0 14898 explained below.
ferencd@0 14899
ferencd@0 14900 @tparam ArrayType container type to store arrays (e.g., `std::vector` or
ferencd@0 14901 `std::list`)
ferencd@0 14902 @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)
ferencd@0 14903
ferencd@0 14904 #### Default type
ferencd@0 14905
ferencd@0 14906 With the default values for @a ArrayType (`std::vector`) and @a
ferencd@0 14907 AllocatorType (`std::allocator`), the default value for @a array_t is:
ferencd@0 14908
ferencd@0 14909 @code {.cpp}
ferencd@0 14910 std::vector<
ferencd@0 14911 basic_json, // value_type
ferencd@0 14912 std::allocator<basic_json> // allocator_type
ferencd@0 14913 >
ferencd@0 14914 @endcode
ferencd@0 14915
ferencd@0 14916 #### Limits
ferencd@0 14917
ferencd@0 14918 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
ferencd@0 14919 > An implementation may set limits on the maximum depth of nesting.
ferencd@0 14920
ferencd@0 14921 In this class, the array's limit of nesting is not explicitly constrained.
ferencd@0 14922 However, a maximum depth of nesting may be introduced by the compiler or
ferencd@0 14923 runtime environment. A theoretical limit can be queried by calling the
ferencd@0 14924 @ref max_size function of a JSON array.
ferencd@0 14925
ferencd@0 14926 #### Storage
ferencd@0 14927
ferencd@0 14928 Arrays are stored as pointers in a @ref basic_json type. That is, for any
ferencd@0 14929 access to array values, a pointer of type `array_t*` must be dereferenced.
ferencd@0 14930
ferencd@0 14931 @sa @ref object_t -- type for an object value
ferencd@0 14932
ferencd@0 14933 @since version 1.0.0
ferencd@0 14934 */
ferencd@0 14935 using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
ferencd@0 14936
ferencd@0 14937 /*!
ferencd@0 14938 @brief a type for a string
ferencd@0 14939
ferencd@0 14940 [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:
ferencd@0 14941 > A string is a sequence of zero or more Unicode characters.
ferencd@0 14942
ferencd@0 14943 To store objects in C++, a type is defined by the template parameter
ferencd@0 14944 described below. Unicode values are split by the JSON class into
ferencd@0 14945 byte-sized characters during deserialization.
ferencd@0 14946
ferencd@0 14947 @tparam StringType the container to store strings (e.g., `std::string`).
ferencd@0 14948 Note this container is used for keys/names in objects, see @ref object_t.
ferencd@0 14949
ferencd@0 14950 #### Default type
ferencd@0 14951
ferencd@0 14952 With the default values for @a StringType (`std::string`), the default
ferencd@0 14953 value for @a string_t is:
ferencd@0 14954
ferencd@0 14955 @code {.cpp}
ferencd@0 14956 std::string
ferencd@0 14957 @endcode
ferencd@0 14958
ferencd@0 14959 #### Encoding
ferencd@0 14960
ferencd@0 14961 Strings are stored in UTF-8 encoding. Therefore, functions like
ferencd@0 14962 `std::string::size()` or `std::string::length()` return the number of
ferencd@0 14963 bytes in the string rather than the number of characters or glyphs.
ferencd@0 14964
ferencd@0 14965 #### String comparison
ferencd@0 14966
ferencd@0 14967 [RFC 7159](http://rfc7159.net/rfc7159) states:
ferencd@0 14968 > Software implementations are typically required to test names of object
ferencd@0 14969 > members for equality. Implementations that transform the textual
ferencd@0 14970 > representation into sequences of Unicode code units and then perform the
ferencd@0 14971 > comparison numerically, code unit by code unit, are interoperable in the
ferencd@0 14972 > sense that implementations will agree in all cases on equality or
ferencd@0 14973 > inequality of two strings. For example, implementations that compare
ferencd@0 14974 > strings with escaped characters unconverted may incorrectly find that
ferencd@0 14975 > `"a\\b"` and `"a\u005Cb"` are not equal.
ferencd@0 14976
ferencd@0 14977 This implementation is interoperable as it does compare strings code unit
ferencd@0 14978 by code unit.
ferencd@0 14979
ferencd@0 14980 #### Storage
ferencd@0 14981
ferencd@0 14982 String values are stored as pointers in a @ref basic_json type. That is,
ferencd@0 14983 for any access to string values, a pointer of type `string_t*` must be
ferencd@0 14984 dereferenced.
ferencd@0 14985
ferencd@0 14986 @since version 1.0.0
ferencd@0 14987 */
ferencd@0 14988 using string_t = StringType;
ferencd@0 14989
ferencd@0 14990 /*!
ferencd@0 14991 @brief a type for a boolean
ferencd@0 14992
ferencd@0 14993 [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a
ferencd@0 14994 type which differentiates the two literals `true` and `false`.
ferencd@0 14995
ferencd@0 14996 To store objects in C++, a type is defined by the template parameter @a
ferencd@0 14997 BooleanType which chooses the type to use.
ferencd@0 14998
ferencd@0 14999 #### Default type
ferencd@0 15000
ferencd@0 15001 With the default values for @a BooleanType (`bool`), the default value for
ferencd@0 15002 @a boolean_t is:
ferencd@0 15003
ferencd@0 15004 @code {.cpp}
ferencd@0 15005 bool
ferencd@0 15006 @endcode
ferencd@0 15007
ferencd@0 15008 #### Storage
ferencd@0 15009
ferencd@0 15010 Boolean values are stored directly inside a @ref basic_json type.
ferencd@0 15011
ferencd@0 15012 @since version 1.0.0
ferencd@0 15013 */
ferencd@0 15014 using boolean_t = BooleanType;
ferencd@0 15015
ferencd@0 15016 /*!
ferencd@0 15017 @brief a type for a number (integer)
ferencd@0 15018
ferencd@0 15019 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
ferencd@0 15020 > The representation of numbers is similar to that used in most
ferencd@0 15021 > programming languages. A number is represented in base 10 using decimal
ferencd@0 15022 > digits. It contains an integer component that may be prefixed with an
ferencd@0 15023 > optional minus sign, which may be followed by a fraction part and/or an
ferencd@0 15024 > exponent part. Leading zeros are not allowed. (...) Numeric values that
ferencd@0 15025 > cannot be represented in the grammar below (such as Infinity and NaN)
ferencd@0 15026 > are not permitted.
ferencd@0 15027
ferencd@0 15028 This description includes both integer and floating-point numbers.
ferencd@0 15029 However, C++ allows more precise storage if it is known whether the number
ferencd@0 15030 is a signed integer, an unsigned integer or a floating-point number.
ferencd@0 15031 Therefore, three different types, @ref number_integer_t, @ref
ferencd@0 15032 number_unsigned_t and @ref number_float_t are used.
ferencd@0 15033
ferencd@0 15034 To store integer numbers in C++, a type is defined by the template
ferencd@0 15035 parameter @a NumberIntegerType which chooses the type to use.
ferencd@0 15036
ferencd@0 15037 #### Default type
ferencd@0 15038
ferencd@0 15039 With the default values for @a NumberIntegerType (`int64_t`), the default
ferencd@0 15040 value for @a number_integer_t is:
ferencd@0 15041
ferencd@0 15042 @code {.cpp}
ferencd@0 15043 int64_t
ferencd@0 15044 @endcode
ferencd@0 15045
ferencd@0 15046 #### Default behavior
ferencd@0 15047
ferencd@0 15048 - The restrictions about leading zeros is not enforced in C++. Instead,
ferencd@0 15049 leading zeros in integer literals lead to an interpretation as octal
ferencd@0 15050 number. Internally, the value will be stored as decimal number. For
ferencd@0 15051 instance, the C++ integer literal `010` will be serialized to `8`.
ferencd@0 15052 During deserialization, leading zeros yield an error.
ferencd@0 15053 - Not-a-number (NaN) values will be serialized to `null`.
ferencd@0 15054
ferencd@0 15055 #### Limits
ferencd@0 15056
ferencd@0 15057 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
ferencd@0 15058 > An implementation may set limits on the range and precision of numbers.
ferencd@0 15059
ferencd@0 15060 When the default type is used, the maximal integer number that can be
ferencd@0 15061 stored is `9223372036854775807` (INT64_MAX) and the minimal integer number
ferencd@0 15062 that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers
ferencd@0 15063 that are out of range will yield over/underflow when used in a
ferencd@0 15064 constructor. During deserialization, too large or small integer numbers
ferencd@0 15065 will be automatically be stored as @ref number_unsigned_t or @ref
ferencd@0 15066 number_float_t.
ferencd@0 15067
ferencd@0 15068 [RFC 7159](http://rfc7159.net/rfc7159) further states:
ferencd@0 15069 > Note that when such software is used, numbers that are integers and are
ferencd@0 15070 > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
ferencd@0 15071 > that implementations will agree exactly on their numeric values.
ferencd@0 15072
ferencd@0 15073 As this range is a subrange of the exactly supported range [INT64_MIN,
ferencd@0 15074 INT64_MAX], this class's integer type is interoperable.
ferencd@0 15075
ferencd@0 15076 #### Storage
ferencd@0 15077
ferencd@0 15078 Integer number values are stored directly inside a @ref basic_json type.
ferencd@0 15079
ferencd@0 15080 @sa @ref number_float_t -- type for number values (floating-point)
ferencd@0 15081
ferencd@0 15082 @sa @ref number_unsigned_t -- type for number values (unsigned integer)
ferencd@0 15083
ferencd@0 15084 @since version 1.0.0
ferencd@0 15085 */
ferencd@0 15086 using number_integer_t = NumberIntegerType;
ferencd@0 15087
ferencd@0 15088 /*!
ferencd@0 15089 @brief a type for a number (unsigned)
ferencd@0 15090
ferencd@0 15091 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
ferencd@0 15092 > The representation of numbers is similar to that used in most
ferencd@0 15093 > programming languages. A number is represented in base 10 using decimal
ferencd@0 15094 > digits. It contains an integer component that may be prefixed with an
ferencd@0 15095 > optional minus sign, which may be followed by a fraction part and/or an
ferencd@0 15096 > exponent part. Leading zeros are not allowed. (...) Numeric values that
ferencd@0 15097 > cannot be represented in the grammar below (such as Infinity and NaN)
ferencd@0 15098 > are not permitted.
ferencd@0 15099
ferencd@0 15100 This description includes both integer and floating-point numbers.
ferencd@0 15101 However, C++ allows more precise storage if it is known whether the number
ferencd@0 15102 is a signed integer, an unsigned integer or a floating-point number.
ferencd@0 15103 Therefore, three different types, @ref number_integer_t, @ref
ferencd@0 15104 number_unsigned_t and @ref number_float_t are used.
ferencd@0 15105
ferencd@0 15106 To store unsigned integer numbers in C++, a type is defined by the
ferencd@0 15107 template parameter @a NumberUnsignedType which chooses the type to use.
ferencd@0 15108
ferencd@0 15109 #### Default type
ferencd@0 15110
ferencd@0 15111 With the default values for @a NumberUnsignedType (`uint64_t`), the
ferencd@0 15112 default value for @a number_unsigned_t is:
ferencd@0 15113
ferencd@0 15114 @code {.cpp}
ferencd@0 15115 uint64_t
ferencd@0 15116 @endcode
ferencd@0 15117
ferencd@0 15118 #### Default behavior
ferencd@0 15119
ferencd@0 15120 - The restrictions about leading zeros is not enforced in C++. Instead,
ferencd@0 15121 leading zeros in integer literals lead to an interpretation as octal
ferencd@0 15122 number. Internally, the value will be stored as decimal number. For
ferencd@0 15123 instance, the C++ integer literal `010` will be serialized to `8`.
ferencd@0 15124 During deserialization, leading zeros yield an error.
ferencd@0 15125 - Not-a-number (NaN) values will be serialized to `null`.
ferencd@0 15126
ferencd@0 15127 #### Limits
ferencd@0 15128
ferencd@0 15129 [RFC 7159](http://rfc7159.net/rfc7159) specifies:
ferencd@0 15130 > An implementation may set limits on the range and precision of numbers.
ferencd@0 15131
ferencd@0 15132 When the default type is used, the maximal integer number that can be
ferencd@0 15133 stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
ferencd@0 15134 number that can be stored is `0`. Integer numbers that are out of range
ferencd@0 15135 will yield over/underflow when used in a constructor. During
ferencd@0 15136 deserialization, too large or small integer numbers will be automatically
ferencd@0 15137 be stored as @ref number_integer_t or @ref number_float_t.
ferencd@0 15138
ferencd@0 15139 [RFC 7159](http://rfc7159.net/rfc7159) further states:
ferencd@0 15140 > Note that when such software is used, numbers that are integers and are
ferencd@0 15141 > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
ferencd@0 15142 > that implementations will agree exactly on their numeric values.
ferencd@0 15143
ferencd@0 15144 As this range is a subrange (when considered in conjunction with the
ferencd@0 15145 number_integer_t type) of the exactly supported range [0, UINT64_MAX],
ferencd@0 15146 this class's integer type is interoperable.
ferencd@0 15147
ferencd@0 15148 #### Storage
ferencd@0 15149
ferencd@0 15150 Integer number values are stored directly inside a @ref basic_json type.
ferencd@0 15151
ferencd@0 15152 @sa @ref number_float_t -- type for number values (floating-point)
ferencd@0 15153 @sa @ref number_integer_t -- type for number values (integer)
ferencd@0 15154
ferencd@0 15155 @since version 2.0.0
ferencd@0 15156 */
ferencd@0 15157 using number_unsigned_t = NumberUnsignedType;
ferencd@0 15158
ferencd@0 15159 /*!
ferencd@0 15160 @brief a type for a number (floating-point)
ferencd@0 15161
ferencd@0 15162 [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
ferencd@0 15163 > The representation of numbers is similar to that used in most
ferencd@0 15164 > programming languages. A number is represented in base 10 using decimal
ferencd@0 15165 > digits. It contains an integer component that may be prefixed with an
ferencd@0 15166 > optional minus sign, which may be followed by a fraction part and/or an
ferencd@0 15167 > exponent part. Leading zeros are not allowed. (...) Numeric values that
ferencd@0 15168 > cannot be represented in the grammar below (such as Infinity and NaN)
ferencd@0 15169 > are not permitted.
ferencd@0 15170
ferencd@0 15171 This description includes both integer and floating-point numbers.
ferencd@0 15172 However, C++ allows more precise storage if it is known whether the number
ferencd@0 15173 is a signed integer, an unsigned integer or a floating-point number.
ferencd@0 15174 Therefore, three different types, @ref number_integer_t, @ref
ferencd@0 15175 number_unsigned_t and @ref number_float_t are used.
ferencd@0 15176
ferencd@0 15177 To store floating-point numbers in C++, a type is defined by the template
ferencd@0 15178 parameter @a NumberFloatType which chooses the type to use.
ferencd@0 15179
ferencd@0 15180 #### Default type
ferencd@0 15181
ferencd@0 15182 With the default values for @a NumberFloatType (`double`), the default
ferencd@0 15183 value for @a number_float_t is:
ferencd@0 15184
ferencd@0 15185 @code {.cpp}
ferencd@0 15186 double
ferencd@0 15187 @endcode
ferencd@0 15188
ferencd@0 15189 #### Default behavior
ferencd@0 15190
ferencd@0 15191 - The restrictions about leading zeros is not enforced in C++. Instead,
ferencd@0 15192 leading zeros in floating-point literals will be ignored. Internally,
ferencd@0 15193 the value will be stored as decimal number. For instance, the C++
ferencd@0 15194 floating-point literal `01.2` will be serialized to `1.2`. During
ferencd@0 15195 deserialization, leading zeros yield an error.
ferencd@0 15196 - Not-a-number (NaN) values will be serialized to `null`.
ferencd@0 15197
ferencd@0 15198 #### Limits
ferencd@0 15199
ferencd@0 15200 [RFC 7159](http://rfc7159.net/rfc7159) states:
ferencd@0 15201 > This specification allows implementations to set limits on the range and
ferencd@0 15202 > precision of numbers accepted. Since software that implements IEEE
ferencd@0 15203 > 754-2008 binary64 (double precision) numbers is generally available and
ferencd@0 15204 > widely used, good interoperability can be achieved by implementations
ferencd@0 15205 > that expect no more precision or range than these provide, in the sense
ferencd@0 15206 > that implementations will approximate JSON numbers within the expected
ferencd@0 15207 > precision.
ferencd@0 15208
ferencd@0 15209 This implementation does exactly follow this approach, as it uses double
ferencd@0 15210 precision floating-point numbers. Note values smaller than
ferencd@0 15211 `-1.79769313486232e+308` and values greater than `1.79769313486232e+308`
ferencd@0 15212 will be stored as NaN internally and be serialized to `null`.
ferencd@0 15213
ferencd@0 15214 #### Storage
ferencd@0 15215
ferencd@0 15216 Floating-point number values are stored directly inside a @ref basic_json
ferencd@0 15217 type.
ferencd@0 15218
ferencd@0 15219 @sa @ref number_integer_t -- type for number values (integer)
ferencd@0 15220
ferencd@0 15221 @sa @ref number_unsigned_t -- type for number values (unsigned integer)
ferencd@0 15222
ferencd@0 15223 @since version 1.0.0
ferencd@0 15224 */
ferencd@0 15225 using number_float_t = NumberFloatType;
ferencd@0 15226
ferencd@0 15227 /// @}
ferencd@0 15228
ferencd@0 15229 private:
ferencd@0 15230
ferencd@0 15231 /// helper for exception-safe object creation
ferencd@0 15232 template<typename T, typename... Args>
ferencd@0 15233 JSON_HEDLEY_RETURNS_NON_NULL
ferencd@0 15234 static T* create(Args&& ... args)
ferencd@0 15235 {
ferencd@0 15236 AllocatorType<T> alloc;
ferencd@0 15237 using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
ferencd@0 15238
ferencd@0 15239 auto deleter = [&](T * object)
ferencd@0 15240 {
ferencd@0 15241 AllocatorTraits::deallocate(alloc, object, 1);
ferencd@0 15242 };
ferencd@0 15243 std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);
ferencd@0 15244 AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);
ferencd@0 15245 assert(object != nullptr);
ferencd@0 15246 return object.release();
ferencd@0 15247 }
ferencd@0 15248
ferencd@0 15249 ////////////////////////
ferencd@0 15250 // JSON value storage //
ferencd@0 15251 ////////////////////////
ferencd@0 15252
ferencd@0 15253 /*!
ferencd@0 15254 @brief a JSON value
ferencd@0 15255
ferencd@0 15256 The actual storage for a JSON value of the @ref basic_json class. This
ferencd@0 15257 union combines the different storage types for the JSON value types
ferencd@0 15258 defined in @ref value_t.
ferencd@0 15259
ferencd@0 15260 JSON type | value_t type | used type
ferencd@0 15261 --------- | --------------- | ------------------------
ferencd@0 15262 object | object | pointer to @ref object_t
ferencd@0 15263 array | array | pointer to @ref array_t
ferencd@0 15264 string | string | pointer to @ref string_t
ferencd@0 15265 boolean | boolean | @ref boolean_t
ferencd@0 15266 number | number_integer | @ref number_integer_t
ferencd@0 15267 number | number_unsigned | @ref number_unsigned_t
ferencd@0 15268 number | number_float | @ref number_float_t
ferencd@0 15269 null | null | *no value is stored*
ferencd@0 15270
ferencd@0 15271 @note Variable-length types (objects, arrays, and strings) are stored as
ferencd@0 15272 pointers. The size of the union should not exceed 64 bits if the default
ferencd@0 15273 value types are used.
ferencd@0 15274
ferencd@0 15275 @since version 1.0.0
ferencd@0 15276 */
ferencd@0 15277 union json_value
ferencd@0 15278 {
ferencd@0 15279 /// object (stored with pointer to save storage)
ferencd@0 15280 object_t* object;
ferencd@0 15281 /// array (stored with pointer to save storage)
ferencd@0 15282 array_t* array;
ferencd@0 15283 /// string (stored with pointer to save storage)
ferencd@0 15284 string_t* string;
ferencd@0 15285 /// boolean
ferencd@0 15286 boolean_t boolean;
ferencd@0 15287 /// number (integer)
ferencd@0 15288 number_integer_t number_integer;
ferencd@0 15289 /// number (unsigned integer)
ferencd@0 15290 number_unsigned_t number_unsigned;
ferencd@0 15291 /// number (floating-point)
ferencd@0 15292 number_float_t number_float;
ferencd@0 15293
ferencd@0 15294 /// default constructor (for null values)
ferencd@0 15295 json_value() = default;
ferencd@0 15296 /// constructor for booleans
ferencd@0 15297 json_value(boolean_t v) noexcept : boolean(v) {}
ferencd@0 15298 /// constructor for numbers (integer)
ferencd@0 15299 json_value(number_integer_t v) noexcept : number_integer(v) {}
ferencd@0 15300 /// constructor for numbers (unsigned)
ferencd@0 15301 json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
ferencd@0 15302 /// constructor for numbers (floating-point)
ferencd@0 15303 json_value(number_float_t v) noexcept : number_float(v) {}
ferencd@0 15304 /// constructor for empty values of a given type
ferencd@0 15305 json_value(value_t t)
ferencd@0 15306 {
ferencd@0 15307 switch (t)
ferencd@0 15308 {
ferencd@0 15309 case value_t::object:
ferencd@0 15310 {
ferencd@0 15311 object = create<object_t>();
ferencd@0 15312 break;
ferencd@0 15313 }
ferencd@0 15314
ferencd@0 15315 case value_t::array:
ferencd@0 15316 {
ferencd@0 15317 array = create<array_t>();
ferencd@0 15318 break;
ferencd@0 15319 }
ferencd@0 15320
ferencd@0 15321 case value_t::string:
ferencd@0 15322 {
ferencd@0 15323 string = create<string_t>("");
ferencd@0 15324 break;
ferencd@0 15325 }
ferencd@0 15326
ferencd@0 15327 case value_t::boolean:
ferencd@0 15328 {
ferencd@0 15329 boolean = boolean_t(false);
ferencd@0 15330 break;
ferencd@0 15331 }
ferencd@0 15332
ferencd@0 15333 case value_t::number_integer:
ferencd@0 15334 {
ferencd@0 15335 number_integer = number_integer_t(0);
ferencd@0 15336 break;
ferencd@0 15337 }
ferencd@0 15338
ferencd@0 15339 case value_t::number_unsigned:
ferencd@0 15340 {
ferencd@0 15341 number_unsigned = number_unsigned_t(0);
ferencd@0 15342 break;
ferencd@0 15343 }
ferencd@0 15344
ferencd@0 15345 case value_t::number_float:
ferencd@0 15346 {
ferencd@0 15347 number_float = number_float_t(0.0);
ferencd@0 15348 break;
ferencd@0 15349 }
ferencd@0 15350
ferencd@0 15351 case value_t::null:
ferencd@0 15352 {
ferencd@0 15353 object = nullptr; // silence warning, see #821
ferencd@0 15354 break;
ferencd@0 15355 }
ferencd@0 15356
ferencd@0 15357 default:
ferencd@0 15358 {
ferencd@0 15359 object = nullptr; // silence warning, see #821
ferencd@0 15360 if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
ferencd@0 15361 {
ferencd@0 15362 JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.7.0")); // LCOV_EXCL_LINE
ferencd@0 15363 }
ferencd@0 15364 break;
ferencd@0 15365 }
ferencd@0 15366 }
ferencd@0 15367 }
ferencd@0 15368
ferencd@0 15369 /// constructor for strings
ferencd@0 15370 json_value(const string_t& value)
ferencd@0 15371 {
ferencd@0 15372 string = create<string_t>(value);
ferencd@0 15373 }
ferencd@0 15374
ferencd@0 15375 /// constructor for rvalue strings
ferencd@0 15376 json_value(string_t&& value)
ferencd@0 15377 {
ferencd@0 15378 string = create<string_t>(std::move(value));
ferencd@0 15379 }
ferencd@0 15380
ferencd@0 15381 /// constructor for objects
ferencd@0 15382 json_value(const object_t& value)
ferencd@0 15383 {
ferencd@0 15384 object = create<object_t>(value);
ferencd@0 15385 }
ferencd@0 15386
ferencd@0 15387 /// constructor for rvalue objects
ferencd@0 15388 json_value(object_t&& value)
ferencd@0 15389 {
ferencd@0 15390 object = create<object_t>(std::move(value));
ferencd@0 15391 }
ferencd@0 15392
ferencd@0 15393 /// constructor for arrays
ferencd@0 15394 json_value(const array_t& value)
ferencd@0 15395 {
ferencd@0 15396 array = create<array_t>(value);
ferencd@0 15397 }
ferencd@0 15398
ferencd@0 15399 /// constructor for rvalue arrays
ferencd@0 15400 json_value(array_t&& value)
ferencd@0 15401 {
ferencd@0 15402 array = create<array_t>(std::move(value));
ferencd@0 15403 }
ferencd@0 15404
ferencd@0 15405 void destroy(value_t t) noexcept
ferencd@0 15406 {
ferencd@0 15407 switch (t)
ferencd@0 15408 {
ferencd@0 15409 case value_t::object:
ferencd@0 15410 {
ferencd@0 15411 AllocatorType<object_t> alloc;
ferencd@0 15412 std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
ferencd@0 15413 std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
ferencd@0 15414 break;
ferencd@0 15415 }
ferencd@0 15416
ferencd@0 15417 case value_t::array:
ferencd@0 15418 {
ferencd@0 15419 AllocatorType<array_t> alloc;
ferencd@0 15420 std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
ferencd@0 15421 std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
ferencd@0 15422 break;
ferencd@0 15423 }
ferencd@0 15424
ferencd@0 15425 case value_t::string:
ferencd@0 15426 {
ferencd@0 15427 AllocatorType<string_t> alloc;
ferencd@0 15428 std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
ferencd@0 15429 std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
ferencd@0 15430 break;
ferencd@0 15431 }
ferencd@0 15432
ferencd@0 15433 default:
ferencd@0 15434 {
ferencd@0 15435 break;
ferencd@0 15436 }
ferencd@0 15437 }
ferencd@0 15438 }
ferencd@0 15439 };
ferencd@0 15440
ferencd@0 15441 /*!
ferencd@0 15442 @brief checks the class invariants
ferencd@0 15443
ferencd@0 15444 This function asserts the class invariants. It needs to be called at the
ferencd@0 15445 end of every constructor to make sure that created objects respect the
ferencd@0 15446 invariant. Furthermore, it has to be called each time the type of a JSON
ferencd@0 15447 value is changed, because the invariant expresses a relationship between
ferencd@0 15448 @a m_type and @a m_value.
ferencd@0 15449 */
ferencd@0 15450 void assert_invariant() const noexcept
ferencd@0 15451 {
ferencd@0 15452 assert(m_type != value_t::object or m_value.object != nullptr);
ferencd@0 15453 assert(m_type != value_t::array or m_value.array != nullptr);
ferencd@0 15454 assert(m_type != value_t::string or m_value.string != nullptr);
ferencd@0 15455 }
ferencd@0 15456
ferencd@0 15457 public:
ferencd@0 15458 //////////////////////////
ferencd@0 15459 // JSON parser callback //
ferencd@0 15460 //////////////////////////
ferencd@0 15461
ferencd@0 15462 /*!
ferencd@0 15463 @brief parser event types
ferencd@0 15464
ferencd@0 15465 The parser callback distinguishes the following events:
ferencd@0 15466 - `object_start`: the parser read `{` and started to process a JSON object
ferencd@0 15467 - `key`: the parser read a key of a value in an object
ferencd@0 15468 - `object_end`: the parser read `}` and finished processing a JSON object
ferencd@0 15469 - `array_start`: the parser read `[` and started to process a JSON array
ferencd@0 15470 - `array_end`: the parser read `]` and finished processing a JSON array
ferencd@0 15471 - `value`: the parser finished reading a JSON value
ferencd@0 15472
ferencd@0 15473 @image html callback_events.png "Example when certain parse events are triggered"
ferencd@0 15474
ferencd@0 15475 @sa @ref parser_callback_t for more information and examples
ferencd@0 15476 */
ferencd@0 15477 using parse_event_t = typename parser::parse_event_t;
ferencd@0 15478
ferencd@0 15479 /*!
ferencd@0 15480 @brief per-element parser callback type
ferencd@0 15481
ferencd@0 15482 With a parser callback function, the result of parsing a JSON text can be
ferencd@0 15483 influenced. When passed to @ref parse, it is called on certain events
ferencd@0 15484 (passed as @ref parse_event_t via parameter @a event) with a set recursion
ferencd@0 15485 depth @a depth and context JSON value @a parsed. The return value of the
ferencd@0 15486 callback function is a boolean indicating whether the element that emitted
ferencd@0 15487 the callback shall be kept or not.
ferencd@0 15488
ferencd@0 15489 We distinguish six scenarios (determined by the event type) in which the
ferencd@0 15490 callback function can be called. The following table describes the values
ferencd@0 15491 of the parameters @a depth, @a event, and @a parsed.
ferencd@0 15492
ferencd@0 15493 parameter @a event | description | parameter @a depth | parameter @a parsed
ferencd@0 15494 ------------------ | ----------- | ------------------ | -------------------
ferencd@0 15495 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
ferencd@0 15496 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
ferencd@0 15497 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
ferencd@0 15498 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
ferencd@0 15499 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
ferencd@0 15500 parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value
ferencd@0 15501
ferencd@0 15502 @image html callback_events.png "Example when certain parse events are triggered"
ferencd@0 15503
ferencd@0 15504 Discarding a value (i.e., returning `false`) has different effects
ferencd@0 15505 depending on the context in which function was called:
ferencd@0 15506
ferencd@0 15507 - Discarded values in structured types are skipped. That is, the parser
ferencd@0 15508 will behave as if the discarded value was never read.
ferencd@0 15509 - In case a value outside a structured type is skipped, it is replaced
ferencd@0 15510 with `null`. This case happens if the top-level element is skipped.
ferencd@0 15511
ferencd@0 15512 @param[in] depth the depth of the recursion during parsing
ferencd@0 15513
ferencd@0 15514 @param[in] event an event of type parse_event_t indicating the context in
ferencd@0 15515 the callback function has been called
ferencd@0 15516
ferencd@0 15517 @param[in,out] parsed the current intermediate parse result; note that
ferencd@0 15518 writing to this value has no effect for parse_event_t::key events
ferencd@0 15519
ferencd@0 15520 @return Whether the JSON value which called the function during parsing
ferencd@0 15521 should be kept (`true`) or not (`false`). In the latter case, it is either
ferencd@0 15522 skipped completely or replaced by an empty discarded object.
ferencd@0 15523
ferencd@0 15524 @sa @ref parse for examples
ferencd@0 15525
ferencd@0 15526 @since version 1.0.0
ferencd@0 15527 */
ferencd@0 15528 using parser_callback_t = typename parser::parser_callback_t;
ferencd@0 15529
ferencd@0 15530 //////////////////
ferencd@0 15531 // constructors //
ferencd@0 15532 //////////////////
ferencd@0 15533
ferencd@0 15534 /// @name constructors and destructors
ferencd@0 15535 /// Constructors of class @ref basic_json, copy/move constructor, copy
ferencd@0 15536 /// assignment, static functions creating objects, and the destructor.
ferencd@0 15537 /// @{
ferencd@0 15538
ferencd@0 15539 /*!
ferencd@0 15540 @brief create an empty value with a given type
ferencd@0 15541
ferencd@0 15542 Create an empty JSON value with a given type. The value will be default
ferencd@0 15543 initialized with an empty value which depends on the type:
ferencd@0 15544
ferencd@0 15545 Value type | initial value
ferencd@0 15546 ----------- | -------------
ferencd@0 15547 null | `null`
ferencd@0 15548 boolean | `false`
ferencd@0 15549 string | `""`
ferencd@0 15550 number | `0`
ferencd@0 15551 object | `{}`
ferencd@0 15552 array | `[]`
ferencd@0 15553
ferencd@0 15554 @param[in] v the type of the value to create
ferencd@0 15555
ferencd@0 15556 @complexity Constant.
ferencd@0 15557
ferencd@0 15558 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 15559 changes to any JSON value.
ferencd@0 15560
ferencd@0 15561 @liveexample{The following code shows the constructor for different @ref
ferencd@0 15562 value_t values,basic_json__value_t}
ferencd@0 15563
ferencd@0 15564 @sa @ref clear() -- restores the postcondition of this constructor
ferencd@0 15565
ferencd@0 15566 @since version 1.0.0
ferencd@0 15567 */
ferencd@0 15568 basic_json(const value_t v)
ferencd@0 15569 : m_type(v), m_value(v)
ferencd@0 15570 {
ferencd@0 15571 assert_invariant();
ferencd@0 15572 }
ferencd@0 15573
ferencd@0 15574 /*!
ferencd@0 15575 @brief create a null object
ferencd@0 15576
ferencd@0 15577 Create a `null` JSON value. It either takes a null pointer as parameter
ferencd@0 15578 (explicitly creating `null`) or no parameter (implicitly creating `null`).
ferencd@0 15579 The passed null pointer itself is not read -- it is only used to choose
ferencd@0 15580 the right constructor.
ferencd@0 15581
ferencd@0 15582 @complexity Constant.
ferencd@0 15583
ferencd@0 15584 @exceptionsafety No-throw guarantee: this constructor never throws
ferencd@0 15585 exceptions.
ferencd@0 15586
ferencd@0 15587 @liveexample{The following code shows the constructor with and without a
ferencd@0 15588 null pointer parameter.,basic_json__nullptr_t}
ferencd@0 15589
ferencd@0 15590 @since version 1.0.0
ferencd@0 15591 */
ferencd@0 15592 basic_json(std::nullptr_t = nullptr) noexcept
ferencd@0 15593 : basic_json(value_t::null)
ferencd@0 15594 {
ferencd@0 15595 assert_invariant();
ferencd@0 15596 }
ferencd@0 15597
ferencd@0 15598 /*!
ferencd@0 15599 @brief create a JSON value
ferencd@0 15600
ferencd@0 15601 This is a "catch all" constructor for all compatible JSON types; that is,
ferencd@0 15602 types for which a `to_json()` method exists. The constructor forwards the
ferencd@0 15603 parameter @a val to that method (to `json_serializer<U>::to_json` method
ferencd@0 15604 with `U = uncvref_t<CompatibleType>`, to be exact).
ferencd@0 15605
ferencd@0 15606 Template type @a CompatibleType includes, but is not limited to, the
ferencd@0 15607 following types:
ferencd@0 15608 - **arrays**: @ref array_t and all kinds of compatible containers such as
ferencd@0 15609 `std::vector`, `std::deque`, `std::list`, `std::forward_list`,
ferencd@0 15610 `std::array`, `std::valarray`, `std::set`, `std::unordered_set`,
ferencd@0 15611 `std::multiset`, and `std::unordered_multiset` with a `value_type` from
ferencd@0 15612 which a @ref basic_json value can be constructed.
ferencd@0 15613 - **objects**: @ref object_t and all kinds of compatible associative
ferencd@0 15614 containers such as `std::map`, `std::unordered_map`, `std::multimap`,
ferencd@0 15615 and `std::unordered_multimap` with a `key_type` compatible to
ferencd@0 15616 @ref string_t and a `value_type` from which a @ref basic_json value can
ferencd@0 15617 be constructed.
ferencd@0 15618 - **strings**: @ref string_t, string literals, and all compatible string
ferencd@0 15619 containers can be used.
ferencd@0 15620 - **numbers**: @ref number_integer_t, @ref number_unsigned_t,
ferencd@0 15621 @ref number_float_t, and all convertible number types such as `int`,
ferencd@0 15622 `size_t`, `int64_t`, `float` or `double` can be used.
ferencd@0 15623 - **boolean**: @ref boolean_t / `bool` can be used.
ferencd@0 15624
ferencd@0 15625 See the examples below.
ferencd@0 15626
ferencd@0 15627 @tparam CompatibleType a type such that:
ferencd@0 15628 - @a CompatibleType is not derived from `std::istream`,
ferencd@0 15629 - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move
ferencd@0 15630 constructors),
ferencd@0 15631 - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments)
ferencd@0 15632 - @a CompatibleType is not a @ref basic_json nested type (e.g.,
ferencd@0 15633 @ref json_pointer, @ref iterator, etc ...)
ferencd@0 15634 - @ref @ref json_serializer<U> has a
ferencd@0 15635 `to_json(basic_json_t&, CompatibleType&&)` method
ferencd@0 15636
ferencd@0 15637 @tparam U = `uncvref_t<CompatibleType>`
ferencd@0 15638
ferencd@0 15639 @param[in] val the value to be forwarded to the respective constructor
ferencd@0 15640
ferencd@0 15641 @complexity Usually linear in the size of the passed @a val, also
ferencd@0 15642 depending on the implementation of the called `to_json()`
ferencd@0 15643 method.
ferencd@0 15644
ferencd@0 15645 @exceptionsafety Depends on the called constructor. For types directly
ferencd@0 15646 supported by the library (i.e., all types for which no `to_json()` function
ferencd@0 15647 was provided), strong guarantee holds: if an exception is thrown, there are
ferencd@0 15648 no changes to any JSON value.
ferencd@0 15649
ferencd@0 15650 @liveexample{The following code shows the constructor with several
ferencd@0 15651 compatible types.,basic_json__CompatibleType}
ferencd@0 15652
ferencd@0 15653 @since version 2.1.0
ferencd@0 15654 */
ferencd@0 15655 template <typename CompatibleType,
ferencd@0 15656 typename U = detail::uncvref_t<CompatibleType>,
ferencd@0 15657 detail::enable_if_t<
ferencd@0 15658 not detail::is_basic_json<U>::value and detail::is_compatible_type<basic_json_t, U>::value, int> = 0>
ferencd@0 15659 basic_json(CompatibleType && val) noexcept(noexcept(
ferencd@0 15660 JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
ferencd@0 15661 std::forward<CompatibleType>(val))))
ferencd@0 15662 {
ferencd@0 15663 JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
ferencd@0 15664 assert_invariant();
ferencd@0 15665 }
ferencd@0 15666
ferencd@0 15667 /*!
ferencd@0 15668 @brief create a JSON value from an existing one
ferencd@0 15669
ferencd@0 15670 This is a constructor for existing @ref basic_json types.
ferencd@0 15671 It does not hijack copy/move constructors, since the parameter has different
ferencd@0 15672 template arguments than the current ones.
ferencd@0 15673
ferencd@0 15674 The constructor tries to convert the internal @ref m_value of the parameter.
ferencd@0 15675
ferencd@0 15676 @tparam BasicJsonType a type such that:
ferencd@0 15677 - @a BasicJsonType is a @ref basic_json type.
ferencd@0 15678 - @a BasicJsonType has different template arguments than @ref basic_json_t.
ferencd@0 15679
ferencd@0 15680 @param[in] val the @ref basic_json value to be converted.
ferencd@0 15681
ferencd@0 15682 @complexity Usually linear in the size of the passed @a val, also
ferencd@0 15683 depending on the implementation of the called `to_json()`
ferencd@0 15684 method.
ferencd@0 15685
ferencd@0 15686 @exceptionsafety Depends on the called constructor. For types directly
ferencd@0 15687 supported by the library (i.e., all types for which no `to_json()` function
ferencd@0 15688 was provided), strong guarantee holds: if an exception is thrown, there are
ferencd@0 15689 no changes to any JSON value.
ferencd@0 15690
ferencd@0 15691 @since version 3.2.0
ferencd@0 15692 */
ferencd@0 15693 template <typename BasicJsonType,
ferencd@0 15694 detail::enable_if_t<
ferencd@0 15695 detail::is_basic_json<BasicJsonType>::value and not std::is_same<basic_json, BasicJsonType>::value, int> = 0>
ferencd@0 15696 basic_json(const BasicJsonType& val)
ferencd@0 15697 {
ferencd@0 15698 using other_boolean_t = typename BasicJsonType::boolean_t;
ferencd@0 15699 using other_number_float_t = typename BasicJsonType::number_float_t;
ferencd@0 15700 using other_number_integer_t = typename BasicJsonType::number_integer_t;
ferencd@0 15701 using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
ferencd@0 15702 using other_string_t = typename BasicJsonType::string_t;
ferencd@0 15703 using other_object_t = typename BasicJsonType::object_t;
ferencd@0 15704 using other_array_t = typename BasicJsonType::array_t;
ferencd@0 15705
ferencd@0 15706 switch (val.type())
ferencd@0 15707 {
ferencd@0 15708 case value_t::boolean:
ferencd@0 15709 JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
ferencd@0 15710 break;
ferencd@0 15711 case value_t::number_float:
ferencd@0 15712 JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
ferencd@0 15713 break;
ferencd@0 15714 case value_t::number_integer:
ferencd@0 15715 JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
ferencd@0 15716 break;
ferencd@0 15717 case value_t::number_unsigned:
ferencd@0 15718 JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
ferencd@0 15719 break;
ferencd@0 15720 case value_t::string:
ferencd@0 15721 JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
ferencd@0 15722 break;
ferencd@0 15723 case value_t::object:
ferencd@0 15724 JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
ferencd@0 15725 break;
ferencd@0 15726 case value_t::array:
ferencd@0 15727 JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
ferencd@0 15728 break;
ferencd@0 15729 case value_t::null:
ferencd@0 15730 *this = nullptr;
ferencd@0 15731 break;
ferencd@0 15732 case value_t::discarded:
ferencd@0 15733 m_type = value_t::discarded;
ferencd@0 15734 break;
ferencd@0 15735 default: // LCOV_EXCL_LINE
ferencd@0 15736 assert(false); // LCOV_EXCL_LINE
ferencd@0 15737 }
ferencd@0 15738 assert_invariant();
ferencd@0 15739 }
ferencd@0 15740
ferencd@0 15741 /*!
ferencd@0 15742 @brief create a container (array or object) from an initializer list
ferencd@0 15743
ferencd@0 15744 Creates a JSON value of type array or object from the passed initializer
ferencd@0 15745 list @a init. In case @a type_deduction is `true` (default), the type of
ferencd@0 15746 the JSON value to be created is deducted from the initializer list @a init
ferencd@0 15747 according to the following rules:
ferencd@0 15748
ferencd@0 15749 1. If the list is empty, an empty JSON object value `{}` is created.
ferencd@0 15750 2. If the list consists of pairs whose first element is a string, a JSON
ferencd@0 15751 object value is created where the first elements of the pairs are
ferencd@0 15752 treated as keys and the second elements are as values.
ferencd@0 15753 3. In all other cases, an array is created.
ferencd@0 15754
ferencd@0 15755 The rules aim to create the best fit between a C++ initializer list and
ferencd@0 15756 JSON values. The rationale is as follows:
ferencd@0 15757
ferencd@0 15758 1. The empty initializer list is written as `{}` which is exactly an empty
ferencd@0 15759 JSON object.
ferencd@0 15760 2. C++ has no way of describing mapped types other than to list a list of
ferencd@0 15761 pairs. As JSON requires that keys must be of type string, rule 2 is the
ferencd@0 15762 weakest constraint one can pose on initializer lists to interpret them
ferencd@0 15763 as an object.
ferencd@0 15764 3. In all other cases, the initializer list could not be interpreted as
ferencd@0 15765 JSON object type, so interpreting it as JSON array type is safe.
ferencd@0 15766
ferencd@0 15767 With the rules described above, the following JSON values cannot be
ferencd@0 15768 expressed by an initializer list:
ferencd@0 15769
ferencd@0 15770 - the empty array (`[]`): use @ref array(initializer_list_t)
ferencd@0 15771 with an empty initializer list in this case
ferencd@0 15772 - arrays whose elements satisfy rule 2: use @ref
ferencd@0 15773 array(initializer_list_t) with the same initializer list
ferencd@0 15774 in this case
ferencd@0 15775
ferencd@0 15776 @note When used without parentheses around an empty initializer list, @ref
ferencd@0 15777 basic_json() is called instead of this function, yielding the JSON null
ferencd@0 15778 value.
ferencd@0 15779
ferencd@0 15780 @param[in] init initializer list with JSON values
ferencd@0 15781
ferencd@0 15782 @param[in] type_deduction internal parameter; when set to `true`, the type
ferencd@0 15783 of the JSON value is deducted from the initializer list @a init; when set
ferencd@0 15784 to `false`, the type provided via @a manual_type is forced. This mode is
ferencd@0 15785 used by the functions @ref array(initializer_list_t) and
ferencd@0 15786 @ref object(initializer_list_t).
ferencd@0 15787
ferencd@0 15788 @param[in] manual_type internal parameter; when @a type_deduction is set
ferencd@0 15789 to `false`, the created JSON value will use the provided type (only @ref
ferencd@0 15790 value_t::array and @ref value_t::object are valid); when @a type_deduction
ferencd@0 15791 is set to `true`, this parameter has no effect
ferencd@0 15792
ferencd@0 15793 @throw type_error.301 if @a type_deduction is `false`, @a manual_type is
ferencd@0 15794 `value_t::object`, but @a init contains an element which is not a pair
ferencd@0 15795 whose first element is a string. In this case, the constructor could not
ferencd@0 15796 create an object. If @a type_deduction would have be `true`, an array
ferencd@0 15797 would have been created. See @ref object(initializer_list_t)
ferencd@0 15798 for an example.
ferencd@0 15799
ferencd@0 15800 @complexity Linear in the size of the initializer list @a init.
ferencd@0 15801
ferencd@0 15802 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 15803 changes to any JSON value.
ferencd@0 15804
ferencd@0 15805 @liveexample{The example below shows how JSON values are created from
ferencd@0 15806 initializer lists.,basic_json__list_init_t}
ferencd@0 15807
ferencd@0 15808 @sa @ref array(initializer_list_t) -- create a JSON array
ferencd@0 15809 value from an initializer list
ferencd@0 15810 @sa @ref object(initializer_list_t) -- create a JSON object
ferencd@0 15811 value from an initializer list
ferencd@0 15812
ferencd@0 15813 @since version 1.0.0
ferencd@0 15814 */
ferencd@0 15815 basic_json(initializer_list_t init,
ferencd@0 15816 bool type_deduction = true,
ferencd@0 15817 value_t manual_type = value_t::array)
ferencd@0 15818 {
ferencd@0 15819 // check if each element is an array with two elements whose first
ferencd@0 15820 // element is a string
ferencd@0 15821 bool is_an_object = std::all_of(init.begin(), init.end(),
ferencd@0 15822 [](const detail::json_ref<basic_json>& element_ref)
ferencd@0 15823 {
ferencd@0 15824 return element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string();
ferencd@0 15825 });
ferencd@0 15826
ferencd@0 15827 // adjust type if type deduction is not wanted
ferencd@0 15828 if (not type_deduction)
ferencd@0 15829 {
ferencd@0 15830 // if array is wanted, do not create an object though possible
ferencd@0 15831 if (manual_type == value_t::array)
ferencd@0 15832 {
ferencd@0 15833 is_an_object = false;
ferencd@0 15834 }
ferencd@0 15835
ferencd@0 15836 // if object is wanted but impossible, throw an exception
ferencd@0 15837 if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object and not is_an_object))
ferencd@0 15838 {
ferencd@0 15839 JSON_THROW(type_error::create(301, "cannot create object from initializer list"));
ferencd@0 15840 }
ferencd@0 15841 }
ferencd@0 15842
ferencd@0 15843 if (is_an_object)
ferencd@0 15844 {
ferencd@0 15845 // the initializer list is a list of pairs -> create object
ferencd@0 15846 m_type = value_t::object;
ferencd@0 15847 m_value = value_t::object;
ferencd@0 15848
ferencd@0 15849 std::for_each(init.begin(), init.end(), [this](const detail::json_ref<basic_json>& element_ref)
ferencd@0 15850 {
ferencd@0 15851 auto element = element_ref.moved_or_copied();
ferencd@0 15852 m_value.object->emplace(
ferencd@0 15853 std::move(*((*element.m_value.array)[0].m_value.string)),
ferencd@0 15854 std::move((*element.m_value.array)[1]));
ferencd@0 15855 });
ferencd@0 15856 }
ferencd@0 15857 else
ferencd@0 15858 {
ferencd@0 15859 // the initializer list describes an array -> create array
ferencd@0 15860 m_type = value_t::array;
ferencd@0 15861 m_value.array = create<array_t>(init.begin(), init.end());
ferencd@0 15862 }
ferencd@0 15863
ferencd@0 15864 assert_invariant();
ferencd@0 15865 }
ferencd@0 15866
ferencd@0 15867 /*!
ferencd@0 15868 @brief explicitly create an array from an initializer list
ferencd@0 15869
ferencd@0 15870 Creates a JSON array value from a given initializer list. That is, given a
ferencd@0 15871 list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the
ferencd@0 15872 initializer list is empty, the empty array `[]` is created.
ferencd@0 15873
ferencd@0 15874 @note This function is only needed to express two edge cases that cannot
ferencd@0 15875 be realized with the initializer list constructor (@ref
ferencd@0 15876 basic_json(initializer_list_t, bool, value_t)). These cases
ferencd@0 15877 are:
ferencd@0 15878 1. creating an array whose elements are all pairs whose first element is a
ferencd@0 15879 string -- in this case, the initializer list constructor would create an
ferencd@0 15880 object, taking the first elements as keys
ferencd@0 15881 2. creating an empty array -- passing the empty initializer list to the
ferencd@0 15882 initializer list constructor yields an empty object
ferencd@0 15883
ferencd@0 15884 @param[in] init initializer list with JSON values to create an array from
ferencd@0 15885 (optional)
ferencd@0 15886
ferencd@0 15887 @return JSON array value
ferencd@0 15888
ferencd@0 15889 @complexity Linear in the size of @a init.
ferencd@0 15890
ferencd@0 15891 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 15892 changes to any JSON value.
ferencd@0 15893
ferencd@0 15894 @liveexample{The following code shows an example for the `array`
ferencd@0 15895 function.,array}
ferencd@0 15896
ferencd@0 15897 @sa @ref basic_json(initializer_list_t, bool, value_t) --
ferencd@0 15898 create a JSON value from an initializer list
ferencd@0 15899 @sa @ref object(initializer_list_t) -- create a JSON object
ferencd@0 15900 value from an initializer list
ferencd@0 15901
ferencd@0 15902 @since version 1.0.0
ferencd@0 15903 */
ferencd@0 15904 JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 15905 static basic_json array(initializer_list_t init = {})
ferencd@0 15906 {
ferencd@0 15907 return basic_json(init, false, value_t::array);
ferencd@0 15908 }
ferencd@0 15909
ferencd@0 15910 /*!
ferencd@0 15911 @brief explicitly create an object from an initializer list
ferencd@0 15912
ferencd@0 15913 Creates a JSON object value from a given initializer list. The initializer
ferencd@0 15914 lists elements must be pairs, and their first elements must be strings. If
ferencd@0 15915 the initializer list is empty, the empty object `{}` is created.
ferencd@0 15916
ferencd@0 15917 @note This function is only added for symmetry reasons. In contrast to the
ferencd@0 15918 related function @ref array(initializer_list_t), there are
ferencd@0 15919 no cases which can only be expressed by this function. That is, any
ferencd@0 15920 initializer list @a init can also be passed to the initializer list
ferencd@0 15921 constructor @ref basic_json(initializer_list_t, bool, value_t).
ferencd@0 15922
ferencd@0 15923 @param[in] init initializer list to create an object from (optional)
ferencd@0 15924
ferencd@0 15925 @return JSON object value
ferencd@0 15926
ferencd@0 15927 @throw type_error.301 if @a init is not a list of pairs whose first
ferencd@0 15928 elements are strings. In this case, no object can be created. When such a
ferencd@0 15929 value is passed to @ref basic_json(initializer_list_t, bool, value_t),
ferencd@0 15930 an array would have been created from the passed initializer list @a init.
ferencd@0 15931 See example below.
ferencd@0 15932
ferencd@0 15933 @complexity Linear in the size of @a init.
ferencd@0 15934
ferencd@0 15935 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 15936 changes to any JSON value.
ferencd@0 15937
ferencd@0 15938 @liveexample{The following code shows an example for the `object`
ferencd@0 15939 function.,object}
ferencd@0 15940
ferencd@0 15941 @sa @ref basic_json(initializer_list_t, bool, value_t) --
ferencd@0 15942 create a JSON value from an initializer list
ferencd@0 15943 @sa @ref array(initializer_list_t) -- create a JSON array
ferencd@0 15944 value from an initializer list
ferencd@0 15945
ferencd@0 15946 @since version 1.0.0
ferencd@0 15947 */
ferencd@0 15948 JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 15949 static basic_json object(initializer_list_t init = {})
ferencd@0 15950 {
ferencd@0 15951 return basic_json(init, false, value_t::object);
ferencd@0 15952 }
ferencd@0 15953
ferencd@0 15954 /*!
ferencd@0 15955 @brief construct an array with count copies of given value
ferencd@0 15956
ferencd@0 15957 Constructs a JSON array value by creating @a cnt copies of a passed value.
ferencd@0 15958 In case @a cnt is `0`, an empty array is created.
ferencd@0 15959
ferencd@0 15960 @param[in] cnt the number of JSON copies of @a val to create
ferencd@0 15961 @param[in] val the JSON value to copy
ferencd@0 15962
ferencd@0 15963 @post `std::distance(begin(),end()) == cnt` holds.
ferencd@0 15964
ferencd@0 15965 @complexity Linear in @a cnt.
ferencd@0 15966
ferencd@0 15967 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 15968 changes to any JSON value.
ferencd@0 15969
ferencd@0 15970 @liveexample{The following code shows examples for the @ref
ferencd@0 15971 basic_json(size_type\, const basic_json&)
ferencd@0 15972 constructor.,basic_json__size_type_basic_json}
ferencd@0 15973
ferencd@0 15974 @since version 1.0.0
ferencd@0 15975 */
ferencd@0 15976 basic_json(size_type cnt, const basic_json& val)
ferencd@0 15977 : m_type(value_t::array)
ferencd@0 15978 {
ferencd@0 15979 m_value.array = create<array_t>(cnt, val);
ferencd@0 15980 assert_invariant();
ferencd@0 15981 }
ferencd@0 15982
ferencd@0 15983 /*!
ferencd@0 15984 @brief construct a JSON container given an iterator range
ferencd@0 15985
ferencd@0 15986 Constructs the JSON value with the contents of the range `[first, last)`.
ferencd@0 15987 The semantics depends on the different types a JSON value can have:
ferencd@0 15988 - In case of a null type, invalid_iterator.206 is thrown.
ferencd@0 15989 - In case of other primitive types (number, boolean, or string), @a first
ferencd@0 15990 must be `begin()` and @a last must be `end()`. In this case, the value is
ferencd@0 15991 copied. Otherwise, invalid_iterator.204 is thrown.
ferencd@0 15992 - In case of structured types (array, object), the constructor behaves as
ferencd@0 15993 similar versions for `std::vector` or `std::map`; that is, a JSON array
ferencd@0 15994 or object is constructed from the values in the range.
ferencd@0 15995
ferencd@0 15996 @tparam InputIT an input iterator type (@ref iterator or @ref
ferencd@0 15997 const_iterator)
ferencd@0 15998
ferencd@0 15999 @param[in] first begin of the range to copy from (included)
ferencd@0 16000 @param[in] last end of the range to copy from (excluded)
ferencd@0 16001
ferencd@0 16002 @pre Iterators @a first and @a last must be initialized. **This
ferencd@0 16003 precondition is enforced with an assertion (see warning).** If
ferencd@0 16004 assertions are switched off, a violation of this precondition yields
ferencd@0 16005 undefined behavior.
ferencd@0 16006
ferencd@0 16007 @pre Range `[first, last)` is valid. Usually, this precondition cannot be
ferencd@0 16008 checked efficiently. Only certain edge cases are detected; see the
ferencd@0 16009 description of the exceptions below. A violation of this precondition
ferencd@0 16010 yields undefined behavior.
ferencd@0 16011
ferencd@0 16012 @warning A precondition is enforced with a runtime assertion that will
ferencd@0 16013 result in calling `std::abort` if this precondition is not met.
ferencd@0 16014 Assertions can be disabled by defining `NDEBUG` at compile time.
ferencd@0 16015 See https://en.cppreference.com/w/cpp/error/assert for more
ferencd@0 16016 information.
ferencd@0 16017
ferencd@0 16018 @throw invalid_iterator.201 if iterators @a first and @a last are not
ferencd@0 16019 compatible (i.e., do not belong to the same JSON value). In this case,
ferencd@0 16020 the range `[first, last)` is undefined.
ferencd@0 16021 @throw invalid_iterator.204 if iterators @a first and @a last belong to a
ferencd@0 16022 primitive type (number, boolean, or string), but @a first does not point
ferencd@0 16023 to the first element any more. In this case, the range `[first, last)` is
ferencd@0 16024 undefined. See example code below.
ferencd@0 16025 @throw invalid_iterator.206 if iterators @a first and @a last belong to a
ferencd@0 16026 null value. In this case, the range `[first, last)` is undefined.
ferencd@0 16027
ferencd@0 16028 @complexity Linear in distance between @a first and @a last.
ferencd@0 16029
ferencd@0 16030 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 16031 changes to any JSON value.
ferencd@0 16032
ferencd@0 16033 @liveexample{The example below shows several ways to create JSON values by
ferencd@0 16034 specifying a subrange with iterators.,basic_json__InputIt_InputIt}
ferencd@0 16035
ferencd@0 16036 @since version 1.0.0
ferencd@0 16037 */
ferencd@0 16038 template<class InputIT, typename std::enable_if<
ferencd@0 16039 std::is_same<InputIT, typename basic_json_t::iterator>::value or
ferencd@0 16040 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>
ferencd@0 16041 basic_json(InputIT first, InputIT last)
ferencd@0 16042 {
ferencd@0 16043 assert(first.m_object != nullptr);
ferencd@0 16044 assert(last.m_object != nullptr);
ferencd@0 16045
ferencd@0 16046 // make sure iterator fits the current value
ferencd@0 16047 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
ferencd@0 16048 {
ferencd@0 16049 JSON_THROW(invalid_iterator::create(201, "iterators are not compatible"));
ferencd@0 16050 }
ferencd@0 16051
ferencd@0 16052 // copy type from first iterator
ferencd@0 16053 m_type = first.m_object->m_type;
ferencd@0 16054
ferencd@0 16055 // check if iterator range is complete for primitive values
ferencd@0 16056 switch (m_type)
ferencd@0 16057 {
ferencd@0 16058 case value_t::boolean:
ferencd@0 16059 case value_t::number_float:
ferencd@0 16060 case value_t::number_integer:
ferencd@0 16061 case value_t::number_unsigned:
ferencd@0 16062 case value_t::string:
ferencd@0 16063 {
ferencd@0 16064 if (JSON_HEDLEY_UNLIKELY(not first.m_it.primitive_iterator.is_begin()
ferencd@0 16065 or not last.m_it.primitive_iterator.is_end()))
ferencd@0 16066 {
ferencd@0 16067 JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
ferencd@0 16068 }
ferencd@0 16069 break;
ferencd@0 16070 }
ferencd@0 16071
ferencd@0 16072 default:
ferencd@0 16073 break;
ferencd@0 16074 }
ferencd@0 16075
ferencd@0 16076 switch (m_type)
ferencd@0 16077 {
ferencd@0 16078 case value_t::number_integer:
ferencd@0 16079 {
ferencd@0 16080 m_value.number_integer = first.m_object->m_value.number_integer;
ferencd@0 16081 break;
ferencd@0 16082 }
ferencd@0 16083
ferencd@0 16084 case value_t::number_unsigned:
ferencd@0 16085 {
ferencd@0 16086 m_value.number_unsigned = first.m_object->m_value.number_unsigned;
ferencd@0 16087 break;
ferencd@0 16088 }
ferencd@0 16089
ferencd@0 16090 case value_t::number_float:
ferencd@0 16091 {
ferencd@0 16092 m_value.number_float = first.m_object->m_value.number_float;
ferencd@0 16093 break;
ferencd@0 16094 }
ferencd@0 16095
ferencd@0 16096 case value_t::boolean:
ferencd@0 16097 {
ferencd@0 16098 m_value.boolean = first.m_object->m_value.boolean;
ferencd@0 16099 break;
ferencd@0 16100 }
ferencd@0 16101
ferencd@0 16102 case value_t::string:
ferencd@0 16103 {
ferencd@0 16104 m_value = *first.m_object->m_value.string;
ferencd@0 16105 break;
ferencd@0 16106 }
ferencd@0 16107
ferencd@0 16108 case value_t::object:
ferencd@0 16109 {
ferencd@0 16110 m_value.object = create<object_t>(first.m_it.object_iterator,
ferencd@0 16111 last.m_it.object_iterator);
ferencd@0 16112 break;
ferencd@0 16113 }
ferencd@0 16114
ferencd@0 16115 case value_t::array:
ferencd@0 16116 {
ferencd@0 16117 m_value.array = create<array_t>(first.m_it.array_iterator,
ferencd@0 16118 last.m_it.array_iterator);
ferencd@0 16119 break;
ferencd@0 16120 }
ferencd@0 16121
ferencd@0 16122 default:
ferencd@0 16123 JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " +
ferencd@0 16124 std::string(first.m_object->type_name())));
ferencd@0 16125 }
ferencd@0 16126
ferencd@0 16127 assert_invariant();
ferencd@0 16128 }
ferencd@0 16129
ferencd@0 16130
ferencd@0 16131 ///////////////////////////////////////
ferencd@0 16132 // other constructors and destructor //
ferencd@0 16133 ///////////////////////////////////////
ferencd@0 16134
ferencd@0 16135 /// @private
ferencd@0 16136 basic_json(const detail::json_ref<basic_json>& ref)
ferencd@0 16137 : basic_json(ref.moved_or_copied())
ferencd@0 16138 {}
ferencd@0 16139
ferencd@0 16140 /*!
ferencd@0 16141 @brief copy constructor
ferencd@0 16142
ferencd@0 16143 Creates a copy of a given JSON value.
ferencd@0 16144
ferencd@0 16145 @param[in] other the JSON value to copy
ferencd@0 16146
ferencd@0 16147 @post `*this == other`
ferencd@0 16148
ferencd@0 16149 @complexity Linear in the size of @a other.
ferencd@0 16150
ferencd@0 16151 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 16152 changes to any JSON value.
ferencd@0 16153
ferencd@0 16154 @requirement This function helps `basic_json` satisfying the
ferencd@0 16155 [Container](https://en.cppreference.com/w/cpp/named_req/Container)
ferencd@0 16156 requirements:
ferencd@0 16157 - The complexity is linear.
ferencd@0 16158 - As postcondition, it holds: `other == basic_json(other)`.
ferencd@0 16159
ferencd@0 16160 @liveexample{The following code shows an example for the copy
ferencd@0 16161 constructor.,basic_json__basic_json}
ferencd@0 16162
ferencd@0 16163 @since version 1.0.0
ferencd@0 16164 */
ferencd@0 16165 basic_json(const basic_json& other)
ferencd@0 16166 : m_type(other.m_type)
ferencd@0 16167 {
ferencd@0 16168 // check of passed value is valid
ferencd@0 16169 other.assert_invariant();
ferencd@0 16170
ferencd@0 16171 switch (m_type)
ferencd@0 16172 {
ferencd@0 16173 case value_t::object:
ferencd@0 16174 {
ferencd@0 16175 m_value = *other.m_value.object;
ferencd@0 16176 break;
ferencd@0 16177 }
ferencd@0 16178
ferencd@0 16179 case value_t::array:
ferencd@0 16180 {
ferencd@0 16181 m_value = *other.m_value.array;
ferencd@0 16182 break;
ferencd@0 16183 }
ferencd@0 16184
ferencd@0 16185 case value_t::string:
ferencd@0 16186 {
ferencd@0 16187 m_value = *other.m_value.string;
ferencd@0 16188 break;
ferencd@0 16189 }
ferencd@0 16190
ferencd@0 16191 case value_t::boolean:
ferencd@0 16192 {
ferencd@0 16193 m_value = other.m_value.boolean;
ferencd@0 16194 break;
ferencd@0 16195 }
ferencd@0 16196
ferencd@0 16197 case value_t::number_integer:
ferencd@0 16198 {
ferencd@0 16199 m_value = other.m_value.number_integer;
ferencd@0 16200 break;
ferencd@0 16201 }
ferencd@0 16202
ferencd@0 16203 case value_t::number_unsigned:
ferencd@0 16204 {
ferencd@0 16205 m_value = other.m_value.number_unsigned;
ferencd@0 16206 break;
ferencd@0 16207 }
ferencd@0 16208
ferencd@0 16209 case value_t::number_float:
ferencd@0 16210 {
ferencd@0 16211 m_value = other.m_value.number_float;
ferencd@0 16212 break;
ferencd@0 16213 }
ferencd@0 16214
ferencd@0 16215 default:
ferencd@0 16216 break;
ferencd@0 16217 }
ferencd@0 16218
ferencd@0 16219 assert_invariant();
ferencd@0 16220 }
ferencd@0 16221
ferencd@0 16222 /*!
ferencd@0 16223 @brief move constructor
ferencd@0 16224
ferencd@0 16225 Move constructor. Constructs a JSON value with the contents of the given
ferencd@0 16226 value @a other using move semantics. It "steals" the resources from @a
ferencd@0 16227 other and leaves it as JSON null value.
ferencd@0 16228
ferencd@0 16229 @param[in,out] other value to move to this object
ferencd@0 16230
ferencd@0 16231 @post `*this` has the same value as @a other before the call.
ferencd@0 16232 @post @a other is a JSON null value.
ferencd@0 16233
ferencd@0 16234 @complexity Constant.
ferencd@0 16235
ferencd@0 16236 @exceptionsafety No-throw guarantee: this constructor never throws
ferencd@0 16237 exceptions.
ferencd@0 16238
ferencd@0 16239 @requirement This function helps `basic_json` satisfying the
ferencd@0 16240 [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible)
ferencd@0 16241 requirements.
ferencd@0 16242
ferencd@0 16243 @liveexample{The code below shows the move constructor explicitly called
ferencd@0 16244 via std::move.,basic_json__moveconstructor}
ferencd@0 16245
ferencd@0 16246 @since version 1.0.0
ferencd@0 16247 */
ferencd@0 16248 basic_json(basic_json&& other) noexcept
ferencd@0 16249 : m_type(std::move(other.m_type)),
ferencd@0 16250 m_value(std::move(other.m_value))
ferencd@0 16251 {
ferencd@0 16252 // check that passed value is valid
ferencd@0 16253 other.assert_invariant();
ferencd@0 16254
ferencd@0 16255 // invalidate payload
ferencd@0 16256 other.m_type = value_t::null;
ferencd@0 16257 other.m_value = {};
ferencd@0 16258
ferencd@0 16259 assert_invariant();
ferencd@0 16260 }
ferencd@0 16261
ferencd@0 16262 /*!
ferencd@0 16263 @brief copy assignment
ferencd@0 16264
ferencd@0 16265 Copy assignment operator. Copies a JSON value via the "copy and swap"
ferencd@0 16266 strategy: It is expressed in terms of the copy constructor, destructor,
ferencd@0 16267 and the `swap()` member function.
ferencd@0 16268
ferencd@0 16269 @param[in] other value to copy from
ferencd@0 16270
ferencd@0 16271 @complexity Linear.
ferencd@0 16272
ferencd@0 16273 @requirement This function helps `basic_json` satisfying the
ferencd@0 16274 [Container](https://en.cppreference.com/w/cpp/named_req/Container)
ferencd@0 16275 requirements:
ferencd@0 16276 - The complexity is linear.
ferencd@0 16277
ferencd@0 16278 @liveexample{The code below shows and example for the copy assignment. It
ferencd@0 16279 creates a copy of value `a` which is then swapped with `b`. Finally\, the
ferencd@0 16280 copy of `a` (which is the null value after the swap) is
ferencd@0 16281 destroyed.,basic_json__copyassignment}
ferencd@0 16282
ferencd@0 16283 @since version 1.0.0
ferencd@0 16284 */
ferencd@0 16285 basic_json& operator=(basic_json other) noexcept (
ferencd@0 16286 std::is_nothrow_move_constructible<value_t>::value and
ferencd@0 16287 std::is_nothrow_move_assignable<value_t>::value and
ferencd@0 16288 std::is_nothrow_move_constructible<json_value>::value and
ferencd@0 16289 std::is_nothrow_move_assignable<json_value>::value
ferencd@0 16290 )
ferencd@0 16291 {
ferencd@0 16292 // check that passed value is valid
ferencd@0 16293 other.assert_invariant();
ferencd@0 16294
ferencd@0 16295 using std::swap;
ferencd@0 16296 swap(m_type, other.m_type);
ferencd@0 16297 swap(m_value, other.m_value);
ferencd@0 16298
ferencd@0 16299 assert_invariant();
ferencd@0 16300 return *this;
ferencd@0 16301 }
ferencd@0 16302
ferencd@0 16303 /*!
ferencd@0 16304 @brief destructor
ferencd@0 16305
ferencd@0 16306 Destroys the JSON value and frees all allocated memory.
ferencd@0 16307
ferencd@0 16308 @complexity Linear.
ferencd@0 16309
ferencd@0 16310 @requirement This function helps `basic_json` satisfying the
ferencd@0 16311 [Container](https://en.cppreference.com/w/cpp/named_req/Container)
ferencd@0 16312 requirements:
ferencd@0 16313 - The complexity is linear.
ferencd@0 16314 - All stored elements are destroyed and all memory is freed.
ferencd@0 16315
ferencd@0 16316 @since version 1.0.0
ferencd@0 16317 */
ferencd@0 16318 ~basic_json() noexcept
ferencd@0 16319 {
ferencd@0 16320 assert_invariant();
ferencd@0 16321 m_value.destroy(m_type);
ferencd@0 16322 }
ferencd@0 16323
ferencd@0 16324 /// @}
ferencd@0 16325
ferencd@0 16326 public:
ferencd@0 16327 ///////////////////////
ferencd@0 16328 // object inspection //
ferencd@0 16329 ///////////////////////
ferencd@0 16330
ferencd@0 16331 /// @name object inspection
ferencd@0 16332 /// Functions to inspect the type of a JSON value.
ferencd@0 16333 /// @{
ferencd@0 16334
ferencd@0 16335 /*!
ferencd@0 16336 @brief serialization
ferencd@0 16337
ferencd@0 16338 Serialization function for JSON values. The function tries to mimic
ferencd@0 16339 Python's `json.dumps()` function, and currently supports its @a indent
ferencd@0 16340 and @a ensure_ascii parameters.
ferencd@0 16341
ferencd@0 16342 @param[in] indent If indent is nonnegative, then array elements and object
ferencd@0 16343 members will be pretty-printed with that indent level. An indent level of
ferencd@0 16344 `0` will only insert newlines. `-1` (the default) selects the most compact
ferencd@0 16345 representation.
ferencd@0 16346 @param[in] indent_char The character to use for indentation if @a indent is
ferencd@0 16347 greater than `0`. The default is ` ` (space).
ferencd@0 16348 @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters
ferencd@0 16349 in the output are escaped with `\uXXXX` sequences, and the result consists
ferencd@0 16350 of ASCII characters only.
ferencd@0 16351 @param[in] error_handler how to react on decoding errors; there are three
ferencd@0 16352 possible values: `strict` (throws and exception in case a decoding error
ferencd@0 16353 occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD),
ferencd@0 16354 and `ignore` (ignore invalid UTF-8 sequences during serialization).
ferencd@0 16355
ferencd@0 16356 @return string containing the serialization of the JSON value
ferencd@0 16357
ferencd@0 16358 @throw type_error.316 if a string stored inside the JSON value is not
ferencd@0 16359 UTF-8 encoded
ferencd@0 16360
ferencd@0 16361 @complexity Linear.
ferencd@0 16362
ferencd@0 16363 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 16364 changes in the JSON value.
ferencd@0 16365
ferencd@0 16366 @liveexample{The following example shows the effect of different @a indent\,
ferencd@0 16367 @a indent_char\, and @a ensure_ascii parameters to the result of the
ferencd@0 16368 serialization.,dump}
ferencd@0 16369
ferencd@0 16370 @see https://docs.python.org/2/library/json.html#json.dump
ferencd@0 16371
ferencd@0 16372 @since version 1.0.0; indentation character @a indent_char, option
ferencd@0 16373 @a ensure_ascii and exceptions added in version 3.0.0; error
ferencd@0 16374 handlers added in version 3.4.0.
ferencd@0 16375 */
ferencd@0 16376 string_t dump(const int indent = -1,
ferencd@0 16377 const char indent_char = ' ',
ferencd@0 16378 const bool ensure_ascii = false,
ferencd@0 16379 const error_handler_t error_handler = error_handler_t::strict) const
ferencd@0 16380 {
ferencd@0 16381 string_t result;
ferencd@0 16382 serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);
ferencd@0 16383
ferencd@0 16384 if (indent >= 0)
ferencd@0 16385 {
ferencd@0 16386 s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
ferencd@0 16387 }
ferencd@0 16388 else
ferencd@0 16389 {
ferencd@0 16390 s.dump(*this, false, ensure_ascii, 0);
ferencd@0 16391 }
ferencd@0 16392
ferencd@0 16393 return result;
ferencd@0 16394 }
ferencd@0 16395
ferencd@0 16396 /*!
ferencd@0 16397 @brief return the type of the JSON value (explicit)
ferencd@0 16398
ferencd@0 16399 Return the type of the JSON value as a value from the @ref value_t
ferencd@0 16400 enumeration.
ferencd@0 16401
ferencd@0 16402 @return the type of the JSON value
ferencd@0 16403 Value type | return value
ferencd@0 16404 ------------------------- | -------------------------
ferencd@0 16405 null | value_t::null
ferencd@0 16406 boolean | value_t::boolean
ferencd@0 16407 string | value_t::string
ferencd@0 16408 number (integer) | value_t::number_integer
ferencd@0 16409 number (unsigned integer) | value_t::number_unsigned
ferencd@0 16410 number (floating-point) | value_t::number_float
ferencd@0 16411 object | value_t::object
ferencd@0 16412 array | value_t::array
ferencd@0 16413 discarded | value_t::discarded
ferencd@0 16414
ferencd@0 16415 @complexity Constant.
ferencd@0 16416
ferencd@0 16417 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16418 exceptions.
ferencd@0 16419
ferencd@0 16420 @liveexample{The following code exemplifies `type()` for all JSON
ferencd@0 16421 types.,type}
ferencd@0 16422
ferencd@0 16423 @sa @ref operator value_t() -- return the type of the JSON value (implicit)
ferencd@0 16424 @sa @ref type_name() -- return the type as string
ferencd@0 16425
ferencd@0 16426 @since version 1.0.0
ferencd@0 16427 */
ferencd@0 16428 constexpr value_t type() const noexcept
ferencd@0 16429 {
ferencd@0 16430 return m_type;
ferencd@0 16431 }
ferencd@0 16432
ferencd@0 16433 /*!
ferencd@0 16434 @brief return whether type is primitive
ferencd@0 16435
ferencd@0 16436 This function returns true if and only if the JSON type is primitive
ferencd@0 16437 (string, number, boolean, or null).
ferencd@0 16438
ferencd@0 16439 @return `true` if type is primitive (string, number, boolean, or null),
ferencd@0 16440 `false` otherwise.
ferencd@0 16441
ferencd@0 16442 @complexity Constant.
ferencd@0 16443
ferencd@0 16444 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16445 exceptions.
ferencd@0 16446
ferencd@0 16447 @liveexample{The following code exemplifies `is_primitive()` for all JSON
ferencd@0 16448 types.,is_primitive}
ferencd@0 16449
ferencd@0 16450 @sa @ref is_structured() -- returns whether JSON value is structured
ferencd@0 16451 @sa @ref is_null() -- returns whether JSON value is `null`
ferencd@0 16452 @sa @ref is_string() -- returns whether JSON value is a string
ferencd@0 16453 @sa @ref is_boolean() -- returns whether JSON value is a boolean
ferencd@0 16454 @sa @ref is_number() -- returns whether JSON value is a number
ferencd@0 16455
ferencd@0 16456 @since version 1.0.0
ferencd@0 16457 */
ferencd@0 16458 constexpr bool is_primitive() const noexcept
ferencd@0 16459 {
ferencd@0 16460 return is_null() or is_string() or is_boolean() or is_number();
ferencd@0 16461 }
ferencd@0 16462
ferencd@0 16463 /*!
ferencd@0 16464 @brief return whether type is structured
ferencd@0 16465
ferencd@0 16466 This function returns true if and only if the JSON type is structured
ferencd@0 16467 (array or object).
ferencd@0 16468
ferencd@0 16469 @return `true` if type is structured (array or object), `false` otherwise.
ferencd@0 16470
ferencd@0 16471 @complexity Constant.
ferencd@0 16472
ferencd@0 16473 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16474 exceptions.
ferencd@0 16475
ferencd@0 16476 @liveexample{The following code exemplifies `is_structured()` for all JSON
ferencd@0 16477 types.,is_structured}
ferencd@0 16478
ferencd@0 16479 @sa @ref is_primitive() -- returns whether value is primitive
ferencd@0 16480 @sa @ref is_array() -- returns whether value is an array
ferencd@0 16481 @sa @ref is_object() -- returns whether value is an object
ferencd@0 16482
ferencd@0 16483 @since version 1.0.0
ferencd@0 16484 */
ferencd@0 16485 constexpr bool is_structured() const noexcept
ferencd@0 16486 {
ferencd@0 16487 return is_array() or is_object();
ferencd@0 16488 }
ferencd@0 16489
ferencd@0 16490 /*!
ferencd@0 16491 @brief return whether value is null
ferencd@0 16492
ferencd@0 16493 This function returns true if and only if the JSON value is null.
ferencd@0 16494
ferencd@0 16495 @return `true` if type is null, `false` otherwise.
ferencd@0 16496
ferencd@0 16497 @complexity Constant.
ferencd@0 16498
ferencd@0 16499 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16500 exceptions.
ferencd@0 16501
ferencd@0 16502 @liveexample{The following code exemplifies `is_null()` for all JSON
ferencd@0 16503 types.,is_null}
ferencd@0 16504
ferencd@0 16505 @since version 1.0.0
ferencd@0 16506 */
ferencd@0 16507 constexpr bool is_null() const noexcept
ferencd@0 16508 {
ferencd@0 16509 return m_type == value_t::null;
ferencd@0 16510 }
ferencd@0 16511
ferencd@0 16512 /*!
ferencd@0 16513 @brief return whether value is a boolean
ferencd@0 16514
ferencd@0 16515 This function returns true if and only if the JSON value is a boolean.
ferencd@0 16516
ferencd@0 16517 @return `true` if type is boolean, `false` otherwise.
ferencd@0 16518
ferencd@0 16519 @complexity Constant.
ferencd@0 16520
ferencd@0 16521 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16522 exceptions.
ferencd@0 16523
ferencd@0 16524 @liveexample{The following code exemplifies `is_boolean()` for all JSON
ferencd@0 16525 types.,is_boolean}
ferencd@0 16526
ferencd@0 16527 @since version 1.0.0
ferencd@0 16528 */
ferencd@0 16529 constexpr bool is_boolean() const noexcept
ferencd@0 16530 {
ferencd@0 16531 return m_type == value_t::boolean;
ferencd@0 16532 }
ferencd@0 16533
ferencd@0 16534 /*!
ferencd@0 16535 @brief return whether value is a number
ferencd@0 16536
ferencd@0 16537 This function returns true if and only if the JSON value is a number. This
ferencd@0 16538 includes both integer (signed and unsigned) and floating-point values.
ferencd@0 16539
ferencd@0 16540 @return `true` if type is number (regardless whether integer, unsigned
ferencd@0 16541 integer or floating-type), `false` otherwise.
ferencd@0 16542
ferencd@0 16543 @complexity Constant.
ferencd@0 16544
ferencd@0 16545 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16546 exceptions.
ferencd@0 16547
ferencd@0 16548 @liveexample{The following code exemplifies `is_number()` for all JSON
ferencd@0 16549 types.,is_number}
ferencd@0 16550
ferencd@0 16551 @sa @ref is_number_integer() -- check if value is an integer or unsigned
ferencd@0 16552 integer number
ferencd@0 16553 @sa @ref is_number_unsigned() -- check if value is an unsigned integer
ferencd@0 16554 number
ferencd@0 16555 @sa @ref is_number_float() -- check if value is a floating-point number
ferencd@0 16556
ferencd@0 16557 @since version 1.0.0
ferencd@0 16558 */
ferencd@0 16559 constexpr bool is_number() const noexcept
ferencd@0 16560 {
ferencd@0 16561 return is_number_integer() or is_number_float();
ferencd@0 16562 }
ferencd@0 16563
ferencd@0 16564 /*!
ferencd@0 16565 @brief return whether value is an integer number
ferencd@0 16566
ferencd@0 16567 This function returns true if and only if the JSON value is a signed or
ferencd@0 16568 unsigned integer number. This excludes floating-point values.
ferencd@0 16569
ferencd@0 16570 @return `true` if type is an integer or unsigned integer number, `false`
ferencd@0 16571 otherwise.
ferencd@0 16572
ferencd@0 16573 @complexity Constant.
ferencd@0 16574
ferencd@0 16575 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16576 exceptions.
ferencd@0 16577
ferencd@0 16578 @liveexample{The following code exemplifies `is_number_integer()` for all
ferencd@0 16579 JSON types.,is_number_integer}
ferencd@0 16580
ferencd@0 16581 @sa @ref is_number() -- check if value is a number
ferencd@0 16582 @sa @ref is_number_unsigned() -- check if value is an unsigned integer
ferencd@0 16583 number
ferencd@0 16584 @sa @ref is_number_float() -- check if value is a floating-point number
ferencd@0 16585
ferencd@0 16586 @since version 1.0.0
ferencd@0 16587 */
ferencd@0 16588 constexpr bool is_number_integer() const noexcept
ferencd@0 16589 {
ferencd@0 16590 return m_type == value_t::number_integer or m_type == value_t::number_unsigned;
ferencd@0 16591 }
ferencd@0 16592
ferencd@0 16593 /*!
ferencd@0 16594 @brief return whether value is an unsigned integer number
ferencd@0 16595
ferencd@0 16596 This function returns true if and only if the JSON value is an unsigned
ferencd@0 16597 integer number. This excludes floating-point and signed integer values.
ferencd@0 16598
ferencd@0 16599 @return `true` if type is an unsigned integer number, `false` otherwise.
ferencd@0 16600
ferencd@0 16601 @complexity Constant.
ferencd@0 16602
ferencd@0 16603 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16604 exceptions.
ferencd@0 16605
ferencd@0 16606 @liveexample{The following code exemplifies `is_number_unsigned()` for all
ferencd@0 16607 JSON types.,is_number_unsigned}
ferencd@0 16608
ferencd@0 16609 @sa @ref is_number() -- check if value is a number
ferencd@0 16610 @sa @ref is_number_integer() -- check if value is an integer or unsigned
ferencd@0 16611 integer number
ferencd@0 16612 @sa @ref is_number_float() -- check if value is a floating-point number
ferencd@0 16613
ferencd@0 16614 @since version 2.0.0
ferencd@0 16615 */
ferencd@0 16616 constexpr bool is_number_unsigned() const noexcept
ferencd@0 16617 {
ferencd@0 16618 return m_type == value_t::number_unsigned;
ferencd@0 16619 }
ferencd@0 16620
ferencd@0 16621 /*!
ferencd@0 16622 @brief return whether value is a floating-point number
ferencd@0 16623
ferencd@0 16624 This function returns true if and only if the JSON value is a
ferencd@0 16625 floating-point number. This excludes signed and unsigned integer values.
ferencd@0 16626
ferencd@0 16627 @return `true` if type is a floating-point number, `false` otherwise.
ferencd@0 16628
ferencd@0 16629 @complexity Constant.
ferencd@0 16630
ferencd@0 16631 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16632 exceptions.
ferencd@0 16633
ferencd@0 16634 @liveexample{The following code exemplifies `is_number_float()` for all
ferencd@0 16635 JSON types.,is_number_float}
ferencd@0 16636
ferencd@0 16637 @sa @ref is_number() -- check if value is number
ferencd@0 16638 @sa @ref is_number_integer() -- check if value is an integer number
ferencd@0 16639 @sa @ref is_number_unsigned() -- check if value is an unsigned integer
ferencd@0 16640 number
ferencd@0 16641
ferencd@0 16642 @since version 1.0.0
ferencd@0 16643 */
ferencd@0 16644 constexpr bool is_number_float() const noexcept
ferencd@0 16645 {
ferencd@0 16646 return m_type == value_t::number_float;
ferencd@0 16647 }
ferencd@0 16648
ferencd@0 16649 /*!
ferencd@0 16650 @brief return whether value is an object
ferencd@0 16651
ferencd@0 16652 This function returns true if and only if the JSON value is an object.
ferencd@0 16653
ferencd@0 16654 @return `true` if type is object, `false` otherwise.
ferencd@0 16655
ferencd@0 16656 @complexity Constant.
ferencd@0 16657
ferencd@0 16658 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16659 exceptions.
ferencd@0 16660
ferencd@0 16661 @liveexample{The following code exemplifies `is_object()` for all JSON
ferencd@0 16662 types.,is_object}
ferencd@0 16663
ferencd@0 16664 @since version 1.0.0
ferencd@0 16665 */
ferencd@0 16666 constexpr bool is_object() const noexcept
ferencd@0 16667 {
ferencd@0 16668 return m_type == value_t::object;
ferencd@0 16669 }
ferencd@0 16670
ferencd@0 16671 /*!
ferencd@0 16672 @brief return whether value is an array
ferencd@0 16673
ferencd@0 16674 This function returns true if and only if the JSON value is an array.
ferencd@0 16675
ferencd@0 16676 @return `true` if type is array, `false` otherwise.
ferencd@0 16677
ferencd@0 16678 @complexity Constant.
ferencd@0 16679
ferencd@0 16680 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16681 exceptions.
ferencd@0 16682
ferencd@0 16683 @liveexample{The following code exemplifies `is_array()` for all JSON
ferencd@0 16684 types.,is_array}
ferencd@0 16685
ferencd@0 16686 @since version 1.0.0
ferencd@0 16687 */
ferencd@0 16688 constexpr bool is_array() const noexcept
ferencd@0 16689 {
ferencd@0 16690 return m_type == value_t::array;
ferencd@0 16691 }
ferencd@0 16692
ferencd@0 16693 /*!
ferencd@0 16694 @brief return whether value is a string
ferencd@0 16695
ferencd@0 16696 This function returns true if and only if the JSON value is a string.
ferencd@0 16697
ferencd@0 16698 @return `true` if type is string, `false` otherwise.
ferencd@0 16699
ferencd@0 16700 @complexity Constant.
ferencd@0 16701
ferencd@0 16702 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16703 exceptions.
ferencd@0 16704
ferencd@0 16705 @liveexample{The following code exemplifies `is_string()` for all JSON
ferencd@0 16706 types.,is_string}
ferencd@0 16707
ferencd@0 16708 @since version 1.0.0
ferencd@0 16709 */
ferencd@0 16710 constexpr bool is_string() const noexcept
ferencd@0 16711 {
ferencd@0 16712 return m_type == value_t::string;
ferencd@0 16713 }
ferencd@0 16714
ferencd@0 16715 /*!
ferencd@0 16716 @brief return whether value is discarded
ferencd@0 16717
ferencd@0 16718 This function returns true if and only if the JSON value was discarded
ferencd@0 16719 during parsing with a callback function (see @ref parser_callback_t).
ferencd@0 16720
ferencd@0 16721 @note This function will always be `false` for JSON values after parsing.
ferencd@0 16722 That is, discarded values can only occur during parsing, but will be
ferencd@0 16723 removed when inside a structured value or replaced by null in other cases.
ferencd@0 16724
ferencd@0 16725 @return `true` if type is discarded, `false` otherwise.
ferencd@0 16726
ferencd@0 16727 @complexity Constant.
ferencd@0 16728
ferencd@0 16729 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16730 exceptions.
ferencd@0 16731
ferencd@0 16732 @liveexample{The following code exemplifies `is_discarded()` for all JSON
ferencd@0 16733 types.,is_discarded}
ferencd@0 16734
ferencd@0 16735 @since version 1.0.0
ferencd@0 16736 */
ferencd@0 16737 constexpr bool is_discarded() const noexcept
ferencd@0 16738 {
ferencd@0 16739 return m_type == value_t::discarded;
ferencd@0 16740 }
ferencd@0 16741
ferencd@0 16742 /*!
ferencd@0 16743 @brief return the type of the JSON value (implicit)
ferencd@0 16744
ferencd@0 16745 Implicitly return the type of the JSON value as a value from the @ref
ferencd@0 16746 value_t enumeration.
ferencd@0 16747
ferencd@0 16748 @return the type of the JSON value
ferencd@0 16749
ferencd@0 16750 @complexity Constant.
ferencd@0 16751
ferencd@0 16752 @exceptionsafety No-throw guarantee: this member function never throws
ferencd@0 16753 exceptions.
ferencd@0 16754
ferencd@0 16755 @liveexample{The following code exemplifies the @ref value_t operator for
ferencd@0 16756 all JSON types.,operator__value_t}
ferencd@0 16757
ferencd@0 16758 @sa @ref type() -- return the type of the JSON value (explicit)
ferencd@0 16759 @sa @ref type_name() -- return the type as string
ferencd@0 16760
ferencd@0 16761 @since version 1.0.0
ferencd@0 16762 */
ferencd@0 16763 constexpr operator value_t() const noexcept
ferencd@0 16764 {
ferencd@0 16765 return m_type;
ferencd@0 16766 }
ferencd@0 16767
ferencd@0 16768 /// @}
ferencd@0 16769
ferencd@0 16770 private:
ferencd@0 16771 //////////////////
ferencd@0 16772 // value access //
ferencd@0 16773 //////////////////
ferencd@0 16774
ferencd@0 16775 /// get a boolean (explicit)
ferencd@0 16776 boolean_t get_impl(boolean_t* /*unused*/) const
ferencd@0 16777 {
ferencd@0 16778 if (JSON_HEDLEY_LIKELY(is_boolean()))
ferencd@0 16779 {
ferencd@0 16780 return m_value.boolean;
ferencd@0 16781 }
ferencd@0 16782
ferencd@0 16783 JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name())));
ferencd@0 16784 }
ferencd@0 16785
ferencd@0 16786 /// get a pointer to the value (object)
ferencd@0 16787 object_t* get_impl_ptr(object_t* /*unused*/) noexcept
ferencd@0 16788 {
ferencd@0 16789 return is_object() ? m_value.object : nullptr;
ferencd@0 16790 }
ferencd@0 16791
ferencd@0 16792 /// get a pointer to the value (object)
ferencd@0 16793 constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
ferencd@0 16794 {
ferencd@0 16795 return is_object() ? m_value.object : nullptr;
ferencd@0 16796 }
ferencd@0 16797
ferencd@0 16798 /// get a pointer to the value (array)
ferencd@0 16799 array_t* get_impl_ptr(array_t* /*unused*/) noexcept
ferencd@0 16800 {
ferencd@0 16801 return is_array() ? m_value.array : nullptr;
ferencd@0 16802 }
ferencd@0 16803
ferencd@0 16804 /// get a pointer to the value (array)
ferencd@0 16805 constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
ferencd@0 16806 {
ferencd@0 16807 return is_array() ? m_value.array : nullptr;
ferencd@0 16808 }
ferencd@0 16809
ferencd@0 16810 /// get a pointer to the value (string)
ferencd@0 16811 string_t* get_impl_ptr(string_t* /*unused*/) noexcept
ferencd@0 16812 {
ferencd@0 16813 return is_string() ? m_value.string : nullptr;
ferencd@0 16814 }
ferencd@0 16815
ferencd@0 16816 /// get a pointer to the value (string)
ferencd@0 16817 constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
ferencd@0 16818 {
ferencd@0 16819 return is_string() ? m_value.string : nullptr;
ferencd@0 16820 }
ferencd@0 16821
ferencd@0 16822 /// get a pointer to the value (boolean)
ferencd@0 16823 boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
ferencd@0 16824 {
ferencd@0 16825 return is_boolean() ? &m_value.boolean : nullptr;
ferencd@0 16826 }
ferencd@0 16827
ferencd@0 16828 /// get a pointer to the value (boolean)
ferencd@0 16829 constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
ferencd@0 16830 {
ferencd@0 16831 return is_boolean() ? &m_value.boolean : nullptr;
ferencd@0 16832 }
ferencd@0 16833
ferencd@0 16834 /// get a pointer to the value (integer number)
ferencd@0 16835 number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
ferencd@0 16836 {
ferencd@0 16837 return is_number_integer() ? &m_value.number_integer : nullptr;
ferencd@0 16838 }
ferencd@0 16839
ferencd@0 16840 /// get a pointer to the value (integer number)
ferencd@0 16841 constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
ferencd@0 16842 {
ferencd@0 16843 return is_number_integer() ? &m_value.number_integer : nullptr;
ferencd@0 16844 }
ferencd@0 16845
ferencd@0 16846 /// get a pointer to the value (unsigned number)
ferencd@0 16847 number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
ferencd@0 16848 {
ferencd@0 16849 return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
ferencd@0 16850 }
ferencd@0 16851
ferencd@0 16852 /// get a pointer to the value (unsigned number)
ferencd@0 16853 constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
ferencd@0 16854 {
ferencd@0 16855 return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
ferencd@0 16856 }
ferencd@0 16857
ferencd@0 16858 /// get a pointer to the value (floating-point number)
ferencd@0 16859 number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
ferencd@0 16860 {
ferencd@0 16861 return is_number_float() ? &m_value.number_float : nullptr;
ferencd@0 16862 }
ferencd@0 16863
ferencd@0 16864 /// get a pointer to the value (floating-point number)
ferencd@0 16865 constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
ferencd@0 16866 {
ferencd@0 16867 return is_number_float() ? &m_value.number_float : nullptr;
ferencd@0 16868 }
ferencd@0 16869
ferencd@0 16870 /*!
ferencd@0 16871 @brief helper function to implement get_ref()
ferencd@0 16872
ferencd@0 16873 This function helps to implement get_ref() without code duplication for
ferencd@0 16874 const and non-const overloads
ferencd@0 16875
ferencd@0 16876 @tparam ThisType will be deduced as `basic_json` or `const basic_json`
ferencd@0 16877
ferencd@0 16878 @throw type_error.303 if ReferenceType does not match underlying value
ferencd@0 16879 type of the current JSON
ferencd@0 16880 */
ferencd@0 16881 template<typename ReferenceType, typename ThisType>
ferencd@0 16882 static ReferenceType get_ref_impl(ThisType& obj)
ferencd@0 16883 {
ferencd@0 16884 // delegate the call to get_ptr<>()
ferencd@0 16885 auto ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();
ferencd@0 16886
ferencd@0 16887 if (JSON_HEDLEY_LIKELY(ptr != nullptr))
ferencd@0 16888 {
ferencd@0 16889 return *ptr;
ferencd@0 16890 }
ferencd@0 16891
ferencd@0 16892 JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name())));
ferencd@0 16893 }
ferencd@0 16894
ferencd@0 16895 public:
ferencd@0 16896 /// @name value access
ferencd@0 16897 /// Direct access to the stored value of a JSON value.
ferencd@0 16898 /// @{
ferencd@0 16899
ferencd@0 16900 /*!
ferencd@0 16901 @brief get special-case overload
ferencd@0 16902
ferencd@0 16903 This overloads avoids a lot of template boilerplate, it can be seen as the
ferencd@0 16904 identity method
ferencd@0 16905
ferencd@0 16906 @tparam BasicJsonType == @ref basic_json
ferencd@0 16907
ferencd@0 16908 @return a copy of *this
ferencd@0 16909
ferencd@0 16910 @complexity Constant.
ferencd@0 16911
ferencd@0 16912 @since version 2.1.0
ferencd@0 16913 */
ferencd@0 16914 template<typename BasicJsonType, detail::enable_if_t<
ferencd@0 16915 std::is_same<typename std::remove_const<BasicJsonType>::type, basic_json_t>::value,
ferencd@0 16916 int> = 0>
ferencd@0 16917 basic_json get() const
ferencd@0 16918 {
ferencd@0 16919 return *this;
ferencd@0 16920 }
ferencd@0 16921
ferencd@0 16922 /*!
ferencd@0 16923 @brief get special-case overload
ferencd@0 16924
ferencd@0 16925 This overloads converts the current @ref basic_json in a different
ferencd@0 16926 @ref basic_json type
ferencd@0 16927
ferencd@0 16928 @tparam BasicJsonType == @ref basic_json
ferencd@0 16929
ferencd@0 16930 @return a copy of *this, converted into @tparam BasicJsonType
ferencd@0 16931
ferencd@0 16932 @complexity Depending on the implementation of the called `from_json()`
ferencd@0 16933 method.
ferencd@0 16934
ferencd@0 16935 @since version 3.2.0
ferencd@0 16936 */
ferencd@0 16937 template<typename BasicJsonType, detail::enable_if_t<
ferencd@0 16938 not std::is_same<BasicJsonType, basic_json>::value and
ferencd@0 16939 detail::is_basic_json<BasicJsonType>::value, int> = 0>
ferencd@0 16940 BasicJsonType get() const
ferencd@0 16941 {
ferencd@0 16942 return *this;
ferencd@0 16943 }
ferencd@0 16944
ferencd@0 16945 /*!
ferencd@0 16946 @brief get a value (explicit)
ferencd@0 16947
ferencd@0 16948 Explicit type conversion between the JSON value and a compatible value
ferencd@0 16949 which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
ferencd@0 16950 and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
ferencd@0 16951 The value is converted by calling the @ref json_serializer<ValueType>
ferencd@0 16952 `from_json()` method.
ferencd@0 16953
ferencd@0 16954 The function is equivalent to executing
ferencd@0 16955 @code {.cpp}
ferencd@0 16956 ValueType ret;
ferencd@0 16957 JSONSerializer<ValueType>::from_json(*this, ret);
ferencd@0 16958 return ret;
ferencd@0 16959 @endcode
ferencd@0 16960
ferencd@0 16961 This overloads is chosen if:
ferencd@0 16962 - @a ValueType is not @ref basic_json,
ferencd@0 16963 - @ref json_serializer<ValueType> has a `from_json()` method of the form
ferencd@0 16964 `void from_json(const basic_json&, ValueType&)`, and
ferencd@0 16965 - @ref json_serializer<ValueType> does not have a `from_json()` method of
ferencd@0 16966 the form `ValueType from_json(const basic_json&)`
ferencd@0 16967
ferencd@0 16968 @tparam ValueTypeCV the provided value type
ferencd@0 16969 @tparam ValueType the returned value type
ferencd@0 16970
ferencd@0 16971 @return copy of the JSON value, converted to @a ValueType
ferencd@0 16972
ferencd@0 16973 @throw what @ref json_serializer<ValueType> `from_json()` method throws
ferencd@0 16974
ferencd@0 16975 @liveexample{The example below shows several conversions from JSON values
ferencd@0 16976 to other types. There a few things to note: (1) Floating-point numbers can
ferencd@0 16977 be converted to integers\, (2) A JSON array can be converted to a standard
ferencd@0 16978 `std::vector<short>`\, (3) A JSON object can be converted to C++
ferencd@0 16979 associative containers such as `std::unordered_map<std::string\,
ferencd@0 16980 json>`.,get__ValueType_const}
ferencd@0 16981
ferencd@0 16982 @since version 2.1.0
ferencd@0 16983 */
ferencd@0 16984 template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
ferencd@0 16985 detail::enable_if_t <
ferencd@0 16986 not detail::is_basic_json<ValueType>::value and
ferencd@0 16987 detail::has_from_json<basic_json_t, ValueType>::value and
ferencd@0 16988 not detail::has_non_default_from_json<basic_json_t, ValueType>::value,
ferencd@0 16989 int> = 0>
ferencd@0 16990 ValueType get() const noexcept(noexcept(
ferencd@0 16991 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))
ferencd@0 16992 {
ferencd@0 16993 // we cannot static_assert on ValueTypeCV being non-const, because
ferencd@0 16994 // there is support for get<const basic_json_t>(), which is why we
ferencd@0 16995 // still need the uncvref
ferencd@0 16996 static_assert(not std::is_reference<ValueTypeCV>::value,
ferencd@0 16997 "get() cannot be used with reference types, you might want to use get_ref()");
ferencd@0 16998 static_assert(std::is_default_constructible<ValueType>::value,
ferencd@0 16999 "types must be DefaultConstructible when used with get()");
ferencd@0 17000
ferencd@0 17001 ValueType ret;
ferencd@0 17002 JSONSerializer<ValueType>::from_json(*this, ret);
ferencd@0 17003 return ret;
ferencd@0 17004 }
ferencd@0 17005
ferencd@0 17006 /*!
ferencd@0 17007 @brief get a value (explicit); special case
ferencd@0 17008
ferencd@0 17009 Explicit type conversion between the JSON value and a compatible value
ferencd@0 17010 which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
ferencd@0 17011 and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
ferencd@0 17012 The value is converted by calling the @ref json_serializer<ValueType>
ferencd@0 17013 `from_json()` method.
ferencd@0 17014
ferencd@0 17015 The function is equivalent to executing
ferencd@0 17016 @code {.cpp}
ferencd@0 17017 return JSONSerializer<ValueTypeCV>::from_json(*this);
ferencd@0 17018 @endcode
ferencd@0 17019
ferencd@0 17020 This overloads is chosen if:
ferencd@0 17021 - @a ValueType is not @ref basic_json and
ferencd@0 17022 - @ref json_serializer<ValueType> has a `from_json()` method of the form
ferencd@0 17023 `ValueType from_json(const basic_json&)`
ferencd@0 17024
ferencd@0 17025 @note If @ref json_serializer<ValueType> has both overloads of
ferencd@0 17026 `from_json()`, this one is chosen.
ferencd@0 17027
ferencd@0 17028 @tparam ValueTypeCV the provided value type
ferencd@0 17029 @tparam ValueType the returned value type
ferencd@0 17030
ferencd@0 17031 @return copy of the JSON value, converted to @a ValueType
ferencd@0 17032
ferencd@0 17033 @throw what @ref json_serializer<ValueType> `from_json()` method throws
ferencd@0 17034
ferencd@0 17035 @since version 2.1.0
ferencd@0 17036 */
ferencd@0 17037 template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,
ferencd@0 17038 detail::enable_if_t<not std::is_same<basic_json_t, ValueType>::value and
ferencd@0 17039 detail::has_non_default_from_json<basic_json_t, ValueType>::value,
ferencd@0 17040 int> = 0>
ferencd@0 17041 ValueType get() const noexcept(noexcept(
ferencd@0 17042 JSONSerializer<ValueTypeCV>::from_json(std::declval<const basic_json_t&>())))
ferencd@0 17043 {
ferencd@0 17044 static_assert(not std::is_reference<ValueTypeCV>::value,
ferencd@0 17045 "get() cannot be used with reference types, you might want to use get_ref()");
ferencd@0 17046 return JSONSerializer<ValueTypeCV>::from_json(*this);
ferencd@0 17047 }
ferencd@0 17048
ferencd@0 17049 /*!
ferencd@0 17050 @brief get a value (explicit)
ferencd@0 17051
ferencd@0 17052 Explicit type conversion between the JSON value and a compatible value.
ferencd@0 17053 The value is filled into the input parameter by calling the @ref json_serializer<ValueType>
ferencd@0 17054 `from_json()` method.
ferencd@0 17055
ferencd@0 17056 The function is equivalent to executing
ferencd@0 17057 @code {.cpp}
ferencd@0 17058 ValueType v;
ferencd@0 17059 JSONSerializer<ValueType>::from_json(*this, v);
ferencd@0 17060 @endcode
ferencd@0 17061
ferencd@0 17062 This overloads is chosen if:
ferencd@0 17063 - @a ValueType is not @ref basic_json,
ferencd@0 17064 - @ref json_serializer<ValueType> has a `from_json()` method of the form
ferencd@0 17065 `void from_json(const basic_json&, ValueType&)`, and
ferencd@0 17066
ferencd@0 17067 @tparam ValueType the input parameter type.
ferencd@0 17068
ferencd@0 17069 @return the input parameter, allowing chaining calls.
ferencd@0 17070
ferencd@0 17071 @throw what @ref json_serializer<ValueType> `from_json()` method throws
ferencd@0 17072
ferencd@0 17073 @liveexample{The example below shows several conversions from JSON values
ferencd@0 17074 to other types. There a few things to note: (1) Floating-point numbers can
ferencd@0 17075 be converted to integers\, (2) A JSON array can be converted to a standard
ferencd@0 17076 `std::vector<short>`\, (3) A JSON object can be converted to C++
ferencd@0 17077 associative containers such as `std::unordered_map<std::string\,
ferencd@0 17078 json>`.,get_to}
ferencd@0 17079
ferencd@0 17080 @since version 3.3.0
ferencd@0 17081 */
ferencd@0 17082 template<typename ValueType,
ferencd@0 17083 detail::enable_if_t <
ferencd@0 17084 not detail::is_basic_json<ValueType>::value and
ferencd@0 17085 detail::has_from_json<basic_json_t, ValueType>::value,
ferencd@0 17086 int> = 0>
ferencd@0 17087 ValueType & get_to(ValueType& v) const noexcept(noexcept(
ferencd@0 17088 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))
ferencd@0 17089 {
ferencd@0 17090 JSONSerializer<ValueType>::from_json(*this, v);
ferencd@0 17091 return v;
ferencd@0 17092 }
ferencd@0 17093
ferencd@0 17094 template <
ferencd@0 17095 typename T, std::size_t N,
ferencd@0 17096 typename Array = T (&)[N],
ferencd@0 17097 detail::enable_if_t <
ferencd@0 17098 detail::has_from_json<basic_json_t, Array>::value, int > = 0 >
ferencd@0 17099 Array get_to(T (&v)[N]) const
ferencd@0 17100 noexcept(noexcept(JSONSerializer<Array>::from_json(
ferencd@0 17101 std::declval<const basic_json_t&>(), v)))
ferencd@0 17102 {
ferencd@0 17103 JSONSerializer<Array>::from_json(*this, v);
ferencd@0 17104 return v;
ferencd@0 17105 }
ferencd@0 17106
ferencd@0 17107
ferencd@0 17108 /*!
ferencd@0 17109 @brief get a pointer value (implicit)
ferencd@0 17110
ferencd@0 17111 Implicit pointer access to the internally stored JSON value. No copies are
ferencd@0 17112 made.
ferencd@0 17113
ferencd@0 17114 @warning Writing data to the pointee of the result yields an undefined
ferencd@0 17115 state.
ferencd@0 17116
ferencd@0 17117 @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
ferencd@0 17118 object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
ferencd@0 17119 @ref number_unsigned_t, or @ref number_float_t. Enforced by a static
ferencd@0 17120 assertion.
ferencd@0 17121
ferencd@0 17122 @return pointer to the internally stored JSON value if the requested
ferencd@0 17123 pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
ferencd@0 17124
ferencd@0 17125 @complexity Constant.
ferencd@0 17126
ferencd@0 17127 @liveexample{The example below shows how pointers to internal values of a
ferencd@0 17128 JSON value can be requested. Note that no type conversions are made and a
ferencd@0 17129 `nullptr` is returned if the value and the requested pointer type does not
ferencd@0 17130 match.,get_ptr}
ferencd@0 17131
ferencd@0 17132 @since version 1.0.0
ferencd@0 17133 */
ferencd@0 17134 template<typename PointerType, typename std::enable_if<
ferencd@0 17135 std::is_pointer<PointerType>::value, int>::type = 0>
ferencd@0 17136 auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
ferencd@0 17137 {
ferencd@0 17138 // delegate the call to get_impl_ptr<>()
ferencd@0 17139 return get_impl_ptr(static_cast<PointerType>(nullptr));
ferencd@0 17140 }
ferencd@0 17141
ferencd@0 17142 /*!
ferencd@0 17143 @brief get a pointer value (implicit)
ferencd@0 17144 @copydoc get_ptr()
ferencd@0 17145 */
ferencd@0 17146 template<typename PointerType, typename std::enable_if<
ferencd@0 17147 std::is_pointer<PointerType>::value and
ferencd@0 17148 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
ferencd@0 17149 constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
ferencd@0 17150 {
ferencd@0 17151 // delegate the call to get_impl_ptr<>() const
ferencd@0 17152 return get_impl_ptr(static_cast<PointerType>(nullptr));
ferencd@0 17153 }
ferencd@0 17154
ferencd@0 17155 /*!
ferencd@0 17156 @brief get a pointer value (explicit)
ferencd@0 17157
ferencd@0 17158 Explicit pointer access to the internally stored JSON value. No copies are
ferencd@0 17159 made.
ferencd@0 17160
ferencd@0 17161 @warning The pointer becomes invalid if the underlying JSON object
ferencd@0 17162 changes.
ferencd@0 17163
ferencd@0 17164 @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
ferencd@0 17165 object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
ferencd@0 17166 @ref number_unsigned_t, or @ref number_float_t.
ferencd@0 17167
ferencd@0 17168 @return pointer to the internally stored JSON value if the requested
ferencd@0 17169 pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
ferencd@0 17170
ferencd@0 17171 @complexity Constant.
ferencd@0 17172
ferencd@0 17173 @liveexample{The example below shows how pointers to internal values of a
ferencd@0 17174 JSON value can be requested. Note that no type conversions are made and a
ferencd@0 17175 `nullptr` is returned if the value and the requested pointer type does not
ferencd@0 17176 match.,get__PointerType}
ferencd@0 17177
ferencd@0 17178 @sa @ref get_ptr() for explicit pointer-member access
ferencd@0 17179
ferencd@0 17180 @since version 1.0.0
ferencd@0 17181 */
ferencd@0 17182 template<typename PointerType, typename std::enable_if<
ferencd@0 17183 std::is_pointer<PointerType>::value, int>::type = 0>
ferencd@0 17184 auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())
ferencd@0 17185 {
ferencd@0 17186 // delegate the call to get_ptr
ferencd@0 17187 return get_ptr<PointerType>();
ferencd@0 17188 }
ferencd@0 17189
ferencd@0 17190 /*!
ferencd@0 17191 @brief get a pointer value (explicit)
ferencd@0 17192 @copydoc get()
ferencd@0 17193 */
ferencd@0 17194 template<typename PointerType, typename std::enable_if<
ferencd@0 17195 std::is_pointer<PointerType>::value, int>::type = 0>
ferencd@0 17196 constexpr auto get() const noexcept -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())
ferencd@0 17197 {
ferencd@0 17198 // delegate the call to get_ptr
ferencd@0 17199 return get_ptr<PointerType>();
ferencd@0 17200 }
ferencd@0 17201
ferencd@0 17202 /*!
ferencd@0 17203 @brief get a reference value (implicit)
ferencd@0 17204
ferencd@0 17205 Implicit reference access to the internally stored JSON value. No copies
ferencd@0 17206 are made.
ferencd@0 17207
ferencd@0 17208 @warning Writing data to the referee of the result yields an undefined
ferencd@0 17209 state.
ferencd@0 17210
ferencd@0 17211 @tparam ReferenceType reference type; must be a reference to @ref array_t,
ferencd@0 17212 @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or
ferencd@0 17213 @ref number_float_t. Enforced by static assertion.
ferencd@0 17214
ferencd@0 17215 @return reference to the internally stored JSON value if the requested
ferencd@0 17216 reference type @a ReferenceType fits to the JSON value; throws
ferencd@0 17217 type_error.303 otherwise
ferencd@0 17218
ferencd@0 17219 @throw type_error.303 in case passed type @a ReferenceType is incompatible
ferencd@0 17220 with the stored JSON value; see example below
ferencd@0 17221
ferencd@0 17222 @complexity Constant.
ferencd@0 17223
ferencd@0 17224 @liveexample{The example shows several calls to `get_ref()`.,get_ref}
ferencd@0 17225
ferencd@0 17226 @since version 1.1.0
ferencd@0 17227 */
ferencd@0 17228 template<typename ReferenceType, typename std::enable_if<
ferencd@0 17229 std::is_reference<ReferenceType>::value, int>::type = 0>
ferencd@0 17230 ReferenceType get_ref()
ferencd@0 17231 {
ferencd@0 17232 // delegate call to get_ref_impl
ferencd@0 17233 return get_ref_impl<ReferenceType>(*this);
ferencd@0 17234 }
ferencd@0 17235
ferencd@0 17236 /*!
ferencd@0 17237 @brief get a reference value (implicit)
ferencd@0 17238 @copydoc get_ref()
ferencd@0 17239 */
ferencd@0 17240 template<typename ReferenceType, typename std::enable_if<
ferencd@0 17241 std::is_reference<ReferenceType>::value and
ferencd@0 17242 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
ferencd@0 17243 ReferenceType get_ref() const
ferencd@0 17244 {
ferencd@0 17245 // delegate call to get_ref_impl
ferencd@0 17246 return get_ref_impl<ReferenceType>(*this);
ferencd@0 17247 }
ferencd@0 17248
ferencd@0 17249 /*!
ferencd@0 17250 @brief get a value (implicit)
ferencd@0 17251
ferencd@0 17252 Implicit type conversion between the JSON value and a compatible value.
ferencd@0 17253 The call is realized by calling @ref get() const.
ferencd@0 17254
ferencd@0 17255 @tparam ValueType non-pointer type compatible to the JSON value, for
ferencd@0 17256 instance `int` for JSON integer numbers, `bool` for JSON booleans, or
ferencd@0 17257 `std::vector` types for JSON arrays. The character type of @ref string_t
ferencd@0 17258 as well as an initializer list of this type is excluded to avoid
ferencd@0 17259 ambiguities as these types implicitly convert to `std::string`.
ferencd@0 17260
ferencd@0 17261 @return copy of the JSON value, converted to type @a ValueType
ferencd@0 17262
ferencd@0 17263 @throw type_error.302 in case passed type @a ValueType is incompatible
ferencd@0 17264 to the JSON value type (e.g., the JSON value is of type boolean, but a
ferencd@0 17265 string is requested); see example below
ferencd@0 17266
ferencd@0 17267 @complexity Linear in the size of the JSON value.
ferencd@0 17268
ferencd@0 17269 @liveexample{The example below shows several conversions from JSON values
ferencd@0 17270 to other types. There a few things to note: (1) Floating-point numbers can
ferencd@0 17271 be converted to integers\, (2) A JSON array can be converted to a standard
ferencd@0 17272 `std::vector<short>`\, (3) A JSON object can be converted to C++
ferencd@0 17273 associative containers such as `std::unordered_map<std::string\,
ferencd@0 17274 json>`.,operator__ValueType}
ferencd@0 17275
ferencd@0 17276 @since version 1.0.0
ferencd@0 17277 */
ferencd@0 17278 template < typename ValueType, typename std::enable_if <
ferencd@0 17279 not std::is_pointer<ValueType>::value and
ferencd@0 17280 not std::is_same<ValueType, detail::json_ref<basic_json>>::value and
ferencd@0 17281 not std::is_same<ValueType, typename string_t::value_type>::value and
ferencd@0 17282 not detail::is_basic_json<ValueType>::value
ferencd@0 17283
ferencd@0 17284 #ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015
ferencd@0 17285 and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
ferencd@0 17286 #if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) and _MSC_VER <= 1914))
ferencd@0 17287 and not std::is_same<ValueType, typename std::string_view>::value
ferencd@0 17288 #endif
ferencd@0 17289 #endif
ferencd@0 17290 and detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value
ferencd@0 17291 , int >::type = 0 >
ferencd@0 17292 operator ValueType() const
ferencd@0 17293 {
ferencd@0 17294 // delegate the call to get<>() const
ferencd@0 17295 return get<ValueType>();
ferencd@0 17296 }
ferencd@0 17297
ferencd@0 17298 /// @}
ferencd@0 17299
ferencd@0 17300
ferencd@0 17301 ////////////////////
ferencd@0 17302 // element access //
ferencd@0 17303 ////////////////////
ferencd@0 17304
ferencd@0 17305 /// @name element access
ferencd@0 17306 /// Access to the JSON value.
ferencd@0 17307 /// @{
ferencd@0 17308
ferencd@0 17309 /*!
ferencd@0 17310 @brief access specified array element with bounds checking
ferencd@0 17311
ferencd@0 17312 Returns a reference to the element at specified location @a idx, with
ferencd@0 17313 bounds checking.
ferencd@0 17314
ferencd@0 17315 @param[in] idx index of the element to access
ferencd@0 17316
ferencd@0 17317 @return reference to the element at index @a idx
ferencd@0 17318
ferencd@0 17319 @throw type_error.304 if the JSON value is not an array; in this case,
ferencd@0 17320 calling `at` with an index makes no sense. See example below.
ferencd@0 17321 @throw out_of_range.401 if the index @a idx is out of range of the array;
ferencd@0 17322 that is, `idx >= size()`. See example below.
ferencd@0 17323
ferencd@0 17324 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 17325 changes in the JSON value.
ferencd@0 17326
ferencd@0 17327 @complexity Constant.
ferencd@0 17328
ferencd@0 17329 @since version 1.0.0
ferencd@0 17330
ferencd@0 17331 @liveexample{The example below shows how array elements can be read and
ferencd@0 17332 written using `at()`. It also demonstrates the different exceptions that
ferencd@0 17333 can be thrown.,at__size_type}
ferencd@0 17334 */
ferencd@0 17335 reference at(size_type idx)
ferencd@0 17336 {
ferencd@0 17337 // at only works for arrays
ferencd@0 17338 if (JSON_HEDLEY_LIKELY(is_array()))
ferencd@0 17339 {
ferencd@0 17340 JSON_TRY
ferencd@0 17341 {
ferencd@0 17342 return m_value.array->at(idx);
ferencd@0 17343 }
ferencd@0 17344 JSON_CATCH (std::out_of_range&)
ferencd@0 17345 {
ferencd@0 17346 // create better exception explanation
ferencd@0 17347 JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
ferencd@0 17348 }
ferencd@0 17349 }
ferencd@0 17350 else
ferencd@0 17351 {
ferencd@0 17352 JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name())));
ferencd@0 17353 }
ferencd@0 17354 }
ferencd@0 17355
ferencd@0 17356 /*!
ferencd@0 17357 @brief access specified array element with bounds checking
ferencd@0 17358
ferencd@0 17359 Returns a const reference to the element at specified location @a idx,
ferencd@0 17360 with bounds checking.
ferencd@0 17361
ferencd@0 17362 @param[in] idx index of the element to access
ferencd@0 17363
ferencd@0 17364 @return const reference to the element at index @a idx
ferencd@0 17365
ferencd@0 17366 @throw type_error.304 if the JSON value is not an array; in this case,
ferencd@0 17367 calling `at` with an index makes no sense. See example below.
ferencd@0 17368 @throw out_of_range.401 if the index @a idx is out of range of the array;
ferencd@0 17369 that is, `idx >= size()`. See example below.
ferencd@0 17370
ferencd@0 17371 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 17372 changes in the JSON value.
ferencd@0 17373
ferencd@0 17374 @complexity Constant.
ferencd@0 17375
ferencd@0 17376 @since version 1.0.0
ferencd@0 17377
ferencd@0 17378 @liveexample{The example below shows how array elements can be read using
ferencd@0 17379 `at()`. It also demonstrates the different exceptions that can be thrown.,
ferencd@0 17380 at__size_type_const}
ferencd@0 17381 */
ferencd@0 17382 const_reference at(size_type idx) const
ferencd@0 17383 {
ferencd@0 17384 // at only works for arrays
ferencd@0 17385 if (JSON_HEDLEY_LIKELY(is_array()))
ferencd@0 17386 {
ferencd@0 17387 JSON_TRY
ferencd@0 17388 {
ferencd@0 17389 return m_value.array->at(idx);
ferencd@0 17390 }
ferencd@0 17391 JSON_CATCH (std::out_of_range&)
ferencd@0 17392 {
ferencd@0 17393 // create better exception explanation
ferencd@0 17394 JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
ferencd@0 17395 }
ferencd@0 17396 }
ferencd@0 17397 else
ferencd@0 17398 {
ferencd@0 17399 JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name())));
ferencd@0 17400 }
ferencd@0 17401 }
ferencd@0 17402
ferencd@0 17403 /*!
ferencd@0 17404 @brief access specified object element with bounds checking
ferencd@0 17405
ferencd@0 17406 Returns a reference to the element at with specified key @a key, with
ferencd@0 17407 bounds checking.
ferencd@0 17408
ferencd@0 17409 @param[in] key key of the element to access
ferencd@0 17410
ferencd@0 17411 @return reference to the element at key @a key
ferencd@0 17412
ferencd@0 17413 @throw type_error.304 if the JSON value is not an object; in this case,
ferencd@0 17414 calling `at` with a key makes no sense. See example below.
ferencd@0 17415 @throw out_of_range.403 if the key @a key is is not stored in the object;
ferencd@0 17416 that is, `find(key) == end()`. See example below.
ferencd@0 17417
ferencd@0 17418 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 17419 changes in the JSON value.
ferencd@0 17420
ferencd@0 17421 @complexity Logarithmic in the size of the container.
ferencd@0 17422
ferencd@0 17423 @sa @ref operator[](const typename object_t::key_type&) for unchecked
ferencd@0 17424 access by reference
ferencd@0 17425 @sa @ref value() for access by value with a default value
ferencd@0 17426
ferencd@0 17427 @since version 1.0.0
ferencd@0 17428
ferencd@0 17429 @liveexample{The example below shows how object elements can be read and
ferencd@0 17430 written using `at()`. It also demonstrates the different exceptions that
ferencd@0 17431 can be thrown.,at__object_t_key_type}
ferencd@0 17432 */
ferencd@0 17433 reference at(const typename object_t::key_type& key)
ferencd@0 17434 {
ferencd@0 17435 // at only works for objects
ferencd@0 17436 if (JSON_HEDLEY_LIKELY(is_object()))
ferencd@0 17437 {
ferencd@0 17438 JSON_TRY
ferencd@0 17439 {
ferencd@0 17440 return m_value.object->at(key);
ferencd@0 17441 }
ferencd@0 17442 JSON_CATCH (std::out_of_range&)
ferencd@0 17443 {
ferencd@0 17444 // create better exception explanation
ferencd@0 17445 JSON_THROW(out_of_range::create(403, "key '" + key + "' not found"));
ferencd@0 17446 }
ferencd@0 17447 }
ferencd@0 17448 else
ferencd@0 17449 {
ferencd@0 17450 JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name())));
ferencd@0 17451 }
ferencd@0 17452 }
ferencd@0 17453
ferencd@0 17454 /*!
ferencd@0 17455 @brief access specified object element with bounds checking
ferencd@0 17456
ferencd@0 17457 Returns a const reference to the element at with specified key @a key,
ferencd@0 17458 with bounds checking.
ferencd@0 17459
ferencd@0 17460 @param[in] key key of the element to access
ferencd@0 17461
ferencd@0 17462 @return const reference to the element at key @a key
ferencd@0 17463
ferencd@0 17464 @throw type_error.304 if the JSON value is not an object; in this case,
ferencd@0 17465 calling `at` with a key makes no sense. See example below.
ferencd@0 17466 @throw out_of_range.403 if the key @a key is is not stored in the object;
ferencd@0 17467 that is, `find(key) == end()`. See example below.
ferencd@0 17468
ferencd@0 17469 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 17470 changes in the JSON value.
ferencd@0 17471
ferencd@0 17472 @complexity Logarithmic in the size of the container.
ferencd@0 17473
ferencd@0 17474 @sa @ref operator[](const typename object_t::key_type&) for unchecked
ferencd@0 17475 access by reference
ferencd@0 17476 @sa @ref value() for access by value with a default value
ferencd@0 17477
ferencd@0 17478 @since version 1.0.0
ferencd@0 17479
ferencd@0 17480 @liveexample{The example below shows how object elements can be read using
ferencd@0 17481 `at()`. It also demonstrates the different exceptions that can be thrown.,
ferencd@0 17482 at__object_t_key_type_const}
ferencd@0 17483 */
ferencd@0 17484 const_reference at(const typename object_t::key_type& key) const
ferencd@0 17485 {
ferencd@0 17486 // at only works for objects
ferencd@0 17487 if (JSON_HEDLEY_LIKELY(is_object()))
ferencd@0 17488 {
ferencd@0 17489 JSON_TRY
ferencd@0 17490 {
ferencd@0 17491 return m_value.object->at(key);
ferencd@0 17492 }
ferencd@0 17493 JSON_CATCH (std::out_of_range&)
ferencd@0 17494 {
ferencd@0 17495 // create better exception explanation
ferencd@0 17496 JSON_THROW(out_of_range::create(403, "key '" + key + "' not found"));
ferencd@0 17497 }
ferencd@0 17498 }
ferencd@0 17499 else
ferencd@0 17500 {
ferencd@0 17501 JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name())));
ferencd@0 17502 }
ferencd@0 17503 }
ferencd@0 17504
ferencd@0 17505 /*!
ferencd@0 17506 @brief access specified array element
ferencd@0 17507
ferencd@0 17508 Returns a reference to the element at specified location @a idx.
ferencd@0 17509
ferencd@0 17510 @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),
ferencd@0 17511 then the array is silently filled up with `null` values to make `idx` a
ferencd@0 17512 valid reference to the last stored element.
ferencd@0 17513
ferencd@0 17514 @param[in] idx index of the element to access
ferencd@0 17515
ferencd@0 17516 @return reference to the element at index @a idx
ferencd@0 17517
ferencd@0 17518 @throw type_error.305 if the JSON value is not an array or null; in that
ferencd@0 17519 cases, using the [] operator with an index makes no sense.
ferencd@0 17520
ferencd@0 17521 @complexity Constant if @a idx is in the range of the array. Otherwise
ferencd@0 17522 linear in `idx - size()`.
ferencd@0 17523
ferencd@0 17524 @liveexample{The example below shows how array elements can be read and
ferencd@0 17525 written using `[]` operator. Note the addition of `null`
ferencd@0 17526 values.,operatorarray__size_type}
ferencd@0 17527
ferencd@0 17528 @since version 1.0.0
ferencd@0 17529 */
ferencd@0 17530 reference operator[](size_type idx)
ferencd@0 17531 {
ferencd@0 17532 // implicitly convert null value to an empty array
ferencd@0 17533 if (is_null())
ferencd@0 17534 {
ferencd@0 17535 m_type = value_t::array;
ferencd@0 17536 m_value.array = create<array_t>();
ferencd@0 17537 assert_invariant();
ferencd@0 17538 }
ferencd@0 17539
ferencd@0 17540 // operator[] only works for arrays
ferencd@0 17541 if (JSON_HEDLEY_LIKELY(is_array()))
ferencd@0 17542 {
ferencd@0 17543 // fill up array with null values if given idx is outside range
ferencd@0 17544 if (idx >= m_value.array->size())
ferencd@0 17545 {
ferencd@0 17546 m_value.array->insert(m_value.array->end(),
ferencd@0 17547 idx - m_value.array->size() + 1,
ferencd@0 17548 basic_json());
ferencd@0 17549 }
ferencd@0 17550
ferencd@0 17551 return m_value.array->operator[](idx);
ferencd@0 17552 }
ferencd@0 17553
ferencd@0 17554 JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name())));
ferencd@0 17555 }
ferencd@0 17556
ferencd@0 17557 /*!
ferencd@0 17558 @brief access specified array element
ferencd@0 17559
ferencd@0 17560 Returns a const reference to the element at specified location @a idx.
ferencd@0 17561
ferencd@0 17562 @param[in] idx index of the element to access
ferencd@0 17563
ferencd@0 17564 @return const reference to the element at index @a idx
ferencd@0 17565
ferencd@0 17566 @throw type_error.305 if the JSON value is not an array; in that case,
ferencd@0 17567 using the [] operator with an index makes no sense.
ferencd@0 17568
ferencd@0 17569 @complexity Constant.
ferencd@0 17570
ferencd@0 17571 @liveexample{The example below shows how array elements can be read using
ferencd@0 17572 the `[]` operator.,operatorarray__size_type_const}
ferencd@0 17573
ferencd@0 17574 @since version 1.0.0
ferencd@0 17575 */
ferencd@0 17576 const_reference operator[](size_type idx) const
ferencd@0 17577 {
ferencd@0 17578 // const operator[] only works for arrays
ferencd@0 17579 if (JSON_HEDLEY_LIKELY(is_array()))
ferencd@0 17580 {
ferencd@0 17581 return m_value.array->operator[](idx);
ferencd@0 17582 }
ferencd@0 17583
ferencd@0 17584 JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name())));
ferencd@0 17585 }
ferencd@0 17586
ferencd@0 17587 /*!
ferencd@0 17588 @brief access specified object element
ferencd@0 17589
ferencd@0 17590 Returns a reference to the element at with specified key @a key.
ferencd@0 17591
ferencd@0 17592 @note If @a key is not found in the object, then it is silently added to
ferencd@0 17593 the object and filled with a `null` value to make `key` a valid reference.
ferencd@0 17594 In case the value was `null` before, it is converted to an object.
ferencd@0 17595
ferencd@0 17596 @param[in] key key of the element to access
ferencd@0 17597
ferencd@0 17598 @return reference to the element at key @a key
ferencd@0 17599
ferencd@0 17600 @throw type_error.305 if the JSON value is not an object or null; in that
ferencd@0 17601 cases, using the [] operator with a key makes no sense.
ferencd@0 17602
ferencd@0 17603 @complexity Logarithmic in the size of the container.
ferencd@0 17604
ferencd@0 17605 @liveexample{The example below shows how object elements can be read and
ferencd@0 17606 written using the `[]` operator.,operatorarray__key_type}
ferencd@0 17607
ferencd@0 17608 @sa @ref at(const typename object_t::key_type&) for access by reference
ferencd@0 17609 with range checking
ferencd@0 17610 @sa @ref value() for access by value with a default value
ferencd@0 17611
ferencd@0 17612 @since version 1.0.0
ferencd@0 17613 */
ferencd@0 17614 reference operator[](const typename object_t::key_type& key)
ferencd@0 17615 {
ferencd@0 17616 // implicitly convert null value to an empty object
ferencd@0 17617 if (is_null())
ferencd@0 17618 {
ferencd@0 17619 m_type = value_t::object;
ferencd@0 17620 m_value.object = create<object_t>();
ferencd@0 17621 assert_invariant();
ferencd@0 17622 }
ferencd@0 17623
ferencd@0 17624 // operator[] only works for objects
ferencd@0 17625 if (JSON_HEDLEY_LIKELY(is_object()))
ferencd@0 17626 {
ferencd@0 17627 return m_value.object->operator[](key);
ferencd@0 17628 }
ferencd@0 17629
ferencd@0 17630 JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
ferencd@0 17631 }
ferencd@0 17632
ferencd@0 17633 /*!
ferencd@0 17634 @brief read-only access specified object element
ferencd@0 17635
ferencd@0 17636 Returns a const reference to the element at with specified key @a key. No
ferencd@0 17637 bounds checking is performed.
ferencd@0 17638
ferencd@0 17639 @warning If the element with key @a key does not exist, the behavior is
ferencd@0 17640 undefined.
ferencd@0 17641
ferencd@0 17642 @param[in] key key of the element to access
ferencd@0 17643
ferencd@0 17644 @return const reference to the element at key @a key
ferencd@0 17645
ferencd@0 17646 @pre The element with key @a key must exist. **This precondition is
ferencd@0 17647 enforced with an assertion.**
ferencd@0 17648
ferencd@0 17649 @throw type_error.305 if the JSON value is not an object; in that case,
ferencd@0 17650 using the [] operator with a key makes no sense.
ferencd@0 17651
ferencd@0 17652 @complexity Logarithmic in the size of the container.
ferencd@0 17653
ferencd@0 17654 @liveexample{The example below shows how object elements can be read using
ferencd@0 17655 the `[]` operator.,operatorarray__key_type_const}
ferencd@0 17656
ferencd@0 17657 @sa @ref at(const typename object_t::key_type&) for access by reference
ferencd@0 17658 with range checking
ferencd@0 17659 @sa @ref value() for access by value with a default value
ferencd@0 17660
ferencd@0 17661 @since version 1.0.0
ferencd@0 17662 */
ferencd@0 17663 const_reference operator[](const typename object_t::key_type& key) const
ferencd@0 17664 {
ferencd@0 17665 // const operator[] only works for objects
ferencd@0 17666 if (JSON_HEDLEY_LIKELY(is_object()))
ferencd@0 17667 {
ferencd@0 17668 assert(m_value.object->find(key) != m_value.object->end());
ferencd@0 17669 return m_value.object->find(key)->second;
ferencd@0 17670 }
ferencd@0 17671
ferencd@0 17672 JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
ferencd@0 17673 }
ferencd@0 17674
ferencd@0 17675 /*!
ferencd@0 17676 @brief access specified object element
ferencd@0 17677
ferencd@0 17678 Returns a reference to the element at with specified key @a key.
ferencd@0 17679
ferencd@0 17680 @note If @a key is not found in the object, then it is silently added to
ferencd@0 17681 the object and filled with a `null` value to make `key` a valid reference.
ferencd@0 17682 In case the value was `null` before, it is converted to an object.
ferencd@0 17683
ferencd@0 17684 @param[in] key key of the element to access
ferencd@0 17685
ferencd@0 17686 @return reference to the element at key @a key
ferencd@0 17687
ferencd@0 17688 @throw type_error.305 if the JSON value is not an object or null; in that
ferencd@0 17689 cases, using the [] operator with a key makes no sense.
ferencd@0 17690
ferencd@0 17691 @complexity Logarithmic in the size of the container.
ferencd@0 17692
ferencd@0 17693 @liveexample{The example below shows how object elements can be read and
ferencd@0 17694 written using the `[]` operator.,operatorarray__key_type}
ferencd@0 17695
ferencd@0 17696 @sa @ref at(const typename object_t::key_type&) for access by reference
ferencd@0 17697 with range checking
ferencd@0 17698 @sa @ref value() for access by value with a default value
ferencd@0 17699
ferencd@0 17700 @since version 1.1.0
ferencd@0 17701 */
ferencd@0 17702 template<typename T>
ferencd@0 17703 JSON_HEDLEY_NON_NULL(2)
ferencd@0 17704 reference operator[](T* key)
ferencd@0 17705 {
ferencd@0 17706 // implicitly convert null to object
ferencd@0 17707 if (is_null())
ferencd@0 17708 {
ferencd@0 17709 m_type = value_t::object;
ferencd@0 17710 m_value = value_t::object;
ferencd@0 17711 assert_invariant();
ferencd@0 17712 }
ferencd@0 17713
ferencd@0 17714 // at only works for objects
ferencd@0 17715 if (JSON_HEDLEY_LIKELY(is_object()))
ferencd@0 17716 {
ferencd@0 17717 return m_value.object->operator[](key);
ferencd@0 17718 }
ferencd@0 17719
ferencd@0 17720 JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
ferencd@0 17721 }
ferencd@0 17722
ferencd@0 17723 /*!
ferencd@0 17724 @brief read-only access specified object element
ferencd@0 17725
ferencd@0 17726 Returns a const reference to the element at with specified key @a key. No
ferencd@0 17727 bounds checking is performed.
ferencd@0 17728
ferencd@0 17729 @warning If the element with key @a key does not exist, the behavior is
ferencd@0 17730 undefined.
ferencd@0 17731
ferencd@0 17732 @param[in] key key of the element to access
ferencd@0 17733
ferencd@0 17734 @return const reference to the element at key @a key
ferencd@0 17735
ferencd@0 17736 @pre The element with key @a key must exist. **This precondition is
ferencd@0 17737 enforced with an assertion.**
ferencd@0 17738
ferencd@0 17739 @throw type_error.305 if the JSON value is not an object; in that case,
ferencd@0 17740 using the [] operator with a key makes no sense.
ferencd@0 17741
ferencd@0 17742 @complexity Logarithmic in the size of the container.
ferencd@0 17743
ferencd@0 17744 @liveexample{The example below shows how object elements can be read using
ferencd@0 17745 the `[]` operator.,operatorarray__key_type_const}
ferencd@0 17746
ferencd@0 17747 @sa @ref at(const typename object_t::key_type&) for access by reference
ferencd@0 17748 with range checking
ferencd@0 17749 @sa @ref value() for access by value with a default value
ferencd@0 17750
ferencd@0 17751 @since version 1.1.0
ferencd@0 17752 */
ferencd@0 17753 template<typename T>
ferencd@0 17754 JSON_HEDLEY_NON_NULL(2)
ferencd@0 17755 const_reference operator[](T* key) const
ferencd@0 17756 {
ferencd@0 17757 // at only works for objects
ferencd@0 17758 if (JSON_HEDLEY_LIKELY(is_object()))
ferencd@0 17759 {
ferencd@0 17760 assert(m_value.object->find(key) != m_value.object->end());
ferencd@0 17761 return m_value.object->find(key)->second;
ferencd@0 17762 }
ferencd@0 17763
ferencd@0 17764 JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name())));
ferencd@0 17765 }
ferencd@0 17766
ferencd@0 17767 /*!
ferencd@0 17768 @brief access specified object element with default value
ferencd@0 17769
ferencd@0 17770 Returns either a copy of an object's element at the specified key @a key
ferencd@0 17771 or a given default value if no element with key @a key exists.
ferencd@0 17772
ferencd@0 17773 The function is basically equivalent to executing
ferencd@0 17774 @code {.cpp}
ferencd@0 17775 try {
ferencd@0 17776 return at(key);
ferencd@0 17777 } catch(out_of_range) {
ferencd@0 17778 return default_value;
ferencd@0 17779 }
ferencd@0 17780 @endcode
ferencd@0 17781
ferencd@0 17782 @note Unlike @ref at(const typename object_t::key_type&), this function
ferencd@0 17783 does not throw if the given key @a key was not found.
ferencd@0 17784
ferencd@0 17785 @note Unlike @ref operator[](const typename object_t::key_type& key), this
ferencd@0 17786 function does not implicitly add an element to the position defined by @a
ferencd@0 17787 key. This function is furthermore also applicable to const objects.
ferencd@0 17788
ferencd@0 17789 @param[in] key key of the element to access
ferencd@0 17790 @param[in] default_value the value to return if @a key is not found
ferencd@0 17791
ferencd@0 17792 @tparam ValueType type compatible to JSON values, for instance `int` for
ferencd@0 17793 JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
ferencd@0 17794 JSON arrays. Note the type of the expected value at @a key and the default
ferencd@0 17795 value @a default_value must be compatible.
ferencd@0 17796
ferencd@0 17797 @return copy of the element at key @a key or @a default_value if @a key
ferencd@0 17798 is not found
ferencd@0 17799
ferencd@0 17800 @throw type_error.302 if @a default_value does not match the type of the
ferencd@0 17801 value at @a key
ferencd@0 17802 @throw type_error.306 if the JSON value is not an object; in that case,
ferencd@0 17803 using `value()` with a key makes no sense.
ferencd@0 17804
ferencd@0 17805 @complexity Logarithmic in the size of the container.
ferencd@0 17806
ferencd@0 17807 @liveexample{The example below shows how object elements can be queried
ferencd@0 17808 with a default value.,basic_json__value}
ferencd@0 17809
ferencd@0 17810 @sa @ref at(const typename object_t::key_type&) for access by reference
ferencd@0 17811 with range checking
ferencd@0 17812 @sa @ref operator[](const typename object_t::key_type&) for unchecked
ferencd@0 17813 access by reference
ferencd@0 17814
ferencd@0 17815 @since version 1.0.0
ferencd@0 17816 */
ferencd@0 17817 template<class ValueType, typename std::enable_if<
ferencd@0 17818 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
ferencd@0 17819 ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
ferencd@0 17820 {
ferencd@0 17821 // at only works for objects
ferencd@0 17822 if (JSON_HEDLEY_LIKELY(is_object()))
ferencd@0 17823 {
ferencd@0 17824 // if key is found, return value and given default value otherwise
ferencd@0 17825 const auto it = find(key);
ferencd@0 17826 if (it != end())
ferencd@0 17827 {
ferencd@0 17828 return *it;
ferencd@0 17829 }
ferencd@0 17830
ferencd@0 17831 return default_value;
ferencd@0 17832 }
ferencd@0 17833
ferencd@0 17834 JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name())));
ferencd@0 17835 }
ferencd@0 17836
ferencd@0 17837 /*!
ferencd@0 17838 @brief overload for a default value of type const char*
ferencd@0 17839 @copydoc basic_json::value(const typename object_t::key_type&, const ValueType&) const
ferencd@0 17840 */
ferencd@0 17841 string_t value(const typename object_t::key_type& key, const char* default_value) const
ferencd@0 17842 {
ferencd@0 17843 return value(key, string_t(default_value));
ferencd@0 17844 }
ferencd@0 17845
ferencd@0 17846 /*!
ferencd@0 17847 @brief access specified object element via JSON Pointer with default value
ferencd@0 17848
ferencd@0 17849 Returns either a copy of an object's element at the specified key @a key
ferencd@0 17850 or a given default value if no element with key @a key exists.
ferencd@0 17851
ferencd@0 17852 The function is basically equivalent to executing
ferencd@0 17853 @code {.cpp}
ferencd@0 17854 try {
ferencd@0 17855 return at(ptr);
ferencd@0 17856 } catch(out_of_range) {
ferencd@0 17857 return default_value;
ferencd@0 17858 }
ferencd@0 17859 @endcode
ferencd@0 17860
ferencd@0 17861 @note Unlike @ref at(const json_pointer&), this function does not throw
ferencd@0 17862 if the given key @a key was not found.
ferencd@0 17863
ferencd@0 17864 @param[in] ptr a JSON pointer to the element to access
ferencd@0 17865 @param[in] default_value the value to return if @a ptr found no value
ferencd@0 17866
ferencd@0 17867 @tparam ValueType type compatible to JSON values, for instance `int` for
ferencd@0 17868 JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
ferencd@0 17869 JSON arrays. Note the type of the expected value at @a key and the default
ferencd@0 17870 value @a default_value must be compatible.
ferencd@0 17871
ferencd@0 17872 @return copy of the element at key @a key or @a default_value if @a key
ferencd@0 17873 is not found
ferencd@0 17874
ferencd@0 17875 @throw type_error.302 if @a default_value does not match the type of the
ferencd@0 17876 value at @a ptr
ferencd@0 17877 @throw type_error.306 if the JSON value is not an object; in that case,
ferencd@0 17878 using `value()` with a key makes no sense.
ferencd@0 17879
ferencd@0 17880 @complexity Logarithmic in the size of the container.
ferencd@0 17881
ferencd@0 17882 @liveexample{The example below shows how object elements can be queried
ferencd@0 17883 with a default value.,basic_json__value_ptr}
ferencd@0 17884
ferencd@0 17885 @sa @ref operator[](const json_pointer&) for unchecked access by reference
ferencd@0 17886
ferencd@0 17887 @since version 2.0.2
ferencd@0 17888 */
ferencd@0 17889 template<class ValueType, typename std::enable_if<
ferencd@0 17890 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
ferencd@0 17891 ValueType value(const json_pointer& ptr, const ValueType& default_value) const
ferencd@0 17892 {
ferencd@0 17893 // at only works for objects
ferencd@0 17894 if (JSON_HEDLEY_LIKELY(is_object()))
ferencd@0 17895 {
ferencd@0 17896 // if pointer resolves a value, return it or use default value
ferencd@0 17897 JSON_TRY
ferencd@0 17898 {
ferencd@0 17899 return ptr.get_checked(this);
ferencd@0 17900 }
ferencd@0 17901 JSON_INTERNAL_CATCH (out_of_range&)
ferencd@0 17902 {
ferencd@0 17903 return default_value;
ferencd@0 17904 }
ferencd@0 17905 }
ferencd@0 17906
ferencd@0 17907 JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name())));
ferencd@0 17908 }
ferencd@0 17909
ferencd@0 17910 /*!
ferencd@0 17911 @brief overload for a default value of type const char*
ferencd@0 17912 @copydoc basic_json::value(const json_pointer&, ValueType) const
ferencd@0 17913 */
ferencd@0 17914 JSON_HEDLEY_NON_NULL(3)
ferencd@0 17915 string_t value(const json_pointer& ptr, const char* default_value) const
ferencd@0 17916 {
ferencd@0 17917 return value(ptr, string_t(default_value));
ferencd@0 17918 }
ferencd@0 17919
ferencd@0 17920 /*!
ferencd@0 17921 @brief access the first element
ferencd@0 17922
ferencd@0 17923 Returns a reference to the first element in the container. For a JSON
ferencd@0 17924 container `c`, the expression `c.front()` is equivalent to `*c.begin()`.
ferencd@0 17925
ferencd@0 17926 @return In case of a structured type (array or object), a reference to the
ferencd@0 17927 first element is returned. In case of number, string, or boolean values, a
ferencd@0 17928 reference to the value is returned.
ferencd@0 17929
ferencd@0 17930 @complexity Constant.
ferencd@0 17931
ferencd@0 17932 @pre The JSON value must not be `null` (would throw `std::out_of_range`)
ferencd@0 17933 or an empty array or object (undefined behavior, **guarded by
ferencd@0 17934 assertions**).
ferencd@0 17935 @post The JSON value remains unchanged.
ferencd@0 17936
ferencd@0 17937 @throw invalid_iterator.214 when called on `null` value
ferencd@0 17938
ferencd@0 17939 @liveexample{The following code shows an example for `front()`.,front}
ferencd@0 17940
ferencd@0 17941 @sa @ref back() -- access the last element
ferencd@0 17942
ferencd@0 17943 @since version 1.0.0
ferencd@0 17944 */
ferencd@0 17945 reference front()
ferencd@0 17946 {
ferencd@0 17947 return *begin();
ferencd@0 17948 }
ferencd@0 17949
ferencd@0 17950 /*!
ferencd@0 17951 @copydoc basic_json::front()
ferencd@0 17952 */
ferencd@0 17953 const_reference front() const
ferencd@0 17954 {
ferencd@0 17955 return *cbegin();
ferencd@0 17956 }
ferencd@0 17957
ferencd@0 17958 /*!
ferencd@0 17959 @brief access the last element
ferencd@0 17960
ferencd@0 17961 Returns a reference to the last element in the container. For a JSON
ferencd@0 17962 container `c`, the expression `c.back()` is equivalent to
ferencd@0 17963 @code {.cpp}
ferencd@0 17964 auto tmp = c.end();
ferencd@0 17965 --tmp;
ferencd@0 17966 return *tmp;
ferencd@0 17967 @endcode
ferencd@0 17968
ferencd@0 17969 @return In case of a structured type (array or object), a reference to the
ferencd@0 17970 last element is returned. In case of number, string, or boolean values, a
ferencd@0 17971 reference to the value is returned.
ferencd@0 17972
ferencd@0 17973 @complexity Constant.
ferencd@0 17974
ferencd@0 17975 @pre The JSON value must not be `null` (would throw `std::out_of_range`)
ferencd@0 17976 or an empty array or object (undefined behavior, **guarded by
ferencd@0 17977 assertions**).
ferencd@0 17978 @post The JSON value remains unchanged.
ferencd@0 17979
ferencd@0 17980 @throw invalid_iterator.214 when called on a `null` value. See example
ferencd@0 17981 below.
ferencd@0 17982
ferencd@0 17983 @liveexample{The following code shows an example for `back()`.,back}
ferencd@0 17984
ferencd@0 17985 @sa @ref front() -- access the first element
ferencd@0 17986
ferencd@0 17987 @since version 1.0.0
ferencd@0 17988 */
ferencd@0 17989 reference back()
ferencd@0 17990 {
ferencd@0 17991 auto tmp = end();
ferencd@0 17992 --tmp;
ferencd@0 17993 return *tmp;
ferencd@0 17994 }
ferencd@0 17995
ferencd@0 17996 /*!
ferencd@0 17997 @copydoc basic_json::back()
ferencd@0 17998 */
ferencd@0 17999 const_reference back() const
ferencd@0 18000 {
ferencd@0 18001 auto tmp = cend();
ferencd@0 18002 --tmp;
ferencd@0 18003 return *tmp;
ferencd@0 18004 }
ferencd@0 18005
ferencd@0 18006 /*!
ferencd@0 18007 @brief remove element given an iterator
ferencd@0 18008
ferencd@0 18009 Removes the element specified by iterator @a pos. The iterator @a pos must
ferencd@0 18010 be valid and dereferenceable. Thus the `end()` iterator (which is valid,
ferencd@0 18011 but is not dereferenceable) cannot be used as a value for @a pos.
ferencd@0 18012
ferencd@0 18013 If called on a primitive type other than `null`, the resulting JSON value
ferencd@0 18014 will be `null`.
ferencd@0 18015
ferencd@0 18016 @param[in] pos iterator to the element to remove
ferencd@0 18017 @return Iterator following the last removed element. If the iterator @a
ferencd@0 18018 pos refers to the last element, the `end()` iterator is returned.
ferencd@0 18019
ferencd@0 18020 @tparam IteratorType an @ref iterator or @ref const_iterator
ferencd@0 18021
ferencd@0 18022 @post Invalidates iterators and references at or after the point of the
ferencd@0 18023 erase, including the `end()` iterator.
ferencd@0 18024
ferencd@0 18025 @throw type_error.307 if called on a `null` value; example: `"cannot use
ferencd@0 18026 erase() with null"`
ferencd@0 18027 @throw invalid_iterator.202 if called on an iterator which does not belong
ferencd@0 18028 to the current JSON value; example: `"iterator does not fit current
ferencd@0 18029 value"`
ferencd@0 18030 @throw invalid_iterator.205 if called on a primitive type with invalid
ferencd@0 18031 iterator (i.e., any iterator which is not `begin()`); example: `"iterator
ferencd@0 18032 out of range"`
ferencd@0 18033
ferencd@0 18034 @complexity The complexity depends on the type:
ferencd@0 18035 - objects: amortized constant
ferencd@0 18036 - arrays: linear in distance between @a pos and the end of the container
ferencd@0 18037 - strings: linear in the length of the string
ferencd@0 18038 - other types: constant
ferencd@0 18039
ferencd@0 18040 @liveexample{The example shows the result of `erase()` for different JSON
ferencd@0 18041 types.,erase__IteratorType}
ferencd@0 18042
ferencd@0 18043 @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
ferencd@0 18044 the given range
ferencd@0 18045 @sa @ref erase(const typename object_t::key_type&) -- removes the element
ferencd@0 18046 from an object at the given key
ferencd@0 18047 @sa @ref erase(const size_type) -- removes the element from an array at
ferencd@0 18048 the given index
ferencd@0 18049
ferencd@0 18050 @since version 1.0.0
ferencd@0 18051 */
ferencd@0 18052 template<class IteratorType, typename std::enable_if<
ferencd@0 18053 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
ferencd@0 18054 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
ferencd@0 18055 = 0>
ferencd@0 18056 IteratorType erase(IteratorType pos)
ferencd@0 18057 {
ferencd@0 18058 // make sure iterator fits the current value
ferencd@0 18059 if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))
ferencd@0 18060 {
ferencd@0 18061 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
ferencd@0 18062 }
ferencd@0 18063
ferencd@0 18064 IteratorType result = end();
ferencd@0 18065
ferencd@0 18066 switch (m_type)
ferencd@0 18067 {
ferencd@0 18068 case value_t::boolean:
ferencd@0 18069 case value_t::number_float:
ferencd@0 18070 case value_t::number_integer:
ferencd@0 18071 case value_t::number_unsigned:
ferencd@0 18072 case value_t::string:
ferencd@0 18073 {
ferencd@0 18074 if (JSON_HEDLEY_UNLIKELY(not pos.m_it.primitive_iterator.is_begin()))
ferencd@0 18075 {
ferencd@0 18076 JSON_THROW(invalid_iterator::create(205, "iterator out of range"));
ferencd@0 18077 }
ferencd@0 18078
ferencd@0 18079 if (is_string())
ferencd@0 18080 {
ferencd@0 18081 AllocatorType<string_t> alloc;
ferencd@0 18082 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
ferencd@0 18083 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
ferencd@0 18084 m_value.string = nullptr;
ferencd@0 18085 }
ferencd@0 18086
ferencd@0 18087 m_type = value_t::null;
ferencd@0 18088 assert_invariant();
ferencd@0 18089 break;
ferencd@0 18090 }
ferencd@0 18091
ferencd@0 18092 case value_t::object:
ferencd@0 18093 {
ferencd@0 18094 result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
ferencd@0 18095 break;
ferencd@0 18096 }
ferencd@0 18097
ferencd@0 18098 case value_t::array:
ferencd@0 18099 {
ferencd@0 18100 result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
ferencd@0 18101 break;
ferencd@0 18102 }
ferencd@0 18103
ferencd@0 18104 default:
ferencd@0 18105 JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
ferencd@0 18106 }
ferencd@0 18107
ferencd@0 18108 return result;
ferencd@0 18109 }
ferencd@0 18110
ferencd@0 18111 /*!
ferencd@0 18112 @brief remove elements given an iterator range
ferencd@0 18113
ferencd@0 18114 Removes the element specified by the range `[first; last)`. The iterator
ferencd@0 18115 @a first does not need to be dereferenceable if `first == last`: erasing
ferencd@0 18116 an empty range is a no-op.
ferencd@0 18117
ferencd@0 18118 If called on a primitive type other than `null`, the resulting JSON value
ferencd@0 18119 will be `null`.
ferencd@0 18120
ferencd@0 18121 @param[in] first iterator to the beginning of the range to remove
ferencd@0 18122 @param[in] last iterator past the end of the range to remove
ferencd@0 18123 @return Iterator following the last removed element. If the iterator @a
ferencd@0 18124 second refers to the last element, the `end()` iterator is returned.
ferencd@0 18125
ferencd@0 18126 @tparam IteratorType an @ref iterator or @ref const_iterator
ferencd@0 18127
ferencd@0 18128 @post Invalidates iterators and references at or after the point of the
ferencd@0 18129 erase, including the `end()` iterator.
ferencd@0 18130
ferencd@0 18131 @throw type_error.307 if called on a `null` value; example: `"cannot use
ferencd@0 18132 erase() with null"`
ferencd@0 18133 @throw invalid_iterator.203 if called on iterators which does not belong
ferencd@0 18134 to the current JSON value; example: `"iterators do not fit current value"`
ferencd@0 18135 @throw invalid_iterator.204 if called on a primitive type with invalid
ferencd@0 18136 iterators (i.e., if `first != begin()` and `last != end()`); example:
ferencd@0 18137 `"iterators out of range"`
ferencd@0 18138
ferencd@0 18139 @complexity The complexity depends on the type:
ferencd@0 18140 - objects: `log(size()) + std::distance(first, last)`
ferencd@0 18141 - arrays: linear in the distance between @a first and @a last, plus linear
ferencd@0 18142 in the distance between @a last and end of the container
ferencd@0 18143 - strings: linear in the length of the string
ferencd@0 18144 - other types: constant
ferencd@0 18145
ferencd@0 18146 @liveexample{The example shows the result of `erase()` for different JSON
ferencd@0 18147 types.,erase__IteratorType_IteratorType}
ferencd@0 18148
ferencd@0 18149 @sa @ref erase(IteratorType) -- removes the element at a given position
ferencd@0 18150 @sa @ref erase(const typename object_t::key_type&) -- removes the element
ferencd@0 18151 from an object at the given key
ferencd@0 18152 @sa @ref erase(const size_type) -- removes the element from an array at
ferencd@0 18153 the given index
ferencd@0 18154
ferencd@0 18155 @since version 1.0.0
ferencd@0 18156 */
ferencd@0 18157 template<class IteratorType, typename std::enable_if<
ferencd@0 18158 std::is_same<IteratorType, typename basic_json_t::iterator>::value or
ferencd@0 18159 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
ferencd@0 18160 = 0>
ferencd@0 18161 IteratorType erase(IteratorType first, IteratorType last)
ferencd@0 18162 {
ferencd@0 18163 // make sure iterator fits the current value
ferencd@0 18164 if (JSON_HEDLEY_UNLIKELY(this != first.m_object or this != last.m_object))
ferencd@0 18165 {
ferencd@0 18166 JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value"));
ferencd@0 18167 }
ferencd@0 18168
ferencd@0 18169 IteratorType result = end();
ferencd@0 18170
ferencd@0 18171 switch (m_type)
ferencd@0 18172 {
ferencd@0 18173 case value_t::boolean:
ferencd@0 18174 case value_t::number_float:
ferencd@0 18175 case value_t::number_integer:
ferencd@0 18176 case value_t::number_unsigned:
ferencd@0 18177 case value_t::string:
ferencd@0 18178 {
ferencd@0 18179 if (JSON_HEDLEY_LIKELY(not first.m_it.primitive_iterator.is_begin()
ferencd@0 18180 or not last.m_it.primitive_iterator.is_end()))
ferencd@0 18181 {
ferencd@0 18182 JSON_THROW(invalid_iterator::create(204, "iterators out of range"));
ferencd@0 18183 }
ferencd@0 18184
ferencd@0 18185 if (is_string())
ferencd@0 18186 {
ferencd@0 18187 AllocatorType<string_t> alloc;
ferencd@0 18188 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);
ferencd@0 18189 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);
ferencd@0 18190 m_value.string = nullptr;
ferencd@0 18191 }
ferencd@0 18192
ferencd@0 18193 m_type = value_t::null;
ferencd@0 18194 assert_invariant();
ferencd@0 18195 break;
ferencd@0 18196 }
ferencd@0 18197
ferencd@0 18198 case value_t::object:
ferencd@0 18199 {
ferencd@0 18200 result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
ferencd@0 18201 last.m_it.object_iterator);
ferencd@0 18202 break;
ferencd@0 18203 }
ferencd@0 18204
ferencd@0 18205 case value_t::array:
ferencd@0 18206 {
ferencd@0 18207 result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
ferencd@0 18208 last.m_it.array_iterator);
ferencd@0 18209 break;
ferencd@0 18210 }
ferencd@0 18211
ferencd@0 18212 default:
ferencd@0 18213 JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
ferencd@0 18214 }
ferencd@0 18215
ferencd@0 18216 return result;
ferencd@0 18217 }
ferencd@0 18218
ferencd@0 18219 /*!
ferencd@0 18220 @brief remove element from a JSON object given a key
ferencd@0 18221
ferencd@0 18222 Removes elements from a JSON object with the key value @a key.
ferencd@0 18223
ferencd@0 18224 @param[in] key value of the elements to remove
ferencd@0 18225
ferencd@0 18226 @return Number of elements removed. If @a ObjectType is the default
ferencd@0 18227 `std::map` type, the return value will always be `0` (@a key was not
ferencd@0 18228 found) or `1` (@a key was found).
ferencd@0 18229
ferencd@0 18230 @post References and iterators to the erased elements are invalidated.
ferencd@0 18231 Other references and iterators are not affected.
ferencd@0 18232
ferencd@0 18233 @throw type_error.307 when called on a type other than JSON object;
ferencd@0 18234 example: `"cannot use erase() with null"`
ferencd@0 18235
ferencd@0 18236 @complexity `log(size()) + count(key)`
ferencd@0 18237
ferencd@0 18238 @liveexample{The example shows the effect of `erase()`.,erase__key_type}
ferencd@0 18239
ferencd@0 18240 @sa @ref erase(IteratorType) -- removes the element at a given position
ferencd@0 18241 @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
ferencd@0 18242 the given range
ferencd@0 18243 @sa @ref erase(const size_type) -- removes the element from an array at
ferencd@0 18244 the given index
ferencd@0 18245
ferencd@0 18246 @since version 1.0.0
ferencd@0 18247 */
ferencd@0 18248 size_type erase(const typename object_t::key_type& key)
ferencd@0 18249 {
ferencd@0 18250 // this erase only works for objects
ferencd@0 18251 if (JSON_HEDLEY_LIKELY(is_object()))
ferencd@0 18252 {
ferencd@0 18253 return m_value.object->erase(key);
ferencd@0 18254 }
ferencd@0 18255
ferencd@0 18256 JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
ferencd@0 18257 }
ferencd@0 18258
ferencd@0 18259 /*!
ferencd@0 18260 @brief remove element from a JSON array given an index
ferencd@0 18261
ferencd@0 18262 Removes element from a JSON array at the index @a idx.
ferencd@0 18263
ferencd@0 18264 @param[in] idx index of the element to remove
ferencd@0 18265
ferencd@0 18266 @throw type_error.307 when called on a type other than JSON object;
ferencd@0 18267 example: `"cannot use erase() with null"`
ferencd@0 18268 @throw out_of_range.401 when `idx >= size()`; example: `"array index 17
ferencd@0 18269 is out of range"`
ferencd@0 18270
ferencd@0 18271 @complexity Linear in distance between @a idx and the end of the container.
ferencd@0 18272
ferencd@0 18273 @liveexample{The example shows the effect of `erase()`.,erase__size_type}
ferencd@0 18274
ferencd@0 18275 @sa @ref erase(IteratorType) -- removes the element at a given position
ferencd@0 18276 @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
ferencd@0 18277 the given range
ferencd@0 18278 @sa @ref erase(const typename object_t::key_type&) -- removes the element
ferencd@0 18279 from an object at the given key
ferencd@0 18280
ferencd@0 18281 @since version 1.0.0
ferencd@0 18282 */
ferencd@0 18283 void erase(const size_type idx)
ferencd@0 18284 {
ferencd@0 18285 // this erase only works for arrays
ferencd@0 18286 if (JSON_HEDLEY_LIKELY(is_array()))
ferencd@0 18287 {
ferencd@0 18288 if (JSON_HEDLEY_UNLIKELY(idx >= size()))
ferencd@0 18289 {
ferencd@0 18290 JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
ferencd@0 18291 }
ferencd@0 18292
ferencd@0 18293 m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
ferencd@0 18294 }
ferencd@0 18295 else
ferencd@0 18296 {
ferencd@0 18297 JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name())));
ferencd@0 18298 }
ferencd@0 18299 }
ferencd@0 18300
ferencd@0 18301 /// @}
ferencd@0 18302
ferencd@0 18303
ferencd@0 18304 ////////////
ferencd@0 18305 // lookup //
ferencd@0 18306 ////////////
ferencd@0 18307
ferencd@0 18308 /// @name lookup
ferencd@0 18309 /// @{
ferencd@0 18310
ferencd@0 18311 /*!
ferencd@0 18312 @brief find an element in a JSON object
ferencd@0 18313
ferencd@0 18314 Finds an element in a JSON object with key equivalent to @a key. If the
ferencd@0 18315 element is not found or the JSON value is not an object, end() is
ferencd@0 18316 returned.
ferencd@0 18317
ferencd@0 18318 @note This method always returns @ref end() when executed on a JSON type
ferencd@0 18319 that is not an object.
ferencd@0 18320
ferencd@0 18321 @param[in] key key value of the element to search for.
ferencd@0 18322
ferencd@0 18323 @return Iterator to an element with key equivalent to @a key. If no such
ferencd@0 18324 element is found or the JSON value is not an object, past-the-end (see
ferencd@0 18325 @ref end()) iterator is returned.
ferencd@0 18326
ferencd@0 18327 @complexity Logarithmic in the size of the JSON object.
ferencd@0 18328
ferencd@0 18329 @liveexample{The example shows how `find()` is used.,find__key_type}
ferencd@0 18330
ferencd@0 18331 @sa @ref contains(KeyT&&) const -- checks whether a key exists
ferencd@0 18332
ferencd@0 18333 @since version 1.0.0
ferencd@0 18334 */
ferencd@0 18335 template<typename KeyT>
ferencd@0 18336 iterator find(KeyT&& key)
ferencd@0 18337 {
ferencd@0 18338 auto result = end();
ferencd@0 18339
ferencd@0 18340 if (is_object())
ferencd@0 18341 {
ferencd@0 18342 result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));
ferencd@0 18343 }
ferencd@0 18344
ferencd@0 18345 return result;
ferencd@0 18346 }
ferencd@0 18347
ferencd@0 18348 /*!
ferencd@0 18349 @brief find an element in a JSON object
ferencd@0 18350 @copydoc find(KeyT&&)
ferencd@0 18351 */
ferencd@0 18352 template<typename KeyT>
ferencd@0 18353 const_iterator find(KeyT&& key) const
ferencd@0 18354 {
ferencd@0 18355 auto result = cend();
ferencd@0 18356
ferencd@0 18357 if (is_object())
ferencd@0 18358 {
ferencd@0 18359 result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));
ferencd@0 18360 }
ferencd@0 18361
ferencd@0 18362 return result;
ferencd@0 18363 }
ferencd@0 18364
ferencd@0 18365 /*!
ferencd@0 18366 @brief returns the number of occurrences of a key in a JSON object
ferencd@0 18367
ferencd@0 18368 Returns the number of elements with key @a key. If ObjectType is the
ferencd@0 18369 default `std::map` type, the return value will always be `0` (@a key was
ferencd@0 18370 not found) or `1` (@a key was found).
ferencd@0 18371
ferencd@0 18372 @note This method always returns `0` when executed on a JSON type that is
ferencd@0 18373 not an object.
ferencd@0 18374
ferencd@0 18375 @param[in] key key value of the element to count
ferencd@0 18376
ferencd@0 18377 @return Number of elements with key @a key. If the JSON value is not an
ferencd@0 18378 object, the return value will be `0`.
ferencd@0 18379
ferencd@0 18380 @complexity Logarithmic in the size of the JSON object.
ferencd@0 18381
ferencd@0 18382 @liveexample{The example shows how `count()` is used.,count}
ferencd@0 18383
ferencd@0 18384 @since version 1.0.0
ferencd@0 18385 */
ferencd@0 18386 template<typename KeyT>
ferencd@0 18387 size_type count(KeyT&& key) const
ferencd@0 18388 {
ferencd@0 18389 // return 0 for all nonobject types
ferencd@0 18390 return is_object() ? m_value.object->count(std::forward<KeyT>(key)) : 0;
ferencd@0 18391 }
ferencd@0 18392
ferencd@0 18393 /*!
ferencd@0 18394 @brief check the existence of an element in a JSON object
ferencd@0 18395
ferencd@0 18396 Check whether an element exists in a JSON object with key equivalent to
ferencd@0 18397 @a key. If the element is not found or the JSON value is not an object,
ferencd@0 18398 false is returned.
ferencd@0 18399
ferencd@0 18400 @note This method always returns false when executed on a JSON type
ferencd@0 18401 that is not an object.
ferencd@0 18402
ferencd@0 18403 @param[in] key key value to check its existence.
ferencd@0 18404
ferencd@0 18405 @return true if an element with specified @a key exists. If no such
ferencd@0 18406 element with such key is found or the JSON value is not an object,
ferencd@0 18407 false is returned.
ferencd@0 18408
ferencd@0 18409 @complexity Logarithmic in the size of the JSON object.
ferencd@0 18410
ferencd@0 18411 @liveexample{The following code shows an example for `contains()`.,contains}
ferencd@0 18412
ferencd@0 18413 @sa @ref find(KeyT&&) -- returns an iterator to an object element
ferencd@0 18414 @sa @ref contains(const json_pointer&) const -- checks the existence for a JSON pointer
ferencd@0 18415
ferencd@0 18416 @since version 3.6.0
ferencd@0 18417 */
ferencd@0 18418 template<typename KeyT, typename std::enable_if<
ferencd@0 18419 not std::is_same<KeyT, json_pointer>::value, int>::type = 0>
ferencd@0 18420 bool contains(KeyT && key) const
ferencd@0 18421 {
ferencd@0 18422 return is_object() and m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end();
ferencd@0 18423 }
ferencd@0 18424
ferencd@0 18425 /*!
ferencd@0 18426 @brief check the existence of an element in a JSON object given a JSON pointer
ferencd@0 18427
ferencd@0 18428 Check wehther the given JSON pointer @a ptr can be resolved in the current
ferencd@0 18429 JSON value.
ferencd@0 18430
ferencd@0 18431 @note This method can be executed on any JSON value type.
ferencd@0 18432
ferencd@0 18433 @param[in] ptr JSON pointer to check its existence.
ferencd@0 18434
ferencd@0 18435 @return true if the JSON pointer can be resolved to a stored value, false
ferencd@0 18436 otherwise.
ferencd@0 18437
ferencd@0 18438 @post If `j.contains(ptr)` returns true, it is safe to call `j[ptr]`.
ferencd@0 18439
ferencd@0 18440 @throw parse_error.106 if an array index begins with '0'
ferencd@0 18441 @throw parse_error.109 if an array index was not a number
ferencd@0 18442
ferencd@0 18443 @complexity Logarithmic in the size of the JSON object.
ferencd@0 18444
ferencd@0 18445 @liveexample{The following code shows an example for `contains()`.,contains_json_pointer}
ferencd@0 18446
ferencd@0 18447 @sa @ref contains(KeyT &&) const -- checks the existence of a key
ferencd@0 18448
ferencd@0 18449 @since version 3.7.0
ferencd@0 18450 */
ferencd@0 18451 bool contains(const json_pointer& ptr) const
ferencd@0 18452 {
ferencd@0 18453 return ptr.contains(this);
ferencd@0 18454 }
ferencd@0 18455
ferencd@0 18456 /// @}
ferencd@0 18457
ferencd@0 18458
ferencd@0 18459 ///////////////
ferencd@0 18460 // iterators //
ferencd@0 18461 ///////////////
ferencd@0 18462
ferencd@0 18463 /// @name iterators
ferencd@0 18464 /// @{
ferencd@0 18465
ferencd@0 18466 /*!
ferencd@0 18467 @brief returns an iterator to the first element
ferencd@0 18468
ferencd@0 18469 Returns an iterator to the first element.
ferencd@0 18470
ferencd@0 18471 @image html range-begin-end.svg "Illustration from cppreference.com"
ferencd@0 18472
ferencd@0 18473 @return iterator to the first element
ferencd@0 18474
ferencd@0 18475 @complexity Constant.
ferencd@0 18476
ferencd@0 18477 @requirement This function helps `basic_json` satisfying the
ferencd@0 18478 [Container](https://en.cppreference.com/w/cpp/named_req/Container)
ferencd@0 18479 requirements:
ferencd@0 18480 - The complexity is constant.
ferencd@0 18481
ferencd@0 18482 @liveexample{The following code shows an example for `begin()`.,begin}
ferencd@0 18483
ferencd@0 18484 @sa @ref cbegin() -- returns a const iterator to the beginning
ferencd@0 18485 @sa @ref end() -- returns an iterator to the end
ferencd@0 18486 @sa @ref cend() -- returns a const iterator to the end
ferencd@0 18487
ferencd@0 18488 @since version 1.0.0
ferencd@0 18489 */
ferencd@0 18490 iterator begin() noexcept
ferencd@0 18491 {
ferencd@0 18492 iterator result(this);
ferencd@0 18493 result.set_begin();
ferencd@0 18494 return result;
ferencd@0 18495 }
ferencd@0 18496
ferencd@0 18497 /*!
ferencd@0 18498 @copydoc basic_json::cbegin()
ferencd@0 18499 */
ferencd@0 18500 const_iterator begin() const noexcept
ferencd@0 18501 {
ferencd@0 18502 return cbegin();
ferencd@0 18503 }
ferencd@0 18504
ferencd@0 18505 /*!
ferencd@0 18506 @brief returns a const iterator to the first element
ferencd@0 18507
ferencd@0 18508 Returns a const iterator to the first element.
ferencd@0 18509
ferencd@0 18510 @image html range-begin-end.svg "Illustration from cppreference.com"
ferencd@0 18511
ferencd@0 18512 @return const iterator to the first element
ferencd@0 18513
ferencd@0 18514 @complexity Constant.
ferencd@0 18515
ferencd@0 18516 @requirement This function helps `basic_json` satisfying the
ferencd@0 18517 [Container](https://en.cppreference.com/w/cpp/named_req/Container)
ferencd@0 18518 requirements:
ferencd@0 18519 - The complexity is constant.
ferencd@0 18520 - Has the semantics of `const_cast<const basic_json&>(*this).begin()`.
ferencd@0 18521
ferencd@0 18522 @liveexample{The following code shows an example for `cbegin()`.,cbegin}
ferencd@0 18523
ferencd@0 18524 @sa @ref begin() -- returns an iterator to the beginning
ferencd@0 18525 @sa @ref end() -- returns an iterator to the end
ferencd@0 18526 @sa @ref cend() -- returns a const iterator to the end
ferencd@0 18527
ferencd@0 18528 @since version 1.0.0
ferencd@0 18529 */
ferencd@0 18530 const_iterator cbegin() const noexcept
ferencd@0 18531 {
ferencd@0 18532 const_iterator result(this);
ferencd@0 18533 result.set_begin();
ferencd@0 18534 return result;
ferencd@0 18535 }
ferencd@0 18536
ferencd@0 18537 /*!
ferencd@0 18538 @brief returns an iterator to one past the last element
ferencd@0 18539
ferencd@0 18540 Returns an iterator to one past the last element.
ferencd@0 18541
ferencd@0 18542 @image html range-begin-end.svg "Illustration from cppreference.com"
ferencd@0 18543
ferencd@0 18544 @return iterator one past the last element
ferencd@0 18545
ferencd@0 18546 @complexity Constant.
ferencd@0 18547
ferencd@0 18548 @requirement This function helps `basic_json` satisfying the
ferencd@0 18549 [Container](https://en.cppreference.com/w/cpp/named_req/Container)
ferencd@0 18550 requirements:
ferencd@0 18551 - The complexity is constant.
ferencd@0 18552
ferencd@0 18553 @liveexample{The following code shows an example for `end()`.,end}
ferencd@0 18554
ferencd@0 18555 @sa @ref cend() -- returns a const iterator to the end
ferencd@0 18556 @sa @ref begin() -- returns an iterator to the beginning
ferencd@0 18557 @sa @ref cbegin() -- returns a const iterator to the beginning
ferencd@0 18558
ferencd@0 18559 @since version 1.0.0
ferencd@0 18560 */
ferencd@0 18561 iterator end() noexcept
ferencd@0 18562 {
ferencd@0 18563 iterator result(this);
ferencd@0 18564 result.set_end();
ferencd@0 18565 return result;
ferencd@0 18566 }
ferencd@0 18567
ferencd@0 18568 /*!
ferencd@0 18569 @copydoc basic_json::cend()
ferencd@0 18570 */
ferencd@0 18571 const_iterator end() const noexcept
ferencd@0 18572 {
ferencd@0 18573 return cend();
ferencd@0 18574 }
ferencd@0 18575
ferencd@0 18576 /*!
ferencd@0 18577 @brief returns a const iterator to one past the last element
ferencd@0 18578
ferencd@0 18579 Returns a const iterator to one past the last element.
ferencd@0 18580
ferencd@0 18581 @image html range-begin-end.svg "Illustration from cppreference.com"
ferencd@0 18582
ferencd@0 18583 @return const iterator one past the last element
ferencd@0 18584
ferencd@0 18585 @complexity Constant.
ferencd@0 18586
ferencd@0 18587 @requirement This function helps `basic_json` satisfying the
ferencd@0 18588 [Container](https://en.cppreference.com/w/cpp/named_req/Container)
ferencd@0 18589 requirements:
ferencd@0 18590 - The complexity is constant.
ferencd@0 18591 - Has the semantics of `const_cast<const basic_json&>(*this).end()`.
ferencd@0 18592
ferencd@0 18593 @liveexample{The following code shows an example for `cend()`.,cend}
ferencd@0 18594
ferencd@0 18595 @sa @ref end() -- returns an iterator to the end
ferencd@0 18596 @sa @ref begin() -- returns an iterator to the beginning
ferencd@0 18597 @sa @ref cbegin() -- returns a const iterator to the beginning
ferencd@0 18598
ferencd@0 18599 @since version 1.0.0
ferencd@0 18600 */
ferencd@0 18601 const_iterator cend() const noexcept
ferencd@0 18602 {
ferencd@0 18603 const_iterator result(this);
ferencd@0 18604 result.set_end();
ferencd@0 18605 return result;
ferencd@0 18606 }
ferencd@0 18607
ferencd@0 18608 /*!
ferencd@0 18609 @brief returns an iterator to the reverse-beginning
ferencd@0 18610
ferencd@0 18611 Returns an iterator to the reverse-beginning; that is, the last element.
ferencd@0 18612
ferencd@0 18613 @image html range-rbegin-rend.svg "Illustration from cppreference.com"
ferencd@0 18614
ferencd@0 18615 @complexity Constant.
ferencd@0 18616
ferencd@0 18617 @requirement This function helps `basic_json` satisfying the
ferencd@0 18618 [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
ferencd@0 18619 requirements:
ferencd@0 18620 - The complexity is constant.
ferencd@0 18621 - Has the semantics of `reverse_iterator(end())`.
ferencd@0 18622
ferencd@0 18623 @liveexample{The following code shows an example for `rbegin()`.,rbegin}
ferencd@0 18624
ferencd@0 18625 @sa @ref crbegin() -- returns a const reverse iterator to the beginning
ferencd@0 18626 @sa @ref rend() -- returns a reverse iterator to the end
ferencd@0 18627 @sa @ref crend() -- returns a const reverse iterator to the end
ferencd@0 18628
ferencd@0 18629 @since version 1.0.0
ferencd@0 18630 */
ferencd@0 18631 reverse_iterator rbegin() noexcept
ferencd@0 18632 {
ferencd@0 18633 return reverse_iterator(end());
ferencd@0 18634 }
ferencd@0 18635
ferencd@0 18636 /*!
ferencd@0 18637 @copydoc basic_json::crbegin()
ferencd@0 18638 */
ferencd@0 18639 const_reverse_iterator rbegin() const noexcept
ferencd@0 18640 {
ferencd@0 18641 return crbegin();
ferencd@0 18642 }
ferencd@0 18643
ferencd@0 18644 /*!
ferencd@0 18645 @brief returns an iterator to the reverse-end
ferencd@0 18646
ferencd@0 18647 Returns an iterator to the reverse-end; that is, one before the first
ferencd@0 18648 element.
ferencd@0 18649
ferencd@0 18650 @image html range-rbegin-rend.svg "Illustration from cppreference.com"
ferencd@0 18651
ferencd@0 18652 @complexity Constant.
ferencd@0 18653
ferencd@0 18654 @requirement This function helps `basic_json` satisfying the
ferencd@0 18655 [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
ferencd@0 18656 requirements:
ferencd@0 18657 - The complexity is constant.
ferencd@0 18658 - Has the semantics of `reverse_iterator(begin())`.
ferencd@0 18659
ferencd@0 18660 @liveexample{The following code shows an example for `rend()`.,rend}
ferencd@0 18661
ferencd@0 18662 @sa @ref crend() -- returns a const reverse iterator to the end
ferencd@0 18663 @sa @ref rbegin() -- returns a reverse iterator to the beginning
ferencd@0 18664 @sa @ref crbegin() -- returns a const reverse iterator to the beginning
ferencd@0 18665
ferencd@0 18666 @since version 1.0.0
ferencd@0 18667 */
ferencd@0 18668 reverse_iterator rend() noexcept
ferencd@0 18669 {
ferencd@0 18670 return reverse_iterator(begin());
ferencd@0 18671 }
ferencd@0 18672
ferencd@0 18673 /*!
ferencd@0 18674 @copydoc basic_json::crend()
ferencd@0 18675 */
ferencd@0 18676 const_reverse_iterator rend() const noexcept
ferencd@0 18677 {
ferencd@0 18678 return crend();
ferencd@0 18679 }
ferencd@0 18680
ferencd@0 18681 /*!
ferencd@0 18682 @brief returns a const reverse iterator to the last element
ferencd@0 18683
ferencd@0 18684 Returns a const iterator to the reverse-beginning; that is, the last
ferencd@0 18685 element.
ferencd@0 18686
ferencd@0 18687 @image html range-rbegin-rend.svg "Illustration from cppreference.com"
ferencd@0 18688
ferencd@0 18689 @complexity Constant.
ferencd@0 18690
ferencd@0 18691 @requirement This function helps `basic_json` satisfying the
ferencd@0 18692 [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
ferencd@0 18693 requirements:
ferencd@0 18694 - The complexity is constant.
ferencd@0 18695 - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.
ferencd@0 18696
ferencd@0 18697 @liveexample{The following code shows an example for `crbegin()`.,crbegin}
ferencd@0 18698
ferencd@0 18699 @sa @ref rbegin() -- returns a reverse iterator to the beginning
ferencd@0 18700 @sa @ref rend() -- returns a reverse iterator to the end
ferencd@0 18701 @sa @ref crend() -- returns a const reverse iterator to the end
ferencd@0 18702
ferencd@0 18703 @since version 1.0.0
ferencd@0 18704 */
ferencd@0 18705 const_reverse_iterator crbegin() const noexcept
ferencd@0 18706 {
ferencd@0 18707 return const_reverse_iterator(cend());
ferencd@0 18708 }
ferencd@0 18709
ferencd@0 18710 /*!
ferencd@0 18711 @brief returns a const reverse iterator to one before the first
ferencd@0 18712
ferencd@0 18713 Returns a const reverse iterator to the reverse-end; that is, one before
ferencd@0 18714 the first element.
ferencd@0 18715
ferencd@0 18716 @image html range-rbegin-rend.svg "Illustration from cppreference.com"
ferencd@0 18717
ferencd@0 18718 @complexity Constant.
ferencd@0 18719
ferencd@0 18720 @requirement This function helps `basic_json` satisfying the
ferencd@0 18721 [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
ferencd@0 18722 requirements:
ferencd@0 18723 - The complexity is constant.
ferencd@0 18724 - Has the semantics of `const_cast<const basic_json&>(*this).rend()`.
ferencd@0 18725
ferencd@0 18726 @liveexample{The following code shows an example for `crend()`.,crend}
ferencd@0 18727
ferencd@0 18728 @sa @ref rend() -- returns a reverse iterator to the end
ferencd@0 18729 @sa @ref rbegin() -- returns a reverse iterator to the beginning
ferencd@0 18730 @sa @ref crbegin() -- returns a const reverse iterator to the beginning
ferencd@0 18731
ferencd@0 18732 @since version 1.0.0
ferencd@0 18733 */
ferencd@0 18734 const_reverse_iterator crend() const noexcept
ferencd@0 18735 {
ferencd@0 18736 return const_reverse_iterator(cbegin());
ferencd@0 18737 }
ferencd@0 18738
ferencd@0 18739 public:
ferencd@0 18740 /*!
ferencd@0 18741 @brief wrapper to access iterator member functions in range-based for
ferencd@0 18742
ferencd@0 18743 This function allows to access @ref iterator::key() and @ref
ferencd@0 18744 iterator::value() during range-based for loops. In these loops, a
ferencd@0 18745 reference to the JSON values is returned, so there is no access to the
ferencd@0 18746 underlying iterator.
ferencd@0 18747
ferencd@0 18748 For loop without iterator_wrapper:
ferencd@0 18749
ferencd@0 18750 @code{cpp}
ferencd@0 18751 for (auto it = j_object.begin(); it != j_object.end(); ++it)
ferencd@0 18752 {
ferencd@0 18753 std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
ferencd@0 18754 }
ferencd@0 18755 @endcode
ferencd@0 18756
ferencd@0 18757 Range-based for loop without iterator proxy:
ferencd@0 18758
ferencd@0 18759 @code{cpp}
ferencd@0 18760 for (auto it : j_object)
ferencd@0 18761 {
ferencd@0 18762 // "it" is of type json::reference and has no key() member
ferencd@0 18763 std::cout << "value: " << it << '\n';
ferencd@0 18764 }
ferencd@0 18765 @endcode
ferencd@0 18766
ferencd@0 18767 Range-based for loop with iterator proxy:
ferencd@0 18768
ferencd@0 18769 @code{cpp}
ferencd@0 18770 for (auto it : json::iterator_wrapper(j_object))
ferencd@0 18771 {
ferencd@0 18772 std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
ferencd@0 18773 }
ferencd@0 18774 @endcode
ferencd@0 18775
ferencd@0 18776 @note When iterating over an array, `key()` will return the index of the
ferencd@0 18777 element as string (see example).
ferencd@0 18778
ferencd@0 18779 @param[in] ref reference to a JSON value
ferencd@0 18780 @return iteration proxy object wrapping @a ref with an interface to use in
ferencd@0 18781 range-based for loops
ferencd@0 18782
ferencd@0 18783 @liveexample{The following code shows how the wrapper is used,iterator_wrapper}
ferencd@0 18784
ferencd@0 18785 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 18786 changes in the JSON value.
ferencd@0 18787
ferencd@0 18788 @complexity Constant.
ferencd@0 18789
ferencd@0 18790 @note The name of this function is not yet final and may change in the
ferencd@0 18791 future.
ferencd@0 18792
ferencd@0 18793 @deprecated This stream operator is deprecated and will be removed in
ferencd@0 18794 future 4.0.0 of the library. Please use @ref items() instead;
ferencd@0 18795 that is, replace `json::iterator_wrapper(j)` with `j.items()`.
ferencd@0 18796 */
ferencd@0 18797 JSON_HEDLEY_DEPRECATED(3.1.0)
ferencd@0 18798 static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
ferencd@0 18799 {
ferencd@0 18800 return ref.items();
ferencd@0 18801 }
ferencd@0 18802
ferencd@0 18803 /*!
ferencd@0 18804 @copydoc iterator_wrapper(reference)
ferencd@0 18805 */
ferencd@0 18806 JSON_HEDLEY_DEPRECATED(3.1.0)
ferencd@0 18807 static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
ferencd@0 18808 {
ferencd@0 18809 return ref.items();
ferencd@0 18810 }
ferencd@0 18811
ferencd@0 18812 /*!
ferencd@0 18813 @brief helper to access iterator member functions in range-based for
ferencd@0 18814
ferencd@0 18815 This function allows to access @ref iterator::key() and @ref
ferencd@0 18816 iterator::value() during range-based for loops. In these loops, a
ferencd@0 18817 reference to the JSON values is returned, so there is no access to the
ferencd@0 18818 underlying iterator.
ferencd@0 18819
ferencd@0 18820 For loop without `items()` function:
ferencd@0 18821
ferencd@0 18822 @code{cpp}
ferencd@0 18823 for (auto it = j_object.begin(); it != j_object.end(); ++it)
ferencd@0 18824 {
ferencd@0 18825 std::cout << "key: " << it.key() << ", value:" << it.value() << '\n';
ferencd@0 18826 }
ferencd@0 18827 @endcode
ferencd@0 18828
ferencd@0 18829 Range-based for loop without `items()` function:
ferencd@0 18830
ferencd@0 18831 @code{cpp}
ferencd@0 18832 for (auto it : j_object)
ferencd@0 18833 {
ferencd@0 18834 // "it" is of type json::reference and has no key() member
ferencd@0 18835 std::cout << "value: " << it << '\n';
ferencd@0 18836 }
ferencd@0 18837 @endcode
ferencd@0 18838
ferencd@0 18839 Range-based for loop with `items()` function:
ferencd@0 18840
ferencd@0 18841 @code{cpp}
ferencd@0 18842 for (auto& el : j_object.items())
ferencd@0 18843 {
ferencd@0 18844 std::cout << "key: " << el.key() << ", value:" << el.value() << '\n';
ferencd@0 18845 }
ferencd@0 18846 @endcode
ferencd@0 18847
ferencd@0 18848 The `items()` function also allows to use
ferencd@0 18849 [structured bindings](https://en.cppreference.com/w/cpp/language/structured_binding)
ferencd@0 18850 (C++17):
ferencd@0 18851
ferencd@0 18852 @code{cpp}
ferencd@0 18853 for (auto& [key, val] : j_object.items())
ferencd@0 18854 {
ferencd@0 18855 std::cout << "key: " << key << ", value:" << val << '\n';
ferencd@0 18856 }
ferencd@0 18857 @endcode
ferencd@0 18858
ferencd@0 18859 @note When iterating over an array, `key()` will return the index of the
ferencd@0 18860 element as string (see example). For primitive types (e.g., numbers),
ferencd@0 18861 `key()` returns an empty string.
ferencd@0 18862
ferencd@0 18863 @return iteration proxy object wrapping @a ref with an interface to use in
ferencd@0 18864 range-based for loops
ferencd@0 18865
ferencd@0 18866 @liveexample{The following code shows how the function is used.,items}
ferencd@0 18867
ferencd@0 18868 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 18869 changes in the JSON value.
ferencd@0 18870
ferencd@0 18871 @complexity Constant.
ferencd@0 18872
ferencd@0 18873 @since version 3.1.0, structured bindings support since 3.5.0.
ferencd@0 18874 */
ferencd@0 18875 iteration_proxy<iterator> items() noexcept
ferencd@0 18876 {
ferencd@0 18877 return iteration_proxy<iterator>(*this);
ferencd@0 18878 }
ferencd@0 18879
ferencd@0 18880 /*!
ferencd@0 18881 @copydoc items()
ferencd@0 18882 */
ferencd@0 18883 iteration_proxy<const_iterator> items() const noexcept
ferencd@0 18884 {
ferencd@0 18885 return iteration_proxy<const_iterator>(*this);
ferencd@0 18886 }
ferencd@0 18887
ferencd@0 18888 /// @}
ferencd@0 18889
ferencd@0 18890
ferencd@0 18891 //////////////
ferencd@0 18892 // capacity //
ferencd@0 18893 //////////////
ferencd@0 18894
ferencd@0 18895 /// @name capacity
ferencd@0 18896 /// @{
ferencd@0 18897
ferencd@0 18898 /*!
ferencd@0 18899 @brief checks whether the container is empty.
ferencd@0 18900
ferencd@0 18901 Checks if a JSON value has no elements (i.e. whether its @ref size is `0`).
ferencd@0 18902
ferencd@0 18903 @return The return value depends on the different types and is
ferencd@0 18904 defined as follows:
ferencd@0 18905 Value type | return value
ferencd@0 18906 ----------- | -------------
ferencd@0 18907 null | `true`
ferencd@0 18908 boolean | `false`
ferencd@0 18909 string | `false`
ferencd@0 18910 number | `false`
ferencd@0 18911 object | result of function `object_t::empty()`
ferencd@0 18912 array | result of function `array_t::empty()`
ferencd@0 18913
ferencd@0 18914 @liveexample{The following code uses `empty()` to check if a JSON
ferencd@0 18915 object contains any elements.,empty}
ferencd@0 18916
ferencd@0 18917 @complexity Constant, as long as @ref array_t and @ref object_t satisfy
ferencd@0 18918 the Container concept; that is, their `empty()` functions have constant
ferencd@0 18919 complexity.
ferencd@0 18920
ferencd@0 18921 @iterators No changes.
ferencd@0 18922
ferencd@0 18923 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 18924
ferencd@0 18925 @note This function does not return whether a string stored as JSON value
ferencd@0 18926 is empty - it returns whether the JSON container itself is empty which is
ferencd@0 18927 false in the case of a string.
ferencd@0 18928
ferencd@0 18929 @requirement This function helps `basic_json` satisfying the
ferencd@0 18930 [Container](https://en.cppreference.com/w/cpp/named_req/Container)
ferencd@0 18931 requirements:
ferencd@0 18932 - The complexity is constant.
ferencd@0 18933 - Has the semantics of `begin() == end()`.
ferencd@0 18934
ferencd@0 18935 @sa @ref size() -- returns the number of elements
ferencd@0 18936
ferencd@0 18937 @since version 1.0.0
ferencd@0 18938 */
ferencd@0 18939 bool empty() const noexcept
ferencd@0 18940 {
ferencd@0 18941 switch (m_type)
ferencd@0 18942 {
ferencd@0 18943 case value_t::null:
ferencd@0 18944 {
ferencd@0 18945 // null values are empty
ferencd@0 18946 return true;
ferencd@0 18947 }
ferencd@0 18948
ferencd@0 18949 case value_t::array:
ferencd@0 18950 {
ferencd@0 18951 // delegate call to array_t::empty()
ferencd@0 18952 return m_value.array->empty();
ferencd@0 18953 }
ferencd@0 18954
ferencd@0 18955 case value_t::object:
ferencd@0 18956 {
ferencd@0 18957 // delegate call to object_t::empty()
ferencd@0 18958 return m_value.object->empty();
ferencd@0 18959 }
ferencd@0 18960
ferencd@0 18961 default:
ferencd@0 18962 {
ferencd@0 18963 // all other types are nonempty
ferencd@0 18964 return false;
ferencd@0 18965 }
ferencd@0 18966 }
ferencd@0 18967 }
ferencd@0 18968
ferencd@0 18969 /*!
ferencd@0 18970 @brief returns the number of elements
ferencd@0 18971
ferencd@0 18972 Returns the number of elements in a JSON value.
ferencd@0 18973
ferencd@0 18974 @return The return value depends on the different types and is
ferencd@0 18975 defined as follows:
ferencd@0 18976 Value type | return value
ferencd@0 18977 ----------- | -------------
ferencd@0 18978 null | `0`
ferencd@0 18979 boolean | `1`
ferencd@0 18980 string | `1`
ferencd@0 18981 number | `1`
ferencd@0 18982 object | result of function object_t::size()
ferencd@0 18983 array | result of function array_t::size()
ferencd@0 18984
ferencd@0 18985 @liveexample{The following code calls `size()` on the different value
ferencd@0 18986 types.,size}
ferencd@0 18987
ferencd@0 18988 @complexity Constant, as long as @ref array_t and @ref object_t satisfy
ferencd@0 18989 the Container concept; that is, their size() functions have constant
ferencd@0 18990 complexity.
ferencd@0 18991
ferencd@0 18992 @iterators No changes.
ferencd@0 18993
ferencd@0 18994 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 18995
ferencd@0 18996 @note This function does not return the length of a string stored as JSON
ferencd@0 18997 value - it returns the number of elements in the JSON value which is 1 in
ferencd@0 18998 the case of a string.
ferencd@0 18999
ferencd@0 19000 @requirement This function helps `basic_json` satisfying the
ferencd@0 19001 [Container](https://en.cppreference.com/w/cpp/named_req/Container)
ferencd@0 19002 requirements:
ferencd@0 19003 - The complexity is constant.
ferencd@0 19004 - Has the semantics of `std::distance(begin(), end())`.
ferencd@0 19005
ferencd@0 19006 @sa @ref empty() -- checks whether the container is empty
ferencd@0 19007 @sa @ref max_size() -- returns the maximal number of elements
ferencd@0 19008
ferencd@0 19009 @since version 1.0.0
ferencd@0 19010 */
ferencd@0 19011 size_type size() const noexcept
ferencd@0 19012 {
ferencd@0 19013 switch (m_type)
ferencd@0 19014 {
ferencd@0 19015 case value_t::null:
ferencd@0 19016 {
ferencd@0 19017 // null values are empty
ferencd@0 19018 return 0;
ferencd@0 19019 }
ferencd@0 19020
ferencd@0 19021 case value_t::array:
ferencd@0 19022 {
ferencd@0 19023 // delegate call to array_t::size()
ferencd@0 19024 return m_value.array->size();
ferencd@0 19025 }
ferencd@0 19026
ferencd@0 19027 case value_t::object:
ferencd@0 19028 {
ferencd@0 19029 // delegate call to object_t::size()
ferencd@0 19030 return m_value.object->size();
ferencd@0 19031 }
ferencd@0 19032
ferencd@0 19033 default:
ferencd@0 19034 {
ferencd@0 19035 // all other types have size 1
ferencd@0 19036 return 1;
ferencd@0 19037 }
ferencd@0 19038 }
ferencd@0 19039 }
ferencd@0 19040
ferencd@0 19041 /*!
ferencd@0 19042 @brief returns the maximum possible number of elements
ferencd@0 19043
ferencd@0 19044 Returns the maximum number of elements a JSON value is able to hold due to
ferencd@0 19045 system or library implementation limitations, i.e. `std::distance(begin(),
ferencd@0 19046 end())` for the JSON value.
ferencd@0 19047
ferencd@0 19048 @return The return value depends on the different types and is
ferencd@0 19049 defined as follows:
ferencd@0 19050 Value type | return value
ferencd@0 19051 ----------- | -------------
ferencd@0 19052 null | `0` (same as `size()`)
ferencd@0 19053 boolean | `1` (same as `size()`)
ferencd@0 19054 string | `1` (same as `size()`)
ferencd@0 19055 number | `1` (same as `size()`)
ferencd@0 19056 object | result of function `object_t::max_size()`
ferencd@0 19057 array | result of function `array_t::max_size()`
ferencd@0 19058
ferencd@0 19059 @liveexample{The following code calls `max_size()` on the different value
ferencd@0 19060 types. Note the output is implementation specific.,max_size}
ferencd@0 19061
ferencd@0 19062 @complexity Constant, as long as @ref array_t and @ref object_t satisfy
ferencd@0 19063 the Container concept; that is, their `max_size()` functions have constant
ferencd@0 19064 complexity.
ferencd@0 19065
ferencd@0 19066 @iterators No changes.
ferencd@0 19067
ferencd@0 19068 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 19069
ferencd@0 19070 @requirement This function helps `basic_json` satisfying the
ferencd@0 19071 [Container](https://en.cppreference.com/w/cpp/named_req/Container)
ferencd@0 19072 requirements:
ferencd@0 19073 - The complexity is constant.
ferencd@0 19074 - Has the semantics of returning `b.size()` where `b` is the largest
ferencd@0 19075 possible JSON value.
ferencd@0 19076
ferencd@0 19077 @sa @ref size() -- returns the number of elements
ferencd@0 19078
ferencd@0 19079 @since version 1.0.0
ferencd@0 19080 */
ferencd@0 19081 size_type max_size() const noexcept
ferencd@0 19082 {
ferencd@0 19083 switch (m_type)
ferencd@0 19084 {
ferencd@0 19085 case value_t::array:
ferencd@0 19086 {
ferencd@0 19087 // delegate call to array_t::max_size()
ferencd@0 19088 return m_value.array->max_size();
ferencd@0 19089 }
ferencd@0 19090
ferencd@0 19091 case value_t::object:
ferencd@0 19092 {
ferencd@0 19093 // delegate call to object_t::max_size()
ferencd@0 19094 return m_value.object->max_size();
ferencd@0 19095 }
ferencd@0 19096
ferencd@0 19097 default:
ferencd@0 19098 {
ferencd@0 19099 // all other types have max_size() == size()
ferencd@0 19100 return size();
ferencd@0 19101 }
ferencd@0 19102 }
ferencd@0 19103 }
ferencd@0 19104
ferencd@0 19105 /// @}
ferencd@0 19106
ferencd@0 19107
ferencd@0 19108 ///////////////
ferencd@0 19109 // modifiers //
ferencd@0 19110 ///////////////
ferencd@0 19111
ferencd@0 19112 /// @name modifiers
ferencd@0 19113 /// @{
ferencd@0 19114
ferencd@0 19115 /*!
ferencd@0 19116 @brief clears the contents
ferencd@0 19117
ferencd@0 19118 Clears the content of a JSON value and resets it to the default value as
ferencd@0 19119 if @ref basic_json(value_t) would have been called with the current value
ferencd@0 19120 type from @ref type():
ferencd@0 19121
ferencd@0 19122 Value type | initial value
ferencd@0 19123 ----------- | -------------
ferencd@0 19124 null | `null`
ferencd@0 19125 boolean | `false`
ferencd@0 19126 string | `""`
ferencd@0 19127 number | `0`
ferencd@0 19128 object | `{}`
ferencd@0 19129 array | `[]`
ferencd@0 19130
ferencd@0 19131 @post Has the same effect as calling
ferencd@0 19132 @code {.cpp}
ferencd@0 19133 *this = basic_json(type());
ferencd@0 19134 @endcode
ferencd@0 19135
ferencd@0 19136 @liveexample{The example below shows the effect of `clear()` to different
ferencd@0 19137 JSON types.,clear}
ferencd@0 19138
ferencd@0 19139 @complexity Linear in the size of the JSON value.
ferencd@0 19140
ferencd@0 19141 @iterators All iterators, pointers and references related to this container
ferencd@0 19142 are invalidated.
ferencd@0 19143
ferencd@0 19144 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 19145
ferencd@0 19146 @sa @ref basic_json(value_t) -- constructor that creates an object with the
ferencd@0 19147 same value than calling `clear()`
ferencd@0 19148
ferencd@0 19149 @since version 1.0.0
ferencd@0 19150 */
ferencd@0 19151 void clear() noexcept
ferencd@0 19152 {
ferencd@0 19153 switch (m_type)
ferencd@0 19154 {
ferencd@0 19155 case value_t::number_integer:
ferencd@0 19156 {
ferencd@0 19157 m_value.number_integer = 0;
ferencd@0 19158 break;
ferencd@0 19159 }
ferencd@0 19160
ferencd@0 19161 case value_t::number_unsigned:
ferencd@0 19162 {
ferencd@0 19163 m_value.number_unsigned = 0;
ferencd@0 19164 break;
ferencd@0 19165 }
ferencd@0 19166
ferencd@0 19167 case value_t::number_float:
ferencd@0 19168 {
ferencd@0 19169 m_value.number_float = 0.0;
ferencd@0 19170 break;
ferencd@0 19171 }
ferencd@0 19172
ferencd@0 19173 case value_t::boolean:
ferencd@0 19174 {
ferencd@0 19175 m_value.boolean = false;
ferencd@0 19176 break;
ferencd@0 19177 }
ferencd@0 19178
ferencd@0 19179 case value_t::string:
ferencd@0 19180 {
ferencd@0 19181 m_value.string->clear();
ferencd@0 19182 break;
ferencd@0 19183 }
ferencd@0 19184
ferencd@0 19185 case value_t::array:
ferencd@0 19186 {
ferencd@0 19187 m_value.array->clear();
ferencd@0 19188 break;
ferencd@0 19189 }
ferencd@0 19190
ferencd@0 19191 case value_t::object:
ferencd@0 19192 {
ferencd@0 19193 m_value.object->clear();
ferencd@0 19194 break;
ferencd@0 19195 }
ferencd@0 19196
ferencd@0 19197 default:
ferencd@0 19198 break;
ferencd@0 19199 }
ferencd@0 19200 }
ferencd@0 19201
ferencd@0 19202 /*!
ferencd@0 19203 @brief add an object to an array
ferencd@0 19204
ferencd@0 19205 Appends the given element @a val to the end of the JSON value. If the
ferencd@0 19206 function is called on a JSON null value, an empty array is created before
ferencd@0 19207 appending @a val.
ferencd@0 19208
ferencd@0 19209 @param[in] val the value to add to the JSON array
ferencd@0 19210
ferencd@0 19211 @throw type_error.308 when called on a type other than JSON array or
ferencd@0 19212 null; example: `"cannot use push_back() with number"`
ferencd@0 19213
ferencd@0 19214 @complexity Amortized constant.
ferencd@0 19215
ferencd@0 19216 @liveexample{The example shows how `push_back()` and `+=` can be used to
ferencd@0 19217 add elements to a JSON array. Note how the `null` value was silently
ferencd@0 19218 converted to a JSON array.,push_back}
ferencd@0 19219
ferencd@0 19220 @since version 1.0.0
ferencd@0 19221 */
ferencd@0 19222 void push_back(basic_json&& val)
ferencd@0 19223 {
ferencd@0 19224 // push_back only works for null objects or arrays
ferencd@0 19225 if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_array())))
ferencd@0 19226 {
ferencd@0 19227 JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
ferencd@0 19228 }
ferencd@0 19229
ferencd@0 19230 // transform null object into an array
ferencd@0 19231 if (is_null())
ferencd@0 19232 {
ferencd@0 19233 m_type = value_t::array;
ferencd@0 19234 m_value = value_t::array;
ferencd@0 19235 assert_invariant();
ferencd@0 19236 }
ferencd@0 19237
ferencd@0 19238 // add element to array (move semantics)
ferencd@0 19239 m_value.array->push_back(std::move(val));
ferencd@0 19240 // invalidate object: mark it null so we do not call the destructor
ferencd@0 19241 // cppcheck-suppress accessMoved
ferencd@0 19242 val.m_type = value_t::null;
ferencd@0 19243 }
ferencd@0 19244
ferencd@0 19245 /*!
ferencd@0 19246 @brief add an object to an array
ferencd@0 19247 @copydoc push_back(basic_json&&)
ferencd@0 19248 */
ferencd@0 19249 reference operator+=(basic_json&& val)
ferencd@0 19250 {
ferencd@0 19251 push_back(std::move(val));
ferencd@0 19252 return *this;
ferencd@0 19253 }
ferencd@0 19254
ferencd@0 19255 /*!
ferencd@0 19256 @brief add an object to an array
ferencd@0 19257 @copydoc push_back(basic_json&&)
ferencd@0 19258 */
ferencd@0 19259 void push_back(const basic_json& val)
ferencd@0 19260 {
ferencd@0 19261 // push_back only works for null objects or arrays
ferencd@0 19262 if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_array())))
ferencd@0 19263 {
ferencd@0 19264 JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
ferencd@0 19265 }
ferencd@0 19266
ferencd@0 19267 // transform null object into an array
ferencd@0 19268 if (is_null())
ferencd@0 19269 {
ferencd@0 19270 m_type = value_t::array;
ferencd@0 19271 m_value = value_t::array;
ferencd@0 19272 assert_invariant();
ferencd@0 19273 }
ferencd@0 19274
ferencd@0 19275 // add element to array
ferencd@0 19276 m_value.array->push_back(val);
ferencd@0 19277 }
ferencd@0 19278
ferencd@0 19279 /*!
ferencd@0 19280 @brief add an object to an array
ferencd@0 19281 @copydoc push_back(basic_json&&)
ferencd@0 19282 */
ferencd@0 19283 reference operator+=(const basic_json& val)
ferencd@0 19284 {
ferencd@0 19285 push_back(val);
ferencd@0 19286 return *this;
ferencd@0 19287 }
ferencd@0 19288
ferencd@0 19289 /*!
ferencd@0 19290 @brief add an object to an object
ferencd@0 19291
ferencd@0 19292 Inserts the given element @a val to the JSON object. If the function is
ferencd@0 19293 called on a JSON null value, an empty object is created before inserting
ferencd@0 19294 @a val.
ferencd@0 19295
ferencd@0 19296 @param[in] val the value to add to the JSON object
ferencd@0 19297
ferencd@0 19298 @throw type_error.308 when called on a type other than JSON object or
ferencd@0 19299 null; example: `"cannot use push_back() with number"`
ferencd@0 19300
ferencd@0 19301 @complexity Logarithmic in the size of the container, O(log(`size()`)).
ferencd@0 19302
ferencd@0 19303 @liveexample{The example shows how `push_back()` and `+=` can be used to
ferencd@0 19304 add elements to a JSON object. Note how the `null` value was silently
ferencd@0 19305 converted to a JSON object.,push_back__object_t__value}
ferencd@0 19306
ferencd@0 19307 @since version 1.0.0
ferencd@0 19308 */
ferencd@0 19309 void push_back(const typename object_t::value_type& val)
ferencd@0 19310 {
ferencd@0 19311 // push_back only works for null objects or objects
ferencd@0 19312 if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_object())))
ferencd@0 19313 {
ferencd@0 19314 JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name())));
ferencd@0 19315 }
ferencd@0 19316
ferencd@0 19317 // transform null object into an object
ferencd@0 19318 if (is_null())
ferencd@0 19319 {
ferencd@0 19320 m_type = value_t::object;
ferencd@0 19321 m_value = value_t::object;
ferencd@0 19322 assert_invariant();
ferencd@0 19323 }
ferencd@0 19324
ferencd@0 19325 // add element to array
ferencd@0 19326 m_value.object->insert(val);
ferencd@0 19327 }
ferencd@0 19328
ferencd@0 19329 /*!
ferencd@0 19330 @brief add an object to an object
ferencd@0 19331 @copydoc push_back(const typename object_t::value_type&)
ferencd@0 19332 */
ferencd@0 19333 reference operator+=(const typename object_t::value_type& val)
ferencd@0 19334 {
ferencd@0 19335 push_back(val);
ferencd@0 19336 return *this;
ferencd@0 19337 }
ferencd@0 19338
ferencd@0 19339 /*!
ferencd@0 19340 @brief add an object to an object
ferencd@0 19341
ferencd@0 19342 This function allows to use `push_back` with an initializer list. In case
ferencd@0 19343
ferencd@0 19344 1. the current value is an object,
ferencd@0 19345 2. the initializer list @a init contains only two elements, and
ferencd@0 19346 3. the first element of @a init is a string,
ferencd@0 19347
ferencd@0 19348 @a init is converted into an object element and added using
ferencd@0 19349 @ref push_back(const typename object_t::value_type&). Otherwise, @a init
ferencd@0 19350 is converted to a JSON value and added using @ref push_back(basic_json&&).
ferencd@0 19351
ferencd@0 19352 @param[in] init an initializer list
ferencd@0 19353
ferencd@0 19354 @complexity Linear in the size of the initializer list @a init.
ferencd@0 19355
ferencd@0 19356 @note This function is required to resolve an ambiguous overload error,
ferencd@0 19357 because pairs like `{"key", "value"}` can be both interpreted as
ferencd@0 19358 `object_t::value_type` or `std::initializer_list<basic_json>`, see
ferencd@0 19359 https://github.com/nlohmann/json/issues/235 for more information.
ferencd@0 19360
ferencd@0 19361 @liveexample{The example shows how initializer lists are treated as
ferencd@0 19362 objects when possible.,push_back__initializer_list}
ferencd@0 19363 */
ferencd@0 19364 void push_back(initializer_list_t init)
ferencd@0 19365 {
ferencd@0 19366 if (is_object() and init.size() == 2 and (*init.begin())->is_string())
ferencd@0 19367 {
ferencd@0 19368 basic_json&& key = init.begin()->moved_or_copied();
ferencd@0 19369 push_back(typename object_t::value_type(
ferencd@0 19370 std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));
ferencd@0 19371 }
ferencd@0 19372 else
ferencd@0 19373 {
ferencd@0 19374 push_back(basic_json(init));
ferencd@0 19375 }
ferencd@0 19376 }
ferencd@0 19377
ferencd@0 19378 /*!
ferencd@0 19379 @brief add an object to an object
ferencd@0 19380 @copydoc push_back(initializer_list_t)
ferencd@0 19381 */
ferencd@0 19382 reference operator+=(initializer_list_t init)
ferencd@0 19383 {
ferencd@0 19384 push_back(init);
ferencd@0 19385 return *this;
ferencd@0 19386 }
ferencd@0 19387
ferencd@0 19388 /*!
ferencd@0 19389 @brief add an object to an array
ferencd@0 19390
ferencd@0 19391 Creates a JSON value from the passed parameters @a args to the end of the
ferencd@0 19392 JSON value. If the function is called on a JSON null value, an empty array
ferencd@0 19393 is created before appending the value created from @a args.
ferencd@0 19394
ferencd@0 19395 @param[in] args arguments to forward to a constructor of @ref basic_json
ferencd@0 19396 @tparam Args compatible types to create a @ref basic_json object
ferencd@0 19397
ferencd@0 19398 @return reference to the inserted element
ferencd@0 19399
ferencd@0 19400 @throw type_error.311 when called on a type other than JSON array or
ferencd@0 19401 null; example: `"cannot use emplace_back() with number"`
ferencd@0 19402
ferencd@0 19403 @complexity Amortized constant.
ferencd@0 19404
ferencd@0 19405 @liveexample{The example shows how `push_back()` can be used to add
ferencd@0 19406 elements to a JSON array. Note how the `null` value was silently converted
ferencd@0 19407 to a JSON array.,emplace_back}
ferencd@0 19408
ferencd@0 19409 @since version 2.0.8, returns reference since 3.7.0
ferencd@0 19410 */
ferencd@0 19411 template<class... Args>
ferencd@0 19412 reference emplace_back(Args&& ... args)
ferencd@0 19413 {
ferencd@0 19414 // emplace_back only works for null objects or arrays
ferencd@0 19415 if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_array())))
ferencd@0 19416 {
ferencd@0 19417 JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name())));
ferencd@0 19418 }
ferencd@0 19419
ferencd@0 19420 // transform null object into an array
ferencd@0 19421 if (is_null())
ferencd@0 19422 {
ferencd@0 19423 m_type = value_t::array;
ferencd@0 19424 m_value = value_t::array;
ferencd@0 19425 assert_invariant();
ferencd@0 19426 }
ferencd@0 19427
ferencd@0 19428 // add element to array (perfect forwarding)
ferencd@0 19429 #ifdef JSON_HAS_CPP_17
ferencd@0 19430 return m_value.array->emplace_back(std::forward<Args>(args)...);
ferencd@0 19431 #else
ferencd@0 19432 m_value.array->emplace_back(std::forward<Args>(args)...);
ferencd@0 19433 return m_value.array->back();
ferencd@0 19434 #endif
ferencd@0 19435 }
ferencd@0 19436
ferencd@0 19437 /*!
ferencd@0 19438 @brief add an object to an object if key does not exist
ferencd@0 19439
ferencd@0 19440 Inserts a new element into a JSON object constructed in-place with the
ferencd@0 19441 given @a args if there is no element with the key in the container. If the
ferencd@0 19442 function is called on a JSON null value, an empty object is created before
ferencd@0 19443 appending the value created from @a args.
ferencd@0 19444
ferencd@0 19445 @param[in] args arguments to forward to a constructor of @ref basic_json
ferencd@0 19446 @tparam Args compatible types to create a @ref basic_json object
ferencd@0 19447
ferencd@0 19448 @return a pair consisting of an iterator to the inserted element, or the
ferencd@0 19449 already-existing element if no insertion happened, and a bool
ferencd@0 19450 denoting whether the insertion took place.
ferencd@0 19451
ferencd@0 19452 @throw type_error.311 when called on a type other than JSON object or
ferencd@0 19453 null; example: `"cannot use emplace() with number"`
ferencd@0 19454
ferencd@0 19455 @complexity Logarithmic in the size of the container, O(log(`size()`)).
ferencd@0 19456
ferencd@0 19457 @liveexample{The example shows how `emplace()` can be used to add elements
ferencd@0 19458 to a JSON object. Note how the `null` value was silently converted to a
ferencd@0 19459 JSON object. Further note how no value is added if there was already one
ferencd@0 19460 value stored with the same key.,emplace}
ferencd@0 19461
ferencd@0 19462 @since version 2.0.8
ferencd@0 19463 */
ferencd@0 19464 template<class... Args>
ferencd@0 19465 std::pair<iterator, bool> emplace(Args&& ... args)
ferencd@0 19466 {
ferencd@0 19467 // emplace only works for null objects or arrays
ferencd@0 19468 if (JSON_HEDLEY_UNLIKELY(not(is_null() or is_object())))
ferencd@0 19469 {
ferencd@0 19470 JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name())));
ferencd@0 19471 }
ferencd@0 19472
ferencd@0 19473 // transform null object into an object
ferencd@0 19474 if (is_null())
ferencd@0 19475 {
ferencd@0 19476 m_type = value_t::object;
ferencd@0 19477 m_value = value_t::object;
ferencd@0 19478 assert_invariant();
ferencd@0 19479 }
ferencd@0 19480
ferencd@0 19481 // add element to array (perfect forwarding)
ferencd@0 19482 auto res = m_value.object->emplace(std::forward<Args>(args)...);
ferencd@0 19483 // create result iterator and set iterator to the result of emplace
ferencd@0 19484 auto it = begin();
ferencd@0 19485 it.m_it.object_iterator = res.first;
ferencd@0 19486
ferencd@0 19487 // return pair of iterator and boolean
ferencd@0 19488 return {it, res.second};
ferencd@0 19489 }
ferencd@0 19490
ferencd@0 19491 /// Helper for insertion of an iterator
ferencd@0 19492 /// @note: This uses std::distance to support GCC 4.8,
ferencd@0 19493 /// see https://github.com/nlohmann/json/pull/1257
ferencd@0 19494 template<typename... Args>
ferencd@0 19495 iterator insert_iterator(const_iterator pos, Args&& ... args)
ferencd@0 19496 {
ferencd@0 19497 iterator result(this);
ferencd@0 19498 assert(m_value.array != nullptr);
ferencd@0 19499
ferencd@0 19500 auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator);
ferencd@0 19501 m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);
ferencd@0 19502 result.m_it.array_iterator = m_value.array->begin() + insert_pos;
ferencd@0 19503
ferencd@0 19504 // This could have been written as:
ferencd@0 19505 // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
ferencd@0 19506 // but the return value of insert is missing in GCC 4.8, so it is written this way instead.
ferencd@0 19507
ferencd@0 19508 return result;
ferencd@0 19509 }
ferencd@0 19510
ferencd@0 19511 /*!
ferencd@0 19512 @brief inserts element
ferencd@0 19513
ferencd@0 19514 Inserts element @a val before iterator @a pos.
ferencd@0 19515
ferencd@0 19516 @param[in] pos iterator before which the content will be inserted; may be
ferencd@0 19517 the end() iterator
ferencd@0 19518 @param[in] val element to insert
ferencd@0 19519 @return iterator pointing to the inserted @a val.
ferencd@0 19520
ferencd@0 19521 @throw type_error.309 if called on JSON values other than arrays;
ferencd@0 19522 example: `"cannot use insert() with string"`
ferencd@0 19523 @throw invalid_iterator.202 if @a pos is not an iterator of *this;
ferencd@0 19524 example: `"iterator does not fit current value"`
ferencd@0 19525
ferencd@0 19526 @complexity Constant plus linear in the distance between @a pos and end of
ferencd@0 19527 the container.
ferencd@0 19528
ferencd@0 19529 @liveexample{The example shows how `insert()` is used.,insert}
ferencd@0 19530
ferencd@0 19531 @since version 1.0.0
ferencd@0 19532 */
ferencd@0 19533 iterator insert(const_iterator pos, const basic_json& val)
ferencd@0 19534 {
ferencd@0 19535 // insert only works for arrays
ferencd@0 19536 if (JSON_HEDLEY_LIKELY(is_array()))
ferencd@0 19537 {
ferencd@0 19538 // check if iterator pos fits to this JSON value
ferencd@0 19539 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
ferencd@0 19540 {
ferencd@0 19541 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
ferencd@0 19542 }
ferencd@0 19543
ferencd@0 19544 // insert to array and return iterator
ferencd@0 19545 return insert_iterator(pos, val);
ferencd@0 19546 }
ferencd@0 19547
ferencd@0 19548 JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
ferencd@0 19549 }
ferencd@0 19550
ferencd@0 19551 /*!
ferencd@0 19552 @brief inserts element
ferencd@0 19553 @copydoc insert(const_iterator, const basic_json&)
ferencd@0 19554 */
ferencd@0 19555 iterator insert(const_iterator pos, basic_json&& val)
ferencd@0 19556 {
ferencd@0 19557 return insert(pos, val);
ferencd@0 19558 }
ferencd@0 19559
ferencd@0 19560 /*!
ferencd@0 19561 @brief inserts elements
ferencd@0 19562
ferencd@0 19563 Inserts @a cnt copies of @a val before iterator @a pos.
ferencd@0 19564
ferencd@0 19565 @param[in] pos iterator before which the content will be inserted; may be
ferencd@0 19566 the end() iterator
ferencd@0 19567 @param[in] cnt number of copies of @a val to insert
ferencd@0 19568 @param[in] val element to insert
ferencd@0 19569 @return iterator pointing to the first element inserted, or @a pos if
ferencd@0 19570 `cnt==0`
ferencd@0 19571
ferencd@0 19572 @throw type_error.309 if called on JSON values other than arrays; example:
ferencd@0 19573 `"cannot use insert() with string"`
ferencd@0 19574 @throw invalid_iterator.202 if @a pos is not an iterator of *this;
ferencd@0 19575 example: `"iterator does not fit current value"`
ferencd@0 19576
ferencd@0 19577 @complexity Linear in @a cnt plus linear in the distance between @a pos
ferencd@0 19578 and end of the container.
ferencd@0 19579
ferencd@0 19580 @liveexample{The example shows how `insert()` is used.,insert__count}
ferencd@0 19581
ferencd@0 19582 @since version 1.0.0
ferencd@0 19583 */
ferencd@0 19584 iterator insert(const_iterator pos, size_type cnt, const basic_json& val)
ferencd@0 19585 {
ferencd@0 19586 // insert only works for arrays
ferencd@0 19587 if (JSON_HEDLEY_LIKELY(is_array()))
ferencd@0 19588 {
ferencd@0 19589 // check if iterator pos fits to this JSON value
ferencd@0 19590 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
ferencd@0 19591 {
ferencd@0 19592 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
ferencd@0 19593 }
ferencd@0 19594
ferencd@0 19595 // insert to array and return iterator
ferencd@0 19596 return insert_iterator(pos, cnt, val);
ferencd@0 19597 }
ferencd@0 19598
ferencd@0 19599 JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
ferencd@0 19600 }
ferencd@0 19601
ferencd@0 19602 /*!
ferencd@0 19603 @brief inserts elements
ferencd@0 19604
ferencd@0 19605 Inserts elements from range `[first, last)` before iterator @a pos.
ferencd@0 19606
ferencd@0 19607 @param[in] pos iterator before which the content will be inserted; may be
ferencd@0 19608 the end() iterator
ferencd@0 19609 @param[in] first begin of the range of elements to insert
ferencd@0 19610 @param[in] last end of the range of elements to insert
ferencd@0 19611
ferencd@0 19612 @throw type_error.309 if called on JSON values other than arrays; example:
ferencd@0 19613 `"cannot use insert() with string"`
ferencd@0 19614 @throw invalid_iterator.202 if @a pos is not an iterator of *this;
ferencd@0 19615 example: `"iterator does not fit current value"`
ferencd@0 19616 @throw invalid_iterator.210 if @a first and @a last do not belong to the
ferencd@0 19617 same JSON value; example: `"iterators do not fit"`
ferencd@0 19618 @throw invalid_iterator.211 if @a first or @a last are iterators into
ferencd@0 19619 container for which insert is called; example: `"passed iterators may not
ferencd@0 19620 belong to container"`
ferencd@0 19621
ferencd@0 19622 @return iterator pointing to the first element inserted, or @a pos if
ferencd@0 19623 `first==last`
ferencd@0 19624
ferencd@0 19625 @complexity Linear in `std::distance(first, last)` plus linear in the
ferencd@0 19626 distance between @a pos and end of the container.
ferencd@0 19627
ferencd@0 19628 @liveexample{The example shows how `insert()` is used.,insert__range}
ferencd@0 19629
ferencd@0 19630 @since version 1.0.0
ferencd@0 19631 */
ferencd@0 19632 iterator insert(const_iterator pos, const_iterator first, const_iterator last)
ferencd@0 19633 {
ferencd@0 19634 // insert only works for arrays
ferencd@0 19635 if (JSON_HEDLEY_UNLIKELY(not is_array()))
ferencd@0 19636 {
ferencd@0 19637 JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
ferencd@0 19638 }
ferencd@0 19639
ferencd@0 19640 // check if iterator pos fits to this JSON value
ferencd@0 19641 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
ferencd@0 19642 {
ferencd@0 19643 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
ferencd@0 19644 }
ferencd@0 19645
ferencd@0 19646 // check if range iterators belong to the same JSON object
ferencd@0 19647 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
ferencd@0 19648 {
ferencd@0 19649 JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
ferencd@0 19650 }
ferencd@0 19651
ferencd@0 19652 if (JSON_HEDLEY_UNLIKELY(first.m_object == this))
ferencd@0 19653 {
ferencd@0 19654 JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container"));
ferencd@0 19655 }
ferencd@0 19656
ferencd@0 19657 // insert to array and return iterator
ferencd@0 19658 return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);
ferencd@0 19659 }
ferencd@0 19660
ferencd@0 19661 /*!
ferencd@0 19662 @brief inserts elements
ferencd@0 19663
ferencd@0 19664 Inserts elements from initializer list @a ilist before iterator @a pos.
ferencd@0 19665
ferencd@0 19666 @param[in] pos iterator before which the content will be inserted; may be
ferencd@0 19667 the end() iterator
ferencd@0 19668 @param[in] ilist initializer list to insert the values from
ferencd@0 19669
ferencd@0 19670 @throw type_error.309 if called on JSON values other than arrays; example:
ferencd@0 19671 `"cannot use insert() with string"`
ferencd@0 19672 @throw invalid_iterator.202 if @a pos is not an iterator of *this;
ferencd@0 19673 example: `"iterator does not fit current value"`
ferencd@0 19674
ferencd@0 19675 @return iterator pointing to the first element inserted, or @a pos if
ferencd@0 19676 `ilist` is empty
ferencd@0 19677
ferencd@0 19678 @complexity Linear in `ilist.size()` plus linear in the distance between
ferencd@0 19679 @a pos and end of the container.
ferencd@0 19680
ferencd@0 19681 @liveexample{The example shows how `insert()` is used.,insert__ilist}
ferencd@0 19682
ferencd@0 19683 @since version 1.0.0
ferencd@0 19684 */
ferencd@0 19685 iterator insert(const_iterator pos, initializer_list_t ilist)
ferencd@0 19686 {
ferencd@0 19687 // insert only works for arrays
ferencd@0 19688 if (JSON_HEDLEY_UNLIKELY(not is_array()))
ferencd@0 19689 {
ferencd@0 19690 JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
ferencd@0 19691 }
ferencd@0 19692
ferencd@0 19693 // check if iterator pos fits to this JSON value
ferencd@0 19694 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
ferencd@0 19695 {
ferencd@0 19696 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value"));
ferencd@0 19697 }
ferencd@0 19698
ferencd@0 19699 // insert to array and return iterator
ferencd@0 19700 return insert_iterator(pos, ilist.begin(), ilist.end());
ferencd@0 19701 }
ferencd@0 19702
ferencd@0 19703 /*!
ferencd@0 19704 @brief inserts elements
ferencd@0 19705
ferencd@0 19706 Inserts elements from range `[first, last)`.
ferencd@0 19707
ferencd@0 19708 @param[in] first begin of the range of elements to insert
ferencd@0 19709 @param[in] last end of the range of elements to insert
ferencd@0 19710
ferencd@0 19711 @throw type_error.309 if called on JSON values other than objects; example:
ferencd@0 19712 `"cannot use insert() with string"`
ferencd@0 19713 @throw invalid_iterator.202 if iterator @a first or @a last does does not
ferencd@0 19714 point to an object; example: `"iterators first and last must point to
ferencd@0 19715 objects"`
ferencd@0 19716 @throw invalid_iterator.210 if @a first and @a last do not belong to the
ferencd@0 19717 same JSON value; example: `"iterators do not fit"`
ferencd@0 19718
ferencd@0 19719 @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number
ferencd@0 19720 of elements to insert.
ferencd@0 19721
ferencd@0 19722 @liveexample{The example shows how `insert()` is used.,insert__range_object}
ferencd@0 19723
ferencd@0 19724 @since version 3.0.0
ferencd@0 19725 */
ferencd@0 19726 void insert(const_iterator first, const_iterator last)
ferencd@0 19727 {
ferencd@0 19728 // insert only works for objects
ferencd@0 19729 if (JSON_HEDLEY_UNLIKELY(not is_object()))
ferencd@0 19730 {
ferencd@0 19731 JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name())));
ferencd@0 19732 }
ferencd@0 19733
ferencd@0 19734 // check if range iterators belong to the same JSON object
ferencd@0 19735 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
ferencd@0 19736 {
ferencd@0 19737 JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
ferencd@0 19738 }
ferencd@0 19739
ferencd@0 19740 // passed iterators must belong to objects
ferencd@0 19741 if (JSON_HEDLEY_UNLIKELY(not first.m_object->is_object()))
ferencd@0 19742 {
ferencd@0 19743 JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
ferencd@0 19744 }
ferencd@0 19745
ferencd@0 19746 m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
ferencd@0 19747 }
ferencd@0 19748
ferencd@0 19749 /*!
ferencd@0 19750 @brief updates a JSON object from another object, overwriting existing keys
ferencd@0 19751
ferencd@0 19752 Inserts all values from JSON object @a j and overwrites existing keys.
ferencd@0 19753
ferencd@0 19754 @param[in] j JSON object to read values from
ferencd@0 19755
ferencd@0 19756 @throw type_error.312 if called on JSON values other than objects; example:
ferencd@0 19757 `"cannot use update() with string"`
ferencd@0 19758
ferencd@0 19759 @complexity O(N*log(size() + N)), where N is the number of elements to
ferencd@0 19760 insert.
ferencd@0 19761
ferencd@0 19762 @liveexample{The example shows how `update()` is used.,update}
ferencd@0 19763
ferencd@0 19764 @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
ferencd@0 19765
ferencd@0 19766 @since version 3.0.0
ferencd@0 19767 */
ferencd@0 19768 void update(const_reference j)
ferencd@0 19769 {
ferencd@0 19770 // implicitly convert null value to an empty object
ferencd@0 19771 if (is_null())
ferencd@0 19772 {
ferencd@0 19773 m_type = value_t::object;
ferencd@0 19774 m_value.object = create<object_t>();
ferencd@0 19775 assert_invariant();
ferencd@0 19776 }
ferencd@0 19777
ferencd@0 19778 if (JSON_HEDLEY_UNLIKELY(not is_object()))
ferencd@0 19779 {
ferencd@0 19780 JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name())));
ferencd@0 19781 }
ferencd@0 19782 if (JSON_HEDLEY_UNLIKELY(not j.is_object()))
ferencd@0 19783 {
ferencd@0 19784 JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name())));
ferencd@0 19785 }
ferencd@0 19786
ferencd@0 19787 for (auto it = j.cbegin(); it != j.cend(); ++it)
ferencd@0 19788 {
ferencd@0 19789 m_value.object->operator[](it.key()) = it.value();
ferencd@0 19790 }
ferencd@0 19791 }
ferencd@0 19792
ferencd@0 19793 /*!
ferencd@0 19794 @brief updates a JSON object from another object, overwriting existing keys
ferencd@0 19795
ferencd@0 19796 Inserts all values from from range `[first, last)` and overwrites existing
ferencd@0 19797 keys.
ferencd@0 19798
ferencd@0 19799 @param[in] first begin of the range of elements to insert
ferencd@0 19800 @param[in] last end of the range of elements to insert
ferencd@0 19801
ferencd@0 19802 @throw type_error.312 if called on JSON values other than objects; example:
ferencd@0 19803 `"cannot use update() with string"`
ferencd@0 19804 @throw invalid_iterator.202 if iterator @a first or @a last does does not
ferencd@0 19805 point to an object; example: `"iterators first and last must point to
ferencd@0 19806 objects"`
ferencd@0 19807 @throw invalid_iterator.210 if @a first and @a last do not belong to the
ferencd@0 19808 same JSON value; example: `"iterators do not fit"`
ferencd@0 19809
ferencd@0 19810 @complexity O(N*log(size() + N)), where N is the number of elements to
ferencd@0 19811 insert.
ferencd@0 19812
ferencd@0 19813 @liveexample{The example shows how `update()` is used__range.,update}
ferencd@0 19814
ferencd@0 19815 @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
ferencd@0 19816
ferencd@0 19817 @since version 3.0.0
ferencd@0 19818 */
ferencd@0 19819 void update(const_iterator first, const_iterator last)
ferencd@0 19820 {
ferencd@0 19821 // implicitly convert null value to an empty object
ferencd@0 19822 if (is_null())
ferencd@0 19823 {
ferencd@0 19824 m_type = value_t::object;
ferencd@0 19825 m_value.object = create<object_t>();
ferencd@0 19826 assert_invariant();
ferencd@0 19827 }
ferencd@0 19828
ferencd@0 19829 if (JSON_HEDLEY_UNLIKELY(not is_object()))
ferencd@0 19830 {
ferencd@0 19831 JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name())));
ferencd@0 19832 }
ferencd@0 19833
ferencd@0 19834 // check if range iterators belong to the same JSON object
ferencd@0 19835 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
ferencd@0 19836 {
ferencd@0 19837 JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
ferencd@0 19838 }
ferencd@0 19839
ferencd@0 19840 // passed iterators must belong to objects
ferencd@0 19841 if (JSON_HEDLEY_UNLIKELY(not first.m_object->is_object()
ferencd@0 19842 or not last.m_object->is_object()))
ferencd@0 19843 {
ferencd@0 19844 JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
ferencd@0 19845 }
ferencd@0 19846
ferencd@0 19847 for (auto it = first; it != last; ++it)
ferencd@0 19848 {
ferencd@0 19849 m_value.object->operator[](it.key()) = it.value();
ferencd@0 19850 }
ferencd@0 19851 }
ferencd@0 19852
ferencd@0 19853 /*!
ferencd@0 19854 @brief exchanges the values
ferencd@0 19855
ferencd@0 19856 Exchanges the contents of the JSON value with those of @a other. Does not
ferencd@0 19857 invoke any move, copy, or swap operations on individual elements. All
ferencd@0 19858 iterators and references remain valid. The past-the-end iterator is
ferencd@0 19859 invalidated.
ferencd@0 19860
ferencd@0 19861 @param[in,out] other JSON value to exchange the contents with
ferencd@0 19862
ferencd@0 19863 @complexity Constant.
ferencd@0 19864
ferencd@0 19865 @liveexample{The example below shows how JSON values can be swapped with
ferencd@0 19866 `swap()`.,swap__reference}
ferencd@0 19867
ferencd@0 19868 @since version 1.0.0
ferencd@0 19869 */
ferencd@0 19870 void swap(reference other) noexcept (
ferencd@0 19871 std::is_nothrow_move_constructible<value_t>::value and
ferencd@0 19872 std::is_nothrow_move_assignable<value_t>::value and
ferencd@0 19873 std::is_nothrow_move_constructible<json_value>::value and
ferencd@0 19874 std::is_nothrow_move_assignable<json_value>::value
ferencd@0 19875 )
ferencd@0 19876 {
ferencd@0 19877 std::swap(m_type, other.m_type);
ferencd@0 19878 std::swap(m_value, other.m_value);
ferencd@0 19879 assert_invariant();
ferencd@0 19880 }
ferencd@0 19881
ferencd@0 19882 /*!
ferencd@0 19883 @brief exchanges the values
ferencd@0 19884
ferencd@0 19885 Exchanges the contents of a JSON array with those of @a other. Does not
ferencd@0 19886 invoke any move, copy, or swap operations on individual elements. All
ferencd@0 19887 iterators and references remain valid. The past-the-end iterator is
ferencd@0 19888 invalidated.
ferencd@0 19889
ferencd@0 19890 @param[in,out] other array to exchange the contents with
ferencd@0 19891
ferencd@0 19892 @throw type_error.310 when JSON value is not an array; example: `"cannot
ferencd@0 19893 use swap() with string"`
ferencd@0 19894
ferencd@0 19895 @complexity Constant.
ferencd@0 19896
ferencd@0 19897 @liveexample{The example below shows how arrays can be swapped with
ferencd@0 19898 `swap()`.,swap__array_t}
ferencd@0 19899
ferencd@0 19900 @since version 1.0.0
ferencd@0 19901 */
ferencd@0 19902 void swap(array_t& other)
ferencd@0 19903 {
ferencd@0 19904 // swap only works for arrays
ferencd@0 19905 if (JSON_HEDLEY_LIKELY(is_array()))
ferencd@0 19906 {
ferencd@0 19907 std::swap(*(m_value.array), other);
ferencd@0 19908 }
ferencd@0 19909 else
ferencd@0 19910 {
ferencd@0 19911 JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name())));
ferencd@0 19912 }
ferencd@0 19913 }
ferencd@0 19914
ferencd@0 19915 /*!
ferencd@0 19916 @brief exchanges the values
ferencd@0 19917
ferencd@0 19918 Exchanges the contents of a JSON object with those of @a other. Does not
ferencd@0 19919 invoke any move, copy, or swap operations on individual elements. All
ferencd@0 19920 iterators and references remain valid. The past-the-end iterator is
ferencd@0 19921 invalidated.
ferencd@0 19922
ferencd@0 19923 @param[in,out] other object to exchange the contents with
ferencd@0 19924
ferencd@0 19925 @throw type_error.310 when JSON value is not an object; example:
ferencd@0 19926 `"cannot use swap() with string"`
ferencd@0 19927
ferencd@0 19928 @complexity Constant.
ferencd@0 19929
ferencd@0 19930 @liveexample{The example below shows how objects can be swapped with
ferencd@0 19931 `swap()`.,swap__object_t}
ferencd@0 19932
ferencd@0 19933 @since version 1.0.0
ferencd@0 19934 */
ferencd@0 19935 void swap(object_t& other)
ferencd@0 19936 {
ferencd@0 19937 // swap only works for objects
ferencd@0 19938 if (JSON_HEDLEY_LIKELY(is_object()))
ferencd@0 19939 {
ferencd@0 19940 std::swap(*(m_value.object), other);
ferencd@0 19941 }
ferencd@0 19942 else
ferencd@0 19943 {
ferencd@0 19944 JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name())));
ferencd@0 19945 }
ferencd@0 19946 }
ferencd@0 19947
ferencd@0 19948 /*!
ferencd@0 19949 @brief exchanges the values
ferencd@0 19950
ferencd@0 19951 Exchanges the contents of a JSON string with those of @a other. Does not
ferencd@0 19952 invoke any move, copy, or swap operations on individual elements. All
ferencd@0 19953 iterators and references remain valid. The past-the-end iterator is
ferencd@0 19954 invalidated.
ferencd@0 19955
ferencd@0 19956 @param[in,out] other string to exchange the contents with
ferencd@0 19957
ferencd@0 19958 @throw type_error.310 when JSON value is not a string; example: `"cannot
ferencd@0 19959 use swap() with boolean"`
ferencd@0 19960
ferencd@0 19961 @complexity Constant.
ferencd@0 19962
ferencd@0 19963 @liveexample{The example below shows how strings can be swapped with
ferencd@0 19964 `swap()`.,swap__string_t}
ferencd@0 19965
ferencd@0 19966 @since version 1.0.0
ferencd@0 19967 */
ferencd@0 19968 void swap(string_t& other)
ferencd@0 19969 {
ferencd@0 19970 // swap only works for strings
ferencd@0 19971 if (JSON_HEDLEY_LIKELY(is_string()))
ferencd@0 19972 {
ferencd@0 19973 std::swap(*(m_value.string), other);
ferencd@0 19974 }
ferencd@0 19975 else
ferencd@0 19976 {
ferencd@0 19977 JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name())));
ferencd@0 19978 }
ferencd@0 19979 }
ferencd@0 19980
ferencd@0 19981 /// @}
ferencd@0 19982
ferencd@0 19983 public:
ferencd@0 19984 //////////////////////////////////////////
ferencd@0 19985 // lexicographical comparison operators //
ferencd@0 19986 //////////////////////////////////////////
ferencd@0 19987
ferencd@0 19988 /// @name lexicographical comparison operators
ferencd@0 19989 /// @{
ferencd@0 19990
ferencd@0 19991 /*!
ferencd@0 19992 @brief comparison: equal
ferencd@0 19993
ferencd@0 19994 Compares two JSON values for equality according to the following rules:
ferencd@0 19995 - Two JSON values are equal if (1) they are from the same type and (2)
ferencd@0 19996 their stored values are the same according to their respective
ferencd@0 19997 `operator==`.
ferencd@0 19998 - Integer and floating-point numbers are automatically converted before
ferencd@0 19999 comparison. Note than two NaN values are always treated as unequal.
ferencd@0 20000 - Two JSON null values are equal.
ferencd@0 20001
ferencd@0 20002 @note Floating-point inside JSON values numbers are compared with
ferencd@0 20003 `json::number_float_t::operator==` which is `double::operator==` by
ferencd@0 20004 default. To compare floating-point while respecting an epsilon, an alternative
ferencd@0 20005 [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39)
ferencd@0 20006 could be used, for instance
ferencd@0 20007 @code {.cpp}
ferencd@0 20008 template<typename T, typename = typename std::enable_if<std::is_floating_point<T>::value, T>::type>
ferencd@0 20009 inline bool is_same(T a, T b, T epsilon = std::numeric_limits<T>::epsilon()) noexcept
ferencd@0 20010 {
ferencd@0 20011 return std::abs(a - b) <= epsilon;
ferencd@0 20012 }
ferencd@0 20013 @endcode
ferencd@0 20014
ferencd@0 20015 @note NaN values never compare equal to themselves or to other NaN values.
ferencd@0 20016
ferencd@0 20017 @param[in] lhs first JSON value to consider
ferencd@0 20018 @param[in] rhs second JSON value to consider
ferencd@0 20019 @return whether the values @a lhs and @a rhs are equal
ferencd@0 20020
ferencd@0 20021 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 20022
ferencd@0 20023 @complexity Linear.
ferencd@0 20024
ferencd@0 20025 @liveexample{The example demonstrates comparing several JSON
ferencd@0 20026 types.,operator__equal}
ferencd@0 20027
ferencd@0 20028 @since version 1.0.0
ferencd@0 20029 */
ferencd@0 20030 friend bool operator==(const_reference lhs, const_reference rhs) noexcept
ferencd@0 20031 {
ferencd@0 20032 const auto lhs_type = lhs.type();
ferencd@0 20033 const auto rhs_type = rhs.type();
ferencd@0 20034
ferencd@0 20035 if (lhs_type == rhs_type)
ferencd@0 20036 {
ferencd@0 20037 switch (lhs_type)
ferencd@0 20038 {
ferencd@0 20039 case value_t::array:
ferencd@0 20040 return *lhs.m_value.array == *rhs.m_value.array;
ferencd@0 20041
ferencd@0 20042 case value_t::object:
ferencd@0 20043 return *lhs.m_value.object == *rhs.m_value.object;
ferencd@0 20044
ferencd@0 20045 case value_t::null:
ferencd@0 20046 return true;
ferencd@0 20047
ferencd@0 20048 case value_t::string:
ferencd@0 20049 return *lhs.m_value.string == *rhs.m_value.string;
ferencd@0 20050
ferencd@0 20051 case value_t::boolean:
ferencd@0 20052 return lhs.m_value.boolean == rhs.m_value.boolean;
ferencd@0 20053
ferencd@0 20054 case value_t::number_integer:
ferencd@0 20055 return lhs.m_value.number_integer == rhs.m_value.number_integer;
ferencd@0 20056
ferencd@0 20057 case value_t::number_unsigned:
ferencd@0 20058 return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned;
ferencd@0 20059
ferencd@0 20060 case value_t::number_float:
ferencd@0 20061 return lhs.m_value.number_float == rhs.m_value.number_float;
ferencd@0 20062
ferencd@0 20063 default:
ferencd@0 20064 return false;
ferencd@0 20065 }
ferencd@0 20066 }
ferencd@0 20067 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
ferencd@0 20068 {
ferencd@0 20069 return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float;
ferencd@0 20070 }
ferencd@0 20071 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
ferencd@0 20072 {
ferencd@0 20073 return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
ferencd@0 20074 }
ferencd@0 20075 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
ferencd@0 20076 {
ferencd@0 20077 return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;
ferencd@0 20078 }
ferencd@0 20079 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
ferencd@0 20080 {
ferencd@0 20081 return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned);
ferencd@0 20082 }
ferencd@0 20083 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
ferencd@0 20084 {
ferencd@0 20085 return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;
ferencd@0 20086 }
ferencd@0 20087 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
ferencd@0 20088 {
ferencd@0 20089 return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned);
ferencd@0 20090 }
ferencd@0 20091
ferencd@0 20092 return false;
ferencd@0 20093 }
ferencd@0 20094
ferencd@0 20095 /*!
ferencd@0 20096 @brief comparison: equal
ferencd@0 20097 @copydoc operator==(const_reference, const_reference)
ferencd@0 20098 */
ferencd@0 20099 template<typename ScalarType, typename std::enable_if<
ferencd@0 20100 std::is_scalar<ScalarType>::value, int>::type = 0>
ferencd@0 20101 friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept
ferencd@0 20102 {
ferencd@0 20103 return lhs == basic_json(rhs);
ferencd@0 20104 }
ferencd@0 20105
ferencd@0 20106 /*!
ferencd@0 20107 @brief comparison: equal
ferencd@0 20108 @copydoc operator==(const_reference, const_reference)
ferencd@0 20109 */
ferencd@0 20110 template<typename ScalarType, typename std::enable_if<
ferencd@0 20111 std::is_scalar<ScalarType>::value, int>::type = 0>
ferencd@0 20112 friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept
ferencd@0 20113 {
ferencd@0 20114 return basic_json(lhs) == rhs;
ferencd@0 20115 }
ferencd@0 20116
ferencd@0 20117 /*!
ferencd@0 20118 @brief comparison: not equal
ferencd@0 20119
ferencd@0 20120 Compares two JSON values for inequality by calculating `not (lhs == rhs)`.
ferencd@0 20121
ferencd@0 20122 @param[in] lhs first JSON value to consider
ferencd@0 20123 @param[in] rhs second JSON value to consider
ferencd@0 20124 @return whether the values @a lhs and @a rhs are not equal
ferencd@0 20125
ferencd@0 20126 @complexity Linear.
ferencd@0 20127
ferencd@0 20128 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 20129
ferencd@0 20130 @liveexample{The example demonstrates comparing several JSON
ferencd@0 20131 types.,operator__notequal}
ferencd@0 20132
ferencd@0 20133 @since version 1.0.0
ferencd@0 20134 */
ferencd@0 20135 friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
ferencd@0 20136 {
ferencd@0 20137 return not (lhs == rhs);
ferencd@0 20138 }
ferencd@0 20139
ferencd@0 20140 /*!
ferencd@0 20141 @brief comparison: not equal
ferencd@0 20142 @copydoc operator!=(const_reference, const_reference)
ferencd@0 20143 */
ferencd@0 20144 template<typename ScalarType, typename std::enable_if<
ferencd@0 20145 std::is_scalar<ScalarType>::value, int>::type = 0>
ferencd@0 20146 friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept
ferencd@0 20147 {
ferencd@0 20148 return lhs != basic_json(rhs);
ferencd@0 20149 }
ferencd@0 20150
ferencd@0 20151 /*!
ferencd@0 20152 @brief comparison: not equal
ferencd@0 20153 @copydoc operator!=(const_reference, const_reference)
ferencd@0 20154 */
ferencd@0 20155 template<typename ScalarType, typename std::enable_if<
ferencd@0 20156 std::is_scalar<ScalarType>::value, int>::type = 0>
ferencd@0 20157 friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept
ferencd@0 20158 {
ferencd@0 20159 return basic_json(lhs) != rhs;
ferencd@0 20160 }
ferencd@0 20161
ferencd@0 20162 /*!
ferencd@0 20163 @brief comparison: less than
ferencd@0 20164
ferencd@0 20165 Compares whether one JSON value @a lhs is less than another JSON value @a
ferencd@0 20166 rhs according to the following rules:
ferencd@0 20167 - If @a lhs and @a rhs have the same type, the values are compared using
ferencd@0 20168 the default `<` operator.
ferencd@0 20169 - Integer and floating-point numbers are automatically converted before
ferencd@0 20170 comparison
ferencd@0 20171 - In case @a lhs and @a rhs have different types, the values are ignored
ferencd@0 20172 and the order of the types is considered, see
ferencd@0 20173 @ref operator<(const value_t, const value_t).
ferencd@0 20174
ferencd@0 20175 @param[in] lhs first JSON value to consider
ferencd@0 20176 @param[in] rhs second JSON value to consider
ferencd@0 20177 @return whether @a lhs is less than @a rhs
ferencd@0 20178
ferencd@0 20179 @complexity Linear.
ferencd@0 20180
ferencd@0 20181 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 20182
ferencd@0 20183 @liveexample{The example demonstrates comparing several JSON
ferencd@0 20184 types.,operator__less}
ferencd@0 20185
ferencd@0 20186 @since version 1.0.0
ferencd@0 20187 */
ferencd@0 20188 friend bool operator<(const_reference lhs, const_reference rhs) noexcept
ferencd@0 20189 {
ferencd@0 20190 const auto lhs_type = lhs.type();
ferencd@0 20191 const auto rhs_type = rhs.type();
ferencd@0 20192
ferencd@0 20193 if (lhs_type == rhs_type)
ferencd@0 20194 {
ferencd@0 20195 switch (lhs_type)
ferencd@0 20196 {
ferencd@0 20197 case value_t::array:
ferencd@0 20198 // note parentheses are necessary, see
ferencd@0 20199 // https://github.com/nlohmann/json/issues/1530
ferencd@0 20200 return (*lhs.m_value.array) < (*rhs.m_value.array);
ferencd@0 20201
ferencd@0 20202 case value_t::object:
ferencd@0 20203 return (*lhs.m_value.object) < (*rhs.m_value.object);
ferencd@0 20204
ferencd@0 20205 case value_t::null:
ferencd@0 20206 return false;
ferencd@0 20207
ferencd@0 20208 case value_t::string:
ferencd@0 20209 return (*lhs.m_value.string) < (*rhs.m_value.string);
ferencd@0 20210
ferencd@0 20211 case value_t::boolean:
ferencd@0 20212 return (lhs.m_value.boolean) < (rhs.m_value.boolean);
ferencd@0 20213
ferencd@0 20214 case value_t::number_integer:
ferencd@0 20215 return (lhs.m_value.number_integer) < (rhs.m_value.number_integer);
ferencd@0 20216
ferencd@0 20217 case value_t::number_unsigned:
ferencd@0 20218 return (lhs.m_value.number_unsigned) < (rhs.m_value.number_unsigned);
ferencd@0 20219
ferencd@0 20220 case value_t::number_float:
ferencd@0 20221 return (lhs.m_value.number_float) < (rhs.m_value.number_float);
ferencd@0 20222
ferencd@0 20223 default:
ferencd@0 20224 return false;
ferencd@0 20225 }
ferencd@0 20226 }
ferencd@0 20227 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
ferencd@0 20228 {
ferencd@0 20229 return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;
ferencd@0 20230 }
ferencd@0 20231 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
ferencd@0 20232 {
ferencd@0 20233 return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);
ferencd@0 20234 }
ferencd@0 20235 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
ferencd@0 20236 {
ferencd@0 20237 return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
ferencd@0 20238 }
ferencd@0 20239 else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
ferencd@0 20240 {
ferencd@0 20241 return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);
ferencd@0 20242 }
ferencd@0 20243 else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
ferencd@0 20244 {
ferencd@0 20245 return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);
ferencd@0 20246 }
ferencd@0 20247 else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
ferencd@0 20248 {
ferencd@0 20249 return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
ferencd@0 20250 }
ferencd@0 20251
ferencd@0 20252 // We only reach this line if we cannot compare values. In that case,
ferencd@0 20253 // we compare types. Note we have to call the operator explicitly,
ferencd@0 20254 // because MSVC has problems otherwise.
ferencd@0 20255 return operator<(lhs_type, rhs_type);
ferencd@0 20256 }
ferencd@0 20257
ferencd@0 20258 /*!
ferencd@0 20259 @brief comparison: less than
ferencd@0 20260 @copydoc operator<(const_reference, const_reference)
ferencd@0 20261 */
ferencd@0 20262 template<typename ScalarType, typename std::enable_if<
ferencd@0 20263 std::is_scalar<ScalarType>::value, int>::type = 0>
ferencd@0 20264 friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept
ferencd@0 20265 {
ferencd@0 20266 return lhs < basic_json(rhs);
ferencd@0 20267 }
ferencd@0 20268
ferencd@0 20269 /*!
ferencd@0 20270 @brief comparison: less than
ferencd@0 20271 @copydoc operator<(const_reference, const_reference)
ferencd@0 20272 */
ferencd@0 20273 template<typename ScalarType, typename std::enable_if<
ferencd@0 20274 std::is_scalar<ScalarType>::value, int>::type = 0>
ferencd@0 20275 friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept
ferencd@0 20276 {
ferencd@0 20277 return basic_json(lhs) < rhs;
ferencd@0 20278 }
ferencd@0 20279
ferencd@0 20280 /*!
ferencd@0 20281 @brief comparison: less than or equal
ferencd@0 20282
ferencd@0 20283 Compares whether one JSON value @a lhs is less than or equal to another
ferencd@0 20284 JSON value by calculating `not (rhs < lhs)`.
ferencd@0 20285
ferencd@0 20286 @param[in] lhs first JSON value to consider
ferencd@0 20287 @param[in] rhs second JSON value to consider
ferencd@0 20288 @return whether @a lhs is less than or equal to @a rhs
ferencd@0 20289
ferencd@0 20290 @complexity Linear.
ferencd@0 20291
ferencd@0 20292 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 20293
ferencd@0 20294 @liveexample{The example demonstrates comparing several JSON
ferencd@0 20295 types.,operator__greater}
ferencd@0 20296
ferencd@0 20297 @since version 1.0.0
ferencd@0 20298 */
ferencd@0 20299 friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
ferencd@0 20300 {
ferencd@0 20301 return not (rhs < lhs);
ferencd@0 20302 }
ferencd@0 20303
ferencd@0 20304 /*!
ferencd@0 20305 @brief comparison: less than or equal
ferencd@0 20306 @copydoc operator<=(const_reference, const_reference)
ferencd@0 20307 */
ferencd@0 20308 template<typename ScalarType, typename std::enable_if<
ferencd@0 20309 std::is_scalar<ScalarType>::value, int>::type = 0>
ferencd@0 20310 friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept
ferencd@0 20311 {
ferencd@0 20312 return lhs <= basic_json(rhs);
ferencd@0 20313 }
ferencd@0 20314
ferencd@0 20315 /*!
ferencd@0 20316 @brief comparison: less than or equal
ferencd@0 20317 @copydoc operator<=(const_reference, const_reference)
ferencd@0 20318 */
ferencd@0 20319 template<typename ScalarType, typename std::enable_if<
ferencd@0 20320 std::is_scalar<ScalarType>::value, int>::type = 0>
ferencd@0 20321 friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept
ferencd@0 20322 {
ferencd@0 20323 return basic_json(lhs) <= rhs;
ferencd@0 20324 }
ferencd@0 20325
ferencd@0 20326 /*!
ferencd@0 20327 @brief comparison: greater than
ferencd@0 20328
ferencd@0 20329 Compares whether one JSON value @a lhs is greater than another
ferencd@0 20330 JSON value by calculating `not (lhs <= rhs)`.
ferencd@0 20331
ferencd@0 20332 @param[in] lhs first JSON value to consider
ferencd@0 20333 @param[in] rhs second JSON value to consider
ferencd@0 20334 @return whether @a lhs is greater than to @a rhs
ferencd@0 20335
ferencd@0 20336 @complexity Linear.
ferencd@0 20337
ferencd@0 20338 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 20339
ferencd@0 20340 @liveexample{The example demonstrates comparing several JSON
ferencd@0 20341 types.,operator__lessequal}
ferencd@0 20342
ferencd@0 20343 @since version 1.0.0
ferencd@0 20344 */
ferencd@0 20345 friend bool operator>(const_reference lhs, const_reference rhs) noexcept
ferencd@0 20346 {
ferencd@0 20347 return not (lhs <= rhs);
ferencd@0 20348 }
ferencd@0 20349
ferencd@0 20350 /*!
ferencd@0 20351 @brief comparison: greater than
ferencd@0 20352 @copydoc operator>(const_reference, const_reference)
ferencd@0 20353 */
ferencd@0 20354 template<typename ScalarType, typename std::enable_if<
ferencd@0 20355 std::is_scalar<ScalarType>::value, int>::type = 0>
ferencd@0 20356 friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept
ferencd@0 20357 {
ferencd@0 20358 return lhs > basic_json(rhs);
ferencd@0 20359 }
ferencd@0 20360
ferencd@0 20361 /*!
ferencd@0 20362 @brief comparison: greater than
ferencd@0 20363 @copydoc operator>(const_reference, const_reference)
ferencd@0 20364 */
ferencd@0 20365 template<typename ScalarType, typename std::enable_if<
ferencd@0 20366 std::is_scalar<ScalarType>::value, int>::type = 0>
ferencd@0 20367 friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept
ferencd@0 20368 {
ferencd@0 20369 return basic_json(lhs) > rhs;
ferencd@0 20370 }
ferencd@0 20371
ferencd@0 20372 /*!
ferencd@0 20373 @brief comparison: greater than or equal
ferencd@0 20374
ferencd@0 20375 Compares whether one JSON value @a lhs is greater than or equal to another
ferencd@0 20376 JSON value by calculating `not (lhs < rhs)`.
ferencd@0 20377
ferencd@0 20378 @param[in] lhs first JSON value to consider
ferencd@0 20379 @param[in] rhs second JSON value to consider
ferencd@0 20380 @return whether @a lhs is greater than or equal to @a rhs
ferencd@0 20381
ferencd@0 20382 @complexity Linear.
ferencd@0 20383
ferencd@0 20384 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 20385
ferencd@0 20386 @liveexample{The example demonstrates comparing several JSON
ferencd@0 20387 types.,operator__greaterequal}
ferencd@0 20388
ferencd@0 20389 @since version 1.0.0
ferencd@0 20390 */
ferencd@0 20391 friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
ferencd@0 20392 {
ferencd@0 20393 return not (lhs < rhs);
ferencd@0 20394 }
ferencd@0 20395
ferencd@0 20396 /*!
ferencd@0 20397 @brief comparison: greater than or equal
ferencd@0 20398 @copydoc operator>=(const_reference, const_reference)
ferencd@0 20399 */
ferencd@0 20400 template<typename ScalarType, typename std::enable_if<
ferencd@0 20401 std::is_scalar<ScalarType>::value, int>::type = 0>
ferencd@0 20402 friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept
ferencd@0 20403 {
ferencd@0 20404 return lhs >= basic_json(rhs);
ferencd@0 20405 }
ferencd@0 20406
ferencd@0 20407 /*!
ferencd@0 20408 @brief comparison: greater than or equal
ferencd@0 20409 @copydoc operator>=(const_reference, const_reference)
ferencd@0 20410 */
ferencd@0 20411 template<typename ScalarType, typename std::enable_if<
ferencd@0 20412 std::is_scalar<ScalarType>::value, int>::type = 0>
ferencd@0 20413 friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept
ferencd@0 20414 {
ferencd@0 20415 return basic_json(lhs) >= rhs;
ferencd@0 20416 }
ferencd@0 20417
ferencd@0 20418 /// @}
ferencd@0 20419
ferencd@0 20420 ///////////////////
ferencd@0 20421 // serialization //
ferencd@0 20422 ///////////////////
ferencd@0 20423
ferencd@0 20424 /// @name serialization
ferencd@0 20425 /// @{
ferencd@0 20426
ferencd@0 20427 /*!
ferencd@0 20428 @brief serialize to stream
ferencd@0 20429
ferencd@0 20430 Serialize the given JSON value @a j to the output stream @a o. The JSON
ferencd@0 20431 value will be serialized using the @ref dump member function.
ferencd@0 20432
ferencd@0 20433 - The indentation of the output can be controlled with the member variable
ferencd@0 20434 `width` of the output stream @a o. For instance, using the manipulator
ferencd@0 20435 `std::setw(4)` on @a o sets the indentation level to `4` and the
ferencd@0 20436 serialization result is the same as calling `dump(4)`.
ferencd@0 20437
ferencd@0 20438 - The indentation character can be controlled with the member variable
ferencd@0 20439 `fill` of the output stream @a o. For instance, the manipulator
ferencd@0 20440 `std::setfill('\\t')` sets indentation to use a tab character rather than
ferencd@0 20441 the default space character.
ferencd@0 20442
ferencd@0 20443 @param[in,out] o stream to serialize to
ferencd@0 20444 @param[in] j JSON value to serialize
ferencd@0 20445
ferencd@0 20446 @return the stream @a o
ferencd@0 20447
ferencd@0 20448 @throw type_error.316 if a string stored inside the JSON value is not
ferencd@0 20449 UTF-8 encoded
ferencd@0 20450
ferencd@0 20451 @complexity Linear.
ferencd@0 20452
ferencd@0 20453 @liveexample{The example below shows the serialization with different
ferencd@0 20454 parameters to `width` to adjust the indentation level.,operator_serialize}
ferencd@0 20455
ferencd@0 20456 @since version 1.0.0; indentation character added in version 3.0.0
ferencd@0 20457 */
ferencd@0 20458 friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
ferencd@0 20459 {
ferencd@0 20460 // read width member and use it as indentation parameter if nonzero
ferencd@0 20461 const bool pretty_print = o.width() > 0;
ferencd@0 20462 const auto indentation = pretty_print ? o.width() : 0;
ferencd@0 20463
ferencd@0 20464 // reset width to 0 for subsequent calls to this stream
ferencd@0 20465 o.width(0);
ferencd@0 20466
ferencd@0 20467 // do the actual serialization
ferencd@0 20468 serializer s(detail::output_adapter<char>(o), o.fill());
ferencd@0 20469 s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
ferencd@0 20470 return o;
ferencd@0 20471 }
ferencd@0 20472
ferencd@0 20473 /*!
ferencd@0 20474 @brief serialize to stream
ferencd@0 20475 @deprecated This stream operator is deprecated and will be removed in
ferencd@0 20476 future 4.0.0 of the library. Please use
ferencd@0 20477 @ref operator<<(std::ostream&, const basic_json&)
ferencd@0 20478 instead; that is, replace calls like `j >> o;` with `o << j;`.
ferencd@0 20479 @since version 1.0.0; deprecated since version 3.0.0
ferencd@0 20480 */
ferencd@0 20481 JSON_HEDLEY_DEPRECATED(3.0.0)
ferencd@0 20482 friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
ferencd@0 20483 {
ferencd@0 20484 return o << j;
ferencd@0 20485 }
ferencd@0 20486
ferencd@0 20487 /// @}
ferencd@0 20488
ferencd@0 20489
ferencd@0 20490 /////////////////////
ferencd@0 20491 // deserialization //
ferencd@0 20492 /////////////////////
ferencd@0 20493
ferencd@0 20494 /// @name deserialization
ferencd@0 20495 /// @{
ferencd@0 20496
ferencd@0 20497 /*!
ferencd@0 20498 @brief deserialize from a compatible input
ferencd@0 20499
ferencd@0 20500 This function reads from a compatible input. Examples are:
ferencd@0 20501 - an array of 1-byte values
ferencd@0 20502 - strings with character/literal type with size of 1 byte
ferencd@0 20503 - input streams
ferencd@0 20504 - container with contiguous storage of 1-byte values. Compatible container
ferencd@0 20505 types include `std::vector`, `std::string`, `std::array`,
ferencd@0 20506 `std::valarray`, and `std::initializer_list`. Furthermore, C-style
ferencd@0 20507 arrays can be used with `std::begin()`/`std::end()`. User-defined
ferencd@0 20508 containers can be used as long as they implement random-access iterators
ferencd@0 20509 and a contiguous storage.
ferencd@0 20510
ferencd@0 20511 @pre Each element of the container has a size of 1 byte. Violating this
ferencd@0 20512 precondition yields undefined behavior. **This precondition is enforced
ferencd@0 20513 with a static assertion.**
ferencd@0 20514
ferencd@0 20515 @pre The container storage is contiguous. Violating this precondition
ferencd@0 20516 yields undefined behavior. **This precondition is enforced with an
ferencd@0 20517 assertion.**
ferencd@0 20518
ferencd@0 20519 @warning There is no way to enforce all preconditions at compile-time. If
ferencd@0 20520 the function is called with a noncompliant container and with
ferencd@0 20521 assertions switched off, the behavior is undefined and will most
ferencd@0 20522 likely yield segmentation violation.
ferencd@0 20523
ferencd@0 20524 @param[in] i input to read from
ferencd@0 20525 @param[in] cb a parser callback function of type @ref parser_callback_t
ferencd@0 20526 which is used to control the deserialization by filtering unwanted values
ferencd@0 20527 (optional)
ferencd@0 20528 @param[in] allow_exceptions whether to throw exceptions in case of a
ferencd@0 20529 parse error (optional, true by default)
ferencd@0 20530
ferencd@0 20531 @return deserialized JSON value; in case of a parse error and
ferencd@0 20532 @a allow_exceptions set to `false`, the return value will be
ferencd@0 20533 value_t::discarded.
ferencd@0 20534
ferencd@0 20535 @throw parse_error.101 if a parse error occurs; example: `""unexpected end
ferencd@0 20536 of input; expected string literal""`
ferencd@0 20537 @throw parse_error.102 if to_unicode fails or surrogate error
ferencd@0 20538 @throw parse_error.103 if to_unicode fails
ferencd@0 20539
ferencd@0 20540 @complexity Linear in the length of the input. The parser is a predictive
ferencd@0 20541 LL(1) parser. The complexity can be higher if the parser callback function
ferencd@0 20542 @a cb has a super-linear complexity.
ferencd@0 20543
ferencd@0 20544 @note A UTF-8 byte order mark is silently ignored.
ferencd@0 20545
ferencd@0 20546 @liveexample{The example below demonstrates the `parse()` function reading
ferencd@0 20547 from an array.,parse__array__parser_callback_t}
ferencd@0 20548
ferencd@0 20549 @liveexample{The example below demonstrates the `parse()` function with
ferencd@0 20550 and without callback function.,parse__string__parser_callback_t}
ferencd@0 20551
ferencd@0 20552 @liveexample{The example below demonstrates the `parse()` function with
ferencd@0 20553 and without callback function.,parse__istream__parser_callback_t}
ferencd@0 20554
ferencd@0 20555 @liveexample{The example below demonstrates the `parse()` function reading
ferencd@0 20556 from a contiguous container.,parse__contiguouscontainer__parser_callback_t}
ferencd@0 20557
ferencd@0 20558 @since version 2.0.3 (contiguous containers)
ferencd@0 20559 */
ferencd@0 20560 JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 20561 static basic_json parse(detail::input_adapter&& i,
ferencd@0 20562 const parser_callback_t cb = nullptr,
ferencd@0 20563 const bool allow_exceptions = true)
ferencd@0 20564 {
ferencd@0 20565 basic_json result;
ferencd@0 20566 parser(i, cb, allow_exceptions).parse(true, result);
ferencd@0 20567 return result;
ferencd@0 20568 }
ferencd@0 20569
ferencd@0 20570 static bool accept(detail::input_adapter&& i)
ferencd@0 20571 {
ferencd@0 20572 return parser(i).accept(true);
ferencd@0 20573 }
ferencd@0 20574
ferencd@0 20575 /*!
ferencd@0 20576 @brief generate SAX events
ferencd@0 20577
ferencd@0 20578 The SAX event lister must follow the interface of @ref json_sax.
ferencd@0 20579
ferencd@0 20580 This function reads from a compatible input. Examples are:
ferencd@0 20581 - an array of 1-byte values
ferencd@0 20582 - strings with character/literal type with size of 1 byte
ferencd@0 20583 - input streams
ferencd@0 20584 - container with contiguous storage of 1-byte values. Compatible container
ferencd@0 20585 types include `std::vector`, `std::string`, `std::array`,
ferencd@0 20586 `std::valarray`, and `std::initializer_list`. Furthermore, C-style
ferencd@0 20587 arrays can be used with `std::begin()`/`std::end()`. User-defined
ferencd@0 20588 containers can be used as long as they implement random-access iterators
ferencd@0 20589 and a contiguous storage.
ferencd@0 20590
ferencd@0 20591 @pre Each element of the container has a size of 1 byte. Violating this
ferencd@0 20592 precondition yields undefined behavior. **This precondition is enforced
ferencd@0 20593 with a static assertion.**
ferencd@0 20594
ferencd@0 20595 @pre The container storage is contiguous. Violating this precondition
ferencd@0 20596 yields undefined behavior. **This precondition is enforced with an
ferencd@0 20597 assertion.**
ferencd@0 20598
ferencd@0 20599 @warning There is no way to enforce all preconditions at compile-time. If
ferencd@0 20600 the function is called with a noncompliant container and with
ferencd@0 20601 assertions switched off, the behavior is undefined and will most
ferencd@0 20602 likely yield segmentation violation.
ferencd@0 20603
ferencd@0 20604 @param[in] i input to read from
ferencd@0 20605 @param[in,out] sax SAX event listener
ferencd@0 20606 @param[in] format the format to parse (JSON, CBOR, MessagePack, or UBJSON)
ferencd@0 20607 @param[in] strict whether the input has to be consumed completely
ferencd@0 20608
ferencd@0 20609 @return return value of the last processed SAX event
ferencd@0 20610
ferencd@0 20611 @throw parse_error.101 if a parse error occurs; example: `""unexpected end
ferencd@0 20612 of input; expected string literal""`
ferencd@0 20613 @throw parse_error.102 if to_unicode fails or surrogate error
ferencd@0 20614 @throw parse_error.103 if to_unicode fails
ferencd@0 20615
ferencd@0 20616 @complexity Linear in the length of the input. The parser is a predictive
ferencd@0 20617 LL(1) parser. The complexity can be higher if the SAX consumer @a sax has
ferencd@0 20618 a super-linear complexity.
ferencd@0 20619
ferencd@0 20620 @note A UTF-8 byte order mark is silently ignored.
ferencd@0 20621
ferencd@0 20622 @liveexample{The example below demonstrates the `sax_parse()` function
ferencd@0 20623 reading from string and processing the events with a user-defined SAX
ferencd@0 20624 event consumer.,sax_parse}
ferencd@0 20625
ferencd@0 20626 @since version 3.2.0
ferencd@0 20627 */
ferencd@0 20628 template <typename SAX>
ferencd@0 20629 JSON_HEDLEY_NON_NULL(2)
ferencd@0 20630 static bool sax_parse(detail::input_adapter&& i, SAX* sax,
ferencd@0 20631 input_format_t format = input_format_t::json,
ferencd@0 20632 const bool strict = true)
ferencd@0 20633 {
ferencd@0 20634 assert(sax);
ferencd@0 20635 return format == input_format_t::json
ferencd@0 20636 ? parser(std::move(i)).sax_parse(sax, strict)
ferencd@0 20637 : detail::binary_reader<basic_json, SAX>(std::move(i)).sax_parse(format, sax, strict);
ferencd@0 20638 }
ferencd@0 20639
ferencd@0 20640 /*!
ferencd@0 20641 @brief deserialize from an iterator range with contiguous storage
ferencd@0 20642
ferencd@0 20643 This function reads from an iterator range of a container with contiguous
ferencd@0 20644 storage of 1-byte values. Compatible container types include
ferencd@0 20645 `std::vector`, `std::string`, `std::array`, `std::valarray`, and
ferencd@0 20646 `std::initializer_list`. Furthermore, C-style arrays can be used with
ferencd@0 20647 `std::begin()`/`std::end()`. User-defined containers can be used as long
ferencd@0 20648 as they implement random-access iterators and a contiguous storage.
ferencd@0 20649
ferencd@0 20650 @pre The iterator range is contiguous. Violating this precondition yields
ferencd@0 20651 undefined behavior. **This precondition is enforced with an assertion.**
ferencd@0 20652 @pre Each element in the range has a size of 1 byte. Violating this
ferencd@0 20653 precondition yields undefined behavior. **This precondition is enforced
ferencd@0 20654 with a static assertion.**
ferencd@0 20655
ferencd@0 20656 @warning There is no way to enforce all preconditions at compile-time. If
ferencd@0 20657 the function is called with noncompliant iterators and with
ferencd@0 20658 assertions switched off, the behavior is undefined and will most
ferencd@0 20659 likely yield segmentation violation.
ferencd@0 20660
ferencd@0 20661 @tparam IteratorType iterator of container with contiguous storage
ferencd@0 20662 @param[in] first begin of the range to parse (included)
ferencd@0 20663 @param[in] last end of the range to parse (excluded)
ferencd@0 20664 @param[in] cb a parser callback function of type @ref parser_callback_t
ferencd@0 20665 which is used to control the deserialization by filtering unwanted values
ferencd@0 20666 (optional)
ferencd@0 20667 @param[in] allow_exceptions whether to throw exceptions in case of a
ferencd@0 20668 parse error (optional, true by default)
ferencd@0 20669
ferencd@0 20670 @return deserialized JSON value; in case of a parse error and
ferencd@0 20671 @a allow_exceptions set to `false`, the return value will be
ferencd@0 20672 value_t::discarded.
ferencd@0 20673
ferencd@0 20674 @throw parse_error.101 in case of an unexpected token
ferencd@0 20675 @throw parse_error.102 if to_unicode fails or surrogate error
ferencd@0 20676 @throw parse_error.103 if to_unicode fails
ferencd@0 20677
ferencd@0 20678 @complexity Linear in the length of the input. The parser is a predictive
ferencd@0 20679 LL(1) parser. The complexity can be higher if the parser callback function
ferencd@0 20680 @a cb has a super-linear complexity.
ferencd@0 20681
ferencd@0 20682 @note A UTF-8 byte order mark is silently ignored.
ferencd@0 20683
ferencd@0 20684 @liveexample{The example below demonstrates the `parse()` function reading
ferencd@0 20685 from an iterator range.,parse__iteratortype__parser_callback_t}
ferencd@0 20686
ferencd@0 20687 @since version 2.0.3
ferencd@0 20688 */
ferencd@0 20689 template<class IteratorType, typename std::enable_if<
ferencd@0 20690 std::is_base_of<
ferencd@0 20691 std::random_access_iterator_tag,
ferencd@0 20692 typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
ferencd@0 20693 static basic_json parse(IteratorType first, IteratorType last,
ferencd@0 20694 const parser_callback_t cb = nullptr,
ferencd@0 20695 const bool allow_exceptions = true)
ferencd@0 20696 {
ferencd@0 20697 basic_json result;
ferencd@0 20698 parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result);
ferencd@0 20699 return result;
ferencd@0 20700 }
ferencd@0 20701
ferencd@0 20702 template<class IteratorType, typename std::enable_if<
ferencd@0 20703 std::is_base_of<
ferencd@0 20704 std::random_access_iterator_tag,
ferencd@0 20705 typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
ferencd@0 20706 static bool accept(IteratorType first, IteratorType last)
ferencd@0 20707 {
ferencd@0 20708 return parser(detail::input_adapter(first, last)).accept(true);
ferencd@0 20709 }
ferencd@0 20710
ferencd@0 20711 template<class IteratorType, class SAX, typename std::enable_if<
ferencd@0 20712 std::is_base_of<
ferencd@0 20713 std::random_access_iterator_tag,
ferencd@0 20714 typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
ferencd@0 20715 JSON_HEDLEY_NON_NULL(3)
ferencd@0 20716 static bool sax_parse(IteratorType first, IteratorType last, SAX* sax)
ferencd@0 20717 {
ferencd@0 20718 return parser(detail::input_adapter(first, last)).sax_parse(sax);
ferencd@0 20719 }
ferencd@0 20720
ferencd@0 20721 /*!
ferencd@0 20722 @brief deserialize from stream
ferencd@0 20723 @deprecated This stream operator is deprecated and will be removed in
ferencd@0 20724 version 4.0.0 of the library. Please use
ferencd@0 20725 @ref operator>>(std::istream&, basic_json&)
ferencd@0 20726 instead; that is, replace calls like `j << i;` with `i >> j;`.
ferencd@0 20727 @since version 1.0.0; deprecated since version 3.0.0
ferencd@0 20728 */
ferencd@0 20729 JSON_HEDLEY_DEPRECATED(3.0.0)
ferencd@0 20730 friend std::istream& operator<<(basic_json& j, std::istream& i)
ferencd@0 20731 {
ferencd@0 20732 return operator>>(i, j);
ferencd@0 20733 }
ferencd@0 20734
ferencd@0 20735 /*!
ferencd@0 20736 @brief deserialize from stream
ferencd@0 20737
ferencd@0 20738 Deserializes an input stream to a JSON value.
ferencd@0 20739
ferencd@0 20740 @param[in,out] i input stream to read a serialized JSON value from
ferencd@0 20741 @param[in,out] j JSON value to write the deserialized input to
ferencd@0 20742
ferencd@0 20743 @throw parse_error.101 in case of an unexpected token
ferencd@0 20744 @throw parse_error.102 if to_unicode fails or surrogate error
ferencd@0 20745 @throw parse_error.103 if to_unicode fails
ferencd@0 20746
ferencd@0 20747 @complexity Linear in the length of the input. The parser is a predictive
ferencd@0 20748 LL(1) parser.
ferencd@0 20749
ferencd@0 20750 @note A UTF-8 byte order mark is silently ignored.
ferencd@0 20751
ferencd@0 20752 @liveexample{The example below shows how a JSON value is constructed by
ferencd@0 20753 reading a serialization from a stream.,operator_deserialize}
ferencd@0 20754
ferencd@0 20755 @sa parse(std::istream&, const parser_callback_t) for a variant with a
ferencd@0 20756 parser callback function to filter values while parsing
ferencd@0 20757
ferencd@0 20758 @since version 1.0.0
ferencd@0 20759 */
ferencd@0 20760 friend std::istream& operator>>(std::istream& i, basic_json& j)
ferencd@0 20761 {
ferencd@0 20762 parser(detail::input_adapter(i)).parse(false, j);
ferencd@0 20763 return i;
ferencd@0 20764 }
ferencd@0 20765
ferencd@0 20766 /// @}
ferencd@0 20767
ferencd@0 20768 ///////////////////////////
ferencd@0 20769 // convenience functions //
ferencd@0 20770 ///////////////////////////
ferencd@0 20771
ferencd@0 20772 /*!
ferencd@0 20773 @brief return the type as string
ferencd@0 20774
ferencd@0 20775 Returns the type name as string to be used in error messages - usually to
ferencd@0 20776 indicate that a function was called on a wrong JSON type.
ferencd@0 20777
ferencd@0 20778 @return a string representation of a the @a m_type member:
ferencd@0 20779 Value type | return value
ferencd@0 20780 ----------- | -------------
ferencd@0 20781 null | `"null"`
ferencd@0 20782 boolean | `"boolean"`
ferencd@0 20783 string | `"string"`
ferencd@0 20784 number | `"number"` (for all number types)
ferencd@0 20785 object | `"object"`
ferencd@0 20786 array | `"array"`
ferencd@0 20787 discarded | `"discarded"`
ferencd@0 20788
ferencd@0 20789 @exceptionsafety No-throw guarantee: this function never throws exceptions.
ferencd@0 20790
ferencd@0 20791 @complexity Constant.
ferencd@0 20792
ferencd@0 20793 @liveexample{The following code exemplifies `type_name()` for all JSON
ferencd@0 20794 types.,type_name}
ferencd@0 20795
ferencd@0 20796 @sa @ref type() -- return the type of the JSON value
ferencd@0 20797 @sa @ref operator value_t() -- return the type of the JSON value (implicit)
ferencd@0 20798
ferencd@0 20799 @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept`
ferencd@0 20800 since 3.0.0
ferencd@0 20801 */
ferencd@0 20802 JSON_HEDLEY_RETURNS_NON_NULL
ferencd@0 20803 const char* type_name() const noexcept
ferencd@0 20804 {
ferencd@0 20805 {
ferencd@0 20806 switch (m_type)
ferencd@0 20807 {
ferencd@0 20808 case value_t::null:
ferencd@0 20809 return "null";
ferencd@0 20810 case value_t::object:
ferencd@0 20811 return "object";
ferencd@0 20812 case value_t::array:
ferencd@0 20813 return "array";
ferencd@0 20814 case value_t::string:
ferencd@0 20815 return "string";
ferencd@0 20816 case value_t::boolean:
ferencd@0 20817 return "boolean";
ferencd@0 20818 case value_t::discarded:
ferencd@0 20819 return "discarded";
ferencd@0 20820 default:
ferencd@0 20821 return "number";
ferencd@0 20822 }
ferencd@0 20823 }
ferencd@0 20824 }
ferencd@0 20825
ferencd@0 20826
ferencd@0 20827 private:
ferencd@0 20828 //////////////////////
ferencd@0 20829 // member variables //
ferencd@0 20830 //////////////////////
ferencd@0 20831
ferencd@0 20832 /// the type of the current element
ferencd@0 20833 value_t m_type = value_t::null;
ferencd@0 20834
ferencd@0 20835 /// the value of the current element
ferencd@0 20836 json_value m_value = {};
ferencd@0 20837
ferencd@0 20838 //////////////////////////////////////////
ferencd@0 20839 // binary serialization/deserialization //
ferencd@0 20840 //////////////////////////////////////////
ferencd@0 20841
ferencd@0 20842 /// @name binary serialization/deserialization support
ferencd@0 20843 /// @{
ferencd@0 20844
ferencd@0 20845 public:
ferencd@0 20846 /*!
ferencd@0 20847 @brief create a CBOR serialization of a given JSON value
ferencd@0 20848
ferencd@0 20849 Serializes a given JSON value @a j to a byte vector using the CBOR (Concise
ferencd@0 20850 Binary Object Representation) serialization format. CBOR is a binary
ferencd@0 20851 serialization format which aims to be more compact than JSON itself, yet
ferencd@0 20852 more efficient to parse.
ferencd@0 20853
ferencd@0 20854 The library uses the following mapping from JSON values types to
ferencd@0 20855 CBOR types according to the CBOR specification (RFC 7049):
ferencd@0 20856
ferencd@0 20857 JSON value type | value/range | CBOR type | first byte
ferencd@0 20858 --------------- | ------------------------------------------ | ---------------------------------- | ---------------
ferencd@0 20859 null | `null` | Null | 0xF6
ferencd@0 20860 boolean | `true` | True | 0xF5
ferencd@0 20861 boolean | `false` | False | 0xF4
ferencd@0 20862 number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B
ferencd@0 20863 number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A
ferencd@0 20864 number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39
ferencd@0 20865 number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38
ferencd@0 20866 number_integer | -24..-1 | Negative integer | 0x20..0x37
ferencd@0 20867 number_integer | 0..23 | Integer | 0x00..0x17
ferencd@0 20868 number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18
ferencd@0 20869 number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19
ferencd@0 20870 number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A
ferencd@0 20871 number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B
ferencd@0 20872 number_unsigned | 0..23 | Integer | 0x00..0x17
ferencd@0 20873 number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18
ferencd@0 20874 number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19
ferencd@0 20875 number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A
ferencd@0 20876 number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B
ferencd@0 20877 number_float | *any value* | Double-Precision Float | 0xFB
ferencd@0 20878 string | *length*: 0..23 | UTF-8 string | 0x60..0x77
ferencd@0 20879 string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78
ferencd@0 20880 string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79
ferencd@0 20881 string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A
ferencd@0 20882 string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B
ferencd@0 20883 array | *size*: 0..23 | array | 0x80..0x97
ferencd@0 20884 array | *size*: 23..255 | array (1 byte follow) | 0x98
ferencd@0 20885 array | *size*: 256..65535 | array (2 bytes follow) | 0x99
ferencd@0 20886 array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A
ferencd@0 20887 array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B
ferencd@0 20888 object | *size*: 0..23 | map | 0xA0..0xB7
ferencd@0 20889 object | *size*: 23..255 | map (1 byte follow) | 0xB8
ferencd@0 20890 object | *size*: 256..65535 | map (2 bytes follow) | 0xB9
ferencd@0 20891 object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA
ferencd@0 20892 object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB
ferencd@0 20893
ferencd@0 20894 @note The mapping is **complete** in the sense that any JSON value type
ferencd@0 20895 can be converted to a CBOR value.
ferencd@0 20896
ferencd@0 20897 @note If NaN or Infinity are stored inside a JSON number, they are
ferencd@0 20898 serialized properly. This behavior differs from the @ref dump()
ferencd@0 20899 function which serializes NaN or Infinity to `null`.
ferencd@0 20900
ferencd@0 20901 @note The following CBOR types are not used in the conversion:
ferencd@0 20902 - byte strings (0x40..0x5F)
ferencd@0 20903 - UTF-8 strings terminated by "break" (0x7F)
ferencd@0 20904 - arrays terminated by "break" (0x9F)
ferencd@0 20905 - maps terminated by "break" (0xBF)
ferencd@0 20906 - date/time (0xC0..0xC1)
ferencd@0 20907 - bignum (0xC2..0xC3)
ferencd@0 20908 - decimal fraction (0xC4)
ferencd@0 20909 - bigfloat (0xC5)
ferencd@0 20910 - tagged items (0xC6..0xD4, 0xD8..0xDB)
ferencd@0 20911 - expected conversions (0xD5..0xD7)
ferencd@0 20912 - simple values (0xE0..0xF3, 0xF8)
ferencd@0 20913 - undefined (0xF7)
ferencd@0 20914 - half and single-precision floats (0xF9-0xFA)
ferencd@0 20915 - break (0xFF)
ferencd@0 20916
ferencd@0 20917 @param[in] j JSON value to serialize
ferencd@0 20918 @return MessagePack serialization as byte vector
ferencd@0 20919
ferencd@0 20920 @complexity Linear in the size of the JSON value @a j.
ferencd@0 20921
ferencd@0 20922 @liveexample{The example shows the serialization of a JSON value to a byte
ferencd@0 20923 vector in CBOR format.,to_cbor}
ferencd@0 20924
ferencd@0 20925 @sa http://cbor.io
ferencd@0 20926 @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the
ferencd@0 20927 analogous deserialization
ferencd@0 20928 @sa @ref to_msgpack(const basic_json&) for the related MessagePack format
ferencd@0 20929 @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the
ferencd@0 20930 related UBJSON format
ferencd@0 20931
ferencd@0 20932 @since version 2.0.9
ferencd@0 20933 */
ferencd@0 20934 static std::vector<uint8_t> to_cbor(const basic_json& j)
ferencd@0 20935 {
ferencd@0 20936 std::vector<uint8_t> result;
ferencd@0 20937 to_cbor(j, result);
ferencd@0 20938 return result;
ferencd@0 20939 }
ferencd@0 20940
ferencd@0 20941 static void to_cbor(const basic_json& j, detail::output_adapter<uint8_t> o)
ferencd@0 20942 {
ferencd@0 20943 binary_writer<uint8_t>(o).write_cbor(j);
ferencd@0 20944 }
ferencd@0 20945
ferencd@0 20946 static void to_cbor(const basic_json& j, detail::output_adapter<char> o)
ferencd@0 20947 {
ferencd@0 20948 binary_writer<char>(o).write_cbor(j);
ferencd@0 20949 }
ferencd@0 20950
ferencd@0 20951 /*!
ferencd@0 20952 @brief create a MessagePack serialization of a given JSON value
ferencd@0 20953
ferencd@0 20954 Serializes a given JSON value @a j to a byte vector using the MessagePack
ferencd@0 20955 serialization format. MessagePack is a binary serialization format which
ferencd@0 20956 aims to be more compact than JSON itself, yet more efficient to parse.
ferencd@0 20957
ferencd@0 20958 The library uses the following mapping from JSON values types to
ferencd@0 20959 MessagePack types according to the MessagePack specification:
ferencd@0 20960
ferencd@0 20961 JSON value type | value/range | MessagePack type | first byte
ferencd@0 20962 --------------- | --------------------------------- | ---------------- | ----------
ferencd@0 20963 null | `null` | nil | 0xC0
ferencd@0 20964 boolean | `true` | true | 0xC3
ferencd@0 20965 boolean | `false` | false | 0xC2
ferencd@0 20966 number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3
ferencd@0 20967 number_integer | -2147483648..-32769 | int32 | 0xD2
ferencd@0 20968 number_integer | -32768..-129 | int16 | 0xD1
ferencd@0 20969 number_integer | -128..-33 | int8 | 0xD0
ferencd@0 20970 number_integer | -32..-1 | negative fixint | 0xE0..0xFF
ferencd@0 20971 number_integer | 0..127 | positive fixint | 0x00..0x7F
ferencd@0 20972 number_integer | 128..255 | uint 8 | 0xCC
ferencd@0 20973 number_integer | 256..65535 | uint 16 | 0xCD
ferencd@0 20974 number_integer | 65536..4294967295 | uint 32 | 0xCE
ferencd@0 20975 number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF
ferencd@0 20976 number_unsigned | 0..127 | positive fixint | 0x00..0x7F
ferencd@0 20977 number_unsigned | 128..255 | uint 8 | 0xCC
ferencd@0 20978 number_unsigned | 256..65535 | uint 16 | 0xCD
ferencd@0 20979 number_unsigned | 65536..4294967295 | uint 32 | 0xCE
ferencd@0 20980 number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF
ferencd@0 20981 number_float | *any value* | float 64 | 0xCB
ferencd@0 20982 string | *length*: 0..31 | fixstr | 0xA0..0xBF
ferencd@0 20983 string | *length*: 32..255 | str 8 | 0xD9
ferencd@0 20984 string | *length*: 256..65535 | str 16 | 0xDA
ferencd@0 20985 string | *length*: 65536..4294967295 | str 32 | 0xDB
ferencd@0 20986 array | *size*: 0..15 | fixarray | 0x90..0x9F
ferencd@0 20987 array | *size*: 16..65535 | array 16 | 0xDC
ferencd@0 20988 array | *size*: 65536..4294967295 | array 32 | 0xDD
ferencd@0 20989 object | *size*: 0..15 | fix map | 0x80..0x8F
ferencd@0 20990 object | *size*: 16..65535 | map 16 | 0xDE
ferencd@0 20991 object | *size*: 65536..4294967295 | map 32 | 0xDF
ferencd@0 20992
ferencd@0 20993 @note The mapping is **complete** in the sense that any JSON value type
ferencd@0 20994 can be converted to a MessagePack value.
ferencd@0 20995
ferencd@0 20996 @note The following values can **not** be converted to a MessagePack value:
ferencd@0 20997 - strings with more than 4294967295 bytes
ferencd@0 20998 - arrays with more than 4294967295 elements
ferencd@0 20999 - objects with more than 4294967295 elements
ferencd@0 21000
ferencd@0 21001 @note The following MessagePack types are not used in the conversion:
ferencd@0 21002 - bin 8 - bin 32 (0xC4..0xC6)
ferencd@0 21003 - ext 8 - ext 32 (0xC7..0xC9)
ferencd@0 21004 - float 32 (0xCA)
ferencd@0 21005 - fixext 1 - fixext 16 (0xD4..0xD8)
ferencd@0 21006
ferencd@0 21007 @note Any MessagePack output created @ref to_msgpack can be successfully
ferencd@0 21008 parsed by @ref from_msgpack.
ferencd@0 21009
ferencd@0 21010 @note If NaN or Infinity are stored inside a JSON number, they are
ferencd@0 21011 serialized properly. This behavior differs from the @ref dump()
ferencd@0 21012 function which serializes NaN or Infinity to `null`.
ferencd@0 21013
ferencd@0 21014 @param[in] j JSON value to serialize
ferencd@0 21015 @return MessagePack serialization as byte vector
ferencd@0 21016
ferencd@0 21017 @complexity Linear in the size of the JSON value @a j.
ferencd@0 21018
ferencd@0 21019 @liveexample{The example shows the serialization of a JSON value to a byte
ferencd@0 21020 vector in MessagePack format.,to_msgpack}
ferencd@0 21021
ferencd@0 21022 @sa http://msgpack.org
ferencd@0 21023 @sa @ref from_msgpack for the analogous deserialization
ferencd@0 21024 @sa @ref to_cbor(const basic_json& for the related CBOR format
ferencd@0 21025 @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the
ferencd@0 21026 related UBJSON format
ferencd@0 21027
ferencd@0 21028 @since version 2.0.9
ferencd@0 21029 */
ferencd@0 21030 static std::vector<uint8_t> to_msgpack(const basic_json& j)
ferencd@0 21031 {
ferencd@0 21032 std::vector<uint8_t> result;
ferencd@0 21033 to_msgpack(j, result);
ferencd@0 21034 return result;
ferencd@0 21035 }
ferencd@0 21036
ferencd@0 21037 static void to_msgpack(const basic_json& j, detail::output_adapter<uint8_t> o)
ferencd@0 21038 {
ferencd@0 21039 binary_writer<uint8_t>(o).write_msgpack(j);
ferencd@0 21040 }
ferencd@0 21041
ferencd@0 21042 static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)
ferencd@0 21043 {
ferencd@0 21044 binary_writer<char>(o).write_msgpack(j);
ferencd@0 21045 }
ferencd@0 21046
ferencd@0 21047 /*!
ferencd@0 21048 @brief create a UBJSON serialization of a given JSON value
ferencd@0 21049
ferencd@0 21050 Serializes a given JSON value @a j to a byte vector using the UBJSON
ferencd@0 21051 (Universal Binary JSON) serialization format. UBJSON aims to be more compact
ferencd@0 21052 than JSON itself, yet more efficient to parse.
ferencd@0 21053
ferencd@0 21054 The library uses the following mapping from JSON values types to
ferencd@0 21055 UBJSON types according to the UBJSON specification:
ferencd@0 21056
ferencd@0 21057 JSON value type | value/range | UBJSON type | marker
ferencd@0 21058 --------------- | --------------------------------- | ----------- | ------
ferencd@0 21059 null | `null` | null | `Z`
ferencd@0 21060 boolean | `true` | true | `T`
ferencd@0 21061 boolean | `false` | false | `F`
ferencd@0 21062 number_integer | -9223372036854775808..-2147483649 | int64 | `L`
ferencd@0 21063 number_integer | -2147483648..-32769 | int32 | `l`
ferencd@0 21064 number_integer | -32768..-129 | int16 | `I`
ferencd@0 21065 number_integer | -128..127 | int8 | `i`
ferencd@0 21066 number_integer | 128..255 | uint8 | `U`
ferencd@0 21067 number_integer | 256..32767 | int16 | `I`
ferencd@0 21068 number_integer | 32768..2147483647 | int32 | `l`
ferencd@0 21069 number_integer | 2147483648..9223372036854775807 | int64 | `L`
ferencd@0 21070 number_unsigned | 0..127 | int8 | `i`
ferencd@0 21071 number_unsigned | 128..255 | uint8 | `U`
ferencd@0 21072 number_unsigned | 256..32767 | int16 | `I`
ferencd@0 21073 number_unsigned | 32768..2147483647 | int32 | `l`
ferencd@0 21074 number_unsigned | 2147483648..9223372036854775807 | int64 | `L`
ferencd@0 21075 number_float | *any value* | float64 | `D`
ferencd@0 21076 string | *with shortest length indicator* | string | `S`
ferencd@0 21077 array | *see notes on optimized format* | array | `[`
ferencd@0 21078 object | *see notes on optimized format* | map | `{`
ferencd@0 21079
ferencd@0 21080 @note The mapping is **complete** in the sense that any JSON value type
ferencd@0 21081 can be converted to a UBJSON value.
ferencd@0 21082
ferencd@0 21083 @note The following values can **not** be converted to a UBJSON value:
ferencd@0 21084 - strings with more than 9223372036854775807 bytes (theoretical)
ferencd@0 21085 - unsigned integer numbers above 9223372036854775807
ferencd@0 21086
ferencd@0 21087 @note The following markers are not used in the conversion:
ferencd@0 21088 - `Z`: no-op values are not created.
ferencd@0 21089 - `C`: single-byte strings are serialized with `S` markers.
ferencd@0 21090
ferencd@0 21091 @note Any UBJSON output created @ref to_ubjson can be successfully parsed
ferencd@0 21092 by @ref from_ubjson.
ferencd@0 21093
ferencd@0 21094 @note If NaN or Infinity are stored inside a JSON number, they are
ferencd@0 21095 serialized properly. This behavior differs from the @ref dump()
ferencd@0 21096 function which serializes NaN or Infinity to `null`.
ferencd@0 21097
ferencd@0 21098 @note The optimized formats for containers are supported: Parameter
ferencd@0 21099 @a use_size adds size information to the beginning of a container and
ferencd@0 21100 removes the closing marker. Parameter @a use_type further checks
ferencd@0 21101 whether all elements of a container have the same type and adds the
ferencd@0 21102 type marker to the beginning of the container. The @a use_type
ferencd@0 21103 parameter must only be used together with @a use_size = true. Note
ferencd@0 21104 that @a use_size = true alone may result in larger representations -
ferencd@0 21105 the benefit of this parameter is that the receiving side is
ferencd@0 21106 immediately informed on the number of elements of the container.
ferencd@0 21107
ferencd@0 21108 @param[in] j JSON value to serialize
ferencd@0 21109 @param[in] use_size whether to add size annotations to container types
ferencd@0 21110 @param[in] use_type whether to add type annotations to container types
ferencd@0 21111 (must be combined with @a use_size = true)
ferencd@0 21112 @return UBJSON serialization as byte vector
ferencd@0 21113
ferencd@0 21114 @complexity Linear in the size of the JSON value @a j.
ferencd@0 21115
ferencd@0 21116 @liveexample{The example shows the serialization of a JSON value to a byte
ferencd@0 21117 vector in UBJSON format.,to_ubjson}
ferencd@0 21118
ferencd@0 21119 @sa http://ubjson.org
ferencd@0 21120 @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the
ferencd@0 21121 analogous deserialization
ferencd@0 21122 @sa @ref to_cbor(const basic_json& for the related CBOR format
ferencd@0 21123 @sa @ref to_msgpack(const basic_json&) for the related MessagePack format
ferencd@0 21124
ferencd@0 21125 @since version 3.1.0
ferencd@0 21126 */
ferencd@0 21127 static std::vector<uint8_t> to_ubjson(const basic_json& j,
ferencd@0 21128 const bool use_size = false,
ferencd@0 21129 const bool use_type = false)
ferencd@0 21130 {
ferencd@0 21131 std::vector<uint8_t> result;
ferencd@0 21132 to_ubjson(j, result, use_size, use_type);
ferencd@0 21133 return result;
ferencd@0 21134 }
ferencd@0 21135
ferencd@0 21136 static void to_ubjson(const basic_json& j, detail::output_adapter<uint8_t> o,
ferencd@0 21137 const bool use_size = false, const bool use_type = false)
ferencd@0 21138 {
ferencd@0 21139 binary_writer<uint8_t>(o).write_ubjson(j, use_size, use_type);
ferencd@0 21140 }
ferencd@0 21141
ferencd@0 21142 static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,
ferencd@0 21143 const bool use_size = false, const bool use_type = false)
ferencd@0 21144 {
ferencd@0 21145 binary_writer<char>(o).write_ubjson(j, use_size, use_type);
ferencd@0 21146 }
ferencd@0 21147
ferencd@0 21148
ferencd@0 21149 /*!
ferencd@0 21150 @brief Serializes the given JSON object `j` to BSON and returns a vector
ferencd@0 21151 containing the corresponding BSON-representation.
ferencd@0 21152
ferencd@0 21153 BSON (Binary JSON) is a binary format in which zero or more ordered key/value pairs are
ferencd@0 21154 stored as a single entity (a so-called document).
ferencd@0 21155
ferencd@0 21156 The library uses the following mapping from JSON values types to BSON types:
ferencd@0 21157
ferencd@0 21158 JSON value type | value/range | BSON type | marker
ferencd@0 21159 --------------- | --------------------------------- | ----------- | ------
ferencd@0 21160 null | `null` | null | 0x0A
ferencd@0 21161 boolean | `true`, `false` | boolean | 0x08
ferencd@0 21162 number_integer | -9223372036854775808..-2147483649 | int64 | 0x12
ferencd@0 21163 number_integer | -2147483648..2147483647 | int32 | 0x10
ferencd@0 21164 number_integer | 2147483648..9223372036854775807 | int64 | 0x12
ferencd@0 21165 number_unsigned | 0..2147483647 | int32 | 0x10
ferencd@0 21166 number_unsigned | 2147483648..9223372036854775807 | int64 | 0x12
ferencd@0 21167 number_unsigned | 9223372036854775808..18446744073709551615| -- | --
ferencd@0 21168 number_float | *any value* | double | 0x01
ferencd@0 21169 string | *any value* | string | 0x02
ferencd@0 21170 array | *any value* | document | 0x04
ferencd@0 21171 object | *any value* | document | 0x03
ferencd@0 21172
ferencd@0 21173 @warning The mapping is **incomplete**, since only JSON-objects (and things
ferencd@0 21174 contained therein) can be serialized to BSON.
ferencd@0 21175 Also, integers larger than 9223372036854775807 cannot be serialized to BSON,
ferencd@0 21176 and the keys may not contain U+0000, since they are serialized a
ferencd@0 21177 zero-terminated c-strings.
ferencd@0 21178
ferencd@0 21179 @throw out_of_range.407 if `j.is_number_unsigned() && j.get<std::uint64_t>() > 9223372036854775807`
ferencd@0 21180 @throw out_of_range.409 if a key in `j` contains a NULL (U+0000)
ferencd@0 21181 @throw type_error.317 if `!j.is_object()`
ferencd@0 21182
ferencd@0 21183 @pre The input `j` is required to be an object: `j.is_object() == true`.
ferencd@0 21184
ferencd@0 21185 @note Any BSON output created via @ref to_bson can be successfully parsed
ferencd@0 21186 by @ref from_bson.
ferencd@0 21187
ferencd@0 21188 @param[in] j JSON value to serialize
ferencd@0 21189 @return BSON serialization as byte vector
ferencd@0 21190
ferencd@0 21191 @complexity Linear in the size of the JSON value @a j.
ferencd@0 21192
ferencd@0 21193 @liveexample{The example shows the serialization of a JSON value to a byte
ferencd@0 21194 vector in BSON format.,to_bson}
ferencd@0 21195
ferencd@0 21196 @sa http://bsonspec.org/spec.html
ferencd@0 21197 @sa @ref from_bson(detail::input_adapter&&, const bool strict) for the
ferencd@0 21198 analogous deserialization
ferencd@0 21199 @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the
ferencd@0 21200 related UBJSON format
ferencd@0 21201 @sa @ref to_cbor(const basic_json&) for the related CBOR format
ferencd@0 21202 @sa @ref to_msgpack(const basic_json&) for the related MessagePack format
ferencd@0 21203 */
ferencd@0 21204 static std::vector<uint8_t> to_bson(const basic_json& j)
ferencd@0 21205 {
ferencd@0 21206 std::vector<uint8_t> result;
ferencd@0 21207 to_bson(j, result);
ferencd@0 21208 return result;
ferencd@0 21209 }
ferencd@0 21210
ferencd@0 21211 /*!
ferencd@0 21212 @brief Serializes the given JSON object `j` to BSON and forwards the
ferencd@0 21213 corresponding BSON-representation to the given output_adapter `o`.
ferencd@0 21214 @param j The JSON object to convert to BSON.
ferencd@0 21215 @param o The output adapter that receives the binary BSON representation.
ferencd@0 21216 @pre The input `j` shall be an object: `j.is_object() == true`
ferencd@0 21217 @sa @ref to_bson(const basic_json&)
ferencd@0 21218 */
ferencd@0 21219 static void to_bson(const basic_json& j, detail::output_adapter<uint8_t> o)
ferencd@0 21220 {
ferencd@0 21221 binary_writer<uint8_t>(o).write_bson(j);
ferencd@0 21222 }
ferencd@0 21223
ferencd@0 21224 /*!
ferencd@0 21225 @copydoc to_bson(const basic_json&, detail::output_adapter<uint8_t>)
ferencd@0 21226 */
ferencd@0 21227 static void to_bson(const basic_json& j, detail::output_adapter<char> o)
ferencd@0 21228 {
ferencd@0 21229 binary_writer<char>(o).write_bson(j);
ferencd@0 21230 }
ferencd@0 21231
ferencd@0 21232
ferencd@0 21233 /*!
ferencd@0 21234 @brief create a JSON value from an input in CBOR format
ferencd@0 21235
ferencd@0 21236 Deserializes a given input @a i to a JSON value using the CBOR (Concise
ferencd@0 21237 Binary Object Representation) serialization format.
ferencd@0 21238
ferencd@0 21239 The library maps CBOR types to JSON value types as follows:
ferencd@0 21240
ferencd@0 21241 CBOR type | JSON value type | first byte
ferencd@0 21242 ---------------------- | --------------- | ----------
ferencd@0 21243 Integer | number_unsigned | 0x00..0x17
ferencd@0 21244 Unsigned integer | number_unsigned | 0x18
ferencd@0 21245 Unsigned integer | number_unsigned | 0x19
ferencd@0 21246 Unsigned integer | number_unsigned | 0x1A
ferencd@0 21247 Unsigned integer | number_unsigned | 0x1B
ferencd@0 21248 Negative integer | number_integer | 0x20..0x37
ferencd@0 21249 Negative integer | number_integer | 0x38
ferencd@0 21250 Negative integer | number_integer | 0x39
ferencd@0 21251 Negative integer | number_integer | 0x3A
ferencd@0 21252 Negative integer | number_integer | 0x3B
ferencd@0 21253 Negative integer | number_integer | 0x40..0x57
ferencd@0 21254 UTF-8 string | string | 0x60..0x77
ferencd@0 21255 UTF-8 string | string | 0x78
ferencd@0 21256 UTF-8 string | string | 0x79
ferencd@0 21257 UTF-8 string | string | 0x7A
ferencd@0 21258 UTF-8 string | string | 0x7B
ferencd@0 21259 UTF-8 string | string | 0x7F
ferencd@0 21260 array | array | 0x80..0x97
ferencd@0 21261 array | array | 0x98
ferencd@0 21262 array | array | 0x99
ferencd@0 21263 array | array | 0x9A
ferencd@0 21264 array | array | 0x9B
ferencd@0 21265 array | array | 0x9F
ferencd@0 21266 map | object | 0xA0..0xB7
ferencd@0 21267 map | object | 0xB8
ferencd@0 21268 map | object | 0xB9
ferencd@0 21269 map | object | 0xBA
ferencd@0 21270 map | object | 0xBB
ferencd@0 21271 map | object | 0xBF
ferencd@0 21272 False | `false` | 0xF4
ferencd@0 21273 True | `true` | 0xF5
ferencd@0 21274 Null | `null` | 0xF6
ferencd@0 21275 Half-Precision Float | number_float | 0xF9
ferencd@0 21276 Single-Precision Float | number_float | 0xFA
ferencd@0 21277 Double-Precision Float | number_float | 0xFB
ferencd@0 21278
ferencd@0 21279 @warning The mapping is **incomplete** in the sense that not all CBOR
ferencd@0 21280 types can be converted to a JSON value. The following CBOR types
ferencd@0 21281 are not supported and will yield parse errors (parse_error.112):
ferencd@0 21282 - byte strings (0x40..0x5F)
ferencd@0 21283 - date/time (0xC0..0xC1)
ferencd@0 21284 - bignum (0xC2..0xC3)
ferencd@0 21285 - decimal fraction (0xC4)
ferencd@0 21286 - bigfloat (0xC5)
ferencd@0 21287 - tagged items (0xC6..0xD4, 0xD8..0xDB)
ferencd@0 21288 - expected conversions (0xD5..0xD7)
ferencd@0 21289 - simple values (0xE0..0xF3, 0xF8)
ferencd@0 21290 - undefined (0xF7)
ferencd@0 21291
ferencd@0 21292 @warning CBOR allows map keys of any type, whereas JSON only allows
ferencd@0 21293 strings as keys in object values. Therefore, CBOR maps with keys
ferencd@0 21294 other than UTF-8 strings are rejected (parse_error.113).
ferencd@0 21295
ferencd@0 21296 @note Any CBOR output created @ref to_cbor can be successfully parsed by
ferencd@0 21297 @ref from_cbor.
ferencd@0 21298
ferencd@0 21299 @param[in] i an input in CBOR format convertible to an input adapter
ferencd@0 21300 @param[in] strict whether to expect the input to be consumed until EOF
ferencd@0 21301 (true by default)
ferencd@0 21302 @param[in] allow_exceptions whether to throw exceptions in case of a
ferencd@0 21303 parse error (optional, true by default)
ferencd@0 21304
ferencd@0 21305 @return deserialized JSON value; in case of a parse error and
ferencd@0 21306 @a allow_exceptions set to `false`, the return value will be
ferencd@0 21307 value_t::discarded.
ferencd@0 21308
ferencd@0 21309 @throw parse_error.110 if the given input ends prematurely or the end of
ferencd@0 21310 file was not reached when @a strict was set to true
ferencd@0 21311 @throw parse_error.112 if unsupported features from CBOR were
ferencd@0 21312 used in the given input @a v or if the input is not valid CBOR
ferencd@0 21313 @throw parse_error.113 if a string was expected as map key, but not found
ferencd@0 21314
ferencd@0 21315 @complexity Linear in the size of the input @a i.
ferencd@0 21316
ferencd@0 21317 @liveexample{The example shows the deserialization of a byte vector in CBOR
ferencd@0 21318 format to a JSON value.,from_cbor}
ferencd@0 21319
ferencd@0 21320 @sa http://cbor.io
ferencd@0 21321 @sa @ref to_cbor(const basic_json&) for the analogous serialization
ferencd@0 21322 @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for the
ferencd@0 21323 related MessagePack format
ferencd@0 21324 @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the
ferencd@0 21325 related UBJSON format
ferencd@0 21326
ferencd@0 21327 @since version 2.0.9; parameter @a start_index since 2.1.1; changed to
ferencd@0 21328 consume input adapters, removed start_index parameter, and added
ferencd@0 21329 @a strict parameter since 3.0.0; added @a allow_exceptions parameter
ferencd@0 21330 since 3.2.0
ferencd@0 21331 */
ferencd@0 21332 JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 21333 static basic_json from_cbor(detail::input_adapter&& i,
ferencd@0 21334 const bool strict = true,
ferencd@0 21335 const bool allow_exceptions = true)
ferencd@0 21336 {
ferencd@0 21337 basic_json result;
ferencd@0 21338 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
ferencd@0 21339 const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::cbor, &sdp, strict);
ferencd@0 21340 return res ? result : basic_json(value_t::discarded);
ferencd@0 21341 }
ferencd@0 21342
ferencd@0 21343 /*!
ferencd@0 21344 @copydoc from_cbor(detail::input_adapter&&, const bool, const bool)
ferencd@0 21345 */
ferencd@0 21346 template<typename A1, typename A2,
ferencd@0 21347 detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
ferencd@0 21348 JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 21349 static basic_json from_cbor(A1 && a1, A2 && a2,
ferencd@0 21350 const bool strict = true,
ferencd@0 21351 const bool allow_exceptions = true)
ferencd@0 21352 {
ferencd@0 21353 basic_json result;
ferencd@0 21354 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
ferencd@0 21355 const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::cbor, &sdp, strict);
ferencd@0 21356 return res ? result : basic_json(value_t::discarded);
ferencd@0 21357 }
ferencd@0 21358
ferencd@0 21359 /*!
ferencd@0 21360 @brief create a JSON value from an input in MessagePack format
ferencd@0 21361
ferencd@0 21362 Deserializes a given input @a i to a JSON value using the MessagePack
ferencd@0 21363 serialization format.
ferencd@0 21364
ferencd@0 21365 The library maps MessagePack types to JSON value types as follows:
ferencd@0 21366
ferencd@0 21367 MessagePack type | JSON value type | first byte
ferencd@0 21368 ---------------- | --------------- | ----------
ferencd@0 21369 positive fixint | number_unsigned | 0x00..0x7F
ferencd@0 21370 fixmap | object | 0x80..0x8F
ferencd@0 21371 fixarray | array | 0x90..0x9F
ferencd@0 21372 fixstr | string | 0xA0..0xBF
ferencd@0 21373 nil | `null` | 0xC0
ferencd@0 21374 false | `false` | 0xC2
ferencd@0 21375 true | `true` | 0xC3
ferencd@0 21376 float 32 | number_float | 0xCA
ferencd@0 21377 float 64 | number_float | 0xCB
ferencd@0 21378 uint 8 | number_unsigned | 0xCC
ferencd@0 21379 uint 16 | number_unsigned | 0xCD
ferencd@0 21380 uint 32 | number_unsigned | 0xCE
ferencd@0 21381 uint 64 | number_unsigned | 0xCF
ferencd@0 21382 int 8 | number_integer | 0xD0
ferencd@0 21383 int 16 | number_integer | 0xD1
ferencd@0 21384 int 32 | number_integer | 0xD2
ferencd@0 21385 int 64 | number_integer | 0xD3
ferencd@0 21386 str 8 | string | 0xD9
ferencd@0 21387 str 16 | string | 0xDA
ferencd@0 21388 str 32 | string | 0xDB
ferencd@0 21389 array 16 | array | 0xDC
ferencd@0 21390 array 32 | array | 0xDD
ferencd@0 21391 map 16 | object | 0xDE
ferencd@0 21392 map 32 | object | 0xDF
ferencd@0 21393 negative fixint | number_integer | 0xE0-0xFF
ferencd@0 21394
ferencd@0 21395 @warning The mapping is **incomplete** in the sense that not all
ferencd@0 21396 MessagePack types can be converted to a JSON value. The following
ferencd@0 21397 MessagePack types are not supported and will yield parse errors:
ferencd@0 21398 - bin 8 - bin 32 (0xC4..0xC6)
ferencd@0 21399 - ext 8 - ext 32 (0xC7..0xC9)
ferencd@0 21400 - fixext 1 - fixext 16 (0xD4..0xD8)
ferencd@0 21401
ferencd@0 21402 @note Any MessagePack output created @ref to_msgpack can be successfully
ferencd@0 21403 parsed by @ref from_msgpack.
ferencd@0 21404
ferencd@0 21405 @param[in] i an input in MessagePack format convertible to an input
ferencd@0 21406 adapter
ferencd@0 21407 @param[in] strict whether to expect the input to be consumed until EOF
ferencd@0 21408 (true by default)
ferencd@0 21409 @param[in] allow_exceptions whether to throw exceptions in case of a
ferencd@0 21410 parse error (optional, true by default)
ferencd@0 21411
ferencd@0 21412 @return deserialized JSON value; in case of a parse error and
ferencd@0 21413 @a allow_exceptions set to `false`, the return value will be
ferencd@0 21414 value_t::discarded.
ferencd@0 21415
ferencd@0 21416 @throw parse_error.110 if the given input ends prematurely or the end of
ferencd@0 21417 file was not reached when @a strict was set to true
ferencd@0 21418 @throw parse_error.112 if unsupported features from MessagePack were
ferencd@0 21419 used in the given input @a i or if the input is not valid MessagePack
ferencd@0 21420 @throw parse_error.113 if a string was expected as map key, but not found
ferencd@0 21421
ferencd@0 21422 @complexity Linear in the size of the input @a i.
ferencd@0 21423
ferencd@0 21424 @liveexample{The example shows the deserialization of a byte vector in
ferencd@0 21425 MessagePack format to a JSON value.,from_msgpack}
ferencd@0 21426
ferencd@0 21427 @sa http://msgpack.org
ferencd@0 21428 @sa @ref to_msgpack(const basic_json&) for the analogous serialization
ferencd@0 21429 @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the
ferencd@0 21430 related CBOR format
ferencd@0 21431 @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for
ferencd@0 21432 the related UBJSON format
ferencd@0 21433 @sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for
ferencd@0 21434 the related BSON format
ferencd@0 21435
ferencd@0 21436 @since version 2.0.9; parameter @a start_index since 2.1.1; changed to
ferencd@0 21437 consume input adapters, removed start_index parameter, and added
ferencd@0 21438 @a strict parameter since 3.0.0; added @a allow_exceptions parameter
ferencd@0 21439 since 3.2.0
ferencd@0 21440 */
ferencd@0 21441 JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 21442 static basic_json from_msgpack(detail::input_adapter&& i,
ferencd@0 21443 const bool strict = true,
ferencd@0 21444 const bool allow_exceptions = true)
ferencd@0 21445 {
ferencd@0 21446 basic_json result;
ferencd@0 21447 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
ferencd@0 21448 const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::msgpack, &sdp, strict);
ferencd@0 21449 return res ? result : basic_json(value_t::discarded);
ferencd@0 21450 }
ferencd@0 21451
ferencd@0 21452 /*!
ferencd@0 21453 @copydoc from_msgpack(detail::input_adapter&&, const bool, const bool)
ferencd@0 21454 */
ferencd@0 21455 template<typename A1, typename A2,
ferencd@0 21456 detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
ferencd@0 21457 JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 21458 static basic_json from_msgpack(A1 && a1, A2 && a2,
ferencd@0 21459 const bool strict = true,
ferencd@0 21460 const bool allow_exceptions = true)
ferencd@0 21461 {
ferencd@0 21462 basic_json result;
ferencd@0 21463 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
ferencd@0 21464 const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::msgpack, &sdp, strict);
ferencd@0 21465 return res ? result : basic_json(value_t::discarded);
ferencd@0 21466 }
ferencd@0 21467
ferencd@0 21468 /*!
ferencd@0 21469 @brief create a JSON value from an input in UBJSON format
ferencd@0 21470
ferencd@0 21471 Deserializes a given input @a i to a JSON value using the UBJSON (Universal
ferencd@0 21472 Binary JSON) serialization format.
ferencd@0 21473
ferencd@0 21474 The library maps UBJSON types to JSON value types as follows:
ferencd@0 21475
ferencd@0 21476 UBJSON type | JSON value type | marker
ferencd@0 21477 ----------- | --------------------------------------- | ------
ferencd@0 21478 no-op | *no value, next value is read* | `N`
ferencd@0 21479 null | `null` | `Z`
ferencd@0 21480 false | `false` | `F`
ferencd@0 21481 true | `true` | `T`
ferencd@0 21482 float32 | number_float | `d`
ferencd@0 21483 float64 | number_float | `D`
ferencd@0 21484 uint8 | number_unsigned | `U`
ferencd@0 21485 int8 | number_integer | `i`
ferencd@0 21486 int16 | number_integer | `I`
ferencd@0 21487 int32 | number_integer | `l`
ferencd@0 21488 int64 | number_integer | `L`
ferencd@0 21489 string | string | `S`
ferencd@0 21490 char | string | `C`
ferencd@0 21491 array | array (optimized values are supported) | `[`
ferencd@0 21492 object | object (optimized values are supported) | `{`
ferencd@0 21493
ferencd@0 21494 @note The mapping is **complete** in the sense that any UBJSON value can
ferencd@0 21495 be converted to a JSON value.
ferencd@0 21496
ferencd@0 21497 @param[in] i an input in UBJSON format convertible to an input adapter
ferencd@0 21498 @param[in] strict whether to expect the input to be consumed until EOF
ferencd@0 21499 (true by default)
ferencd@0 21500 @param[in] allow_exceptions whether to throw exceptions in case of a
ferencd@0 21501 parse error (optional, true by default)
ferencd@0 21502
ferencd@0 21503 @return deserialized JSON value; in case of a parse error and
ferencd@0 21504 @a allow_exceptions set to `false`, the return value will be
ferencd@0 21505 value_t::discarded.
ferencd@0 21506
ferencd@0 21507 @throw parse_error.110 if the given input ends prematurely or the end of
ferencd@0 21508 file was not reached when @a strict was set to true
ferencd@0 21509 @throw parse_error.112 if a parse error occurs
ferencd@0 21510 @throw parse_error.113 if a string could not be parsed successfully
ferencd@0 21511
ferencd@0 21512 @complexity Linear in the size of the input @a i.
ferencd@0 21513
ferencd@0 21514 @liveexample{The example shows the deserialization of a byte vector in
ferencd@0 21515 UBJSON format to a JSON value.,from_ubjson}
ferencd@0 21516
ferencd@0 21517 @sa http://ubjson.org
ferencd@0 21518 @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the
ferencd@0 21519 analogous serialization
ferencd@0 21520 @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the
ferencd@0 21521 related CBOR format
ferencd@0 21522 @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for
ferencd@0 21523 the related MessagePack format
ferencd@0 21524 @sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for
ferencd@0 21525 the related BSON format
ferencd@0 21526
ferencd@0 21527 @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0
ferencd@0 21528 */
ferencd@0 21529 JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 21530 static basic_json from_ubjson(detail::input_adapter&& i,
ferencd@0 21531 const bool strict = true,
ferencd@0 21532 const bool allow_exceptions = true)
ferencd@0 21533 {
ferencd@0 21534 basic_json result;
ferencd@0 21535 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
ferencd@0 21536 const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::ubjson, &sdp, strict);
ferencd@0 21537 return res ? result : basic_json(value_t::discarded);
ferencd@0 21538 }
ferencd@0 21539
ferencd@0 21540 /*!
ferencd@0 21541 @copydoc from_ubjson(detail::input_adapter&&, const bool, const bool)
ferencd@0 21542 */
ferencd@0 21543 template<typename A1, typename A2,
ferencd@0 21544 detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
ferencd@0 21545 JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 21546 static basic_json from_ubjson(A1 && a1, A2 && a2,
ferencd@0 21547 const bool strict = true,
ferencd@0 21548 const bool allow_exceptions = true)
ferencd@0 21549 {
ferencd@0 21550 basic_json result;
ferencd@0 21551 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
ferencd@0 21552 const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::ubjson, &sdp, strict);
ferencd@0 21553 return res ? result : basic_json(value_t::discarded);
ferencd@0 21554 }
ferencd@0 21555
ferencd@0 21556 /*!
ferencd@0 21557 @brief Create a JSON value from an input in BSON format
ferencd@0 21558
ferencd@0 21559 Deserializes a given input @a i to a JSON value using the BSON (Binary JSON)
ferencd@0 21560 serialization format.
ferencd@0 21561
ferencd@0 21562 The library maps BSON record types to JSON value types as follows:
ferencd@0 21563
ferencd@0 21564 BSON type | BSON marker byte | JSON value type
ferencd@0 21565 --------------- | ---------------- | ---------------------------
ferencd@0 21566 double | 0x01 | number_float
ferencd@0 21567 string | 0x02 | string
ferencd@0 21568 document | 0x03 | object
ferencd@0 21569 array | 0x04 | array
ferencd@0 21570 binary | 0x05 | still unsupported
ferencd@0 21571 undefined | 0x06 | still unsupported
ferencd@0 21572 ObjectId | 0x07 | still unsupported
ferencd@0 21573 boolean | 0x08 | boolean
ferencd@0 21574 UTC Date-Time | 0x09 | still unsupported
ferencd@0 21575 null | 0x0A | null
ferencd@0 21576 Regular Expr. | 0x0B | still unsupported
ferencd@0 21577 DB Pointer | 0x0C | still unsupported
ferencd@0 21578 JavaScript Code | 0x0D | still unsupported
ferencd@0 21579 Symbol | 0x0E | still unsupported
ferencd@0 21580 JavaScript Code | 0x0F | still unsupported
ferencd@0 21581 int32 | 0x10 | number_integer
ferencd@0 21582 Timestamp | 0x11 | still unsupported
ferencd@0 21583 128-bit decimal float | 0x13 | still unsupported
ferencd@0 21584 Max Key | 0x7F | still unsupported
ferencd@0 21585 Min Key | 0xFF | still unsupported
ferencd@0 21586
ferencd@0 21587 @warning The mapping is **incomplete**. The unsupported mappings
ferencd@0 21588 are indicated in the table above.
ferencd@0 21589
ferencd@0 21590 @param[in] i an input in BSON format convertible to an input adapter
ferencd@0 21591 @param[in] strict whether to expect the input to be consumed until EOF
ferencd@0 21592 (true by default)
ferencd@0 21593 @param[in] allow_exceptions whether to throw exceptions in case of a
ferencd@0 21594 parse error (optional, true by default)
ferencd@0 21595
ferencd@0 21596 @return deserialized JSON value; in case of a parse error and
ferencd@0 21597 @a allow_exceptions set to `false`, the return value will be
ferencd@0 21598 value_t::discarded.
ferencd@0 21599
ferencd@0 21600 @throw parse_error.114 if an unsupported BSON record type is encountered
ferencd@0 21601
ferencd@0 21602 @complexity Linear in the size of the input @a i.
ferencd@0 21603
ferencd@0 21604 @liveexample{The example shows the deserialization of a byte vector in
ferencd@0 21605 BSON format to a JSON value.,from_bson}
ferencd@0 21606
ferencd@0 21607 @sa http://bsonspec.org/spec.html
ferencd@0 21608 @sa @ref to_bson(const basic_json&) for the analogous serialization
ferencd@0 21609 @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the
ferencd@0 21610 related CBOR format
ferencd@0 21611 @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for
ferencd@0 21612 the related MessagePack format
ferencd@0 21613 @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the
ferencd@0 21614 related UBJSON format
ferencd@0 21615 */
ferencd@0 21616 JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 21617 static basic_json from_bson(detail::input_adapter&& i,
ferencd@0 21618 const bool strict = true,
ferencd@0 21619 const bool allow_exceptions = true)
ferencd@0 21620 {
ferencd@0 21621 basic_json result;
ferencd@0 21622 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
ferencd@0 21623 const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::bson, &sdp, strict);
ferencd@0 21624 return res ? result : basic_json(value_t::discarded);
ferencd@0 21625 }
ferencd@0 21626
ferencd@0 21627 /*!
ferencd@0 21628 @copydoc from_bson(detail::input_adapter&&, const bool, const bool)
ferencd@0 21629 */
ferencd@0 21630 template<typename A1, typename A2,
ferencd@0 21631 detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
ferencd@0 21632 JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 21633 static basic_json from_bson(A1 && a1, A2 && a2,
ferencd@0 21634 const bool strict = true,
ferencd@0 21635 const bool allow_exceptions = true)
ferencd@0 21636 {
ferencd@0 21637 basic_json result;
ferencd@0 21638 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
ferencd@0 21639 const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::bson, &sdp, strict);
ferencd@0 21640 return res ? result : basic_json(value_t::discarded);
ferencd@0 21641 }
ferencd@0 21642
ferencd@0 21643
ferencd@0 21644
ferencd@0 21645 /// @}
ferencd@0 21646
ferencd@0 21647 //////////////////////////
ferencd@0 21648 // JSON Pointer support //
ferencd@0 21649 //////////////////////////
ferencd@0 21650
ferencd@0 21651 /// @name JSON Pointer functions
ferencd@0 21652 /// @{
ferencd@0 21653
ferencd@0 21654 /*!
ferencd@0 21655 @brief access specified element via JSON Pointer
ferencd@0 21656
ferencd@0 21657 Uses a JSON pointer to retrieve a reference to the respective JSON value.
ferencd@0 21658 No bound checking is performed. Similar to @ref operator[](const typename
ferencd@0 21659 object_t::key_type&), `null` values are created in arrays and objects if
ferencd@0 21660 necessary.
ferencd@0 21661
ferencd@0 21662 In particular:
ferencd@0 21663 - If the JSON pointer points to an object key that does not exist, it
ferencd@0 21664 is created an filled with a `null` value before a reference to it
ferencd@0 21665 is returned.
ferencd@0 21666 - If the JSON pointer points to an array index that does not exist, it
ferencd@0 21667 is created an filled with a `null` value before a reference to it
ferencd@0 21668 is returned. All indices between the current maximum and the given
ferencd@0 21669 index are also filled with `null`.
ferencd@0 21670 - The special value `-` is treated as a synonym for the index past the
ferencd@0 21671 end.
ferencd@0 21672
ferencd@0 21673 @param[in] ptr a JSON pointer
ferencd@0 21674
ferencd@0 21675 @return reference to the element pointed to by @a ptr
ferencd@0 21676
ferencd@0 21677 @complexity Constant.
ferencd@0 21678
ferencd@0 21679 @throw parse_error.106 if an array index begins with '0'
ferencd@0 21680 @throw parse_error.109 if an array index was not a number
ferencd@0 21681 @throw out_of_range.404 if the JSON pointer can not be resolved
ferencd@0 21682
ferencd@0 21683 @liveexample{The behavior is shown in the example.,operatorjson_pointer}
ferencd@0 21684
ferencd@0 21685 @since version 2.0.0
ferencd@0 21686 */
ferencd@0 21687 reference operator[](const json_pointer& ptr)
ferencd@0 21688 {
ferencd@0 21689 return ptr.get_unchecked(this);
ferencd@0 21690 }
ferencd@0 21691
ferencd@0 21692 /*!
ferencd@0 21693 @brief access specified element via JSON Pointer
ferencd@0 21694
ferencd@0 21695 Uses a JSON pointer to retrieve a reference to the respective JSON value.
ferencd@0 21696 No bound checking is performed. The function does not change the JSON
ferencd@0 21697 value; no `null` values are created. In particular, the the special value
ferencd@0 21698 `-` yields an exception.
ferencd@0 21699
ferencd@0 21700 @param[in] ptr JSON pointer to the desired element
ferencd@0 21701
ferencd@0 21702 @return const reference to the element pointed to by @a ptr
ferencd@0 21703
ferencd@0 21704 @complexity Constant.
ferencd@0 21705
ferencd@0 21706 @throw parse_error.106 if an array index begins with '0'
ferencd@0 21707 @throw parse_error.109 if an array index was not a number
ferencd@0 21708 @throw out_of_range.402 if the array index '-' is used
ferencd@0 21709 @throw out_of_range.404 if the JSON pointer can not be resolved
ferencd@0 21710
ferencd@0 21711 @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}
ferencd@0 21712
ferencd@0 21713 @since version 2.0.0
ferencd@0 21714 */
ferencd@0 21715 const_reference operator[](const json_pointer& ptr) const
ferencd@0 21716 {
ferencd@0 21717 return ptr.get_unchecked(this);
ferencd@0 21718 }
ferencd@0 21719
ferencd@0 21720 /*!
ferencd@0 21721 @brief access specified element via JSON Pointer
ferencd@0 21722
ferencd@0 21723 Returns a reference to the element at with specified JSON pointer @a ptr,
ferencd@0 21724 with bounds checking.
ferencd@0 21725
ferencd@0 21726 @param[in] ptr JSON pointer to the desired element
ferencd@0 21727
ferencd@0 21728 @return reference to the element pointed to by @a ptr
ferencd@0 21729
ferencd@0 21730 @throw parse_error.106 if an array index in the passed JSON pointer @a ptr
ferencd@0 21731 begins with '0'. See example below.
ferencd@0 21732
ferencd@0 21733 @throw parse_error.109 if an array index in the passed JSON pointer @a ptr
ferencd@0 21734 is not a number. See example below.
ferencd@0 21735
ferencd@0 21736 @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr
ferencd@0 21737 is out of range. See example below.
ferencd@0 21738
ferencd@0 21739 @throw out_of_range.402 if the array index '-' is used in the passed JSON
ferencd@0 21740 pointer @a ptr. As `at` provides checked access (and no elements are
ferencd@0 21741 implicitly inserted), the index '-' is always invalid. See example below.
ferencd@0 21742
ferencd@0 21743 @throw out_of_range.403 if the JSON pointer describes a key of an object
ferencd@0 21744 which cannot be found. See example below.
ferencd@0 21745
ferencd@0 21746 @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.
ferencd@0 21747 See example below.
ferencd@0 21748
ferencd@0 21749 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 21750 changes in the JSON value.
ferencd@0 21751
ferencd@0 21752 @complexity Constant.
ferencd@0 21753
ferencd@0 21754 @since version 2.0.0
ferencd@0 21755
ferencd@0 21756 @liveexample{The behavior is shown in the example.,at_json_pointer}
ferencd@0 21757 */
ferencd@0 21758 reference at(const json_pointer& ptr)
ferencd@0 21759 {
ferencd@0 21760 return ptr.get_checked(this);
ferencd@0 21761 }
ferencd@0 21762
ferencd@0 21763 /*!
ferencd@0 21764 @brief access specified element via JSON Pointer
ferencd@0 21765
ferencd@0 21766 Returns a const reference to the element at with specified JSON pointer @a
ferencd@0 21767 ptr, with bounds checking.
ferencd@0 21768
ferencd@0 21769 @param[in] ptr JSON pointer to the desired element
ferencd@0 21770
ferencd@0 21771 @return reference to the element pointed to by @a ptr
ferencd@0 21772
ferencd@0 21773 @throw parse_error.106 if an array index in the passed JSON pointer @a ptr
ferencd@0 21774 begins with '0'. See example below.
ferencd@0 21775
ferencd@0 21776 @throw parse_error.109 if an array index in the passed JSON pointer @a ptr
ferencd@0 21777 is not a number. See example below.
ferencd@0 21778
ferencd@0 21779 @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr
ferencd@0 21780 is out of range. See example below.
ferencd@0 21781
ferencd@0 21782 @throw out_of_range.402 if the array index '-' is used in the passed JSON
ferencd@0 21783 pointer @a ptr. As `at` provides checked access (and no elements are
ferencd@0 21784 implicitly inserted), the index '-' is always invalid. See example below.
ferencd@0 21785
ferencd@0 21786 @throw out_of_range.403 if the JSON pointer describes a key of an object
ferencd@0 21787 which cannot be found. See example below.
ferencd@0 21788
ferencd@0 21789 @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.
ferencd@0 21790 See example below.
ferencd@0 21791
ferencd@0 21792 @exceptionsafety Strong guarantee: if an exception is thrown, there are no
ferencd@0 21793 changes in the JSON value.
ferencd@0 21794
ferencd@0 21795 @complexity Constant.
ferencd@0 21796
ferencd@0 21797 @since version 2.0.0
ferencd@0 21798
ferencd@0 21799 @liveexample{The behavior is shown in the example.,at_json_pointer_const}
ferencd@0 21800 */
ferencd@0 21801 const_reference at(const json_pointer& ptr) const
ferencd@0 21802 {
ferencd@0 21803 return ptr.get_checked(this);
ferencd@0 21804 }
ferencd@0 21805
ferencd@0 21806 /*!
ferencd@0 21807 @brief return flattened JSON value
ferencd@0 21808
ferencd@0 21809 The function creates a JSON object whose keys are JSON pointers (see [RFC
ferencd@0 21810 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all
ferencd@0 21811 primitive. The original JSON value can be restored using the @ref
ferencd@0 21812 unflatten() function.
ferencd@0 21813
ferencd@0 21814 @return an object that maps JSON pointers to primitive values
ferencd@0 21815
ferencd@0 21816 @note Empty objects and arrays are flattened to `null` and will not be
ferencd@0 21817 reconstructed correctly by the @ref unflatten() function.
ferencd@0 21818
ferencd@0 21819 @complexity Linear in the size the JSON value.
ferencd@0 21820
ferencd@0 21821 @liveexample{The following code shows how a JSON object is flattened to an
ferencd@0 21822 object whose keys consist of JSON pointers.,flatten}
ferencd@0 21823
ferencd@0 21824 @sa @ref unflatten() for the reverse function
ferencd@0 21825
ferencd@0 21826 @since version 2.0.0
ferencd@0 21827 */
ferencd@0 21828 basic_json flatten() const
ferencd@0 21829 {
ferencd@0 21830 basic_json result(value_t::object);
ferencd@0 21831 json_pointer::flatten("", *this, result);
ferencd@0 21832 return result;
ferencd@0 21833 }
ferencd@0 21834
ferencd@0 21835 /*!
ferencd@0 21836 @brief unflatten a previously flattened JSON value
ferencd@0 21837
ferencd@0 21838 The function restores the arbitrary nesting of a JSON value that has been
ferencd@0 21839 flattened before using the @ref flatten() function. The JSON value must
ferencd@0 21840 meet certain constraints:
ferencd@0 21841 1. The value must be an object.
ferencd@0 21842 2. The keys must be JSON pointers (see
ferencd@0 21843 [RFC 6901](https://tools.ietf.org/html/rfc6901))
ferencd@0 21844 3. The mapped values must be primitive JSON types.
ferencd@0 21845
ferencd@0 21846 @return the original JSON from a flattened version
ferencd@0 21847
ferencd@0 21848 @note Empty objects and arrays are flattened by @ref flatten() to `null`
ferencd@0 21849 values and can not unflattened to their original type. Apart from
ferencd@0 21850 this example, for a JSON value `j`, the following is always true:
ferencd@0 21851 `j == j.flatten().unflatten()`.
ferencd@0 21852
ferencd@0 21853 @complexity Linear in the size the JSON value.
ferencd@0 21854
ferencd@0 21855 @throw type_error.314 if value is not an object
ferencd@0 21856 @throw type_error.315 if object values are not primitive
ferencd@0 21857
ferencd@0 21858 @liveexample{The following code shows how a flattened JSON object is
ferencd@0 21859 unflattened into the original nested JSON object.,unflatten}
ferencd@0 21860
ferencd@0 21861 @sa @ref flatten() for the reverse function
ferencd@0 21862
ferencd@0 21863 @since version 2.0.0
ferencd@0 21864 */
ferencd@0 21865 basic_json unflatten() const
ferencd@0 21866 {
ferencd@0 21867 return json_pointer::unflatten(*this);
ferencd@0 21868 }
ferencd@0 21869
ferencd@0 21870 /// @}
ferencd@0 21871
ferencd@0 21872 //////////////////////////
ferencd@0 21873 // JSON Patch functions //
ferencd@0 21874 //////////////////////////
ferencd@0 21875
ferencd@0 21876 /// @name JSON Patch functions
ferencd@0 21877 /// @{
ferencd@0 21878
ferencd@0 21879 /*!
ferencd@0 21880 @brief applies a JSON patch
ferencd@0 21881
ferencd@0 21882 [JSON Patch](http://jsonpatch.com) defines a JSON document structure for
ferencd@0 21883 expressing a sequence of operations to apply to a JSON) document. With
ferencd@0 21884 this function, a JSON Patch is applied to the current JSON value by
ferencd@0 21885 executing all operations from the patch.
ferencd@0 21886
ferencd@0 21887 @param[in] json_patch JSON patch document
ferencd@0 21888 @return patched document
ferencd@0 21889
ferencd@0 21890 @note The application of a patch is atomic: Either all operations succeed
ferencd@0 21891 and the patched document is returned or an exception is thrown. In
ferencd@0 21892 any case, the original value is not changed: the patch is applied
ferencd@0 21893 to a copy of the value.
ferencd@0 21894
ferencd@0 21895 @throw parse_error.104 if the JSON patch does not consist of an array of
ferencd@0 21896 objects
ferencd@0 21897
ferencd@0 21898 @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory
ferencd@0 21899 attributes are missing); example: `"operation add must have member path"`
ferencd@0 21900
ferencd@0 21901 @throw out_of_range.401 if an array index is out of range.
ferencd@0 21902
ferencd@0 21903 @throw out_of_range.403 if a JSON pointer inside the patch could not be
ferencd@0 21904 resolved successfully in the current JSON value; example: `"key baz not
ferencd@0 21905 found"`
ferencd@0 21906
ferencd@0 21907 @throw out_of_range.405 if JSON pointer has no parent ("add", "remove",
ferencd@0 21908 "move")
ferencd@0 21909
ferencd@0 21910 @throw other_error.501 if "test" operation was unsuccessful
ferencd@0 21911
ferencd@0 21912 @complexity Linear in the size of the JSON value and the length of the
ferencd@0 21913 JSON patch. As usually only a fraction of the JSON value is affected by
ferencd@0 21914 the patch, the complexity can usually be neglected.
ferencd@0 21915
ferencd@0 21916 @liveexample{The following code shows how a JSON patch is applied to a
ferencd@0 21917 value.,patch}
ferencd@0 21918
ferencd@0 21919 @sa @ref diff -- create a JSON patch by comparing two JSON values
ferencd@0 21920
ferencd@0 21921 @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
ferencd@0 21922 @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)
ferencd@0 21923
ferencd@0 21924 @since version 2.0.0
ferencd@0 21925 */
ferencd@0 21926 basic_json patch(const basic_json& json_patch) const
ferencd@0 21927 {
ferencd@0 21928 // make a working copy to apply the patch to
ferencd@0 21929 basic_json result = *this;
ferencd@0 21930
ferencd@0 21931 // the valid JSON Patch operations
ferencd@0 21932 enum class patch_operations {add, remove, replace, move, copy, test, invalid};
ferencd@0 21933
ferencd@0 21934 const auto get_op = [](const std::string & op)
ferencd@0 21935 {
ferencd@0 21936 if (op == "add")
ferencd@0 21937 {
ferencd@0 21938 return patch_operations::add;
ferencd@0 21939 }
ferencd@0 21940 if (op == "remove")
ferencd@0 21941 {
ferencd@0 21942 return patch_operations::remove;
ferencd@0 21943 }
ferencd@0 21944 if (op == "replace")
ferencd@0 21945 {
ferencd@0 21946 return patch_operations::replace;
ferencd@0 21947 }
ferencd@0 21948 if (op == "move")
ferencd@0 21949 {
ferencd@0 21950 return patch_operations::move;
ferencd@0 21951 }
ferencd@0 21952 if (op == "copy")
ferencd@0 21953 {
ferencd@0 21954 return patch_operations::copy;
ferencd@0 21955 }
ferencd@0 21956 if (op == "test")
ferencd@0 21957 {
ferencd@0 21958 return patch_operations::test;
ferencd@0 21959 }
ferencd@0 21960
ferencd@0 21961 return patch_operations::invalid;
ferencd@0 21962 };
ferencd@0 21963
ferencd@0 21964 // wrapper for "add" operation; add value at ptr
ferencd@0 21965 const auto operation_add = [&result](json_pointer & ptr, basic_json val)
ferencd@0 21966 {
ferencd@0 21967 // adding to the root of the target document means replacing it
ferencd@0 21968 if (ptr.empty())
ferencd@0 21969 {
ferencd@0 21970 result = val;
ferencd@0 21971 return;
ferencd@0 21972 }
ferencd@0 21973
ferencd@0 21974 // make sure the top element of the pointer exists
ferencd@0 21975 json_pointer top_pointer = ptr.top();
ferencd@0 21976 if (top_pointer != ptr)
ferencd@0 21977 {
ferencd@0 21978 result.at(top_pointer);
ferencd@0 21979 }
ferencd@0 21980
ferencd@0 21981 // get reference to parent of JSON pointer ptr
ferencd@0 21982 const auto last_path = ptr.back();
ferencd@0 21983 ptr.pop_back();
ferencd@0 21984 basic_json& parent = result[ptr];
ferencd@0 21985
ferencd@0 21986 switch (parent.m_type)
ferencd@0 21987 {
ferencd@0 21988 case value_t::null:
ferencd@0 21989 case value_t::object:
ferencd@0 21990 {
ferencd@0 21991 // use operator[] to add value
ferencd@0 21992 parent[last_path] = val;
ferencd@0 21993 break;
ferencd@0 21994 }
ferencd@0 21995
ferencd@0 21996 case value_t::array:
ferencd@0 21997 {
ferencd@0 21998 if (last_path == "-")
ferencd@0 21999 {
ferencd@0 22000 // special case: append to back
ferencd@0 22001 parent.push_back(val);
ferencd@0 22002 }
ferencd@0 22003 else
ferencd@0 22004 {
ferencd@0 22005 const auto idx = json_pointer::array_index(last_path);
ferencd@0 22006 if (JSON_HEDLEY_UNLIKELY(static_cast<size_type>(idx) > parent.size()))
ferencd@0 22007 {
ferencd@0 22008 // avoid undefined behavior
ferencd@0 22009 JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
ferencd@0 22010 }
ferencd@0 22011
ferencd@0 22012 // default case: insert add offset
ferencd@0 22013 parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
ferencd@0 22014 }
ferencd@0 22015 break;
ferencd@0 22016 }
ferencd@0 22017
ferencd@0 22018 // if there exists a parent it cannot be primitive
ferencd@0 22019 default: // LCOV_EXCL_LINE
ferencd@0 22020 assert(false); // LCOV_EXCL_LINE
ferencd@0 22021 }
ferencd@0 22022 };
ferencd@0 22023
ferencd@0 22024 // wrapper for "remove" operation; remove value at ptr
ferencd@0 22025 const auto operation_remove = [&result](json_pointer & ptr)
ferencd@0 22026 {
ferencd@0 22027 // get reference to parent of JSON pointer ptr
ferencd@0 22028 const auto last_path = ptr.back();
ferencd@0 22029 ptr.pop_back();
ferencd@0 22030 basic_json& parent = result.at(ptr);
ferencd@0 22031
ferencd@0 22032 // remove child
ferencd@0 22033 if (parent.is_object())
ferencd@0 22034 {
ferencd@0 22035 // perform range check
ferencd@0 22036 auto it = parent.find(last_path);
ferencd@0 22037 if (JSON_HEDLEY_LIKELY(it != parent.end()))
ferencd@0 22038 {
ferencd@0 22039 parent.erase(it);
ferencd@0 22040 }
ferencd@0 22041 else
ferencd@0 22042 {
ferencd@0 22043 JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found"));
ferencd@0 22044 }
ferencd@0 22045 }
ferencd@0 22046 else if (parent.is_array())
ferencd@0 22047 {
ferencd@0 22048 // note erase performs range check
ferencd@0 22049 parent.erase(static_cast<size_type>(json_pointer::array_index(last_path)));
ferencd@0 22050 }
ferencd@0 22051 };
ferencd@0 22052
ferencd@0 22053 // type check: top level value must be an array
ferencd@0 22054 if (JSON_HEDLEY_UNLIKELY(not json_patch.is_array()))
ferencd@0 22055 {
ferencd@0 22056 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
ferencd@0 22057 }
ferencd@0 22058
ferencd@0 22059 // iterate and apply the operations
ferencd@0 22060 for (const auto& val : json_patch)
ferencd@0 22061 {
ferencd@0 22062 // wrapper to get a value for an operation
ferencd@0 22063 const auto get_value = [&val](const std::string & op,
ferencd@0 22064 const std::string & member,
ferencd@0 22065 bool string_type) -> basic_json &
ferencd@0 22066 {
ferencd@0 22067 // find value
ferencd@0 22068 auto it = val.m_value.object->find(member);
ferencd@0 22069
ferencd@0 22070 // context-sensitive error message
ferencd@0 22071 const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'";
ferencd@0 22072
ferencd@0 22073 // check if desired value is present
ferencd@0 22074 if (JSON_HEDLEY_UNLIKELY(it == val.m_value.object->end()))
ferencd@0 22075 {
ferencd@0 22076 JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'"));
ferencd@0 22077 }
ferencd@0 22078
ferencd@0 22079 // check if result is of type string
ferencd@0 22080 if (JSON_HEDLEY_UNLIKELY(string_type and not it->second.is_string()))
ferencd@0 22081 {
ferencd@0 22082 JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'"));
ferencd@0 22083 }
ferencd@0 22084
ferencd@0 22085 // no error: return value
ferencd@0 22086 return it->second;
ferencd@0 22087 };
ferencd@0 22088
ferencd@0 22089 // type check: every element of the array must be an object
ferencd@0 22090 if (JSON_HEDLEY_UNLIKELY(not val.is_object()))
ferencd@0 22091 {
ferencd@0 22092 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects"));
ferencd@0 22093 }
ferencd@0 22094
ferencd@0 22095 // collect mandatory members
ferencd@0 22096 const std::string op = get_value("op", "op", true);
ferencd@0 22097 const std::string path = get_value(op, "path", true);
ferencd@0 22098 json_pointer ptr(path);
ferencd@0 22099
ferencd@0 22100 switch (get_op(op))
ferencd@0 22101 {
ferencd@0 22102 case patch_operations::add:
ferencd@0 22103 {
ferencd@0 22104 operation_add(ptr, get_value("add", "value", false));
ferencd@0 22105 break;
ferencd@0 22106 }
ferencd@0 22107
ferencd@0 22108 case patch_operations::remove:
ferencd@0 22109 {
ferencd@0 22110 operation_remove(ptr);
ferencd@0 22111 break;
ferencd@0 22112 }
ferencd@0 22113
ferencd@0 22114 case patch_operations::replace:
ferencd@0 22115 {
ferencd@0 22116 // the "path" location must exist - use at()
ferencd@0 22117 result.at(ptr) = get_value("replace", "value", false);
ferencd@0 22118 break;
ferencd@0 22119 }
ferencd@0 22120
ferencd@0 22121 case patch_operations::move:
ferencd@0 22122 {
ferencd@0 22123 const std::string from_path = get_value("move", "from", true);
ferencd@0 22124 json_pointer from_ptr(from_path);
ferencd@0 22125
ferencd@0 22126 // the "from" location must exist - use at()
ferencd@0 22127 basic_json v = result.at(from_ptr);
ferencd@0 22128
ferencd@0 22129 // The move operation is functionally identical to a
ferencd@0 22130 // "remove" operation on the "from" location, followed
ferencd@0 22131 // immediately by an "add" operation at the target
ferencd@0 22132 // location with the value that was just removed.
ferencd@0 22133 operation_remove(from_ptr);
ferencd@0 22134 operation_add(ptr, v);
ferencd@0 22135 break;
ferencd@0 22136 }
ferencd@0 22137
ferencd@0 22138 case patch_operations::copy:
ferencd@0 22139 {
ferencd@0 22140 const std::string from_path = get_value("copy", "from", true);
ferencd@0 22141 const json_pointer from_ptr(from_path);
ferencd@0 22142
ferencd@0 22143 // the "from" location must exist - use at()
ferencd@0 22144 basic_json v = result.at(from_ptr);
ferencd@0 22145
ferencd@0 22146 // The copy is functionally identical to an "add"
ferencd@0 22147 // operation at the target location using the value
ferencd@0 22148 // specified in the "from" member.
ferencd@0 22149 operation_add(ptr, v);
ferencd@0 22150 break;
ferencd@0 22151 }
ferencd@0 22152
ferencd@0 22153 case patch_operations::test:
ferencd@0 22154 {
ferencd@0 22155 bool success = false;
ferencd@0 22156 JSON_TRY
ferencd@0 22157 {
ferencd@0 22158 // check if "value" matches the one at "path"
ferencd@0 22159 // the "path" location must exist - use at()
ferencd@0 22160 success = (result.at(ptr) == get_value("test", "value", false));
ferencd@0 22161 }
ferencd@0 22162 JSON_INTERNAL_CATCH (out_of_range&)
ferencd@0 22163 {
ferencd@0 22164 // ignore out of range errors: success remains false
ferencd@0 22165 }
ferencd@0 22166
ferencd@0 22167 // throw an exception if test fails
ferencd@0 22168 if (JSON_HEDLEY_UNLIKELY(not success))
ferencd@0 22169 {
ferencd@0 22170 JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump()));
ferencd@0 22171 }
ferencd@0 22172
ferencd@0 22173 break;
ferencd@0 22174 }
ferencd@0 22175
ferencd@0 22176 default:
ferencd@0 22177 {
ferencd@0 22178 // op must be "add", "remove", "replace", "move", "copy", or
ferencd@0 22179 // "test"
ferencd@0 22180 JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid"));
ferencd@0 22181 }
ferencd@0 22182 }
ferencd@0 22183 }
ferencd@0 22184
ferencd@0 22185 return result;
ferencd@0 22186 }
ferencd@0 22187
ferencd@0 22188 /*!
ferencd@0 22189 @brief creates a diff as a JSON patch
ferencd@0 22190
ferencd@0 22191 Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can
ferencd@0 22192 be changed into the value @a target by calling @ref patch function.
ferencd@0 22193
ferencd@0 22194 @invariant For two JSON values @a source and @a target, the following code
ferencd@0 22195 yields always `true`:
ferencd@0 22196 @code {.cpp}
ferencd@0 22197 source.patch(diff(source, target)) == target;
ferencd@0 22198 @endcode
ferencd@0 22199
ferencd@0 22200 @note Currently, only `remove`, `add`, and `replace` operations are
ferencd@0 22201 generated.
ferencd@0 22202
ferencd@0 22203 @param[in] source JSON value to compare from
ferencd@0 22204 @param[in] target JSON value to compare against
ferencd@0 22205 @param[in] path helper value to create JSON pointers
ferencd@0 22206
ferencd@0 22207 @return a JSON patch to convert the @a source to @a target
ferencd@0 22208
ferencd@0 22209 @complexity Linear in the lengths of @a source and @a target.
ferencd@0 22210
ferencd@0 22211 @liveexample{The following code shows how a JSON patch is created as a
ferencd@0 22212 diff for two JSON values.,diff}
ferencd@0 22213
ferencd@0 22214 @sa @ref patch -- apply a JSON patch
ferencd@0 22215 @sa @ref merge_patch -- apply a JSON Merge Patch
ferencd@0 22216
ferencd@0 22217 @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
ferencd@0 22218
ferencd@0 22219 @since version 2.0.0
ferencd@0 22220 */
ferencd@0 22221 JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 22222 static basic_json diff(const basic_json& source, const basic_json& target,
ferencd@0 22223 const std::string& path = "")
ferencd@0 22224 {
ferencd@0 22225 // the patch
ferencd@0 22226 basic_json result(value_t::array);
ferencd@0 22227
ferencd@0 22228 // if the values are the same, return empty patch
ferencd@0 22229 if (source == target)
ferencd@0 22230 {
ferencd@0 22231 return result;
ferencd@0 22232 }
ferencd@0 22233
ferencd@0 22234 if (source.type() != target.type())
ferencd@0 22235 {
ferencd@0 22236 // different types: replace value
ferencd@0 22237 result.push_back(
ferencd@0 22238 {
ferencd@0 22239 {"op", "replace"}, {"path", path}, {"value", target}
ferencd@0 22240 });
ferencd@0 22241 return result;
ferencd@0 22242 }
ferencd@0 22243
ferencd@0 22244 switch (source.type())
ferencd@0 22245 {
ferencd@0 22246 case value_t::array:
ferencd@0 22247 {
ferencd@0 22248 // first pass: traverse common elements
ferencd@0 22249 std::size_t i = 0;
ferencd@0 22250 while (i < source.size() and i < target.size())
ferencd@0 22251 {
ferencd@0 22252 // recursive call to compare array values at index i
ferencd@0 22253 auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
ferencd@0 22254 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
ferencd@0 22255 ++i;
ferencd@0 22256 }
ferencd@0 22257
ferencd@0 22258 // i now reached the end of at least one array
ferencd@0 22259 // in a second pass, traverse the remaining elements
ferencd@0 22260
ferencd@0 22261 // remove my remaining elements
ferencd@0 22262 const auto end_index = static_cast<difference_type>(result.size());
ferencd@0 22263 while (i < source.size())
ferencd@0 22264 {
ferencd@0 22265 // add operations in reverse order to avoid invalid
ferencd@0 22266 // indices
ferencd@0 22267 result.insert(result.begin() + end_index, object(
ferencd@0 22268 {
ferencd@0 22269 {"op", "remove"},
ferencd@0 22270 {"path", path + "/" + std::to_string(i)}
ferencd@0 22271 }));
ferencd@0 22272 ++i;
ferencd@0 22273 }
ferencd@0 22274
ferencd@0 22275 // add other remaining elements
ferencd@0 22276 while (i < target.size())
ferencd@0 22277 {
ferencd@0 22278 result.push_back(
ferencd@0 22279 {
ferencd@0 22280 {"op", "add"},
ferencd@0 22281 {"path", path + "/" + std::to_string(i)},
ferencd@0 22282 {"value", target[i]}
ferencd@0 22283 });
ferencd@0 22284 ++i;
ferencd@0 22285 }
ferencd@0 22286
ferencd@0 22287 break;
ferencd@0 22288 }
ferencd@0 22289
ferencd@0 22290 case value_t::object:
ferencd@0 22291 {
ferencd@0 22292 // first pass: traverse this object's elements
ferencd@0 22293 for (auto it = source.cbegin(); it != source.cend(); ++it)
ferencd@0 22294 {
ferencd@0 22295 // escape the key name to be used in a JSON patch
ferencd@0 22296 const auto key = json_pointer::escape(it.key());
ferencd@0 22297
ferencd@0 22298 if (target.find(it.key()) != target.end())
ferencd@0 22299 {
ferencd@0 22300 // recursive call to compare object values at key it
ferencd@0 22301 auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key);
ferencd@0 22302 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
ferencd@0 22303 }
ferencd@0 22304 else
ferencd@0 22305 {
ferencd@0 22306 // found a key that is not in o -> remove it
ferencd@0 22307 result.push_back(object(
ferencd@0 22308 {
ferencd@0 22309 {"op", "remove"}, {"path", path + "/" + key}
ferencd@0 22310 }));
ferencd@0 22311 }
ferencd@0 22312 }
ferencd@0 22313
ferencd@0 22314 // second pass: traverse other object's elements
ferencd@0 22315 for (auto it = target.cbegin(); it != target.cend(); ++it)
ferencd@0 22316 {
ferencd@0 22317 if (source.find(it.key()) == source.end())
ferencd@0 22318 {
ferencd@0 22319 // found a key that is not in this -> add it
ferencd@0 22320 const auto key = json_pointer::escape(it.key());
ferencd@0 22321 result.push_back(
ferencd@0 22322 {
ferencd@0 22323 {"op", "add"}, {"path", path + "/" + key},
ferencd@0 22324 {"value", it.value()}
ferencd@0 22325 });
ferencd@0 22326 }
ferencd@0 22327 }
ferencd@0 22328
ferencd@0 22329 break;
ferencd@0 22330 }
ferencd@0 22331
ferencd@0 22332 default:
ferencd@0 22333 {
ferencd@0 22334 // both primitive type: replace value
ferencd@0 22335 result.push_back(
ferencd@0 22336 {
ferencd@0 22337 {"op", "replace"}, {"path", path}, {"value", target}
ferencd@0 22338 });
ferencd@0 22339 break;
ferencd@0 22340 }
ferencd@0 22341 }
ferencd@0 22342
ferencd@0 22343 return result;
ferencd@0 22344 }
ferencd@0 22345
ferencd@0 22346 /// @}
ferencd@0 22347
ferencd@0 22348 ////////////////////////////////
ferencd@0 22349 // JSON Merge Patch functions //
ferencd@0 22350 ////////////////////////////////
ferencd@0 22351
ferencd@0 22352 /// @name JSON Merge Patch functions
ferencd@0 22353 /// @{
ferencd@0 22354
ferencd@0 22355 /*!
ferencd@0 22356 @brief applies a JSON Merge Patch
ferencd@0 22357
ferencd@0 22358 The merge patch format is primarily intended for use with the HTTP PATCH
ferencd@0 22359 method as a means of describing a set of modifications to a target
ferencd@0 22360 resource's content. This function applies a merge patch to the current
ferencd@0 22361 JSON value.
ferencd@0 22362
ferencd@0 22363 The function implements the following algorithm from Section 2 of
ferencd@0 22364 [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396):
ferencd@0 22365
ferencd@0 22366 ```
ferencd@0 22367 define MergePatch(Target, Patch):
ferencd@0 22368 if Patch is an Object:
ferencd@0 22369 if Target is not an Object:
ferencd@0 22370 Target = {} // Ignore the contents and set it to an empty Object
ferencd@0 22371 for each Name/Value pair in Patch:
ferencd@0 22372 if Value is null:
ferencd@0 22373 if Name exists in Target:
ferencd@0 22374 remove the Name/Value pair from Target
ferencd@0 22375 else:
ferencd@0 22376 Target[Name] = MergePatch(Target[Name], Value)
ferencd@0 22377 return Target
ferencd@0 22378 else:
ferencd@0 22379 return Patch
ferencd@0 22380 ```
ferencd@0 22381
ferencd@0 22382 Thereby, `Target` is the current object; that is, the patch is applied to
ferencd@0 22383 the current value.
ferencd@0 22384
ferencd@0 22385 @param[in] apply_patch the patch to apply
ferencd@0 22386
ferencd@0 22387 @complexity Linear in the lengths of @a patch.
ferencd@0 22388
ferencd@0 22389 @liveexample{The following code shows how a JSON Merge Patch is applied to
ferencd@0 22390 a JSON document.,merge_patch}
ferencd@0 22391
ferencd@0 22392 @sa @ref patch -- apply a JSON patch
ferencd@0 22393 @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396)
ferencd@0 22394
ferencd@0 22395 @since version 3.0.0
ferencd@0 22396 */
ferencd@0 22397 void merge_patch(const basic_json& apply_patch)
ferencd@0 22398 {
ferencd@0 22399 if (apply_patch.is_object())
ferencd@0 22400 {
ferencd@0 22401 if (not is_object())
ferencd@0 22402 {
ferencd@0 22403 *this = object();
ferencd@0 22404 }
ferencd@0 22405 for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)
ferencd@0 22406 {
ferencd@0 22407 if (it.value().is_null())
ferencd@0 22408 {
ferencd@0 22409 erase(it.key());
ferencd@0 22410 }
ferencd@0 22411 else
ferencd@0 22412 {
ferencd@0 22413 operator[](it.key()).merge_patch(it.value());
ferencd@0 22414 }
ferencd@0 22415 }
ferencd@0 22416 }
ferencd@0 22417 else
ferencd@0 22418 {
ferencd@0 22419 *this = apply_patch;
ferencd@0 22420 }
ferencd@0 22421 }
ferencd@0 22422
ferencd@0 22423 /// @}
ferencd@0 22424 };
ferencd@0 22425
ferencd@0 22426 /*!
ferencd@0 22427 @brief user-defined to_string function for JSON values
ferencd@0 22428
ferencd@0 22429 This function implements a user-defined to_string for JSON objects.
ferencd@0 22430
ferencd@0 22431 @param[in] j a JSON object
ferencd@0 22432 @return a std::string object
ferencd@0 22433 */
ferencd@0 22434
ferencd@0 22435 NLOHMANN_BASIC_JSON_TPL_DECLARATION
ferencd@0 22436 std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j)
ferencd@0 22437 {
ferencd@0 22438 return j.dump();
ferencd@0 22439 }
ferencd@0 22440 } // namespace nlohmann
ferencd@0 22441
ferencd@0 22442 ///////////////////////
ferencd@0 22443 // nonmember support //
ferencd@0 22444 ///////////////////////
ferencd@0 22445
ferencd@0 22446 // specialization of std::swap, and std::hash
ferencd@0 22447 namespace std
ferencd@0 22448 {
ferencd@0 22449
ferencd@0 22450 /// hash value for JSON objects
ferencd@0 22451 template<>
ferencd@0 22452 struct hash<nlohmann::json>
ferencd@0 22453 {
ferencd@0 22454 /*!
ferencd@0 22455 @brief return a hash value for a JSON object
ferencd@0 22456
ferencd@0 22457 @since version 1.0.0
ferencd@0 22458 */
ferencd@0 22459 std::size_t operator()(const nlohmann::json& j) const
ferencd@0 22460 {
ferencd@0 22461 // a naive hashing via the string representation
ferencd@0 22462 const auto& h = hash<nlohmann::json::string_t>();
ferencd@0 22463 return h(j.dump());
ferencd@0 22464 }
ferencd@0 22465 };
ferencd@0 22466
ferencd@0 22467 /// specialization for std::less<value_t>
ferencd@0 22468 /// @note: do not remove the space after '<',
ferencd@0 22469 /// see https://github.com/nlohmann/json/pull/679
ferencd@0 22470 template<>
ferencd@0 22471 struct less< ::nlohmann::detail::value_t>
ferencd@0 22472 {
ferencd@0 22473 /*!
ferencd@0 22474 @brief compare two value_t enum values
ferencd@0 22475 @since version 3.0.0
ferencd@0 22476 */
ferencd@0 22477 bool operator()(nlohmann::detail::value_t lhs,
ferencd@0 22478 nlohmann::detail::value_t rhs) const noexcept
ferencd@0 22479 {
ferencd@0 22480 return nlohmann::detail::operator<(lhs, rhs);
ferencd@0 22481 }
ferencd@0 22482 };
ferencd@0 22483
ferencd@0 22484 /*!
ferencd@0 22485 @brief exchanges the values of two JSON objects
ferencd@0 22486
ferencd@0 22487 @since version 1.0.0
ferencd@0 22488 */
ferencd@0 22489 template<>
ferencd@0 22490 inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept(
ferencd@0 22491 is_nothrow_move_constructible<nlohmann::json>::value and
ferencd@0 22492 is_nothrow_move_assignable<nlohmann::json>::value
ferencd@0 22493 )
ferencd@0 22494 {
ferencd@0 22495 j1.swap(j2);
ferencd@0 22496 }
ferencd@0 22497
ferencd@0 22498 } // namespace std
ferencd@0 22499
ferencd@0 22500 /*!
ferencd@0 22501 @brief user-defined string literal for JSON values
ferencd@0 22502
ferencd@0 22503 This operator implements a user-defined string literal for JSON objects. It
ferencd@0 22504 can be used by adding `"_json"` to a string literal and returns a JSON object
ferencd@0 22505 if no parse error occurred.
ferencd@0 22506
ferencd@0 22507 @param[in] s a string representation of a JSON object
ferencd@0 22508 @param[in] n the length of string @a s
ferencd@0 22509 @return a JSON object
ferencd@0 22510
ferencd@0 22511 @since version 1.0.0
ferencd@0 22512 */
ferencd@0 22513 JSON_HEDLEY_NON_NULL(1)
ferencd@0 22514 inline nlohmann::json operator "" _json(const char* s, std::size_t n)
ferencd@0 22515 {
ferencd@0 22516 return nlohmann::json::parse(s, s + n);
ferencd@0 22517 }
ferencd@0 22518
ferencd@0 22519 /*!
ferencd@0 22520 @brief user-defined string literal for JSON pointer
ferencd@0 22521
ferencd@0 22522 This operator implements a user-defined string literal for JSON Pointers. It
ferencd@0 22523 can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer
ferencd@0 22524 object if no parse error occurred.
ferencd@0 22525
ferencd@0 22526 @param[in] s a string representation of a JSON Pointer
ferencd@0 22527 @param[in] n the length of string @a s
ferencd@0 22528 @return a JSON pointer object
ferencd@0 22529
ferencd@0 22530 @since version 2.0.0
ferencd@0 22531 */
ferencd@0 22532 JSON_HEDLEY_NON_NULL(1)
ferencd@0 22533 inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
ferencd@0 22534 {
ferencd@0 22535 return nlohmann::json::json_pointer(std::string(s, n));
ferencd@0 22536 }
ferencd@0 22537
ferencd@0 22538 // #include <nlohmann/detail/macro_unscope.hpp>
ferencd@0 22539
ferencd@0 22540
ferencd@0 22541 // restore GCC/clang diagnostic settings
ferencd@0 22542 #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
ferencd@0 22543 #pragma GCC diagnostic pop
ferencd@0 22544 #endif
ferencd@0 22545 #if defined(__clang__)
ferencd@0 22546 #pragma GCC diagnostic pop
ferencd@0 22547 #endif
ferencd@0 22548
ferencd@0 22549 // clean up
ferencd@0 22550 #undef JSON_INTERNAL_CATCH
ferencd@0 22551 #undef JSON_CATCH
ferencd@0 22552 #undef JSON_THROW
ferencd@0 22553 #undef JSON_TRY
ferencd@0 22554 #undef JSON_HAS_CPP_14
ferencd@0 22555 #undef JSON_HAS_CPP_17
ferencd@0 22556 #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
ferencd@0 22557 #undef NLOHMANN_BASIC_JSON_TPL
ferencd@0 22558
ferencd@0 22559 // #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
ferencd@0 22560 #undef JSON_HEDLEY_ALWAYS_INLINE
ferencd@0 22561 #undef JSON_HEDLEY_ARM_VERSION
ferencd@0 22562 #undef JSON_HEDLEY_ARM_VERSION_CHECK
ferencd@0 22563 #undef JSON_HEDLEY_ARRAY_PARAM
ferencd@0 22564 #undef JSON_HEDLEY_ASSUME
ferencd@0 22565 #undef JSON_HEDLEY_BEGIN_C_DECLS
ferencd@0 22566 #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
ferencd@0 22567 #undef JSON_HEDLEY_CLANG_HAS_BUILTIN
ferencd@0 22568 #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
ferencd@0 22569 #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
ferencd@0 22570 #undef JSON_HEDLEY_CLANG_HAS_EXTENSION
ferencd@0 22571 #undef JSON_HEDLEY_CLANG_HAS_FEATURE
ferencd@0 22572 #undef JSON_HEDLEY_CLANG_HAS_WARNING
ferencd@0 22573 #undef JSON_HEDLEY_COMPCERT_VERSION
ferencd@0 22574 #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK
ferencd@0 22575 #undef JSON_HEDLEY_CONCAT
ferencd@0 22576 #undef JSON_HEDLEY_CONCAT_EX
ferencd@0 22577 #undef JSON_HEDLEY_CONST
ferencd@0 22578 #undef JSON_HEDLEY_CONSTEXPR
ferencd@0 22579 #undef JSON_HEDLEY_CONST_CAST
ferencd@0 22580 #undef JSON_HEDLEY_CPP_CAST
ferencd@0 22581 #undef JSON_HEDLEY_CRAY_VERSION
ferencd@0 22582 #undef JSON_HEDLEY_CRAY_VERSION_CHECK
ferencd@0 22583 #undef JSON_HEDLEY_C_DECL
ferencd@0 22584 #undef JSON_HEDLEY_DEPRECATED
ferencd@0 22585 #undef JSON_HEDLEY_DEPRECATED_FOR
ferencd@0 22586 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
ferencd@0 22587 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
ferencd@0 22588 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
ferencd@0 22589 #undef JSON_HEDLEY_DIAGNOSTIC_POP
ferencd@0 22590 #undef JSON_HEDLEY_DIAGNOSTIC_PUSH
ferencd@0 22591 #undef JSON_HEDLEY_DMC_VERSION
ferencd@0 22592 #undef JSON_HEDLEY_DMC_VERSION_CHECK
ferencd@0 22593 #undef JSON_HEDLEY_EMSCRIPTEN_VERSION
ferencd@0 22594 #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK
ferencd@0 22595 #undef JSON_HEDLEY_END_C_DECLS
ferencd@0 22596 #undef JSON_HEDLEY_FALL_THROUGH
ferencd@0 22597 #undef JSON_HEDLEY_FLAGS
ferencd@0 22598 #undef JSON_HEDLEY_FLAGS_CAST
ferencd@0 22599 #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE
ferencd@0 22600 #undef JSON_HEDLEY_GCC_HAS_BUILTIN
ferencd@0 22601 #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE
ferencd@0 22602 #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE
ferencd@0 22603 #undef JSON_HEDLEY_GCC_HAS_EXTENSION
ferencd@0 22604 #undef JSON_HEDLEY_GCC_HAS_FEATURE
ferencd@0 22605 #undef JSON_HEDLEY_GCC_HAS_WARNING
ferencd@0 22606 #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK
ferencd@0 22607 #undef JSON_HEDLEY_GCC_VERSION
ferencd@0 22608 #undef JSON_HEDLEY_GCC_VERSION_CHECK
ferencd@0 22609 #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE
ferencd@0 22610 #undef JSON_HEDLEY_GNUC_HAS_BUILTIN
ferencd@0 22611 #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE
ferencd@0 22612 #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE
ferencd@0 22613 #undef JSON_HEDLEY_GNUC_HAS_EXTENSION
ferencd@0 22614 #undef JSON_HEDLEY_GNUC_HAS_FEATURE
ferencd@0 22615 #undef JSON_HEDLEY_GNUC_HAS_WARNING
ferencd@0 22616 #undef JSON_HEDLEY_GNUC_VERSION
ferencd@0 22617 #undef JSON_HEDLEY_GNUC_VERSION_CHECK
ferencd@0 22618 #undef JSON_HEDLEY_HAS_ATTRIBUTE
ferencd@0 22619 #undef JSON_HEDLEY_HAS_BUILTIN
ferencd@0 22620 #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE
ferencd@0 22621 #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE
ferencd@0 22622 #undef JSON_HEDLEY_HAS_EXTENSION
ferencd@0 22623 #undef JSON_HEDLEY_HAS_FEATURE
ferencd@0 22624 #undef JSON_HEDLEY_HAS_WARNING
ferencd@0 22625 #undef JSON_HEDLEY_IAR_VERSION
ferencd@0 22626 #undef JSON_HEDLEY_IAR_VERSION_CHECK
ferencd@0 22627 #undef JSON_HEDLEY_IBM_VERSION
ferencd@0 22628 #undef JSON_HEDLEY_IBM_VERSION_CHECK
ferencd@0 22629 #undef JSON_HEDLEY_IMPORT
ferencd@0 22630 #undef JSON_HEDLEY_INLINE
ferencd@0 22631 #undef JSON_HEDLEY_INTEL_VERSION
ferencd@0 22632 #undef JSON_HEDLEY_INTEL_VERSION_CHECK
ferencd@0 22633 #undef JSON_HEDLEY_IS_CONSTANT
ferencd@0 22634 #undef JSON_HEDLEY_LIKELY
ferencd@0 22635 #undef JSON_HEDLEY_MALLOC
ferencd@0 22636 #undef JSON_HEDLEY_MESSAGE
ferencd@0 22637 #undef JSON_HEDLEY_MSVC_VERSION
ferencd@0 22638 #undef JSON_HEDLEY_MSVC_VERSION_CHECK
ferencd@0 22639 #undef JSON_HEDLEY_NEVER_INLINE
ferencd@0 22640 #undef JSON_HEDLEY_NON_NULL
ferencd@0 22641 #undef JSON_HEDLEY_NO_RETURN
ferencd@0 22642 #undef JSON_HEDLEY_NO_THROW
ferencd@0 22643 #undef JSON_HEDLEY_PELLES_VERSION
ferencd@0 22644 #undef JSON_HEDLEY_PELLES_VERSION_CHECK
ferencd@0 22645 #undef JSON_HEDLEY_PGI_VERSION
ferencd@0 22646 #undef JSON_HEDLEY_PGI_VERSION_CHECK
ferencd@0 22647 #undef JSON_HEDLEY_PREDICT
ferencd@0 22648 #undef JSON_HEDLEY_PRINTF_FORMAT
ferencd@0 22649 #undef JSON_HEDLEY_PRIVATE
ferencd@0 22650 #undef JSON_HEDLEY_PUBLIC
ferencd@0 22651 #undef JSON_HEDLEY_PURE
ferencd@0 22652 #undef JSON_HEDLEY_REINTERPRET_CAST
ferencd@0 22653 #undef JSON_HEDLEY_REQUIRE
ferencd@0 22654 #undef JSON_HEDLEY_REQUIRE_CONSTEXPR
ferencd@0 22655 #undef JSON_HEDLEY_REQUIRE_MSG
ferencd@0 22656 #undef JSON_HEDLEY_RESTRICT
ferencd@0 22657 #undef JSON_HEDLEY_RETURNS_NON_NULL
ferencd@0 22658 #undef JSON_HEDLEY_SENTINEL
ferencd@0 22659 #undef JSON_HEDLEY_STATIC_ASSERT
ferencd@0 22660 #undef JSON_HEDLEY_STATIC_CAST
ferencd@0 22661 #undef JSON_HEDLEY_STRINGIFY
ferencd@0 22662 #undef JSON_HEDLEY_STRINGIFY_EX
ferencd@0 22663 #undef JSON_HEDLEY_SUNPRO_VERSION
ferencd@0 22664 #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK
ferencd@0 22665 #undef JSON_HEDLEY_TINYC_VERSION
ferencd@0 22666 #undef JSON_HEDLEY_TINYC_VERSION_CHECK
ferencd@0 22667 #undef JSON_HEDLEY_TI_VERSION
ferencd@0 22668 #undef JSON_HEDLEY_TI_VERSION_CHECK
ferencd@0 22669 #undef JSON_HEDLEY_UNAVAILABLE
ferencd@0 22670 #undef JSON_HEDLEY_UNLIKELY
ferencd@0 22671 #undef JSON_HEDLEY_UNPREDICTABLE
ferencd@0 22672 #undef JSON_HEDLEY_UNREACHABLE
ferencd@0 22673 #undef JSON_HEDLEY_UNREACHABLE_RETURN
ferencd@0 22674 #undef JSON_HEDLEY_VERSION
ferencd@0 22675 #undef JSON_HEDLEY_VERSION_DECODE_MAJOR
ferencd@0 22676 #undef JSON_HEDLEY_VERSION_DECODE_MINOR
ferencd@0 22677 #undef JSON_HEDLEY_VERSION_DECODE_REVISION
ferencd@0 22678 #undef JSON_HEDLEY_VERSION_ENCODE
ferencd@0 22679 #undef JSON_HEDLEY_WARNING
ferencd@0 22680 #undef JSON_HEDLEY_WARN_UNUSED_RESULT
ferencd@0 22681
ferencd@0 22682
ferencd@0 22683
ferencd@0 22684 #endif // INCLUDE_NLOHMANN_JSON_HPP_