Одна из самых быстрых библиотек JSON в мире. Glaze читает и записывает из объектной памяти, упрощая интерфейсы и обеспечивая невероятную производительность.
Glaze также поддерживает:
Чистое отражение времени компиляции для структур.
Соответствие JSON RFC 8259 проверке UTF-8
Поддержка стандартной библиотеки C++.
Только заголовок
Прямая сериализация/десериализация в память
Компилируйте карты времени с постоянным поиском по времени и идеальным хешированием.
Мощные оболочки для изменения поведения чтения/записи (обертки).
Используйте свои собственные функции чтения/записи (Custom Read/Write)
Обрабатывайте неизвестные ключи быстро и гибко.
Прямой доступ к памяти через синтаксис указателя JSON.
Двоичные данные через один и тот же API для максимальной производительности
Никаких исключений (компилируется с -fno-exceptions
)
Информация о типе времени выполнения не требуется (компилируется с -fno-rtti
)
Быстрая обработка ошибок с помощью короткого замыкания
Поддержка JSON-RPC 2.0
Генерация схемы JSON
Чрезвычайно портативный, использует тщательно оптимизированный SWAR (SIMD Within A Register) для широкой совместимости.
Поддержка частичного чтения и частичной записи
Чтение/запись CSV
Гораздо больше!
См. DOCS для получения дополнительной документации.
Библиотека | Время туда и обратно (с) | Запись (МБ/с) | Чтение (МБ/с) |
---|---|---|---|
Глазурь | 1.04 | 1366 | 1224 |
симджсон (по запросу) | Н/Д | Н/Д | 1198 |
юйсон | 1.23 | 1005 | 1107 |
daw_json_link | 2,93 | 365 | 553 |
РапидJSON | 3,65 | 290 | 450 |
Boost.JSON (прямой) | 4,76 | 199 | 447 |
json_struct | 5.50 | 182 | 326 |
Нломанн | 15.71 | 84 | 80 |
Код теста производительности доступен здесь
Предостережения по поводу производительности: simdjson и yyjson великолепны, но они испытывают серьезные потери производительности, когда данные не находятся в ожидаемой последовательности или отсутствуют какие-либо ключи (проблема возрастает по мере увеличения размера файла, поскольку им приходится повторять весь документ).
Кроме того, simdjson и yyjson не поддерживают автоматическую обработку экранированных строк, поэтому, если какая-либо из текущих неэкранированных строк в этом тесте будет содержать escape-символы, escape-символы не будут обработаны.
ABC Test показывает, насколько плоха производительность simdjson, когда ключи расположены не в ожидаемой последовательности:
Библиотека | Чтение (МБ/с) |
---|---|
Глазурь | 678 |
симджсон (по запросу) | 93 |
Бинарная спецификация с меткой: BEVE
Метрика | Время туда и обратно (с) | Запись (МБ/с) | Чтение (МБ/с) |
---|---|---|---|
Чистая производительность | 0,42 | 3235 | 2468 |
Эквивалентные данные JSON* | 0,42 | 3547 | 2706 |
Размер JSON: 670 байт.
Размер BEVE: 611 байт
*BEVE упаковывает более эффективно, чем JSON, поэтому передача тех же данных происходит еще быстрее.
Ваша структура будет автоматически отражена! Пользователю не требуются метаданные.
struct my_struct
{
int i = 287 ;
double d = 3.14 ;
std::string hello = " Hello World " ;
std::array< uint64_t , 3 > arr = { 1 , 2 , 3 };
std::map<std::string, int > map{{ " one " , 1 }, { " two " , 2 }};
};
JSON (уточненный)
{
"i" : 287 ,
"d" : 3.14 ,
"hello" : " Hello World " ,
"arr" : [
1 ,
2 ,
3
],
"map" : {
"one" : 1 ,
"two" : 2
}
}
Напишите JSON
my_struct s{};
std::string buffer = glz::write_json(s).value_or( " error " );
или
my_struct s{};
std::string buffer{};
auto ec = glz::write_json(s, buffer);
if (ec) {
// handle error
}
Чтение JSON
std::string buffer = R"( {"i":287,"d":3.14,"hello":"Hello World","arr":[1,2,3],"map":{"one":1,"two":2}} )" ;
auto s = glz::read_json<my_struct>(buffer);
if (s) // check std::expected
{
s. value (); // s.value() is a my_struct populated from buffer
}
или
std::string buffer = R"( {"i":287,"d":3.14,"hello":"Hello World","arr":[1,2,3],"map":{"one":1,"two":2}} )" ;
my_struct s{};
auto ec = glz::read_json(s, buffer); // populates s from buffer
if (ec) {
// handle error
}
auto ec = glz::read_file_json(obj, " ./obj.json " , std::string{});
auto ec = glz::write_file_json(obj, " ./obj.json " , std::string{});
Важный
Имя файла (2-й аргумент) должно заканчиваться нулем.
Действия создаются и тестируются с помощью Clang (17+), MSVC (2022) и GCC (12+) на Apple, Windows и Linux.
Glaze стремится поддерживать совместимость с тремя последними версиями GCC и Clang, а также с последней версией MSVC и Apple Clang.
Glaze требуется препроцессор, соответствующий стандарту C++, для которого требуется флаг /Zc:preprocessor
при сборке с помощью MSVC.
У CMake есть опция glaze_ENABLE_AVX2
. В некоторых случаях будет предпринята попытка использовать инструкции AVX2
SIMD для повышения производительности, если система, которую вы настраиваете, поддерживает это. Установите для этой опции значение OFF
, чтобы отключить набор инструкций AVX2, например, если вы выполняете кросс-компиляцию для Arm. Если вы не используете CMake, макрос GLZ_USE_AVX2
включает эту функцию, если она определена.
include (FetchContent)
FetchContent_Declare(
glaze
GIT_REPOSITORY https://github.com/stephenberry/glaze.git
GIT_TAG main
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(glaze)
target_link_libraries ( ${PROJECT_NAME} PRIVATE glaze::glaze)
find_package(glaze REQUIRED)
target_link_libraries(main PRIVATE glaze::glaze)
import libs = libglaze%lib{glaze}
Если вы хотите специализировать свое отражение, вы можете дополнительно написать код ниже:
Эти метаданные также необходимы для неагрегированных инициализируемых структур.
template <>
struct glz ::meta<my_struct> {
using T = my_struct;
static constexpr auto value = object(
&T::i,
&T::d,
&T::hello,
&T::arr,
&T::map
);
};
struct my_struct
{
int i = 287 ;
double d = 3.14 ;
std::string hello = " Hello World " ;
std::array< uint64_t , 3 > arr = { 1 , 2 , 3 };
std::map<std::string, int > map{{ " one " , 1 }, { " two " , 2 }};
struct glaze {
using T = my_struct;
static constexpr auto value = glz::object(
&T::i,
&T::d,
&T::hello,
&T::arr,
&T::map
);
};
};
Когда вы определяете метаданные Glaze, объекты автоматически отражают нестатические имена указателей объектов-членов. Однако если вам нужны собственные имена или вы регистрируете лямбда-функции или оболочки, которые не предоставляют имена для ваших полей, вы можете при желании добавить имена полей в свои метаданные.
Пример произвольных имен:
template <>
struct glz ::meta<my_struct> {
using T = my_struct;
static constexpr auto value = object(
" integer " , &T::i,
" double " , &T::d,
" string " , &T::hello,
" array " , &T::arr,
" my map " , &T::map
);
};
Каждая из этих строк является необязательной и может быть удалена для отдельных полей, если вы хотите, чтобы имя отображалось.
Имена необходимы для:
- статические переменные-члены constexpr
- Обертки
- Лямбда-функции
Glaze предоставляет API отражения во время компиляции, который можно изменить с помощью специализаций glz::meta
. Этот API отражения использует чистое отражение, если не предоставлена специализация glz::meta
, и в этом случае поведение по умолчанию переопределяется разработчиком.
static_assert (glz::reflect<my_struct>::size == 5 ); // Number of fields
static_assert (glz::reflect<my_struct>::keys[ 0 ] == " i " ); // Access keys
Предупреждение
Поля glz::reflect
описанные выше, формализованы и вряд ли изменятся. Другие поля внутри структуры glz::reflect
могут развиваться по мере того, как мы продолжаем формализовать спецификацию. Поэтому в будущем могут произойти критические изменения для недокументированных полей.
Пользовательское чтение и запись могут быть достигнуты с помощью мощного подхода to
специализации и from
, который описан здесь: custom-serialization.md. Однако это работает только для пользовательских типов.
Для распространенных случаев использования или случаев, когда конкретная переменная-член должна иметь специальное чтение и запись, вы можете использовать glz::custom
для регистрации функций-членов чтения/записи, std::functions или лямбда-функций.
struct custom_encoding
{
uint64_t x{};
std::string y{};
std::array< uint32_t , 3 > z{};
void read_x ( const std::string& s) {
x = std::stoi (s);
}
uint64_t write_x () {
return x;
}
void read_y ( const std::string& s) {
y = " hello " + s;
}
auto & write_z () {
z[ 0 ] = 5 ;
return z;
}
};
template <>
struct glz ::meta<custom_encoding>
{
using T = custom_encoding;
static constexpr auto value = object( " x " , custom<&T::read_x, &T::write_x>, //
" y " , custom<&T::read_y, &T::y>, //
" z " , custom<&T::z, &T::write_z>);
};
suite custom_encoding_test = [] {
" custom_reading " _test = [] {
custom_encoding obj{};
std::string s = R"( {"x":"3","y":"world","z":[1,2,3]} )" ;
expect (! glz::read_json (obj, s));
expect (obj. x == 3 );
expect (obj. y == " helloworld " );
expect (obj. z == std::array< uint32_t , 3 >{ 1 , 2 , 3 });
};
" custom_writing " _test = [] {
custom_encoding obj{};
std::string s = R"( {"x":"3","y":"world","z":[1,2,3]} )" ;
expect (! glz::read_json (obj, s));
std::string out{};
expect ( not glz::write_json (obj, out));
expect (out == R"( {"x":3,"y":"helloworld","z":[5,2,3]} )" );
};
};
При использовании указателей на члены (например &T::a
) структуры классов C++ должны соответствовать интерфейсу JSON. Может оказаться желательным сопоставить классы C++ с разными макетами с одним и тем же объектным интерфейсом. Это достигается путем регистрации лямбда-функций вместо указателей на члены.
template <>
struct glz ::meta<Thing> {
static constexpr auto value = object(
" i " , []( auto && self) -> auto & { return self. subclass . i ; }
);
};
Значение self
, передаваемое лямбда-функции, будет объектом Thing
, а лямбда-функция позволяет нам сделать подкласс невидимым для интерфейса объекта.
Лямбда-функции по умолчанию копируют возвраты, поэтому тип возврата auto&
обычно требуется для того, чтобы Glaze мог записывать в память.
Обратите внимание, что переназначение также может быть достигнуто с помощью указателей/ссылок, поскольку glaze обрабатывает значения, указатели и ссылки одинаковым образом при записи/чтении.
Класс можно рассматривать как базовое значение следующим образом:
struct S {
int x{};
};
template <>
struct glz ::meta<S> {
static constexpr auto value{ &S::x };
};
или используя лямбду:
template <>
struct glz ::meta<S> {
static constexpr auto value = []( auto & self) -> auto & { return self. x ; };
};
Glaze безопасно использовать с ненадежными сообщениями. Ошибки возвращаются в виде кодов ошибок, обычно внутри glz::expected
, который ведет себя так же, как std::expected
.
Glaze работает для короткого замыкания обработки ошибок, что означает, что анализ завершается очень быстро, если возникает ошибка.
Чтобы генерировать более полезные сообщения об ошибках, вызовите format_error
:
auto pe = glz::read_json(obj, buffer);
if (pe) {
std::string descriptive_error = glz::format_error (pe, buffer);
}
Этот тестовый пример:
{ "Hello" : " World " x, "color": "red" }
Выдает эту ошибку:
1:17: expected_comma
{"Hello":"World"x, "color": "red"}
^
Обозначая, что x здесь недействителен.
Для входных буферов рекомендуется использовать неконстантный std::string
, поскольку это позволяет Glaze повысить производительность за счет временного заполнения, и буфер будет завершаться нулем.
По умолчанию для параметра null_terminated
установлено значение true
, и при анализе JSON необходимо использовать буферы с нулевым завершением. Эту опцию можно отключить с небольшой потерей производительности, что позволяет использовать буферы с ненулевым завершением:
constexpr glz::opts options{. null_terminated = false };
auto ec = glz::read<options>(value, buffer); // read in a non-null terminated buffer
Нулевое завершение не требуется при анализе BEVE (двоичный файл). Это не имеет никакого значения в производительности.
Предупреждение
В настоящее время null_terminated = false
недопустимо для анализа CSV, а буферы должны заканчиваться нулем.
Типы массивов логически преобразуются в значения массива JSON. Концепции используются для разрешения использования различных контейнеров и даже пользовательских контейнеров, если они соответствуют стандартным библиотечным интерфейсам.
glz::array
(смешанные типы во время компиляции)std::tuple
(смешанные типы во время компиляции)std::array
std::vector
std::deque
std::list
std::forward_list
std::span
std::set
std::unordered_set
Типы объектов логически преобразуются в значения объектов JSON, например карты. Как и JSON, Glaze рассматривает определения объектов как неупорядоченные карты. Поэтому порядок расположения объектов не обязательно должен соответствовать одной и той же двоичной последовательности в C++.
glz::object
(смешанные типы во время компиляции)std::map
std::unordered_map
std::pair
(включает динамические ключи в хранилище стека)
std::pair
обрабатывается как объект с одним ключом и значением, но когдаstd::pair
используется в массиве, Glaze объединяет пары в один объект.std::vector<std::pair<...>>
будет сериализоваться как один объект. Если вы не хотите такого поведения, установите параметр времени компиляции.concatenate = false
.
std::variant
Дополнительную информацию см. в разделе «Обработка вариантов».
std::unique_ptr
std::shared_ptr
std::optional
Типы, допускающие значение NULL, могут быть выделены допустимым вводом или обнулены ключевым словом null
.
std::unique_ptr< int > ptr{};
std::string buffer{};
expect ( not glz::write_json (ptr, buffer));
expect (buffer == " null " );
expect ( not glz::read_json (ptr, " 5 " ));
expect (*ptr == 5 );
buffer.clear();
expect ( not glz::write_json (ptr, buffer));
expect (buffer == " 5 " );
expect ( not glz::read_json (ptr, " null " ));
expect (! bool (ptr));
По умолчанию перечисления будут записываться и читаться в целочисленной форме. Если это желаемое поведение glz::meta
не требуется.
Однако, если вы предпочитаете использовать перечисления как строки в JSON, их можно зарегистрировать в glz::meta
следующим образом:
enum class Color { Red, Green, Blue };
template <>
struct glz ::meta<Color> {
using enum Color;
static constexpr auto value = enumerate(Red,
Green,
Blue
);
};
В использовании:
Color color = Color::Red;
std::string buffer{};
glz::write_json (color, buffer);
expect (buffer == " " Red " " );
Комментарии поддерживаются спецификацией, определенной здесь: JSONC.
Поддержка чтения комментариев обеспечивается с помощью glz::read_jsonc
или glz::read<glz::opts{.comments = true}>(...)
.
Форматированный JSON можно записать напрямую с помощью опции времени компиляции:
auto ec = glz::write<glz::opts{. prettify = true }>(obj, buffer);
Или текст JSON можно отформатировать с помощью функции glz::prettify_json
:
std::string buffer = R"( {"i":287,"d":3.14,"hello":"Hello World","arr":[1,2,3]} )" );
auto beautiful = glz::prettify_json(buffer);
beautiful
сейчас:
{
"i" : 287 ,
"d" : 3.14 ,
"hello" : " Hello World " ,
"arr" : [
1 ,
2 ,
3
]
}
Чтобы написать минифицированный JSON:
auto ec = glz::write_json(obj, buffer); // default is minified
Чтобы минимизировать текстовый вызов JSON:
std::string minified = glz::minify_json(buffer);
Если вы хотите использовать минимизированный JSON или знаете, что ваши входные данные всегда будут минимизированы, вы можете немного повысить производительность, используя параметр времени компиляции .minified = true
.
auto ec = glz::read<glz::opts{. minified = true }>(obj, buffer);
Glaze поддерживает регистрацию набора логических флагов, которые ведут себя как массив строковых параметров:
struct flags_t {
bool x{ true };
bool y{};
bool z{ true };
};
template <>
struct glz ::meta< flags_t > {
using T = flags_t ;
static constexpr auto value = flags( " x " , &T::x, " y " , &T::y, " z " , &T::z);
};
Пример:
flags_t s{};
expect (glz::write_json(s) == R"([ " x " , " z " ])");
Выписаны только "x"
и "z"
, потому что они истинные. Чтение в буфере установит соответствующие логические значения.
При написании BEVE
flags
используют только один бит на логическое значение (выравнивание по байтам).
Иногда вам просто хочется писать структуры JSON «на лету» как можно эффективнее. Glaze предоставляет структуры, подобные кортежам, которые позволяют объединять структуры выделения для высокоскоростной записи JSON. Эти структуры называются glz::obj
для объектов и glz::arr
для массивов.
Ниже приведен пример построения объекта, который также содержит массив, и его записи.
auto obj = glz::obj{ " pi " , 3.14 , " happy " , true , " name " , " Stephen " , " arr " , glz::arr{ " Hello " , " World " , 2 }};
std::string s{};
expect ( not glz::write_json (obj, s));
expect (s == R"( {"pi":3.14,"happy":true,"name":"Stephen","arr":["Hello","World",2]} )" );
Этот подход значительно быстрее, чем
glz::json_t
для общего JSON. Но может подойти не для всех контекстов.
glz::merge
позволяет пользователю объединять несколько типов объектов JSON в один объект.
glz::obj o{ " pi " , 3.141 };
std::map<std::string_view, int > map = {{ " a " , 1 }, { " b " , 2 }, { " c " , 3 }};
auto merged = glz::merge{o, map};
std::string s{};
glz::write_json (merged, s); // will write out a single, merged object
// s is now: {"pi":3.141,"a":0,"b":2,"c":3}
glz::merge
сохраняет ссылки на lvalue, чтобы избежать копирования.
См. раздел «Общий JSON» для glz::json_t
.
glz:: json_t json{};
std::string buffer = R"( [5,"Hello World",{"pi":3.14}] )" ;
glz::read_json (json, buffer);
assert (json[ 2 ][ " pi " ].get< double >() == 3.14);
Glaze выполняет запись в std::string
примерно так же быстро, как и в буфер необработанных символов. Если у вас достаточно выделенного места в буфере, вы можете писать в необработанный буфер, как показано ниже, но это не рекомендуется.
glz::read_json(obj, buffer);
const auto n = glz::write_json(obj, buffer.data()).value_or(0);
buffer.resize(n);
Структура glz::opts
определяет дополнительные настройки времени компиляции для чтения/записи.
Вместо вызова glz::read_json(...)
вы можете вызвать glz::read<glz::opts{}>(...)
и настроить параметры.
Например: glz::read<glz::opts{.error_on_unknown_keys = false}>(...)
отключит ошибки на неизвестных ключах и просто пропустит элементы.
glz::opts
также может переключаться между форматами:
glz::read<glz::opts{.format = glz::BEVE}>(...)
-> glz::read_beve(...)
glz::read<glz::opts{.format = glz::JSON}>(...)
-> glz::read_json(...)
В приведенной ниже структуре показаны доступные параметры и поведение по умолчанию.
struct opts {
uint32_t format = json;
bool comments = false ; // Support reading in JSONC style comments
bool error_on_unknown_keys = true ; // Error when an unknown key is encountered
bool skip_null_members = true ; // Skip writing out params in an object if the value is null
bool use_hash_comparison = true ; // Will replace some string equality checks with hash checks
bool prettify = false ; // Write out prettified JSON
bool minified = false ; // Require minified input for JSON, which results in faster read performance
char indentation_char = ' ' ; // Prettified JSON indentation char
uint8_t indentation_width = 3 ; // Prettified JSON indentation size
bool new_lines_in_arrays = true ; // Whether prettified arrays should have new lines for each element
bool shrink_to_fit = false ; // Shrinks dynamic containers to new size to save memory
bool write_type_info = true ; // Write type info for meta objects in variants
bool error_on_missing_keys = false ; // Require all non nullable keys to be present in the object. Use
// skip_null_members = false to require nullable members
bool error_on_const_read =
false ; // Error if attempt is made to read into a const value, by default the value is skipped without error
bool validate_skipped = false ; // If full validation should be performed on skipped values
bool validate_trailing_whitespace =
false ; // If, after parsing a value, we want to validate the trailing whitespace
uint8_t layout = rowwise; // CSV row wise output/input
// The maximum precision type used for writing floats, higher precision floats will be cast down to this precision
float_precision float_max_write_precision{};
bool bools_as_numbers = false ; // Read and write booleans with 1's and 0's
bool quoted_num = false ; // treat numbers as quoted or array-like types as having quoted numbers
bool number = false ; // read numbers as strings and write these string as numbers
bool raw = false ; // write out string like values without quotes
bool raw_string =
false ; // do not decode/encode escaped characters for strings (improves read/write performance)
bool structs_as_arrays = false ; // Handle structs (reading/writing) without keys, which applies
bool allow_conversions = true ; // Whether conversions between convertible types are
// allowed in binary, e.g. double -> float
bool partial_read =
false ; // Reads into only existing fields and elements and then exits without parsing the rest of the input
// glaze_object_t concepts
bool partial_read_nested = false ; // Advance the partially read struct to the end of the struct
bool concatenate = true ; // Concatenates ranges of std::pair into single objects when writing
bool hide_non_invocable =
true ; // Hides non-invocable members from the cli_menu (may be applied elsewhere in the future)
};
Многие из этих параметров времени компиляции имеют оболочки, позволяющие применять параметр только к одному полю. Дополнительные сведения см. в разделе Обертки.
По умолчанию Glaze строго соответствует последнему стандарту JSON, за исключением двух случаев со связанными опциями:
validate_skipped
Этот параметр выполняет полную проверку JSON для пропущенных значений при синтаксическом анализе. По умолчанию этот параметр не установлен, поскольку значения обычно пропускаются, когда пользователь не обращает на них внимания, а Glaze по-прежнему проверяет наличие серьезных проблем. Но это ускоряет пропуск, поскольку не заботится о том, соответствуют ли пропущенные значения JSON. Например, по умолчанию Glaze гарантирует, что пропущенные числа содержат все допустимые числовые символы, но не будет проверять наличие таких проблем, как ведущие нули в пропущенных числах, если не включен validate_skipped
. Везде, где Glaze анализирует значение, которое будет использоваться, оно полностью проверяется.validate_trailing_whitespace
Этот параметр проверяет конечные пробелы в анализируемом документе. Поскольку Glaze анализирует структуры C++, обычно нет необходимости продолжать анализ после того, как интересующий объект был прочитан. Включите эту опцию, если вы хотите убедиться, что остальная часть документа имеет допустимые пробелы, в противном случае Glaze просто проигнорирует содержимое после того, как интересующее его содержимое будет проанализировано. Примечание
Glaze не преобразует автоматически управляющие символы Unicode (например, "x1f"
до "u001f"
), поскольку это создает риск внедрения нулевых символов и других невидимых символов в строки. Будет добавлена опция времени компиляции для включения этих преобразований (открытая проблема: экранированная запись в Юникоде), но это не будет поведением по умолчанию.
Подтверждение существования ключей в объекте может оказаться полезным для предотвращения ошибок, однако значение может не потребоваться или не существовать в C++. Эти случаи обрабатываются путем регистрации типа glz::skip
в метаданных.
struct S {
int i{};
};
template <>
struct glz ::meta<S> {
static constexpr auto value = object( " key_to_skip " , skip{}, &S::i);
};
std::string buffer = R"( {"key_to_skip": [1,2,3], "i": 7} )" ;
S s{};
glz::read_json (s, buffer);
// The value [1,2,3] will be skipped
expect (s.i == 7 ); // only the value i will be read into
Glaze предназначен для помощи в создании универсальных API. Иногда значение необходимо предоставить API, но нежелательно считывать или записывать значение в формате JSON. Это вариант использования glz::hide
.
glz::hide
скрывает значение из вывода JSON, сохраняя при этом доступ к API (и указателю JSON).
struct hide_struct {
int i = 287 ;
double d = 3.14 ;
std::string hello = " Hello World " ;
};
template <>
struct glz ::meta<hide_struct> {
using T = hide_struct;
static constexpr auto value = object(&T::i, //
&T::d, //
" hello " , hide{&T::hello});
};
hide_struct s{};
auto b = glz::write_json(s);
expect (b == R"( {"i":287,"d":3.14} )" ); // notice that "hello" is hidden from the output
Вы можете анализировать числа JSON в кавычках непосредственно на типы, такие как double
, int
и т. д., используя оболочку glz::quoted
.
struct A {
double x;
std::vector< uint32_t > y;
};
template <>
struct glz ::meta<A> {
static constexpr auto value = object( " x " , glz::quoted_num<&A::x>, " y " , glz::quoted_num<&A::y>;
};
{
"x" : " 3.14 " ,
"y" : [ " 1 " , " 2 " , " 3 " ]
}
Числа JSON в кавычках будут преобразованы непосредственно в double
и std::vector<uint32_t>
. Функция glz::quoted
также работает для вложенных объектов и массивов.
Glaze поддерживает строки JSON (или JSON с разделителями новой строки) для типов, подобных массивам (например, std::vector
и std::tuple
).
std::vector<std::string> x = { " Hello " , " World " , " Ice " , " Cream " };
std::string s = glz::write_ndjson(x).value_or( " error " );
auto ec = glz::read_ndjson(x, s);
См. каталог ext
для расширений.
Glaze распространяется по лицензии MIT за исключением встроенных форм:
--- Необязательное исключение из лицензии ---
В качестве исключения, если в результате компиляции исходного кода части данного Программного обеспечения встроены в машинно-исполняемую объектную форму такого исходного кода, вы можете распространять такие встроенные части в такой объектной форме без включения авторских прав и разрешений. уведомления.