- Notifications
You must be signed in to change notification settings - Fork12
Ultra-fast and intuitive C++ JSON reader/writer with yyjson backend
License
yosh-matsuda/cpp-yyjson
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Ultra-fast and intuitive C++ JSON reader/writer with yyjson backend.
- 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
- 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++
The following is an overview of reading and writing JSON using cpp-yyjson. See thereference for details.
#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}
#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}};
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 with
VISITABLE_STRUCTmacro. - User-defined 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
(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"
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.
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 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.
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.
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.
Theyyjson namespace includes the following function and classes. Typically, you will start with them for reading and writing JSON.
| Function | |
|---|---|
yyjson::read | Read a JSON string and return animmutable JSON document class which is alias ofyyjson::reader::value |
| JSON Type | |
|---|---|
yyjson::value | Mutable JSON value class; alias ofyyjson::writer::value |
yyjson::array | Mutable JSON array class; alias ofyyjson::writer::array |
yyjson::object | Mutable JSON object class; alias ofyyjson::writer::object |
| Allocator class | |
|---|---|
yyjson::dynamic_allocator | Dynamic memory allocator wrapper, available for yyjson >= v0.8.0 |
yyjson::pool_allocator | Fixed size memory allocator wrapper on the heap |
yyjson::stack_pool_allocator | Fixed 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 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.
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.
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// }
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
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 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;
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));
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]]
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}}
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.
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);}
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);// ...}
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
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:
- Pre-defined STL casters.
- Conversion using compile-time reflection.
- Registration of field names with
VISITABLE_STRUCTmacro. - User-defined 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::optionalstd::variantstd::tuple-likestd::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"}}
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"}
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"}
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.
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.
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}};
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);
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);
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);
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);}
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"] ="❤️";
Yoshiki Matsuda (@yosh-matsuda)
About
Ultra-fast and intuitive C++ JSON reader/writer with yyjson backend
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Uh oh!
There was an error while loading.Please reload this page.
Contributors6
Uh oh!
There was an error while loading.Please reload this page.




















