Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Ultra-fast and intuitive C++ JSON reader/writer with yyjson backend

License

NotificationsYou must be signed in to change notification settings

yosh-matsuda/cpp-yyjson

Repository files navigation

Ultra-fast and intuitive C++ JSON reader/writer with yyjson backend.

CI

  1. Features
  2. Requirements
  3. Overview
    1. JSON Reader
    2. JSON Writer
    3. Serialization and Deserialization
  4. Installation
    1. Using CMake
  5. Benchmark
    1. Read performance
    2. Write performance
  6. Reference
    1. Namespaces
    2. Immutable JSON classes
    3. Mutable JSON classes
    4. Allocator classes
    5. Serialize and deserialize JSON
    6. Performance best practices
    7. Misc
  7. Author

Features

  • Header-only
  • C++20 range adaption
  • STL-like accessors
  • Intuitive JSON construction
  • Mutual transformation of JSON and C++ classes with
    • compile-time reflection of struct/class field name
    • pre-defined STL casters
    • user-defined casters in two ways
  • Minimum overhead compared to yyjson
  • Object lifetime safety

Requirements

  • C++20 compiler with range supports
    • LLVM >= 16
    • GCC >= 12
    • clang-cl >= 17 (Windows)
    • Visual Studio >= 2022 version 17.5 (experimental)
      • ❌️ MSVC 19.36.32546.0
      • ✅ MSVC 19.38.33141.0
      • ✅ MSVC 19.39.33523.0
      • ✅ MSVC 19.40.33816.0
      • ❌️ MSVC 19.41.34123.0
      • ❌️ MSVC 19.43.34808.0
  • yyjson
  • {fmt}
  • Nameof C++

Overview

The following is an overview of reading and writing JSON using cpp-yyjson. See thereference for details.

JSON Reader

#include"cpp_yyjson.hpp"usingnamespaceyyjson;auto json_str =R"({    "id": 1,    "pi": 3.141592,    "name": "example",    "array": [0, 1, 2, 3, 4],    "currency": {        "USD": 129.66,        "EUR": 140.35,        "GBP": 158.72    },    "success": true})";// Read JSON stringauto val = read(json_str);// as_xxx methods return std::optional<T>auto obj = *val.as_object();// Key access to the JSON object classauto id = *obj["id"].as_int();auto pi = *obj["pi"].as_real();auto name = *obj["name"].as_string();auto success = *obj["success"].as_bool();// JSON array/object classes adapt the range conceptauto list = *obj["array"].as_array();for (constauto& v : list){// `write` returns JSON read-only string    std::cout << v.write() << std::endl;}// The range value type of object class is a key-value pairauto dict = *obj["currency"].as_object();for (constauto& [k, v] : dict){    std::cout <<"{" << k <<":" << v.write() <<"}" << std::endl;}// JSON array/object to container conversionauto numbers = cast<std::vector<int>>(list);auto currency = cast<std::map<std::string_view,double>>(dict);// Stringify read-only stringstd::cout << obj.write() << std::endl;// -> {"id":1,"pi":3.141592,"name":"example","array":[0,1,2,3,4],//     "currency":{"USD":129.66,"EUR":140.35,"GBP":158.72},"success":true}

JSON Writer

#include"cpp_yyjson.hpp"usingnamespaceyyjson;// Create a new JSON value from primitive typesauto v_null = value();// Initial value as nullauto v_bool = value(true);auto v_num = value(3.141592);auto v_str = value("example");// Create a new empty JSON arrayauto arr = array();arr.emplace_back(1);arr.emplace_back("string");// Create a new empty JSON objectauto obj = object();obj.emplace("USD",129.66);obj.emplace("date","Wed Feb 1 2023");// Conversion from range to JSON array classauto vec = std::vector{1,2,3};auto vec_nst = std::vector<std::vector<int>>{{1,2}, {3,4}};auto arr_vec = array(vec);// -> [1,2,3]auto arr_nst = array(vec_nst);// -> [[1,2],[3,4]]array arr_rng =// transformation via range adaptors    std::vector{1,2,3} | std::ranges::views::transform([](auto x) {return x * x; });// -> [1,4,9]// Conversion from key-value-like range to JSON object classauto kv_map =    std::map<std::string_view,double>{{"first",1.0}, {"second",2.0}, {"third",3.0}};auto val_map =    std::map<std::string_view, value>{{"number",1.5}, {"error",nullptr}, {"text","abc"}};auto obj_map = object(kv_map);auto obj_kv  = object(val_map);// Construction by std::initializer_listauto init_arr = array{nullptr,true,"2",3.0, {4.0,"5",false}, {{"7",8}, {"9", {0}}}};auto init_obj = object{{"id",1},                       {"pi",3.141592},                       {"name","example"},                       {"array", {0,1,2,3,4}},                       {"currency", {{"USD",129.66}, {"EUR",140.35}, {"GBP",158.72}}},                       {"success",true}};

Serialization and Deserialization

As shown above, cpp-yyjson provides conversion between JSON value/array/object classes and C++ ranges and container types recursively. In addition to that, the following additional JSON casters are available (see thereference in detail):

  • Pre-defined STL casters (e.g.,std::optional,std::variant,std::tuple (C++23 tuple-like)).
  • Conversion using compile-time reflection of struct/class if it is available.
  • Registration of field names withVISITABLE_STRUCT macro.
  • User-defined casters.

Pre-defined STL casters

// cast JSON value from/to std::optionalauto nullable = std::optional<int>(3);auto serialized = value(nullable);// serialize std::optional to JSON valueauto deserialized = cast<decltype(nullable)>(serialized);// deserialize JSON value into std::optional// cast JSON value from/to std::variantauto variant = std::variant<std::monostate,int, std::string>("example");auto serialized = value(variant);// serialize std::variant to JSON valueauto deserialized = cast<decltype(variant)>(serialized);// deserialize JSON value into std::variant// cast JSON array class from/to tuple-like array typeauto tpl_arr = std::tuple{nullptr,true,"2",3.0, std::tuple{4.0,"5",false}};auto serialized = array(tpl_arr);// serialize tuple-like array to JSON arrayauto deserialized = cast<decltype(tpl_arr)>(serialized);// deserialize JSON array into tuple-like// cast JSON object class from/to tuple-like object typestd::tuple tpl_obj = {std::pair{"number",1.5}, std::pair{"error",nullptr}, std::pair{"text","abc"}};auto serialized = object(tpl_obj);// serialize tuple-like object to JSON objectauto deserialized = cast<decltype(tpl_obj)>(serialized);// deserialize JSON object into tuple-like

Automatic casting from/to JSON object with compile-time reflection

(see thereference about available conditions)

structX{int a;    std::optional<double> b;    std::string c ="default";};// serialize struxt X to JSON object with field-name reflectionauto reflectable = X{.a =1, .b = std::nullopt, .c ="x"};auto serialized = object(visitable);// -> {"a":1,"b":null,"c":"x"}// deserialize JSON object into struct X with field-name reflectionauto deserialized = cast<X>(serialized);// -> X{.a = 1, .b = std::nullopt, .c = "x"}

Field name registration withVISITABLE_STRUCT macro:

// register fields except `c` on purposeVISITABLE_STRUCT(X, a, b);// serialize visitable struxt X to JSON objectauto visitable = X{.a =1, .b = std::nullopt, .c ="x"};auto serialized = object(visitable);// -> {"a":1,"b":null}// deserialize JSON object into struct Xauto deserialized = cast<X>(serialized);// -> X{.a = 1, .b = std::nullopt, .c = "default"}

User-define caster (see thereference in detail)

template<>structyyjson::caster<X>{// convert X to string (serialize)inlinestaticautoto_json(const X& x)    {returnfmt::format("{} {} {}", x.a, (x.b ?fmt::format("{}", *y.b) :"null"), x.c);    }};// convert struxt X to JSON string with user-defined casterauto  = X{.a =1, .b = std::nullopt, .c ="x"};auto serialized = value(visitable);// -> "1 null x"

Installation

To use cpp-yyjson, the dependent packages are required to be installed. It is convenient to usevcpkg to install the packages:

$ ./vcpkg install yyjson fmt nameof

Then add the pathinclude/cpp_yyjson.hpp to the include directory of your project.

Using CMake

To integrate cpp-yyjson into your CMake project, simply add the following:

add_subdirectory(<PATH_TO_CLONE_DIR>/cpp-yyjson${CMAKE_CURRENT_BINARY_DIR}/cpp-yyjson)target_link_libraries(${PROJECT_NAME}PRIVATE cpp_yyjson::cpp_yyjson)

If you have installed cpp-yyjson via CMake,find_package command is enabled:

find_package(cpp_yyjson CONFIG REQUIRED)target_link_libraries(${PROJECT_NAME}PRIVATE cpp_yyjson::cpp_yyjson)

Benchmark

Benchmark results are described to compare the cpp-yyjson with other prominent fast C/C++ JSON libraries:yyjson v0.6.0,simdjson v3.0.1,rapidjson #232389d, andnlohmann-json v3.9.1.

The results are obtained on Ubuntu 22.04, INTEL Core i9-12900K with all E cores and HTT disabled, compiled with GCC 12.1.0. The benchmark programs are in thetest directory.

Read performance

In each library, the following options are there for reading JSON. By using the appropriate options for your use case, the best performance can be achieved.

In-situ parsing: Modify the input JSON string during parsing. This can be used if the string is writable (and/or padded at the end) and can be discarded after parsing. Therefore, this method cannot be used for a given fixed-length read-only JSON string. Alternatively, you can copy the input string once and use in-situ parsing.
Theyyjson andsimdjson require some padding at the end of the JSON string for in-situ parsing but therapidjson does not. For the former libraries, the JSON string must be copied even if it is writable but has a fixed length. Thesimdjson has two methods for parsing, which are "DOM" and "On Demand". The "On Demand" approach seems to be faster than "DOM" but less flexible because it behaves as a forward iterator like a stream and can only receive padded JSON strings.

Single buffer: Reuse a single pre-allocated buffer or a parser object for multiple parsing. This is suitable for tasks that repeatedly read multiple JSON strings, e.g. API servers.
Theyyjson can prepare a pre-allocated buffer and the maximum required size of the buffer can be estimated from the length of the JSON string. The allocator can be given in the same way for therapidjson, but we need to clear it explicitly after parsing because the buffer will probably not be released automatically (please let me know if I make a wrong manner). For thesimdjson, the parser object is reusable to minimize the new allocation cost. Reusing string objects when copying JSON strings for in-situ and padding can also be considered a single buffer.

The benchmarks were performed on each JSON library with all possible patterns with the above options. Classified by the following keywords.

(no mark): No option.

insitu,pad: In-situ parsing is used/a padded string is input.

dom,ond_pad: "DOM" and "On Demand" parsing for thesimdjson, respectively.

single: Reuse the parsing and temporal object as much as possible.

copy: Create a copy of the input string for in-situ parsing or padded string input.

The JSON datasets are fromyyjson_benchmark. Measurements are the median time to parse and iterate all elements with 100 repetitions ongoogle benchmark. The time unit isms and the raw logs are availablehere.

The cpp-yyjson shows a very good read performance, as same as the originalyyjson. A small overhead of cpp-yyjson compared to theyyjson may be from the pointer wrapped bystd::shared_ptr.

Write performance

The write performance is measured by the time it takes to create a large array or object and output it as a JSON string. One option when creating a JSON is to make a copy of the string or not. Theyyjson and therapidjson have such as option and make a small difference in speed. The results are obtained by the size of 1,000,000 elements with 100 repetitions ongoogle benchmark. The time unit isms and the raw logs are availablehere.

The cpp-yyjson andyyjson show excellent write performance. In some cases, the cpp-yyjson performs slightly better than the originalyyjson because it implements an additionalrange-based conversion to a JSON array and object.

Reference

Namespaces

Theyyjson namespace includes the following function and classes. Typically, you will start with them for reading and writing JSON.

Function
yyjson::readRead a JSON string and return animmutable JSON document class which is alias ofyyjson::reader::value
JSON Type
yyjson::valueMutable JSON value class; alias ofyyjson::writer::value
yyjson::arrayMutable JSON array class; alias ofyyjson::writer::array
yyjson::objectMutable JSON object class; alias ofyyjson::writer::object
Allocator class
yyjson::dynamic_allocatorDynamic memory allocator wrapper, available for yyjson >= v0.8.0
yyjson::pool_allocatorFixed size memory allocator wrapper on the heap
yyjson::stack_pool_allocatorFixed size memory allocator wrapper on the stack

In internal namespaces, the cpp-yyjson provides JSON value, array, object, reference, and iterator classes. Each internalyyjson::reader andyyjson::writer namespace definesimmutable andmutable JSON classes, respectively. Although you rarely need to be aware of the classes provided in the internal namespaces, thereference classes are noted here.

The JSON value, array, and object classes have the correspondingreference (only formutable classes) andconst reference versions of them as shown later, such asvalue_ref,const_value_ref,array_ref,const_array_ref, and so on. Thereference classes have member functions with almost the same signature as the normal versions. The difference between a normalvalue class and a[const_]value_ref class is whether they have their data ownership or not. The(const) reference JSON classes appear in return types of member functions of the JSON classes. This is to maximize performance by avoiding copying.

Note

Thereference class refers to data in the owner, so its lifetime should be noted.

Immutable JSON classes

Immutable JSON classes defined inyyjson::reader namespace are derived from theyyjson::read function that reads a JSON text string. It may not be necessary to use these classes directly.

yyjson::read

Read a JSON string and return animmutable JSON value.

See the reference of yyjson for the information onreader flags.

yyjson::reader::valueread(std::string_view json_string, [std::size_t len,] [Allocator alc,] ReadFlag = ReadFlag::NoFlag);yyjson::reader::valueread(const std::string& json_string, [std::size_t len,] [Allocator alc,] ReadFlag = ReadFlag::NoFlag);yyjson::reader::valueread(constchar* json_string, [std::size_t len,] [Allocator alc,] ReadFlag = ReadFlag::NoFlag);yyjson::reader::valueread(std::string& json_string, [std::size_t len,] [Allocator alc,] ReadFlag = ReadFlag::NoFlag);yyjson::reader::valueread(char* json_string, [std::size_t len,] [Allocator alc,] ReadFlag = ReadFlag::NoFlag);enumclassyyjson::ReadFlag : yyjson_read_flag{    NoFlag = YYJSON_READ_NOFLAG,    ReadInsitu = YYJSON_READ_INSITU,    AllowTrailingCommas = YYJSON_READ_ALLOW_TRAILING_COMMAS,    AllowComments = YYJSON_READ_ALLOW_COMMENTS,    AllowInfAndNan = YYJSON_READ_ALLOW_INF_AND_NAN,    NumberAsRaw = YYJSON_READ_NUMBER_AS_RAW,    AllowInvalidUnicode = YYJSON_READ_ALLOW_INVALID_UNICODE,    BignumAsRaw = YYJSON_READ_BIGNUM_AS_RAW// for yyjson >= v0.7.0};

Theread function takes a JSON string and returns an immutable JSON value. The function argument may optionally specify a string length and an allocator to be describedlater. Otherwise, the length of the JSON string is determined and the yyjson default allocator is used.

If the read option has theReadInsitu flag, You must specify the JSON string as writable (std::string& orchar*) and its length. This writable string must be padded at leastYYJSON_PADDING_SIZE bytes to the end. The length of the JSON string should be unpadded.

yyjson::reader::value

The immutable JSON value class is returned fromyyjson::read function.

Constructor

yyjson::reader::value() = delete;yyjson::reader::value(const yyjson::reader::value&) = default;yyjson::reader::value(yyjson::reader::value&&) = default;

Member function

// Check the type of JSONboolis_null()const;// nullboolis_true()const;// trueboolis_false()const;// falseboolis_bool()const;// boolboolis_uint()const;// std::uint64_tboolis_sint()const;// std::int64_tboolis_int()const;// std::uint64_t/std::int64_tboolis_real()const;// doubleboolis_num()const;// std::uint64_t/std::int64_t/doubleboolis_string()const;// stringboolis_array()const;// arrayboolis_object()const;// objectboolis_container()const;// array/object// Get the content of the JSON valuestd::optional<std::nullptr_t>as_null()const;std::optional<bool>as_bool()const;std::optional<std::uint64_t>as_uint()const;std::optional<std::int64_t>as_sint()const;std::optional<std::int64_t>as_int()const;std::optional<double>as_real()const;std::optional<double>as_num()const;std::optional<std::string_view>as_string()const&;std::optional<std::string>as_string() &&;std::optional<yyjson::reader::const_array_ref>as_array()const&;std::optional<yyjson::reader::array>as_array() &&;std::optional<yyjson::reader::const_object_ref>as_object()const&;std::optional<yyjson::reader::object>as_object() &&;// Casttemplate<typename T>T cast<T>()const;template<typename T>explicitoperatorT()const;// Output JSON stringyyjson::json_stringwrite(WriteFlag write_flag = WriteFlag::NoFlag)const;template<yyjson_allocator Allocator>yyjson::json_stringwrite(Allocator alc, WriteFlag write_flag = WriteFlag::NoFlag)const;enumclassyyjson::WriteFlag : yyjson_write_flag{    NoFlag = YYJSON_WRITE_NOFLAG,    Pretty = YYJSON_WRITE_PRETTY,    EscapeUnicode = YYJSON_WRITE_ESCAPE_UNICODE,    EscapeSlashes = YYJSON_WRITE_ESCAPE_SLASHES,    AllowInfAndNan = YYJSON_WRITE_ALLOW_INF_AND_NAN,    InfAndNanAsNull = YYJSON_WRITE_INF_AND_NAN_AS_NULL,    AllowInvalidUnicode = YYJSON_WRITE_ALLOW_INVALID_UNICODE,    PrettyTwoSpaces = YYJSON_WRITE_PRETTY_TWO_SPACES// for yyjson >= v0.7.0};

Thewrite function returns a read-only string which is inherited fromstd::string_view.

See the reference of yyjson for the information onwriter flags.

Example

See alsoOverview.

usingnamespaceyyjson;std::string_view json_str =R"({    "id": 1,    "pi": 3.141592,    "emoji": "🫠",    "array": [0, 1, 2, 3, 4],    "currency": {        "USD": 129.66,        "EUR": 140.35,        "GBP": 158.72    },    "success": true})";auto val = read(json_str);std::cout << val.write(WriteFlag::Pretty) << std::endl;// {//     "id": 1,//     "pi": 3.141592,//     "emoji": "🫠",//     "array": [//         0,//         1,//         2,//         3,//         4//     ],//     "currency": {//         "USD": 129.66,//         "EUR": 140.35,//         "GBP": 158.72//     },//     "success": true// }

yyjson::reader::array,yyjson::reader::const_array_ref

The immutable JSON array class is created by thevalue::as_array member function. This class adaptsstd::ranges::input_range concept.

Constructor

yyjson::reader::array() = delete;yyjson::reader::array(const yyjson::reader::array&) = default;yyjson::reader::array(yyjson::reader::array&&) = default;yyjson::reader::array(const yyjson::reader::value&);yyjson::reader::array(yyjson::reader::value&&);yyjson::reader::const_array_ref() = delete;yyjson::reader::const_array_ref(const yyjson::reader::const_array_ref&) = default;yyjson::reader::const_array_ref(yyjson::reader::const_array_ref&&) = default;

Member function

// STL-like functionsyyjson::reader::const_array_itercbegin()const;yyjson::reader::const_array_iterbegin()const;yyjson::reader::const_array_itercend()const;yyjson::reader::const_array_iterend()const;yyjson::reader::const_value_reffront()const;yyjson::reader::const_value_refback()const;yyjson::reader::const_value_refoperator[](std::size_t)const;std::size_tsize()const;boolempty()const;// Casttemplate<typename T>T cast<T>()const;template<typename T>explicitoperatorT()const;// Output JSON string (inherited)yyjson::json_stringwrite(WriteFlag write_flag = WriteFlag::NoFlag)const;template<yyjson_allocator Allocator>yyjson::json_stringwrite(Allocator alc, WriteFlag write_flag = WriteFlag::NoFlag)const;// Range conceptstd::ranges::iterator_t<yyjson::reader::const_array_ref> -> yyjson::reader::const_array_iterstd::ranges::range_value_t<yyjson::reader::const_array_ref> -> yyjson::reader::const_value_ref

Example

See alsoOverview.

usingnamespaceyyjson;std::string_view json_str =R"([0, "1", 2.0])";auto val = read(json_str);assert(val.is_array());// NOTE: Prior to C++23 (P2644R1), range-based for loop for temporal std::optional// instance requires initializer because std::optional<T>::value() returns T&&.// for (const auto& v : *val.as_array()) { ... }             // 💀 UBfor (constauto arr = *val.as_array();constauto& v : arr)// ✅ OK{    std::cout << v.write() << std::endl;}// 0// "1"// 2.0

yyjson::reader::object,yyjson::reader::const_object_ref

The immutable JSON object class is created by thevalue::as_object member function. This class adaptsstd::ranges::input_range concept.

Constructor

yyjson::reader::object() = delete;yyjson::reader::object(const yyjson::reader::object&) = default;yyjson::reader::object(yyjson::reader::object&&) = default;yyjson::reader::object(const yyjson::reader::value&);yyjson::reader::object(yyjson::reader::value&&);yyjson::reader::const_object_ref() = delete;yyjson::reader::const_object_ref(const yyjson::reader::const_object_ref&) = default;yyjson::reader::const_object_ref(yyjson::reader::const_object_ref&&) = default;

Member function

// STL-like functionsyyjson::reader::const_object_itercbegin()const;yyjson::reader::const_object_iterbegin()const;yyjson::reader::const_object_itercend()const;yyjson::reader::const_object_iterend()const;yyjson::reader::const_object_iterfind(std::string_view key)const;// Note: O(N)yyjson::reader::const_value_refoperator[](std::string_view key)const;// Note: O(N)std::size_tsize()const;boolempty()const;boolcontains(std::string_view key)const;// Note: O(N)// Casttemplate<typename T>T cast<T>()const;template<typename T>explicitoperatorT()const;// Output JSON string (inherited)yyjson::json_stringwrite(WriteFlag write_flag = WriteFlag::NoFlag)const;template<yyjson_allocator Allocator>yyjson::json_stringwrite(Allocator alc, WriteFlag write_flag = WriteFlag::NoFlag)const;// Range conceptusing yyjson::reader::const_key_value_ref_pair = std::pair<std::string_view, yyjson::reader::const_value_ref>;std::ranges::iterator_t<yyjson::reader::const_object_ref> -> yyjson::reader::const_object_iterstd::ranges::range_value_t<yyjson::reader::const_object_ref> -> yyjson::reader::const_key_value_ref_pair

Example

See alsoOverview.

usingnamespaceyyjson;std::string_view json_str =R"({"USD": 129.66, "EUR": 140.35, "GBP": 158.72})";auto val = read(json_str);assert(val.is_object());auto obj = *val.as_object();std::cout << *obj["USD"].as_real() << std::endl;std::cout << *obj["EUR"].as_real() << std::endl;std::cout << *obj["GBP"].as_real() << std::endl;// 129.66// 140.35// 158.72

Mutable JSON classes

Mutable JSON classes are defined inyyjson::writer namespace. The following user-constructible classes are exported in the topyyjson namespace,

using yyjson::value = yyjson::writer::value;using yyjson::array = yyjson::writer::array;using yyjson::object = yyjson::writer::object;

yyjson::value

The mutable JSON value classyyjson::value constructs JSON values such asnull,bool,number,string,array, andobject.

Constructor

// Concepts (not defined in the library, but described for explanation)template<typename T>conceptvalue_constructible = std::constructible_from<yyjson::value, T>;template<typename T>conceptarray_constructible = std::ranges::input_range<T> && value_constructible<std::ranges::range_value_t<T>>;template<typename T>conceptobject_constructible = std::ranges::input_range<T> && key_value_like<std::ranges::range_value_t<T>> &&                               value_constructible<std::tuple_element_t<1, std::ranges::range_value_t<T>>>;// Conversion to primitive typesyyjson::value(std::nullptr_t);yyjson::value(bool);yyjson::value(std::unsigned_integral);yyjson::value(std::signed_integral);yyjson::value(std::floating_point);yyjson::value(const std::string&, [yyjson::copy_string_t]);yyjson::value(std::string_view, [yyjson::copy_string_t]);yyjson::value(constchar*, [yyjson::copy_string_t]);// Conversion to array typestemplate<array_constructible T>yyjson::value(T&&, [yyjson::copy_string_t]);// Conversion to object typestemplate<object_constructible T>yyjson::value(T&&, [yyjson::copy_string_t]);// std::initializer_listyyjson::value(std::initialize_list<yyjson::value>);yyjson::value(std::initialize_list<yyjson::writer::key_value_pair>, [yyjson::copy_string_t]);// Copy from other JSON classesusing reference_types = yyjson::{reader,writer}::[const_]{value,array,object}[_ref];yyjson::value(const reference_types&);yyjson::value(reference_types&);yyjson::value(reference_types&&);// Default constructor (null by default)yyjson::value();// Copy constructoryyjson::value(const yyjson::value&) = default;yyjson::value(yyjson::value&&) = default;

Member function

// Check the type of JSONboolis_null()const;// nullboolis_true()const;// trueboolis_false()const;// falseboolis_bool()const;// boolboolis_uint()const;// std::uint64_tboolis_sint()const;// std::int64_tboolis_int()const;// std::uint64_t/std::int64_tboolis_real()const;// doubleboolis_num()const;// std::uint64_t/std::int64_t/doubleboolis_string()const;// stringboolis_array()const;// arrayboolis_object()const;// objectboolis_container()const;// array/object// Get the content of the JSON valuestd::optional<std::nullptr_t>as_null()const;std::optional<bool>as_bool()const;std::optional<std::uint64_t>as_uint()const;std::optional<std::int64_t>as_sint()const;std::optional<std::int64_t>as_int()const;std::optional<double>as_real()const;std::optional<double>as_num()const;std::optional<std::string_view>as_string()const;std::optional<yyjson::writer::const_array_ref>as_array()const&;std::optional<yyjson::writer::array_ref>as_array() &;std::optional<yyjson::writer::array>as_array() &&;std::optional<yyjson::writer::const_object_ref>as_object()const&;std::optional<yyjson::writer::object_ref>as_object() &;std::optional<yyjson::writer::object>as_object() &&;// operator=yyjson::value& yyjson::value::operator=(const yyjson::value&);yyjson::value& yyjson::value::operator=(yyjson::value&&)noexcept;template<value_constructible T>yyjson::value& yyjson::value::operator=(T&&);template<value_constructible T>yyjson::value& yyjson::value::operator=(pair_like<T, yyjson::copy_string_t>);// Casttemplate<typename T>T cast<T>()const;template<typename T>explicitoperatorT()const;// Output JSON stringyyjson::json_stringwrite(WriteFlag write_flag = WriteFlag::NoFlag)const;template<yyjson_allocator Allocator>yyjson::json_stringwrite(Allocator alc, WriteFlag write_flag = WriteFlag::NoFlag)const;

Conceptsvalue_constructible,array_constructible, andobject_constructible areNOT defined in the library but are described in the above for explanation hereafter.

Since yyjson does not copy (but refer) strings to JSON documents by default, it is possible to explicitly specify that strings will be copied to JSON by giving the tag type valueyyjson::copy_string as the second argument to the constructor. For safety, the implicit copy occurs whenstd::string&& is converted to the JSON string without specifyingyyjson::copy_string.

JSON arrays and objects are constructed recursively from ranges as long as therange's value type can be constructed to JSON value. Theyyjson::copy_string is also passed recursively if it is given. The same manner applies to the other functions of mutable JSON classes.

Example

See alsoOverview.

usingnamespaceyyjson;usingnamespacestd::literals;// Conversion constructorsauto v_bool = value(true);auto v_null = value(nullptr);auto v_int = value(-1);auto v_real = value(3.14);// String typesauto strlit ="string literal";auto stdstr ="string example"s;auto strviw = std::string_view(stdstr);// Explicit copyauto v_lit_cp = value(strlit, copy_string);auto v_str_cp = value(stdstr, copy_string);auto v_viw_cp = value(strviw, copy_string);// No copy: the life time of a string must be managedauto v_lit = value(strlit);auto v_str = value(stdstr);auto v_viw = value(strviw);// If the original string is modified, the uncopied JSON string seems to be also modified.// (but string length is not changed; it may occur memory access violation)stdstr ="modified string";std::cout << v_str_cp.write() << std::endl;// "string example"std::cout << v_str.write() << std::endl;// "modified strin"// Implicitly copy string if the argument type is `std::string&&` for safetyauto v_str_cp = value(std::move(stdstr));

yyjson::array

The mutable JSON array class is created by therange of JSON value constructible or theyyjson::value::as_array member function. This class adaptsstd::ranges::input_range concept.

Constructor

// Conversion from rangetemplate<array_constructible T>yyjson::array(array_constructible, [yyjson::copy_string]);// std::initializer_listyyjson::array(std::initialize_list<value>);// Copy from other JSON classes// throw yyjson::bad_cast if the JSON value is not convertible to a JSON arrayusing reference_types = yyjson::{reader,writer}::[const_]{value,array}[_ref];yyjson::array(const reference_types&);yyjson::array(reference_types&);yyjson::array(reference_types&&);// Default constructor (empty by default)yyjson::array();// Copy constructoryyjson::array(const yyjson::array&) = default;yyjson::array(yyjson::array&&) = default;

Member function

// STL-like functionsconst_array_itercbegin()const;const_array_itercend()const;const_array_iterbegin()const;const_array_iterend()const;array_iterbegin();array_iterend();yyjson::writer::const_value_reffront()const;yyjson::writer::value_reffront();yyjson::writer::const_value_refback()const;yyjson::writer::value_refback();yyjson::writer::const_value_refoperator[](std::size_t)const;// Note: O(N)yyjson::writer::value_refoperator[](std::size_t);// Note: O(N)std::size_tsize()const;boolempty()const;voiderase(std::size_t);voidclear();// Insert value_constructibletemplate<value_constructible T>array_iteremplace_back(T&&, [yyjson::copy_string_t]);template<value_constructible T>array_iteremplace_front(T&&, [yyjson::copy_string_t]);template<value_constructible T>array_iteremplace(std::size_t, T&&, [yyjson::copy_string_t]);// Note: O(N)// Insert empty array/objectyyjson::writer::array_refemplace_back(yyjson::empty_array_t);yyjson::writer::object_refemplace_back(yyjson::empty_object_t);yyjson::writer::array_refemplace_front(yyjson::empty_array_t);yyjson::writer::object_refemplace_front(yyjson::empty_object_t);yyjson::writer::array_refemplace(std::size_t, yyjson::empty_array_t);// Note: O(N)yyjson::writer::object_refemplace(std::size_t, yyjson::empty_object_t);// Note: O(N)// operator=yyjson::array&operator=(const yyjson::array&);yyjson::array&operator=(yyjson::array&&)noexcept;template<array_constructible T>yyjson::array&operator=(T&&);template<array_constructible T>yyjson::array&operator=(pair_like<T, yyjson::copy_string_t>);// Casttemplate<typename T>T cast<T>()const;template<typename T>explicitoperatorT()const;// Output JSON stringyyjson::json_stringwrite(WriteFlag write_flag = WriteFlag::NoFlag)const;template<yyjson_allocator Allocator>yyjson::json_stringwrite(Allocator alc, WriteFlag write_flag = WriteFlag::NoFlag)const;// Range conceptstd::ranges::range_value_t<yyjson::array&>       -> yyjson::writer::value_refstd::ranges::range_value_t<const yyjson::array&> -> yyjson::writer::const_value_ref

Theyyjson::array is designed to be implemented like STL containers but extended to allow easy insertion of an empty array and object withyyjson::empty_array andyyjson::empty_object tag type values, respectively. These special modifiers also have a different return type, which is not an array iterator but a reference to a newly inserted empty array/object of typeyyjson::writer::array_ref oryyjson::writer::object_ref. These are introduced to optimize the performance by not creating a new JSON array/object; see also theperformance best practices section.

Iterator classes are not exposed. They are tentatively described asarray_iter andconst_array_iter in the above.

Example

See alsoOverview.

usingnamespaceyyjson;// Create a new mutable JSON array from rangeauto arr = array(std::vector{1,2,3});// Insert a new valuearr.emplace_back("4");// Insert an empty array and insert values into itauto nested = arr.emplace_back(empty_array);nested.emplace_back(5.0);nested.emplace_back("6");nested.emplace_back(7);std::cout << arr.write() << std::endl;// [1,2,3,"4",[5.0,"6",7]]// Range-based for loopfor (auto&& v : arr){if (v.is_int()) v = *v.as_int() *2;}std::cout << arr.write() << std::endl;// [2,4,6,"4",[5.0,"6",7]]

yyjson::object

The mutable JSON object class is created by thekey-value range of JSON value constructible or theyyjson::value::as_object member function. This class adaptsstd::ranges::input_range concept.

Constructor

// Conversion from key-value-like rangetemplate<object_constructible T>yyjson::object(object_constructible, [yyjson::copy_string]);// std::initializer_listyyjson::object(std::initialize_list<yyjson::writer::key_value_pair>);// Copy from other JSON classes// throw yyjson::bad_cast if the JSON value is not convertible to a JSON objectusing reference_types = yyjson::{reader,writer}::[const_]{value,object}[_ref];yyjson::object(const reference_types&);yyjson::object(reference_types&);yyjson::object(reference_types&&);// Default constructor (empty by default)yyjson::object();// Copy constructoryyjson::object(const yyjson::object&) = default;yyjson::object(yyjson::object&&) = default;

Member function

// STL-like functionsconst_object_itercbegin()const;const_object_itercend()const;const_object_iterbegin()const;const_object_iterend()const;const_object_iterfind(std::string_view key)const;// Note: O(N)object_iterbegin();object_iterend();object_iterfind(std::string_view key);// Note: O(N)std::size_tsize()const;boolempty()const;voiderase(std::string_view);voidclear();boolcontains(std::string_view key)const;// Note: O(N)// Insert value_constructible, no duplicate checktemplate<value_constructible ValueType>object_iteremplace(KeyType&&, ValueType&&, [yyjson::copy_string_t]);// Note: O(N), throw std::out_of_range if a key is not foundyyjson::writer::const_value_refoperator[](std::string_view)const;// Note: O(N), construct default value if a key is not foundyyjson::writer::value_refoperator[](std::string_view);// Insert empty array/objectyyjson::writer::array_refemplace(KeyType&&, yyjson::empty_array_t,  [yyjson::copy_string_t]);yyjson::writer::object_refemplace(KeyType&&, yyjson::empty_object_t, [yyjson::copy_string_t]);// Try emplace, O(N) for duplicate checktemplate<value_constructible ValueType>std::pair<object_iter,bool>try_emplace(KeyType&&, ValueType&&, [yyjson::copy_string_t]);// operator=yyjson::object&operator=(const yyjson::object&);yyjson::object&operator=(yyjson::object&&)noexcept;template<object_constructible T>yyjson::object&operator=(T&&);template<object_constructible T>yyjson::object&operator=(pair_like<T, yyjson::copy_string_t>);// Casttemplate<typename T>T cast<T>()const;template<typename T>explicitoperatorT()const;// Output JSON stringyyjson::json_stringwrite(WriteFlag write_flag = WriteFlag::NoFlag)const;template<yyjson_allocator Allocator>yyjson::json_stringwrite(Allocator alc, WriteFlag write_flag = WriteFlag::NoFlag)const;// Range conceptusing yyjson::writer::key_value_ref_pair = std::pair<std::string_view, yyjson::reader::value_ref>;using yyjson::writer::const_key_value_ref_pair = std::pair<std::string_view, yyjson::reader::const_value_ref>;std::ranges::range_value_t<yyjson::object&>       -> yyjson::writer::key_value_ref_pairstd::ranges::range_value_t<const yyjson::object&> -> yyjson::writer::const_key_value_ref_pair

Theyyjson::object is also designed to be implemented like STL map containers and to allow easy insertion of an empty array and object withyyjson::empty_array andyyjson::empty_object tag type values, respectively. These special modifiers also have a different return type, which is not an object iterator but a reference to a newly inserted empty array/object of typeyyjson::writer::array_ref oryyjson::writer::object_ref. These are introduced to optimize the performance by not creating a new JSON array/object; see also theperformance best practices section.

Iterator classes are not exposed. They are tentatively described asobejct_iter andconst_object_iter in the above.

Note

Theemplace member functions doNOT check for key duplication.

Example

See alsoOverview.

usingnamespaceyyjson;// Create a new mutable JSON object from a key-value-like rangeauto obj = object(std::map<std::string, std::map<std::string,int>>{{"key0", {{"a",0}, {"b",1}}},                                                                    {"key1", {{"c",2}, {"d",3}}}});// Insert a new key-value pairobj.emplace("key2", std::vector{4,5});// Insert an empty object and insert key-value pairs into itauto nested = obj.emplace("key3", empty_object);nested.emplace("g",6);nested.emplace("h",7);std::cout << obj.write() << std::endl;// {"key0":{"a":0,"b":1},"key1":{"c":2,"d":3},"key2":[4,5],"key3":{"g":6,"h":7}}// Key access and modifyobj["key2"] = std::map<std::string,int>{{"e",4}, {"f",5}};std::cout << obj.write() << std::endl;// {"key0":{"a":0,"b":1},"key1":{"c":2,"d":3},"key2":{"e":4,"f":5},"key3":{"e":6,"f":7}}

Allocator classes

This library provides the following memory allocator wrappers for reading and writing JSON strings. They are useful to improve performance for tasks that parse or stringify multiple JSON strings to avoid multiple memory allocations and deallocations.

yyjson::dynamic_allocator

This is a smart pointer wrapper for the dynamic allocator of yyjson. The lifetime of the allocator's internal smart pointer will be tied to JSON objects and strings created byread/write (member) functions, respectively. This allocator is for general purposes since it can automatically expand the buffer.

Note

This allocator is only available for yyjson >= v0.8.0.

Constructor

// Default constructorsdynamic_allocator() = default;dynamic_allocator(const dynamic_allocator&) = default;dynamic_allocator(dynamic_allocator&&)noexcept = default;

Member function

// Reset to a new dynamic allocatorvoidreset()const;

Example

usingnamespaceyyjson;auto alc = dynamic_allocator();// Read JSON string using dynamic allocatorautoread_json(const string& json){returnread(json, alc);}// Create JSON string using dynamic allocatorautowrite_json(constauto& json){return json.write(alc);}

yyjson::pool_allocator

This is a smart pointer wrapper for the fixed-size memory allocator of yyjson. The lifetime of the allocator's internal smart pointer will be tied to JSON objects and strings created byread/write (member) functions, respectively. This allocator is useful when the required memory size is known; for reading JSON strings. Since the buffer size is fixed, theread function using the single buffer would be faster than the dynamic allocator.

If the free space of the buffer is not large enough, theread orwrite (member) function will throw an exception. Thereset function re-creates the buffer with the specified size and thereserve function can be used to expand the buffer size to be required.

Constructor

// Default constructorspool_allocator() = default;pool_allocator(const pool_allocator&) = default;pool_allocator(pool_allocator&&)noexcept = default;// Allocate specified bytes of bufferexplicitpool_allocator(std::size_t size_byte);// Allocate a buffer large enough to read the specified JSON string with read flagsexplicitpool_allocator(std::string_view json, ReadFlag flag = ReadFlag::NoFlag);

Member function

// Return the buffer sizestd::size_tsize()const;// Reset to a new fixed size allocatorvoidreset(std::size_t size_byte =0);voidreset(std::string_view json, ReadFlag flag = ReadFlag::NoFlag);// Expand the buffer to required sizevoidreserve(std::size_t size_byte);voidreserve(std::string_view json, ReadFlag flag = ReadFlag::NoFlag);// Check if the buffer, when empty, is large enough to read the specified JSON string with read flagsboolcheck_capacity(std::string_view json, ReadFlag = ReadFlag::NoFlag)const;

Example

usingnamespaceyyjson;// Create a single buffer allocatorauto alc = pool_allocator();// Read JSON string using pool allocator multiple timesfor (constauto& json : json_strings){// Expand the buffer required to read JSON string    alc.reserve(json);auto val =read(json, alc);// ...}
yyjson::stack_pool_allocator<std::size_t Byte>

This allocator is a fixed-size and stack-allocated buffer. The buffer size is specified by the template parameter and thus the buffer size cannot be changed. The required buffer size must be known in advance.

Note

The lifetime ofstack_pool_allocator is not managed automatically unlike other allocators. Not to destroy the allocator while an instance of the JSON object/string is in use.

Constructor

// Default constructorsstack_pool_allocator() = default;stack_pool_allocator(const stack_pool_allocator&) = default;stack_pool_allocator(stack_pool_allocator&&)noexcept = default;

Member function

// Return the buffer sizeconstexpr std::size_tsize()const;// Reset to a new fixed size allocatorvoidreset();// Check if the buffer, when empty, is large enough to read the specified JSON string with read flagsboolcheck_capacity(std::string_view json, ReadFlag = ReadFlag::NoFlag)const

Serialize and deserialize JSON

In the cpp-yyjson, conversion from C++ objects to JSON values is very flexible and vice versa.

Conversion to JSON values, arrays, and objects is provided by their respective constructors. Conversely, to convert from a JSON value, call theyyjson::cast function orstatic_cast.

usingnamespaceyyjson;auto val = value(3);// -> 3auto num = cast<int>(val);// -> 3auto arr = array(std::vector<std::vector<int>>{{1,2}, {3,4}});// -> [[1, 2], [3, 4]]auto vec = cast<std::vector<std::vector<int>>>(arr);// -> {{1, 2}, {3, 4}}auto obj = object(std::unordered_map<std::string,double>{{"first",1.5}, {"second",2.5}, {"third",3.5}});// -> {"first": 1.5, "second": 2.5, "third": 3.5}auto map = cast<std::unordered_map<std::string,double>>(obj);// -> {{"first", 1.5}, {"second", 2.5}, {"third", 3.5}}

If the conversion fails, theyyjson::bad_cast exception is thrown or a compile error occurs.

Note that thecast function andstatic_cast may give a different result. Thecast function tries to convert JSON directly to a given type, whilestatic_cast follows the C++ conversion rules. For example,cast<std::optional<int>>(value(nullptr)) succeeds butstatic_cast<std::optional<int>>(value(nullptr)) does not. This is becausestd::optional<int> has a conversion constructor fromint, butvalue(nullptr) cannot be converted toint.

In addition to the above, the following four methods are provided for convertingarbitrary C++ types from/to JSON value, array and object:

  1. Pre-defined STL casters.
  2. Conversion using compile-time reflection.
  3. Registration of field names withVISITABLE_STRUCT macro.
  4. User-defined casters.

Pre-defined STL casters

Several casters from/to STL classes to JSON are pre-defined in the library for convenience. Currently, available STL types are as follows:

  • std::optional
  • std::variant
  • std::tuple-like
  • std::vector<bool> (specialized)

For example, if you receive elements of multiple types, casts from/tostd::optional orstd::variant are useful.

usingnamespaceyyjson;auto val = value(std::optional<int>(3));// serialize// -> 3auto num = cast<std::optional<int>>(val);// deserialize// -> 3auto val = value(std::optional<int>(std::nullopt));// serialize// -> nullauto num = cast<std::optional<int>>(val);// deserialize// -> std::nulloptauto val = value(std::variant<std::monostate,int, std::string>());// serialize// -> nullauto var = cast<std::variant<std::monostate,int, std::string>>(val);// deserialize// -> std::monostate()auto val = value(std::variant<std::monostate,int, std::string>(1));// serialize// -> 1auto var = cast<std::variant<std::monostate,int, std::string>>(val);// deserialize// -> 1auto val = value(std::variant<std::monostate,int, std::string>("a"));// serialize// -> "a"auto var = cast<std::variant<std::monostate,int, std::string>>(val);// deserialize// -> "a"

For a multi-type JSON array or object, using the caster forstd::tuple is valuable and efficient.

usingnamespaceyyjson;auto tpl_arr = std::tuple{nullptr,true,"2",3.0, std::tuple{4.0,"5",false}};auto json_arr = array(tpl_arr);// serialize// -> [null, true, "2", 3.0, [4.0, "5", false]]auto tpl_arr2 = cast<decltype(tpl_arr)>(arr);// deserialize// -> {nullptr, true, "2", 3.0, {4.0, "5", false}}auto tpl_obj = std::tuple{std::pair{"number",1.5}, std::pair{"error",nullptr}, std::pair{"text","abc"}};auto json_obj = object(tpl_obj);// serialize// -> {"number": 1.5, "error": null, "text": "abc"}auto tpl_obj2 = cast<decltype(tpl_obj)>(json_obj);// deserialize// -> {{"number", 1.5}, {"error", nullptr}, {"text", "abc"}}

Automatic casting with compile-time reflection

The compile-time reflection is supported to automatically convert C++ struct/class to JSON object and vice versa. This feature is provided by usingfield-reflection and is included in this library.

If a C++ struct/class satisfies thefield_reflection::field_namable concept (seefield-reflection), it is possible to automatically convert from/to JSON objects with its field names and no need to write a caster definition or registration of field names with macros explained later.

In practice, the following conditions are required for C++ types for automatic conversion:

  • default initializable
  • aggregate type
  • not a derived class
  • no reference member

Example:

usingnamespaceyyjson;structX{int a;    std::optional<double> b;    std::string c ="default";};// serialize struxt X to JSON object with field-name reflectionauto reflectable = X{.a =1, .b = std::nullopt, .c ="x"};auto serialized = object(visitable);// -> {"a":1,"b":null,"c":"x"}// deserialize JSON object into struct X with field-name reflectionauto deserialized = cast<X>(serialized);// -> X{.a = 1, .b = std::nullopt, .c = "x"}

Registration of field names of struct/class

Even if the compile-time reflection isNOT available for a C++ type or you want to partially select the fields to be converted, it is possible to register the field names of the C++ type with theVISITABLE_STRUCT macro:

// register fields except `c` on purposeVISITABLE_STRUCT(X, a, b);// serialize visitable struxt X to JSON objectauto visitable = X{.a =1, .b = std::nullopt, .c ="x"};auto serialized = object(visitable);// -> {"a":1,"b":null}// deserialize JSON object into struct Xauto deserialized = cast<X>(serialized);// -> X{.a = 1, .b = std::nullopt, .c = "default"}

User-defined casters

The most flexible way to convert C++ types to/from JSON is to define custom casters. The custom conversion always has the highest priority among the other conversions. To define a custom caster, specialize theyyjson::caster struct template and implement thefrom_json and/orto_json template functions.

The example implementation of thefrom_json template function is as follows:

template<>structyyjson::caster<X>{template<typename Json>static Xfrom_json(const Json& json)    {if (constauto obj = json.as_object(); obj.has_value())        {auto result =X();for (constauto& kv : *obj)            {if (kv.first =="a")                    result.a = yyjson::cast<decltype(result.a)>(kv.second);elseif (kv.first =="b")                    result.b = yyjson::cast<decltype(result.b)>(kv.second);elseif (kv.first =="c")                    result.c = yyjson::cast<decltype(result.c)>(kv.second);            }return result;        }throwbad_cast(fmt::format("{} is not constructible from JSON",NAMEOF_TYPE(X)));    }};

Thefrom_json template function has a JSON value as an argument template and must return typeX.

For theto_json function, there are two ways. The first way is to define atranslator for avalue_constructible type and return it. The return type must bevalue_constructible:

template<>structyyjson::caster<X>{template<typename... Ts>staticautoto_json(const X& x, Ts...)    {// Convert X object to JSON stringreturnfmt::format("{} {} {}", x.a, (x.b ?fmt::format("{}", *x.b) :"null"), x.c);    }};

Theto_json function takes acopy_string in the last argument, but this can be ignored if not needed.

The second way is to create a JSON value/array/object directly in theto_json function. The example for the classX equivalent to automatic casting orVISITABLE_STRUCT registration is as follows.

template<>structyyjson::caster<X>{template<typename... Ts>staticvoidto_json(writer::object_ref& obj,const X& x, Ts... ts)    {        obj.emplace("a", x.a, ts...);        obj.emplace("b", x.b, ts...);        obj.emplace("c", x.c, ts...);    }};

The first argument type is a target JSON class to create. There are 3 options,writer::object_ref&,writer::array_ref& andwriter::value_ref&; if you want to convert the classX to JSON array, the first argument should bewriter::array_ref&.

The casters are applied recursively to convert from/to JSON classes including custom casters. It is not always necessary to implement bothfrom_json andto_json functions, and the two conversions do not have to be symmetric.

Performance best practices

Creating a newyyjson::value,yyjson::array, oryyjson::object is expensive. This is one point we should be aware of when building JSON to maximize performance.

(1) JSON array/object construction

Although JSON arrays and objects can be constructed fromstd::initializer_list<value>, which is useful and intuitive, usingstd::tuple andstd::pair is more efficient as it avoids the construction ofyyjson::value. The drawback is that you have to write the type in every bracket.

usingnamespaceyyjson;// 🙁 Construction from std::initializer_list is costlyobject json = {{"id",1},               {"pi",3.141592},               {"name","example"},               {"array", {0,1,2,3,4}},               {"currency", {{"USD",129.66}, {"EUR",140.35}, {"GBP",158.72}}},               {"success",true}};// 🙄 Construction from std::tuple is efficient, but it seems tedious to have to write the type every time.object json = std::tuple{std::pair{"id",1},                         std::pair{"pi",3.141592},                         std::pair{"name","example"},                         std::pair{"array", std::tuple{0,1,2,3,4}},                         std::pair{"currency", std::tuple{std::pair{"USD",129.66}, std::pair{"EUR",140.35},                                                          std::pair{"GBP",158.72}}},                         std::pair{"success",true}};

(2) JSON array/object insertion

When creating a nested JSON array or object, it is more efficient to insert an empty array/object rather than to construct a new array/object.

usingnamespaceyyjson;auto obj = object();// 🙁 Create a new object and insert itauto nested = object();obj.emplace("currency", nested);// 😀 Insert an empty object and use returned object referenceauto nested = obj.emplace("currency", empty_object);nested.emplace("USD",129.66);nested.emplace("EUR",140.35);nested.emplace("GBP",158.72);

(3) Multi-threaded JSON construction

On the other hand, creating a new array/object may be useful for the multi-threaded construction of large JSON. The following example creates a 1000x1000000 JSON array with 4 threads usingBS::thread_pool. In this example, a speedup of about 3x compared to single threading was measured.

#include"BS_thread_pool.hpp"usingnamespaceyyjson;auto nums = std::vector<double>(1000000);std::iota(nums.begin(), nums.end(), 0);// Multi-threaded construction of 1000x1000000 JSON arrayauto tp = BS::thread_pool(4);auto parallel_results = tp.parallelize_loop(0,1000,                                            [&nums](constint a,constint b)                                            {auto result = std::vector<array>();                                                result.reserve(b - a);for (int i = a; i < b; ++i) result.emplace_back(nums);return result;                                            }).get();auto arr = yyjson::array();for (auto&& vec : parallel_results)for (auto&& a : vec) arr.emplace_back(std::move(a));// Single-threaded version equivalent to the aboveauto arr = yyjson::array();for (auto i =0; i <1000; ++i) arr.emplace_back(nums);

Misc

Support for {fmt} format

The cpp-yyjson defines a specialization offmt::formatter of the{fmt} library. The JSON classes are formattable as follows:

usingnamespaceyyjson;auto obj = object(...);auto json_str = fmt::format("{}", obj);fmt::print("{}", obj);

Object dependence safety

Unlike the original yyjson, cpp-yyjson can safely add the same JSON value/array/object to the container multiple times.

usingnamespaceyyjson;auto src_vec = std::vector{value("0"),value(1),value(2.0)};auto arr = array();for (auto&& v : src_vec){// the first addition    arr.emplace_back(v);}for (auto&& v : src_vec){// the second addition: makes a copy and append it    arr.emplace_back(v);}

Conversion from immutable to mutable

If you want to make an immutable JSON instance writable, convert it to a mutable type.

usingnamespaceyyjson;std::string_view json_str =R"({    "id": 1,    "pi": 3.141592,    "name": "🫠",    "array": [0, 1, 2, 3, 4],    "currency": {        "USD": 129.66,        "EUR": 140.35,        "GBP": 158.72    },    "success": true})";// Read JSON string and make mutableauto obj = object(read(json_str));obj["name"] ="❤️";

Author

Yoshiki Matsuda (@yosh-matsuda)

About

Ultra-fast and intuitive C++ JSON reader/writer with yyjson backend

Topics

Resources

License

Stars

Watchers

Forks

Contributors6


[8]ページ先頭

©2009-2025 Movatter.jp