Uma das bibliotecas JSON mais rápidas do mundo. Glaze lê e grava na memória de objetos, simplificando interfaces e oferecendo desempenho incrível.
O Glaze também suporta:
Reflexão pura em tempo de compilação para estruturas
Conformidade com JSON RFC 8259 com validação UTF-8
Suporte à biblioteca C++ padrão
Somente cabeçalho
Serialização/desserialização direta para memória
Compile mapas de tempo com pesquisas de tempo constantes e hashing perfeito
Wrappers poderosos para modificar o comportamento de leitura/gravação (Wrappers)
Use suas próprias funções personalizadas de leitura/gravação (leitura/gravação personalizada)
Lide com chaves desconhecidas de maneira rápida e flexível
Acesso direto à memória por meio da sintaxe do ponteiro JSON
Dados binários através da mesma API para desempenho máximo
Sem exceções (compila com -fno-exceptions
)
Nenhuma informação de tipo de tempo de execução é necessária (compila com -fno-rtti
)
Tratamento rápido de erros com curto-circuito
Suporte JSON-RPC 2.0
Geração de esquema JSON
Extremamente portátil, usa SWAR (SIMD Within A Register) cuidadosamente otimizado para ampla compatibilidade
Suporte para leitura parcial e gravação parcial
Leitura/Escrita de CSV
Muito mais!
Consulte DOCS para obter mais documentação.
Biblioteca | Tempo(s) de ida e volta | Gravar (MB/s) | Leitura (MB/s) |
---|---|---|---|
Esmalte | 1.04 | 1366 | 1224 |
simdjson (sob demanda) | N / D | N / D | 1198 |
yyjson | 1.23 | 1005 | 1107 |
daw_json_link | 2,93 | 365 | 553 |
RapidJSON | 3,65 | 290 | 450 |
Boost.JSON (direto) | 4,76 | 199 | 447 |
json_struct | 5,50 | 182 | 326 |
Nlohmann | 15,71 | 84 | 80 |
Código de teste de desempenho disponível aqui
Advertências de desempenho: simdjson e yyjson são ótimos, mas sofrem grandes perdas de desempenho quando os dados não estão na sequência esperada ou alguma chave está faltando (o problema aumenta à medida que o tamanho do arquivo aumenta, pois eles devem repetir a iteração no documento).
Além disso, simdjson e yyjson não suportam manipulação automática de strings com escape, portanto, se alguma das strings atualmente sem escape neste benchmark contivesse um escape, os escapes não seriam manipulados.
O teste ABC mostra como simdjson tem desempenho ruim quando as chaves não estão na sequência esperada:
Biblioteca | Leitura (MB/s) |
---|---|
Esmalte | 678 |
simdjson (sob demanda) | 93 |
Especificação binária marcada: BEVE
Métrica | Tempo(s) de ida e volta | Gravar (MB/s) | Leitura (MB/s) |
---|---|---|---|
Desempenho bruto | 0,42 | 3235 | 2468 |
Dados JSON equivalentes* | 0,42 | 3547 | 2706 |
Tamanho JSON: 670 bytes
Tamanho do BEVE: 611 bytes
*BEVE empacota com mais eficiência que JSON, portanto, transportar os mesmos dados é ainda mais rápido.
Sua estrutura será refletida automaticamente! Nenhum metadado é exigido pelo usuário.
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 (embelezado)
{
"i" : 287 ,
"d" : 3.14 ,
"hello" : " Hello World " ,
"arr" : [
1 ,
2 ,
3
],
"map" : {
"one" : 1 ,
"two" : 2
}
}
Escreva JSON
my_struct s{};
std::string buffer = glz::write_json(s).value_or( " error " );
ou
my_struct s{};
std::string buffer{};
auto ec = glz::write_json(s, buffer);
if (ec) {
// handle error
}
Ler 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
}
ou
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{});
Importante
O nome do arquivo (2º argumento) deve ser terminado em nulo.
Ações são criadas e testadas com Clang (17+), MSVC (2022) e GCC (12+) em apple, windows e linux.
Glaze busca manter a compatibilidade com as três versões mais recentes do GCC e Clang, bem como com a versão mais recente do MSVC e Apple Clang.
Glaze requer um pré-processador compatível com o padrão C++, que requer o sinalizador /Zc:preprocessor
ao compilar com MSVC.
O CMake possui a opção glaze_ENABLE_AVX2
. Isso tentará usar as instruções AVX2
SIMD em alguns casos para melhorar o desempenho, desde que o sistema que você está configurando as suporte. Defina esta opção como OFF
para desabilitar o conjunto de instruções AVX2, como se você estivesse fazendo compilação cruzada para Arm. Se você não estiver usando o CMake, a macro GLZ_USE_AVX2
habilita o recurso, se definido.
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}
Se quiser especializar sua reflexão, você pode opcionalmente escrever o código abaixo:
Esses metadados também são necessários para estruturas inicializáveis não agregadas.
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
);
};
};
Quando você define os metadados do Glaze, os objetos refletirão automaticamente os nomes não estáticos dos ponteiros do objeto membro. No entanto, se desejar nomes personalizados ou registrar funções lambda ou wrappers que não fornecem nomes para seus campos, você poderá opcionalmente adicionar nomes de campos em seus metadados.
Exemplo de nomes personalizados:
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
);
};
Cada uma dessas strings é opcional e pode ser removida de campos individuais se você quiser que o nome seja refletido.
Os nomes são necessários para:
- variáveis de membro constexpr estáticas
- Invólucros
- Funções lambda
Glaze fornece uma API de reflexão em tempo de compilação que pode ser modificada por meio de especializações glz::meta
. Esta API de reflexão usa reflexão pura, a menos que uma especialização glz::meta
seja fornecida, caso em que o comportamento padrão é substituído pelo desenvolvedor.
static_assert (glz::reflect<my_struct>::size == 5 ); // Number of fields
static_assert (glz::reflect<my_struct>::keys[ 0 ] == " i " ); // Access keys
Aviso
Os campos glz::reflect
descritos acima foram formalizados e é improvável que mudem. Outros campos dentro da estrutura glz::reflect
podem evoluir à medida que continuamos a formalizar a especificação. Portanto, alterações significativas podem ocorrer em campos não documentados no futuro.
A leitura e a gravação personalizadas podem ser alcançadas por meio da poderosa abordagem de especialização to
/ from
, descrita aqui: custom-serialization.md. No entanto, isso funciona apenas para tipos definidos pelo usuário.
Para casos de uso comuns ou casos em que uma variável de membro específica deve ter leitura e gravação especiais, você pode usar glz::custom
para registrar funções de membro de leitura/gravação, std::functions ou funções lambda.
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]} )" );
};
};
Ao usar ponteiros de membro (por exemplo, &T::a
) as estruturas de classe C++ devem corresponder à interface JSON. Pode ser desejável mapear classes C++ com layouts diferentes para a mesma interface de objeto. Isso é feito registrando funções lambda em vez de ponteiros de membros.
template <>
struct glz ::meta<Thing> {
static constexpr auto value = object(
" i " , []( auto && self) -> auto & { return self. subclass . i ; }
);
};
O valor passado self
para a função lambda será um objeto Thing
, e a função lambda nos permite tornar a subclasse invisível para a interface do objeto.
As funções Lambda por padrão copiam retornos, portanto, o tipo de retorno auto&
normalmente é necessário para que o Glaze grave na memória.
Observe que o remapeamento também pode ser obtido por meio de ponteiros/referências, pois o Glaze trata valores, ponteiros e referências da mesma maneira ao escrever/ler.
Uma classe pode ser tratada como um valor subjacente da seguinte forma:
struct S {
int x{};
};
template <>
struct glz ::meta<S> {
static constexpr auto value{ &S::x };
};
ou usando um lambda:
template <>
struct glz ::meta<S> {
static constexpr auto value = []( auto & self) -> auto & { return self. x ; };
};
Glaze é seguro para uso com mensagens não confiáveis. Os erros são retornados como códigos de erro, normalmente dentro de um glz::expected
, que se comporta exatamente como um std::expected
.
Glaze funciona no tratamento de erros de curto-circuito, o que significa que a análise termina muito rapidamente se um erro for encontrado.
Para gerar mensagens de erro mais úteis, chame format_error
:
auto pe = glz::read_json(obj, buffer);
if (pe) {
std::string descriptive_error = glz::format_error (pe, buffer);
}
Este caso de teste:
{ "Hello" : " World " x, "color": "red" }
Produz este erro:
1:17: expected_comma
{"Hello":"World"x, "color": "red"}
^
Denotando que x é inválido aqui.
Um std::string
não const é recomendado para buffers de entrada, pois isso permite que o Glaze melhore o desempenho com preenchimento temporário e o buffer será terminado em nulo.
Por padrão, a opção null_terminated
é definida como true
e buffers terminados em nulo devem ser usados ao analisar JSON. A opção pode ser desativada com uma pequena perda de desempenho, o que permite buffers com terminação não nula:
constexpr glz::opts options{. null_terminated = false };
auto ec = glz::read<options>(value, buffer); // read in a non-null terminated buffer
A terminação nula não é necessária ao analisar BEVE (binário). Não faz diferença no desempenho.
Aviso
Atualmente, null_terminated = false
não é válido para análise de CSV e os buffers devem ter terminação nula.
Os tipos de array são convertidos logicamente em valores de array JSON. Os conceitos são usados para permitir vários contêineres e até mesmo contêineres de usuário, se corresponderem às interfaces de biblioteca padrão.
glz::array
(tipos mistos em tempo de compilação)std::tuple
(tipos mistos em tempo de compilação)std::array
std::vector
std::deque
std::list
std::forward_list
std::span
std::set
std::unordered_set
Os tipos de objetos são convertidos logicamente em valores de objetos JSON, como mapas. Assim como o JSON, o Glaze trata as definições de objetos como mapas não ordenados. Portanto, a ordem de um layout de objeto não precisa corresponder à mesma sequência binária em C++.
glz::object
(tipos mistos em tempo de compilação)std::map
std::unordered_map
std::pair
(habilita chaves dinâmicas no armazenamento de pilha)
std::pair
é tratado como um objeto com uma única chave e valor, mas quandostd::pair
é usado em uma matriz, Glaze concatena os pares em um único objeto.std::vector<std::pair<...>>
será serializado como um único objeto. Se você não deseja esse comportamento, defina a opção de tempo de compilação.concatenate = false
.
std::variant
Consulte Tratamento de variantes para obter mais informações.
std::unique_ptr
std::shared_ptr
std::optional
Os tipos anuláveis podem ser alocados por entrada válida ou anulados pela palavra-chave 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));
Por padrão, as enumerações serão escritas e lidas em formato inteiro. Nenhum glz::meta
é necessário se este for o comportamento desejado.
Porém, se você preferir usar enums como strings em JSON, eles podem ser registrados no glz::meta
da seguinte maneira:
enum class Color { Red, Green, Blue };
template <>
struct glz ::meta<Color> {
using enum Color;
static constexpr auto value = enumerate(Red,
Green,
Blue
);
};
Em uso:
Color color = Color::Red;
std::string buffer{};
glz::write_json (color, buffer);
expect (buffer == " " Red " " );
Os comentários são suportados com a especificação definida aqui: JSONC
O suporte de leitura para comentários é fornecido com glz::read_jsonc
ou glz::read<glz::opts{.comments = true}>(...)
.
JSON formatado pode ser gravado diretamente por meio de uma opção de tempo de compilação:
auto ec = glz::write<glz::opts{. prettify = true }>(obj, buffer);
Ou o texto JSON pode ser formatado com a função 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
é agora:
{
"i" : 287 ,
"d" : 3.14 ,
"hello" : " Hello World " ,
"arr" : [
1 ,
2 ,
3
]
}
Para escrever JSON reduzido:
auto ec = glz::write_json(obj, buffer); // default is minified
Para reduzir a chamada de texto JSON:
std::string minified = glz::minify_json(buffer);
Se você deseja exigir JSON minificado ou sabe que sua entrada sempre será minificada, você pode obter um pouco mais de desempenho usando a opção de tempo de compilação .minified = true
.
auto ec = glz::read<glz::opts{. minified = true }>(obj, buffer);
Glaze suporta o registro de um conjunto de sinalizadores booleanos que se comportam como uma matriz de opções de string:
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);
};
Exemplo:
flags_t s{};
expect (glz::write_json(s) == R"([ " x " , " z " ])");
Apenas "x"
e "z"
são escritos, porque são verdadeiros. A leitura no buffer definirá os booleanos apropriados.
Ao escrever BEVE,
flags
usam apenas um bit por booleano (byte alinhado).
Às vezes, você deseja apenas escrever estruturas JSON dinamicamente da maneira mais eficiente possível. Glaze fornece estruturas semelhantes a tuplas que permitem empilhar estruturas de alocação para escrever JSON em alta velocidade. Essas estruturas são denominadas glz::obj
para objetos e glz::arr
para arrays.
Abaixo está um exemplo de construção de um objeto, que também contém um array, e sua gravação.
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]} )" );
Essa abordagem é significativamente mais rápida que
glz::json_t
para JSON genérico. Mas pode não ser adequado para todos os contextos.
glz::merge
permite ao usuário mesclar vários tipos de objetos JSON em um único objeto.
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
armazena referências a lvalues para evitar cópias
Consulte JSON genérico para 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 é tão rápido gravando em um std::string
quanto gravando em um buffer de char bruto. Se você tiver espaço suficiente alocado em seu buffer, poderá gravar no buffer bruto, conforme mostrado abaixo, mas isso não é recomendado.
glz::read_json(obj, buffer);
const auto n = glz::write_json(obj, buffer.data()).value_or(0);
buffer.resize(n);
A estrutura glz::opts
define configurações opcionais de tempo de compilação para leitura/gravação.
Em vez de chamar glz::read_json(...)
, você pode chamar glz::read<glz::opts{}>(...)
e personalizar as opções.
Por exemplo: glz::read<glz::opts{.error_on_unknown_keys = false}>(...)
desativará erros em chaves desconhecidas e simplesmente ignorará os itens.
glz::opts
também pode alternar entre formatos:
glz::read<glz::opts{.format = glz::BEVE}>(...)
-> glz::read_beve(...)
glz::read<glz::opts{.format = glz::JSON}>(...)
-> glz::read_json(...)
A estrutura abaixo mostra as opções disponíveis e o comportamento padrão.
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)
};
Muitas dessas opções de tempo de compilação possuem wrappers para aplicar a opção a apenas um único campo. Consulte Wrappers para obter mais detalhes.
Por padrão, o Glaze está estritamente em conformidade com o padrão JSON mais recente, exceto em dois casos com opções associadas:
validate_skipped
Esta opção faz validação JSON completa para valores ignorados durante a análise. Isso não é definido por padrão porque os valores normalmente são ignorados quando o usuário não está preocupado com eles, e o Glaze ainda valida problemas importantes. Porém, isso torna o salto mais rápido, não se importando se os valores ignorados são exatamente compatíveis com JSON. Por exemplo, por padrão, o Glaze garantirá que os números ignorados tenham todos os caracteres numéricos válidos, mas não validará problemas como zeros à esquerda em números ignorados, a menos que validate_skipped
esteja ativado. Sempre que o Glaze analisa um valor a ser usado, ele é totalmente validado.validate_trailing_whitespace
Esta opção valida o espaço em branco final em um documento analisado. Como o Glaze analisa estruturas C++, normalmente não há necessidade de continuar a análise após a leitura do objeto de interesse. Ative esta opção se quiser garantir que o restante do documento tenha espaços em branco válidos, caso contrário, o Glaze simplesmente ignorará o conteúdo após o conteúdo de interesse ter sido analisado. Observação
Glaze não unicode automaticamente caracteres de controle de escape (por exemplo, "x1f"
para "u001f"
), pois isso representa um risco de incorporar caracteres nulos e outros caracteres invisíveis em strings. Uma opção de tempo de compilação será adicionada para permitir essas conversões (problema aberto: gravação com escape unicode), mas não será o comportamento padrão.
Pode ser útil reconhecer a existência de uma chave em um objeto para evitar erros e, ainda assim, o valor pode não ser necessário ou existir em C++. Esses casos são tratados registrando um glz::skip
com os metadados.
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 foi projetado para ajudar na construção de APIs genéricas. Às vezes, um valor precisa ser exposto à API, mas não é desejável ler ou escrever o valor em JSON. Este é o caso de uso de glz::hide
.
glz::hide
oculta o valor da saída JSON enquanto ainda permite acesso à API (e ao ponteiro 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
Você pode analisar números JSON citados diretamente em tipos como double
, int
, etc. utilizando o glz::quoted
wrapper.
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 " ]
}
Os números JSON citados serão analisados diretamente em double
e std::vector<uint32_t>
. A função glz::quoted
também funciona para objetos aninhados e matrizes.
Glaze suporta linhas JSON (ou JSON delimitado por nova linha) para tipos semelhantes a array (por exemplo, std::vector
e 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);
Consulte o diretório ext
para extensões.
Glaze é distribuído sob a licença do MIT, com exceção para formulários incorporados:
--- Exceção opcional à licença ---
Como exceção, se, como resultado da compilação do seu código-fonte, partes deste Software forem incorporadas em uma forma de objeto executável por máquina desse código-fonte, você poderá redistribuir essas partes incorporadas em tal forma de objeto sem incluir os direitos autorais e a permissão avisos.