Eine der schnellsten JSON-Bibliotheken der Welt. Glaze liest und schreibt aus dem Objektspeicher, vereinfacht die Schnittstellen und bietet eine unglaubliche Leistung.
Glaze unterstützt außerdem:
Reine Kompilierzeitreflexion für Strukturen
JSON RFC 8259-Konformität mit UTF-8-Validierung
Unterstützung der Standard-C++-Bibliothek
Nur Kopfzeile
Direkte Serialisierung/Deserialisierung im Speicher
Erstellen Sie Zeitkarten mit konstanten Zeitabfragen und perfektem Hashing
Leistungsstarke Wrapper zur Änderung des Lese-/Schreibverhaltens (Wrapper)
Verwenden Sie Ihre eigenen benutzerdefinierten Lese-/Schreibfunktionen (Custom Read/Write)
Behandeln Sie unbekannte Schlüssel schnell und flexibel
Direkter Speicherzugriff über JSON-Zeigersyntax
Binärdaten über dieselbe API für maximale Leistung
Keine Ausnahmen (kompiliert mit -fno-exceptions
)
Keine Informationen zum Laufzeittyp erforderlich (kompiliert mit -fno-rtti
)
Schnelle Fehlerbehandlung bei Kurzschluss
JSON-RPC 2.0-Unterstützung
JSON-Schema-Generierung
Extrem portabel, verwendet sorgfältig optimiertes SWAR (SIMD Within A Register) für umfassende Kompatibilität
Unterstützung für teilweises Lesen und teilweises Schreiben
CSV-Lesen/Schreiben
Viel mehr!
Weitere Dokumentation finden Sie unter DOCS.
Bibliothek | Hin- und Rückfahrtzeit (en) | Schreiben (MB/s) | Lesen (MB/s) |
---|---|---|---|
Glasur | 1.04 | 1366 | 1224 |
simdjson (auf Anfrage) | N / A | N / A | 1198 |
yyjson | 1.23 | 1005 | 1107 |
daw_json_link | 2,93 | 365 | 553 |
RapidJSON | 3,65 | 290 | 450 |
Boost.JSON (direkt) | 4,76 | 199 | 447 |
json_struct | 5,50 | 182 | 326 |
nlohmann | 15.71 | 84 | 80 |
Den Code für den Leistungstest finden Sie hier
Leistungseinbußen: simdjson und yyjson sind großartig, aber es kommt zu erheblichen Leistungseinbußen, wenn die Daten nicht in der erwarteten Reihenfolge sind oder Schlüssel fehlen (das Problem nimmt mit zunehmender Dateigröße zu, da sie das Dokument erneut durchlaufen müssen).
Außerdem unterstützen simdjson und yyjson keine automatische Verarbeitung von mit Escapezeichen versehenen Zeichenfolgen. Wenn also eine der derzeit nicht mit Escapezeichen versehenen Zeichenfolgen in diesem Benchmark ein Escape enthalten würde, würden die Escapezeichen nicht behandelt.
Der ABC-Test zeigt, dass simdjson eine schlechte Leistung aufweist, wenn Schlüssel nicht in der erwarteten Reihenfolge sind:
Bibliothek | Lesen (MB/s) |
---|---|
Glasur | 678 |
simdjson (auf Anfrage) | 93 |
Markierte binäre Spezifikation: BEVE
Metrisch | Hin- und Rückfahrtzeit (en) | Schreiben (MB/s) | Lesen (MB/s) |
---|---|---|---|
Rohe Leistung | 0,42 | 3235 | 2468 |
Äquivalente JSON-Daten* | 0,42 | 3547 | 2706 |
JSON-Größe: 670 Byte
BEVE-Größe: 611 Byte
*BEVE packt effizienter als JSON, sodass der Transport derselben Daten noch schneller erfolgt.
Ihre Struktur wird automatisch reflektiert! Für den Benutzer sind keine Metadaten erforderlich.
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 (verschönert)
{
"i" : 287 ,
"d" : 3.14 ,
"hello" : " Hello World " ,
"arr" : [
1 ,
2 ,
3
],
"map" : {
"one" : 1 ,
"two" : 2
}
}
Schreiben Sie JSON
my_struct s{};
std::string buffer = glz::write_json(s).value_or( " error " );
oder
my_struct s{};
std::string buffer{};
auto ec = glz::write_json(s, buffer);
if (ec) {
// handle error
}
JSON lesen
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
}
oder
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{});
Wichtig
Der Dateiname (2. Argument) muss nullterminiert sein.
Aktionen erstellen und testen mit Clang (17+), MSVC (2022) und GCC (12+) auf Apple, Windows und Linux.
Glaze ist bestrebt, die Kompatibilität mit den neuesten drei Versionen von GCC und Clang sowie der neuesten Version von MSVC und Apple Clang aufrechtzuerhalten.
Glaze erfordert einen dem C++-Standard entsprechenden Präprozessor, der beim Erstellen mit MSVC das Flag /Zc:preprocessor
erfordert.
Das CMake verfügt über die Option glaze_ENABLE_AVX2
. Dadurch wird in einigen Fällen versucht, AVX2
SIMD-Anweisungen zu verwenden, um die Leistung zu verbessern, sofern das System, auf dem Sie konfigurieren, dies unterstützt. Setzen Sie diese Option auf OFF
um den AVX2-Befehlssatz zu deaktivieren, beispielsweise wenn Sie eine Cross-Kompilierung für Arm durchführen. Wenn Sie CMake nicht verwenden, aktiviert das Makro GLZ_USE_AVX2
die Funktion, sofern definiert.
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}
Wenn Sie Ihre Reflexion spezialisieren möchten, können Sie optional den folgenden Code schreiben:
Diese Metadaten sind auch für nicht aggregierte initialisierbare Strukturen erforderlich.
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
);
};
};
Wenn Sie Glaze-Metadaten definieren, spiegeln Objekte automatisch die nicht statischen Namen Ihrer Mitgliedsobjektzeiger wider. Wenn Sie jedoch benutzerdefinierte Namen wünschen oder Lambda-Funktionen oder Wrapper registrieren, die keine Namen für Ihre Felder bereitstellen, können Sie optional Feldnamen in Ihren Metadaten hinzufügen.
Beispiel für benutzerdefinierte Namen:
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
);
};
Jede dieser Zeichenfolgen ist optional und kann für einzelne Felder entfernt werden, wenn der Name wiedergegeben werden soll.
Namen sind erforderlich für:
- statische constexpr-Mitgliedsvariablen
- Wrapper
- Lambda-Funktionen
Glaze bietet eine Reflexions-API zur Kompilierungszeit, die über glz::meta
-Spezialisierungen geändert werden kann. Diese Reflection-API verwendet reine Reflection, es sei denn, es wird eine glz::meta
Spezialisierung bereitgestellt. In diesem Fall wird das Standardverhalten vom Entwickler überschrieben.
static_assert (glz::reflect<my_struct>::size == 5 ); // Number of fields
static_assert (glz::reflect<my_struct>::keys[ 0 ] == " i " ); // Access keys
Warnung
Die oben beschriebenen glz::reflect
Felder wurden formalisiert und werden sich wahrscheinlich nicht ändern. Andere Felder innerhalb der glz::reflect
Struktur können sich weiterentwickeln, während wir die Spezifikation weiter formalisieren. Daher kann es in Zukunft zu wichtigen Änderungen für undokumentierte Felder kommen.
Benutzerdefiniertes Lesen und Schreiben kann durch den leistungsstarken to
/ from
“-Spezialisierungsansatz erreicht werden, der hier beschrieben wird: custom-serialization.md. Dies funktioniert jedoch nur für benutzerdefinierte Typen.
Für häufige Anwendungsfälle oder Fälle, in denen eine bestimmte Mitgliedsvariable über spezielle Lese- und Schreibfunktionen verfügen sollte, können Sie glz::custom
verwenden, um Lese-/Schreib-Mitgliedsfunktionen, std::functions oder Lambda-Funktionen zu registrieren.
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]} )" );
};
};
Bei der Verwendung von Memberzeigern (z. B. &T::a
) müssen die C++-Klassenstrukturen mit der JSON-Schnittstelle übereinstimmen. Es kann wünschenswert sein, C++-Klassen mit unterschiedlichen Layouts derselben Objektschnittstelle zuzuordnen. Dies wird durch die Registrierung von Lambda-Funktionen anstelle von Mitgliedszeigern erreicht.
template <>
struct glz ::meta<Thing> {
static constexpr auto value = object(
" i " , []( auto && self) -> auto & { return self. subclass . i ; }
);
};
Der an die Lambda-Funktion übergebene Wert self
ist ein Thing
-Objekt, und die Lambda-Funktion ermöglicht es uns, die Unterklasse für die Objektschnittstelle unsichtbar zu machen.
Lambda-Funktionen kopieren standardmäßig Rückgaben, daher ist normalerweise der Typ auto&
Return“ erforderlich, damit Glaze in den Speicher schreiben kann.
Beachten Sie, dass eine Neuzuordnung auch durch Zeiger/Referenzen erreicht werden kann, da Glaze Werte, Zeiger und Referenzen beim Schreiben/Lesen auf die gleiche Weise behandelt.
Eine Klasse kann wie folgt als zugrunde liegender Wert behandelt werden:
struct S {
int x{};
};
template <>
struct glz ::meta<S> {
static constexpr auto value{ &S::x };
};
oder mit einem Lambda:
template <>
struct glz ::meta<S> {
static constexpr auto value = []( auto & self) -> auto & { return self. x ; };
};
Glaze kann sicher mit nicht vertrauenswürdigen Nachrichten verwendet werden. Fehler werden als Fehlercodes zurückgegeben, normalerweise innerhalb eines glz::expected
, das sich genau wie ein std::expected
verhält.
Glaze verkürzt die Fehlerbehandlung, was bedeutet, dass die Analyse sehr schnell beendet wird, wenn ein Fehler auftritt.
Um weitere hilfreiche Fehlermeldungen zu generieren, rufen Sie format_error
auf:
auto pe = glz::read_json(obj, buffer);
if (pe) {
std::string descriptive_error = glz::format_error (pe, buffer);
}
Dieser Testfall:
{ "Hello" : " World " x, "color": "red" }
Erzeugt diesen Fehler:
1:17: expected_comma
{"Hello":"World"x, "color": "red"}
^
Das bedeutet, dass x hier ungültig ist.
Für Eingabepuffer wird ein nicht konstanter std::string
empfohlen, da Glaze dadurch die Leistung durch temporäres Auffüllen verbessern kann und der Puffer nullterminiert wird.
Standardmäßig ist die Option null_terminated
auf true
gesetzt und beim Parsen von JSON müssen nullterminierte Puffer verwendet werden. Die Option kann mit einem kleinen Leistungsverlust deaktiviert werden, was nicht-null-terminierte Puffer ermöglicht:
constexpr glz::opts options{. null_terminated = false };
auto ec = glz::read<options>(value, buffer); // read in a non-null terminated buffer
Beim Parsen von BEVE (binär) ist keine Nullterminierung erforderlich. Es macht keinen Unterschied in der Leistung.
Warnung
Derzeit ist null_terminated = false
für die CSV-Analyse nicht gültig und Puffer müssen nullterminiert sein.
Array-Typen werden logisch in JSON-Array-Werte konvertiert. Es werden Konzepte verwendet, um verschiedene Container und sogar Benutzercontainer zuzulassen, wenn sie mit Standardbibliotheksschnittstellen übereinstimmen.
glz::array
(gemischte Typen zur Kompilierungszeit)std::tuple
(gemischte Typen zur Kompilierungszeit)std::array
std::vector
std::deque
std::list
std::forward_list
std::span
std::set
std::unordered_set
Objekttypen werden logisch in JSON-Objektwerte konvertiert, beispielsweise Karten. Wie JSON behandelt Glaze Objektdefinitionen als ungeordnete Karten. Daher muss die Reihenfolge eines Objektlayouts nicht mit derselben Binärsequenz in C++ übereinstimmen.
glz::object
(gemischte Typen zur Kompilierungszeit)std::map
std::unordered_map
std::pair
(aktiviert dynamische Schlüssel im Stapelspeicher)
std::pair
wird als Objekt mit einem einzelnen Schlüssel und Wert behandelt, aber wennstd::pair
in einem Array verwendet wird, verkettet Glaze die Paare zu einem einzigen Objekt.std::vector<std::pair<...>>
wird als einzelnes Objekt serialisiert. Wenn Sie dieses Verhalten nicht wünschen, legen Sie die Kompilierzeitoption.concatenate = false
fest.
std::variant
Weitere Informationen finden Sie unter Variantenbehandlung.
std::unique_ptr
std::shared_ptr
std::optional
Nullable-Typen können durch eine gültige Eingabe zugewiesen oder durch das null
null auf Null gesetzt werden.
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));
Standardmäßig werden Aufzählungen in Ganzzahlform geschrieben und gelesen. Wenn dies das gewünschte Verhalten ist, ist kein glz::meta
erforderlich.
Wenn Sie Enums jedoch lieber als Strings in JSON verwenden möchten, können Sie diese wie folgt im glz::meta
registrieren:
enum class Color { Red, Green, Blue };
template <>
struct glz ::meta<Color> {
using enum Color;
static constexpr auto value = enumerate(Red,
Green,
Blue
);
};
Im Einsatz:
Color color = Color::Red;
std::string buffer{};
glz::write_json (color, buffer);
expect (buffer == " " Red " " );
Kommentare werden mit der hier definierten Spezifikation unterstützt: JSONC
Leseunterstützung für Kommentare wird mit glz::read_jsonc
oder glz::read<glz::opts{.comments = true}>(...)
bereitgestellt.
Formatiertes JSON kann über eine Option zur Kompilierungszeit direkt ausgeschrieben werden:
auto ec = glz::write<glz::opts{. prettify = true }>(obj, buffer);
Alternativ kann JSON-Text mit der Funktion glz::prettify_json
formatiert werden:
std::string buffer = R"( {"i":287,"d":3.14,"hello":"Hello World","arr":[1,2,3]} )" );
auto beautiful = glz::prettify_json(buffer);
beautiful
ist jetzt:
{
"i" : 287 ,
"d" : 3.14 ,
"hello" : " Hello World " ,
"arr" : [
1 ,
2 ,
3
]
}
So schreiben Sie minimiertes JSON:
auto ec = glz::write_json(obj, buffer); // default is minified
So minimieren Sie den JSON-Textaufruf:
std::string minified = glz::minify_json(buffer);
Wenn Sie minimiertes JSON benötigen oder wissen, dass Ihre Eingabe immer minimiert wird, können Sie mit der Kompilierzeitoption .minified = true
etwas mehr Leistung erzielen.
auto ec = glz::read<glz::opts{. minified = true }>(obj, buffer);
Glaze unterstützt die Registrierung einer Reihe boolescher Flags, die sich wie ein Array von String-Optionen verhalten:
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);
};
Beispiel:
flags_t s{};
expect (glz::write_json(s) == R"([ " x " , " z " ])");
Es werden nur "x"
und "z"
ausgeschrieben, weil sie wahr sind. Beim Einlesen des Puffers werden die entsprechenden booleschen Werte gesetzt.
Beim Schreiben von BEVE verwenden
flags
nur ein Bit pro Boolescher Wert (Byte-ausgerichtet).
Manchmal möchten Sie JSON-Strukturen einfach so effizient wie möglich spontan schreiben. Glaze bietet tupelartige Strukturen, mit denen Sie Zuweisungsstrukturen stapeln können, um JSON mit hoher Geschwindigkeit zu schreiben. Diese Strukturen heißen glz::obj
für Objekte und glz::arr
für Arrays.
Unten sehen Sie ein Beispiel für den Aufbau und das Ausschreiben eines Objekts, das auch ein Array enthält.
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]} )" );
Dieser Ansatz ist deutlich schneller als
glz::json_t
für generisches JSON. Ist jedoch möglicherweise nicht für alle Kontexte geeignet.
glz::merge
ermöglicht es dem Benutzer, mehrere JSON-Objekttypen in einem einzigen Objekt zusammenzuführen.
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
speichert Verweise auf L-Werte, um Kopien zu vermeiden
Siehe Generisches JSON für 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 schreibt in einen std::string
genauso schnell wie in einen rohen Zeichenpuffer. Wenn Sie ausreichend Speicherplatz in Ihrem Puffer zugewiesen haben, können Sie wie unten gezeigt in den Rohpuffer schreiben, dies wird jedoch nicht empfohlen.
glz::read_json(obj, buffer);
const auto n = glz::write_json(obj, buffer.data()).value_or(0);
buffer.resize(n);
Die glz::opts
-Struktur definiert optionale Einstellungen zur Kompilierungszeit für das Lesen/Schreiben.
Anstatt glz::read_json(...)
aufzurufen, können Sie glz::read<glz::opts{}>(...)
aufrufen und die Optionen anpassen.
Beispiel: glz::read<glz::opts{.error_on_unknown_keys = false}>(...)
deaktiviert die Fehlererkennung bei unbekannten Schlüsseln und überspringt einfach die Elemente.
glz::opts
kann auch zwischen Formaten wechseln:
glz::read<glz::opts{.format = glz::BEVE}>(...)
-> glz::read_beve(...)
glz::read<glz::opts{.format = glz::JSON}>(...)
-> glz::read_json(...)
Die folgende Struktur zeigt die verfügbaren Optionen und das Standardverhalten.
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)
};
Viele dieser Kompilierzeitoptionen verfügen über Wrapper, um die Option nur auf ein einzelnes Feld anzuwenden. Weitere Einzelheiten finden Sie unter Wrapper.
Standardmäßig entspricht Glaze strikt dem neuesten JSON-Standard, außer in zwei Fällen mit zugehörigen Optionen:
validate_skipped
Diese Option führt beim Parsen eine vollständige JSON-Validierung für übersprungene Werte durch. Dies ist nicht standardmäßig festgelegt, da Werte normalerweise übersprungen werden, wenn der Benutzer sich nicht um sie kümmert, und Glaze weiterhin auf schwerwiegende Probleme überprüft. Dies beschleunigt das Überspringen jedoch, da es nicht darauf ankommt, ob die übersprungenen Werte genau JSON-konform sind. Standardmäßig stellt Glaze beispielsweise sicher, dass übersprungene Zahlen alle gültigen numerischen Zeichen enthalten, prüft jedoch nicht auf Probleme wie führende Nullen in übersprungenen Zahlen, es sei denn, validate_skipped
ist aktiviert. Wo immer Glaze einen zu verwendenden Wert analysiert, wird er vollständig validiert.validate_trailing_whitespace
Diese Option validiert den abschließenden Leerraum in einem analysierten Dokument. Da Glaze C++-Strukturen analysiert, besteht in der Regel keine Notwendigkeit, mit der Analyse fortzufahren, nachdem das interessierende Objekt gelesen wurde. Aktivieren Sie diese Option, wenn Sie sicherstellen möchten, dass der Rest des Dokuments gültige Leerzeichen enthält. Andernfalls ignoriert Glaze den Inhalt einfach, nachdem der gewünschte Inhalt analysiert wurde. Notiz
Glaze unikodiert Escape-Steuerzeichen nicht automatisch (z. B. "x1f"
zu "u001f"
), da dadurch das Risiko besteht, dass Nullzeichen und andere unsichtbare Zeichen in Zeichenfolgen eingebettet werden. Es wird eine Kompilierzeitoption hinzugefügt, um diese Konvertierungen zu ermöglichen (offenes Problem: Unicode-Escape-Schreiben), aber dies wird nicht das Standardverhalten sein.
Es kann nützlich sein, das Vorhandensein eines Schlüssels in einem Objekt zu bestätigen, um Fehler zu vermeiden, obwohl der Wert möglicherweise nicht benötigt wird oder in C++ nicht vorhanden ist. Diese Fälle werden durch die Registrierung eines glz::skip
Typs mit den Metadaten behandelt.
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 soll bei der Erstellung generischer APIs helfen. Manchmal muss ein Wert der API zugänglich gemacht werden, es ist jedoch nicht wünschenswert, den Wert in JSON einzulesen oder auszuschreiben. Dies ist der Anwendungsfall für glz::hide
.
glz::hide
verbirgt den Wert aus der JSON-Ausgabe und ermöglicht gleichzeitig den Zugriff auf die API (und den JSON-Zeiger).
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
Sie können JSON-Zahlen in Anführungszeichen direkt in Typen wie double
, int
usw. analysieren, indem Sie den glz::quoted
-Wrapper verwenden.
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 " ]
}
Die in Anführungszeichen gesetzten JSON-Nummern werden direkt in das double
und std::vector<uint32_t>
geparst. Die Funktion glz::quoted
funktioniert auch für verschachtelte Objekte und Arrays.
Glaze unterstützt JSON Lines (oder Newline Delimited JSON) für Array-ähnliche Typen (z. B. std::vector
und 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);
Erweiterungen finden Sie im ext
-Verzeichnis.
Glaze wird unter der MIT-Lizenz vertrieben, mit Ausnahme für eingebettete Formulare:
--- Optionale Ausnahme von der Lizenz ---
Ausnahmsweise gilt: Wenn infolge der Kompilierung Ihres Quellcodes Teile dieser Software in eine maschinenausführbare Objektform dieses Quellcodes eingebettet werden, dürfen Sie diese eingebetteten Teile in dieser Objektform ohne Einbeziehung des Urheberrechts und der Genehmigung weiterverbreiten Hinweise.