หนึ่งในไลบรารี JSON ที่เร็วที่สุดในโลก Glaze อ่านและเขียนจากหน่วยความจำอ็อบเจ็กต์ ลดความซับซ้อนของอินเทอร์เฟซ และมอบประสิทธิภาพอันน่าทึ่ง
Glaze ยังรองรับ:
การสะท้อนเวลาคอมไพล์ที่บริสุทธิ์สำหรับโครงสร้าง
การปฏิบัติตาม JSON RFC 8259 พร้อมการตรวจสอบ UTF-8
รองรับไลบรารี C++ มาตรฐาน
เฉพาะส่วนหัวเท่านั้น
ตรงไปยังซีเรียลไลซ์/ดีซีเรียลไลซ์หน่วยความจำ
รวบรวมแผนที่เวลาด้วยการค้นหาเวลาคงที่และการแฮชที่สมบูรณ์แบบ
Wrappers อันทรงพลังเพื่อปรับเปลี่ยนพฤติกรรมการอ่าน/เขียน (Wrappers)
ใช้ฟังก์ชันอ่าน/เขียนที่คุณกำหนดเอง (อ่าน/เขียนแบบกำหนดเอง)
จัดการคีย์ที่ไม่รู้จักในลักษณะที่รวดเร็วและยืดหยุ่น
เข้าถึงหน่วยความจำโดยตรงผ่านไวยากรณ์ตัวชี้ JSON
ข้อมูลไบนารีผ่าน API เดียวกันเพื่อประสิทธิภาพสูงสุด
ไม่มีข้อยกเว้น (คอมไพล์ด้วย -fno-exceptions
)
ไม่จำเป็นต้องมีข้อมูลประเภทรันไทม์ (คอมไพล์ด้วย -fno-rtti
)
การจัดการข้อผิดพลาดอย่างรวดเร็วด้วยการลัดวงจร
รองรับ JSON-RPC 2.0
การสร้างสคีมา JSON
พกพาสะดวกมาก ใช้ SWAR (SIMD ภายใน A Register) ที่ได้รับการปรับปรุงอย่างระมัดระวังเพื่อความเข้ากันได้ในวงกว้าง
รองรับการอ่านบางส่วนและการเขียนบางส่วน
การอ่าน/การเขียน CSV
มากขึ้น!
ดู DOCS สำหรับเอกสารเพิ่มเติม
ห้องสมุด | เวลาไปกลับ (s) | เขียน (MB/s) | อ่าน (MB/s) |
---|---|---|---|
เคลือบ | 1.04 | 1366 | 1224 |
ซิมดีสัน (ตามความต้องการ) | ไม่มี | ไม่มี | 1198 |
ใช่ๆ | 1.23 | 1005 | 1107 |
daw_json_link | 2.93 | 365 | 553 |
RapidJSON | 3.65 | 290 | 450 |
Boost.JSON (โดยตรง) | 4.76 | 199 | 447 |
json_struct.json_struct | 5.50 | 182 | 326 |
นโลมันน์ | 15.71 | 84 | 80 |
รหัสทดสอบประสิทธิภาพมีอยู่ที่นี่
คำเตือนด้านประสิทธิภาพ: simdjson และ yyjson นั้นดีมาก แต่ประสิทธิภาพจะลดลงอย่างมากเมื่อข้อมูลไม่อยู่ในลำดับที่คาดไว้หรือคีย์ใด ๆ หายไป (ปัญหาจะเพิ่มขึ้นเมื่อขนาดไฟล์เพิ่มขึ้น เนื่องจากต้องวนซ้ำผ่านเอกสาร)
นอกจากนี้ simdjson และ yyjson ไม่รองรับการจัดการสตริงที่ Escape โดยอัตโนมัติ ดังนั้น หากสตริงใดๆ ที่ไม่ได้ Escape ในปัจจุบันในการวัดประสิทธิภาพนี้มี Escape การ Escape จะไม่ได้รับการจัดการ
การทดสอบ ABC แสดงให้เห็นว่า simdjson มีประสิทธิภาพต่ำอย่างไรเมื่อคีย์ไม่อยู่ในลำดับที่คาดหวัง:
ห้องสมุด | อ่าน (MB/s) |
---|---|
เคลือบ | 678 |
ซิมดีสัน (ตามความต้องการ) | 93 |
ข้อกำหนดไบนารีที่ติดแท็ก: BEVE
เมตริก | เวลาไปกลับ (s) | เขียน (MB/s) | อ่าน (MB/s) |
---|---|---|---|
ประสิทธิภาพดิบ | 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) จะต้องสิ้นสุดด้วยค่า null
การดำเนินการสร้างและทดสอบด้วย 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 ออบเจ็กต์จะแสดงชื่อที่ไม่คงที่ของตัวชี้ออบเจ็กต์สมาชิกของคุณโดยอัตโนมัติ อย่างไรก็ตาม หากคุณต้องการชื่อที่กำหนดเองหรือลงทะเบียนฟังก์ชัน lambda หรือ Wrapper ที่ไม่ได้ระบุชื่อให้กับช่องของคุณ คุณสามารถเลือกเพิ่มชื่อช่องในข้อมูลเมตาของคุณได้
ตัวอย่างชื่อที่กำหนดเอง:
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
struct อาจพัฒนาไปเมื่อเราดำเนินการปรับแต่งข้อมูลจำเพาะต่อไป ดังนั้น การเปลี่ยนแปลงที่เสียหายอาจเกิดขึ้นสำหรับเขตข้อมูลที่ไม่มีเอกสารในอนาคต
การอ่านและการเขียนแบบกำหนดเองสามารถทำได้โดยใช้แนวทางเฉพาะ to
from
มีประสิทธิภาพ ซึ่งอธิบายไว้ที่นี่: custom-serialization.md อย่างไรก็ตาม วิธีนี้ใช้ได้กับประเภทที่ผู้ใช้กำหนดเท่านั้น
สำหรับกรณีการใช้งานทั่วไปหรือกรณีที่ตัวแปรสมาชิกเฉพาะควรมีการอ่านและการเขียนแบบพิเศษ คุณสามารถใช้ glz::custom
เพื่อลงทะเบียนฟังก์ชันสมาชิกการอ่าน/เขียน, std::functions หรือฟังก์ชัน 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]} )" );
};
};
เมื่อใช้ตัวชี้สมาชิก (เช่น &T::a
) โครงสร้างคลาส C++ จะต้องตรงกับอินเทอร์เฟซ JSON อาจเป็นที่พึงปรารถนาที่จะแมปคลาส C ++ ด้วยเลย์เอาต์ที่แตกต่างกันไปยังอินเทอร์เฟซออบเจ็กต์เดียวกัน ซึ่งสามารถทำได้โดยการลงทะเบียนฟังก์ชันแลมบ์ดาแทนตัวชี้สมาชิก
template <>
struct glz ::meta<Thing> {
static constexpr auto value = object(
" i " , []( auto && self) -> auto & { return self. subclass . i ; }
);
};
ค่า self
ส่งผ่านไปยังฟังก์ชัน lambda จะเป็นวัตถุ Thing
และฟังก์ชัน lambda ช่วยให้เราสามารถทำให้คลาสย่อยมองไม่เห็นในอินเทอร์เฟซของวัตถุ
ฟังก์ชัน Lambda จะส่งกลับการคัดลอกตามค่าเริ่มต้น ดังนั้นโดยทั่วไปจำเป็นต้องใช้ประเภทการส่งคืน auto&
เพื่อให้การเคลือบเขียนลงในหน่วยความจำ
โปรดทราบว่าการแมปใหม่สามารถทำได้ผ่านพอยน์เตอร์/ข้อมูลอ้างอิง เนื่องจากการเคลือบจะถือว่าค่า พอยน์เตอร์ และการอ้างอิงในลักษณะเดียวกันเมื่อเขียน/อ่าน
คลาสสามารถถือเป็นค่าพื้นฐานได้ดังนี้:
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 ไม่ถูกต้องตรงนี้
แนะนำให้ใช้สตริงที่ไม่ใช่ const std::string
สำหรับบัฟเฟอร์อินพุต เนื่องจากจะทำให้ Glaze ปรับปรุงประสิทธิภาพด้วยการเติมชั่วคราว และบัฟเฟอร์จะถูกยกเลิกด้วยค่าว่าง
ตามค่าเริ่มต้น ตัวเลือก null_terminated
ถูกตั้งค่าเป็น true
และต้องใช้บัฟเฟอร์ที่สิ้นสุดด้วย null เมื่อแยกวิเคราะห์ JSON ตัวเลือกสามารถปิดได้โดยมีการสูญเสียประสิทธิภาพเล็กน้อย ซึ่งอนุญาตให้บัฟเฟอร์ที่สิ้นสุดที่ไม่ใช่ค่าว่าง:
constexpr glz::opts options{. null_terminated = false };
auto ec = glz::read<options>(value, buffer); // read in a non-null terminated buffer
ไม่จำเป็นต้องยุติค่า Null เมื่อแยกวิเคราะห์ BEVE (ไบนารี) มันไม่ทำให้ความแตกต่างในประสิทธิภาพ
คำเตือน
ปัจจุบัน null_terminated = false
ไม่ถูกต้องสำหรับการแยกวิเคราะห์ CSV และบัฟเฟอร์จะต้องถูกยกเลิกด้วยค่า null
ประเภทอาร์เรย์จะแปลงค่าอาร์เรย์ 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
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));
ตามค่าเริ่มต้น enums จะถูกเขียนและอ่านในรูปแบบจำนวนเต็ม ไม่จำเป็นต้องมี glz::meta
หากนี่เป็นพฤติกรรมที่ต้องการ
อย่างไรก็ตาม หากคุณต้องการใช้ enum เป็นสตริงใน 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
เก็บการอ้างอิงถึงค่า lvalues เพื่อหลีกเลี่ยงการคัดลอก
ดู 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)
};
ตัวเลือกเวลาคอมไพล์เหล่านี้จำนวนมากมี wrappers เพื่อนำตัวเลือกไปใช้กับฟิลด์เดียวเท่านั้น ดู Wrappers สำหรับรายละเอียดเพิ่มเติม
ตามค่าเริ่มต้น Glaze จะปฏิบัติตามมาตรฐาน JSON ล่าสุดอย่างเคร่งครัด ยกเว้นในสองกรณีที่มีตัวเลือกที่เกี่ยวข้องกัน:
validate_skipped
ตัวเลือกนี้จะทำการตรวจสอบ JSON เต็มรูปแบบสำหรับค่าที่ข้ามเมื่อแยกวิเคราะห์ ค่านี้ไม่ได้ตั้งค่าไว้ตามค่าเริ่มต้น เนื่องจากโดยทั่วไปแล้วค่าต่างๆ จะถูกข้ามไปเมื่อผู้ใช้ไม่สนใจ และ Glaze ยังคงตรวจสอบปัญหาหลักๆ แต่สิ่งนี้ทำให้การข้ามเร็วขึ้นโดยไม่สนใจว่าค่าที่ข้ามนั้นเป็นไปตาม JSON หรือไม่ ตัวอย่างเช่น โดยค่าเริ่มต้น Glaze จะตรวจสอบให้แน่ใจว่าตัวเลขที่ข้ามมีอักขระตัวเลขที่ถูกต้องทั้งหมด แต่จะไม่ตรวจสอบปัญหาเช่นเลขศูนย์นำหน้าในตัวเลขที่ข้าม เว้นแต่ว่า validate_skipped
เปิดอยู่ เมื่อใดก็ตามที่ Glaze แยกวิเคราะห์ค่าที่จะใช้ จะมีการตรวจสอบความถูกต้องโดยสมบูรณ์validate_trailing_whitespace
ตัวเลือกนี้ตรวจสอบช่องว่างต่อท้ายในเอกสารที่แยกวิเคราะห์ เนื่องจาก Glaze แยกวิเคราะห์โครงสร้าง C++ โดยทั่วไปจึงไม่จำเป็นต้องแยกวิเคราะห์ต่อไปหลังจากอ่านวัตถุที่สนใจแล้ว เปิดตัวเลือกนี้หากคุณต้องการให้แน่ใจว่าส่วนที่เหลือของเอกสารมีช่องว่างที่ถูกต้อง มิฉะนั้น Glaze จะเพิกเฉยต่อเนื้อหาหลังจากแยกวิเคราะห์เนื้อหาที่สนใจแล้ว บันทึก
Glaze จะไม่ใช้ Unicode อักขระควบคุม Escape โดยอัตโนมัติ (เช่น "x1f"
ถึง "u001f"
) เนื่องจากอาจเสี่ยงต่อการฝังอักขระ Null และอักขระที่มองไม่เห็นอื่นๆ ในสตริง ตัวเลือกเวลาคอมไพล์จะถูกเพิ่มเพื่อเปิดใช้งานการแปลงเหล่านี้ (ปัญหาเปิด: การเขียนแบบ Escape ของ Unicode) แต่จะไม่ใช่พฤติกรรมเริ่มต้น
อาจเป็นประโยชน์ในการรับทราบถึงการมีอยู่ของคีย์ในออบเจ็กต์เพื่อป้องกันข้อผิดพลาด แต่ค่าดังกล่าวอาจไม่จำเป็นหรือมีอยู่ใน 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
ฯลฯ ได้โดยตรงโดยใช้ wrapper 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 Lines (หรือ Newline Delimited 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 โดยมีข้อยกเว้นสำหรับแบบฟอร์มฝังตัว:
--- ข้อยกเว้นเพิ่มเติมสำหรับใบอนุญาต ---
เป็นข้อยกเว้น หากผลของการคอมไพล์ซอร์สโค้ดของคุณ บางส่วนของซอฟต์แวร์นี้ถูกฝังอยู่ในรูปแบบออบเจ็กต์ที่สามารถเรียกทำงานได้ด้วยเครื่องจักรของซอร์สโค้ดดังกล่าว คุณสามารถแจกจ่ายส่วนที่ฝังไว้ดังกล่าวในรูปแบบออบเจ็กต์ดังกล่าวอีกครั้งได้โดยไม่รวมถึงลิขสิทธิ์และการอนุญาต ประกาศ