From c4058d9d226aba9e1cf1f41e8bfe91b804cbb1d4 Mon Sep 17 00:00:00 2001 From: Francisco Geiman Thiesen Date: Fri, 8 Aug 2025 02:24:12 +0000 Subject: [PATCH] Adding scripts with both serialization and deserialization --- examples/conference_demo_serialization.sh | 322 ++++++++++++++++++++++ examples/github_serialization_demo.cpp | 95 +++++++ examples/reflection_roundtrip_demo.cpp | 86 ++++++ examples/serialization_benchmark.cpp | 85 ++++++ 4 files changed, 588 insertions(+) create mode 100755 examples/conference_demo_serialization.sh create mode 100644 examples/github_serialization_demo.cpp create mode 100644 examples/reflection_roundtrip_demo.cpp create mode 100644 examples/serialization_benchmark.cpp diff --git a/examples/conference_demo_serialization.sh b/examples/conference_demo_serialization.sh new file mode 100755 index 000000000..6d5bd5a33 --- /dev/null +++ b/examples/conference_demo_serialization.sh @@ -0,0 +1,322 @@ +#!/bin/bash +# Conference Demo Script - simdjson One-Liner Magic (WITH SERIALIZATION!) +# Extended demo showcasing both deserialization AND serialization with C++26 reflection + +# Check if cpr is built +if [ ! -f "../deps/cpr/build/lib/libcpr.a" ]; then + echo "āš ļø CPR library not found. Building it first..." + echo "" + if [ ! -d "../deps/cpr" ]; then + mkdir -p ../deps + cd ../deps + git clone https://github.com/libcpr/cpr.git + cd cpr && git checkout 1.10.5 + cd ../.. + fi + cd ../deps/cpr + mkdir -p build && cd build + cmake .. -DCMAKE_CXX_COMPILER=clang++ -DCPR_USE_SYSTEM_CURL=ON -DBUILD_SHARED_LIBS=OFF -DCPR_ENABLE_SSL=OFF + make -j4 + cd ../../../examples + echo "āœ… CPR built successfully!" + echo "" +fi + +clear +echo "šŸš€ simdjson: Complete JSON Round-Trip with C++26 Reflection" +echo "============================================================" +echo "" +echo "Today we'll showcase BOTH deserialization AND serialization!" +echo "" +echo "Press Enter to continue..." +read + +# Create a demo program that shows serialization +cat > github_serialization_demo.cpp << 'EOF' +#include +#include +#include "simdjson.h" +#include + +struct GitHubUser { + std::string login; + std::optional name; + std::optional company; + std::optional blog; + std::optional location; + std::optional email; + std::optional bio; + int64_t public_repos; + int64_t followers; + int64_t following; +}; + +int main() { + std::cout << "šŸ”„ C++26 Reflection: Complete JSON Round-Trip Demo\n"; + std::cout << "================================================\n\n"; + + // Step 1: Fetch real data from GitHub + std::cout << "šŸ“” Fetching GitHub user data...\n"; + auto response = cpr::Get(cpr::Url{"https://api.github.com/users/simdjson"}); + + if (response.status_code != 200) { + std::cerr << "Error: Failed to fetch data\n"; + return 1; + } + + std::cout << "āœ… Received " << response.text.length() << " bytes of JSON\n\n"; + + // Step 2: Deserialize with ONE LINE + std::cout << "šŸ“„ DESERIALIZATION (JSON → Struct)\n"; + std::cout << "Code: GitHubUser user = simdjson::from(simdjson::padded_string(response.text));\n\n"; + + GitHubUser user = simdjson::from(simdjson::padded_string(response.text)); + + // Show the data we parsed + std::cout << "Parsed data:\n"; + std::cout << " • Login: " << user.login << "\n"; + std::cout << " • Name: " << (user.name.has_value() ? *user.name : "") << "\n"; + std::cout << " • Company: " << (user.company.has_value() ? *user.company : "") << "\n"; + std::cout << " • Location: " << (user.location.has_value() ? *user.location : "") << "\n"; + std::cout << " • Bio: " << (user.bio.has_value() ? *user.bio : "") << "\n"; + std::cout << " • Repos: " << user.public_repos << "\n"; + std::cout << " • Followers: " << user.followers << "\n\n"; + + // Step 3: Modify the data + std::cout << "āœļø Modifying data...\n"; + user.followers += 1000; // Wishful thinking! + user.name = "simdjson - JSON at the speed of light"; // Set a name + user.bio = user.bio.value_or("") + " (Now with C++26 reflection!)"; + std::cout << " • Added 1000 followers (we can dream!)\n"; + std::cout << " • Set organization name\n"; + std::cout << " • Updated bio\n\n"; + + // Step 4: Serialize back to JSON with ONE LINE + std::cout << "šŸ“¤ SERIALIZATION (Struct → JSON)\n"; + std::cout << "Code: std::string json = simdjson::builder::to_json_string(user);\n\n"; + + auto json_result = simdjson::builder::to_json_string(user); + if (json_result.error()) { + std::cerr << "Serialization error!\n"; + return 1; + } + std::string json = json_result.value(); + + std::cout << "Generated JSON (" << json.length() << " bytes):\n"; + // Pretty print first 200 chars + if (json.length() > 200) { + std::cout << json.substr(0, 200) << "...\n\n"; + } else { + std::cout << json << "\n\n"; + } + + // Step 5: Verify round-trip + std::cout << "šŸ”„ ROUND-TRIP VERIFICATION\n"; + std::cout << "Parsing our generated JSON back...\n"; + + GitHubUser user2 = simdjson::from(simdjson::padded_string(json)); + + std::cout << "āœ… Round-trip successful!\n"; + std::cout << " • Original followers: " << user.followers << "\n"; + std::cout << " • Parsed followers: " << user2.followers << "\n"; + std::cout << " • Name set correctly: " << (user2.name.has_value() && *user2.name == *user.name ? "YES" : "NO") << "\n"; + std::cout << " • Bio preserved: " << (user2.bio.has_value() ? "YES" : "NO") << "\n\n"; + + std::cout << "šŸŽ‰ That's it! Two lines of code for complete JSON handling:\n"; + std::cout << " • Deserialization: simdjson::from(...)\n"; + std::cout << " • Serialization: simdjson::builder::to_json_string(...)\n"; + + return 0; +} +EOF + +# Create a benchmark that includes serialization +cat > serialization_benchmark.cpp << 'EOF' +#include +#include +#include +#include "simdjson.h" +#include + +struct TestData { + std::string name; + std::vector numbers; + std::map metrics; + bool active; + std::optional description; +}; + +int main() { + std::cout << "⚔ Serialization Performance Benchmark\n"; + std::cout << "=====================================\n\n"; + + // Create test data + TestData data{ + .name = "Performance Test", + .numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + .metrics = {{"latency", 1.23}, {"throughput", 456.78}, {"cpu", 89.01}}, + .active = true, + .description = "Testing reflection-based serialization performance" + }; + + const int iterations = 100000; + + // Benchmark serialization + std::cout << "šŸ“¤ Benchmarking serialization (" << iterations << " iterations)...\n"; + + auto start = std::chrono::high_resolution_clock::now(); + + std::string json; + for (int i = 0; i < iterations; i++) { + auto result = simdjson::builder::to_json_string(data); + if (i == 0 && !result.error()) { + json = result.value(); + } + } + + auto end = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(end - start); + + std::cout << "\nResults:\n"; + std::cout << " • Generated JSON size: " << json.length() << " bytes\n"; + std::cout << " • Total time: " << duration.count() / 1000.0 << " ms\n"; + + double time_per_iteration_us = duration.count() / double(iterations); + double time_per_iteration_s = time_per_iteration_us / 1000000.0; + double bytes_per_second = json.length() / time_per_iteration_s; + double mb_per_second = bytes_per_second / (1024.0 * 1024.0); + + std::cout << " • Time per serialization: " << std::fixed << std::setprecision(2) << time_per_iteration_us << " μs\n"; + std::cout << " • Throughput: " << std::fixed << std::setprecision(2) << mb_per_second << " MB/s\n"; + + std::cout << "\nGenerated JSON:\n" << json << "\n\n"; + + // Benchmark deserialization for comparison + std::cout << "šŸ“„ Benchmarking deserialization (for comparison)...\n"; + + simdjson::padded_string padded_json(json); + start = std::chrono::high_resolution_clock::now(); + + for (int i = 0; i < iterations; i++) { + TestData parsed = simdjson::from(padded_json); + } + + end = std::chrono::high_resolution_clock::now(); + duration = std::chrono::duration_cast(end - start); + + std::cout << "\nResults:\n"; + time_per_iteration_us = duration.count() / double(iterations); + time_per_iteration_s = time_per_iteration_us / 1000000.0; + bytes_per_second = json.length() / time_per_iteration_s; + mb_per_second = bytes_per_second / (1024.0 * 1024.0); + + std::cout << " • Time per deserialization: " << std::fixed << std::setprecision(2) << time_per_iteration_us << " μs\n"; + std::cout << " • Throughput: " << std::fixed << std::setprecision(2) << mb_per_second << " MB/s\n"; + + std::cout << "\nāœ… Both serialization and deserialization work with reflection!\n"; + + return 0; +} +EOF + +echo "šŸ“ First, let's see the traditional approach to serialization..." +echo "" +echo "Press Enter to see manual serialization code..." +read + +cat > manual_serialization_example.cpp << 'EOF' +// The OLD way - Manual serialization +std::string serialize_github_user(const GitHubUser& user) { + std::string json = "{"; + json += "\"login\":\"" + user.login + "\","; + json += "\"name\":\"" + user.name + "\","; + json += "\"company\":\"" + user.company + "\","; + json += "\"blog\":\"" + user.blog + "\","; + json += "\"location\":\"" + user.location + "\","; + + if (user.email.has_value()) { + json += "\"email\":\"" + *user.email + "\","; + } + if (user.bio.has_value()) { + json += "\"bio\":\"" + *user.bio + "\","; + } + + json += "\"public_repos\":" + std::to_string(user.public_repos) + ","; + json += "\"followers\":" + std::to_string(user.followers) + ","; + json += "\"following\":" + std::to_string(user.following); + json += "}"; + + return json; +} +EOF + +cat manual_serialization_example.cpp +echo "" +echo "šŸ˜“ That's error-prone and doesn't handle escaping!" +echo "" +echo "Press Enter to see the MODERN approach..." +read + +clear +echo "✨ The MODERN approach with C++26 reflection:" +echo "" +echo "Deserialization:" +echo " GitHubUser user = simdjson::from(json);" +echo "" +echo "Serialization:" +echo " std::string json = simdjson::builder::to_json_string(user);" +echo "" +echo "🤯 That's it! Bidirectional JSON handling in TWO lines!" +echo "" +echo "Press Enter to compile and run the complete demo..." +read + +# Compile and run serialization demo +echo "šŸ”Ø Compiling serialization demo..." +clang++ -std=c++26 -freflection -DSIMDJSON_STATIC_REFLECTION=1 \ + -I../deps/cpr/include -I../deps/cpr/build/cpr_generated_includes \ + -I../include -I.. github_serialization_demo.cpp ../singleheader/simdjson.cpp \ + ../deps/cpr/build/lib/libcpr.a -lcurl -pthread -o serialization_demo + +echo "āœ… Compiled!" +echo "" +echo "šŸƒ Running complete round-trip demo..." +echo "" +./serialization_demo + +echo "" +echo "Press Enter to run performance benchmarks..." +read + +clear +echo "⚔ PERFORMANCE BENCHMARKS" +echo "========================" +echo "" + +# Compile benchmark +echo "šŸ”Ø Compiling performance benchmark..." +clang++ -std=c++26 -freflection -O3 -march=native \ + -DSIMDJSON_STATIC_REFLECTION=1 \ + -I../include -I.. serialization_benchmark.cpp ../singleheader/simdjson.cpp \ + -pthread -o serialization_benchmark + +echo "āœ… Compiled!" +echo "" +echo "šŸƒ Running benchmark..." +echo "" +./serialization_benchmark + +echo "" +echo "šŸŽ‰ Summary:" +echo "===========" +echo "• ONE line for deserialization" +echo "• ONE line for serialization" +echo "• Works with complex nested structures" +echo "• Handles optional fields automatically" +echo "• Type-safe and performant" +echo "• No manual parsing/building code needed!" +echo "" +echo "The future of C++ JSON handling is here! šŸš€" + +# Cleanup +rm -f manual_serialization_example.cpp \ No newline at end of file diff --git a/examples/github_serialization_demo.cpp b/examples/github_serialization_demo.cpp new file mode 100644 index 000000000..0d38d99d6 --- /dev/null +++ b/examples/github_serialization_demo.cpp @@ -0,0 +1,95 @@ +#include +#include +#include "simdjson.h" +#include + +struct GitHubUser { + std::string login; + std::optional name; + std::optional company; + std::optional blog; + std::optional location; + std::optional email; + std::optional bio; + int64_t public_repos; + int64_t followers; + int64_t following; +}; + +int main() { + std::cout << "šŸ”„ C++26 Reflection: Complete JSON Round-Trip Demo\n"; + std::cout << "================================================\n\n"; + + // Step 1: Fetch real data from GitHub + std::cout << "šŸ“” Fetching GitHub user data...\n"; + auto response = cpr::Get(cpr::Url{"https://api.github.com/users/simdjson"}); + + if (response.status_code != 200) { + std::cerr << "Error: Failed to fetch data\n"; + return 1; + } + + std::cout << "āœ… Received " << response.text.length() << " bytes of JSON\n\n"; + + // Step 2: Deserialize with ONE LINE + std::cout << "šŸ“„ DESERIALIZATION (JSON → Struct)\n"; + std::cout << "Code: GitHubUser user = simdjson::from(simdjson::padded_string(response.text));\n\n"; + + GitHubUser user = simdjson::from(simdjson::padded_string(response.text)); + + // Show the data we parsed + std::cout << "Parsed data:\n"; + std::cout << " • Login: " << user.login << "\n"; + std::cout << " • Name: " << (user.name.has_value() ? *user.name : "") << "\n"; + std::cout << " • Company: " << (user.company.has_value() ? *user.company : "") << "\n"; + std::cout << " • Location: " << (user.location.has_value() ? *user.location : "") << "\n"; + std::cout << " • Bio: " << (user.bio.has_value() ? *user.bio : "") << "\n"; + std::cout << " • Repos: " << user.public_repos << "\n"; + std::cout << " • Followers: " << user.followers << "\n\n"; + + // Step 3: Modify the data + std::cout << "āœļø Modifying data...\n"; + user.followers += 1000; // Wishful thinking! + user.name = "simdjson - JSON at the speed of light"; // Set a name + user.bio = user.bio.value_or("") + " (Now with C++26 reflection!)"; + std::cout << " • Added 1000 followers (we can dream!)\n"; + std::cout << " • Set organization name\n"; + std::cout << " • Updated bio\n\n"; + + // Step 4: Serialize back to JSON with ONE LINE + std::cout << "šŸ“¤ SERIALIZATION (Struct → JSON)\n"; + std::cout << "Code: std::string json = simdjson::builder::to_json_string(user);\n\n"; + + auto json_result = simdjson::builder::to_json_string(user); + if (json_result.error()) { + std::cerr << "Serialization error!\n"; + return 1; + } + std::string json = json_result.value(); + + std::cout << "Generated JSON (" << json.length() << " bytes):\n"; + // Pretty print first 200 chars + if (json.length() > 200) { + std::cout << json.substr(0, 200) << "...\n\n"; + } else { + std::cout << json << "\n\n"; + } + + // Step 5: Verify round-trip + std::cout << "šŸ”„ ROUND-TRIP VERIFICATION\n"; + std::cout << "Parsing our generated JSON back...\n"; + + GitHubUser user2 = simdjson::from(simdjson::padded_string(json)); + + std::cout << "āœ… Round-trip successful!\n"; + std::cout << " • Original followers: " << user.followers << "\n"; + std::cout << " • Parsed followers: " << user2.followers << "\n"; + std::cout << " • Name set correctly: " << (user2.name.has_value() && *user2.name == *user.name ? "YES" : "NO") << "\n"; + std::cout << " • Bio preserved: " << (user2.bio.has_value() ? "YES" : "NO") << "\n\n"; + + std::cout << "šŸŽ‰ That's it! Two lines of code for complete JSON handling:\n"; + std::cout << " • Deserialization: simdjson::from(...)\n"; + std::cout << " • Serialization: simdjson::builder::to_json_string(...)\n"; + + return 0; +} diff --git a/examples/reflection_roundtrip_demo.cpp b/examples/reflection_roundtrip_demo.cpp new file mode 100644 index 000000000..b6b950f3a --- /dev/null +++ b/examples/reflection_roundtrip_demo.cpp @@ -0,0 +1,86 @@ +// Complete JSON Round-Trip Demo with C++26 Reflection +// Compile with: clang++ -std=c++26 -freflection -DSIMDJSON_STATIC_REFLECTION=1 reflection_roundtrip_demo.cpp ../singleheader/simdjson.cpp -o reflection_roundtrip_demo +#include +#include +#include +#include "simdjson.h" + +// Define our data structure - just a plain struct! +struct Product { + std::string name; + double price; + std::vector tags; + std::optional description; + bool in_stock; +}; + +int main() { + std::cout << "šŸ”„ simdjson C++26 Reflection Round-Trip Demo\n"; + std::cout << "============================================\n\n"; + + // Original JSON data + const char* json_data = R"({ + "name": "High-Performance JSON Parser", + "price": 0.0, + "tags": ["C++", "performance", "json", "reflection"], + "description": "The fastest JSON parser with C++26 reflection support", + "in_stock": true + })"; + + std::cout << "šŸ“„ Original JSON:\n" << json_data << "\n\n"; + + // Step 1: Deserialize JSON to struct with ONE line + std::cout << "šŸ“„ Deserializing JSON → Struct...\n"; + Product product = simdjson::from(simdjson::padded_string(json_data)); + + std::cout << "āœ… Deserialized successfully!\n"; + std::cout << " • Name: " << product.name << "\n"; + std::cout << " • Price: $" << product.price << "\n"; + std::cout << " • Tags: "; + for (const auto& tag : product.tags) { + std::cout << tag << " "; + } + std::cout << "\n • In stock: " << (product.in_stock ? "Yes" : "No") << "\n\n"; + + // Step 2: Modify the data + std::cout << "āœļø Modifying data...\n"; + product.price = 99.99; // It's worth something now! + product.tags.push_back("C++26"); + product.description = "Now with serialization support!"; + std::cout << " • Changed price to $99.99\n"; + std::cout << " • Added 'C++26' tag\n"; + std::cout << " • Updated description\n\n"; + + // Step 3: Serialize struct back to JSON with ONE line + std::cout << "šŸ“¤ Serializing Struct → JSON...\n"; + auto json_result = simdjson::builder::to_json_string(product); + + if (json_result.error()) { + std::cerr << "āŒ Serialization failed!\n"; + return 1; + } + + std::string new_json = json_result.value(); + std::cout << "āœ… Serialized successfully!\n\n"; + + std::cout << "šŸ“„ Generated JSON:\n" << new_json << "\n\n"; + + // Step 4: Verify round-trip by parsing again + std::cout << "šŸ” Verifying round-trip...\n"; + Product product2 = simdjson::from(simdjson::padded_string(new_json)); + + std::cout << "āœ… Round-trip successful!\n"; + std::cout << " • Price preserved: $" << product2.price << "\n"; + std::cout << " • New tag present: " + << (std::find(product2.tags.begin(), product2.tags.end(), "C++26") != product2.tags.end() ? "Yes" : "No") + << "\n"; + std::cout << " • Description updated: " << (product2.description.has_value() ? "Yes" : "No") << "\n\n"; + + std::cout << "šŸŽ‰ That's it! Complete JSON handling in just 2 lines:\n"; + std::cout << " • Deserialize: auto obj = simdjson::from(json);\n"; + std::cout << " • Serialize: auto json = simdjson::builder::to_json_string(obj);\n\n"; + + std::cout << "⚔ No manual parsing, no boilerplate, just pure C++26 magic!\n"; + + return 0; +} \ No newline at end of file diff --git a/examples/serialization_benchmark.cpp b/examples/serialization_benchmark.cpp new file mode 100644 index 000000000..c917f9daa --- /dev/null +++ b/examples/serialization_benchmark.cpp @@ -0,0 +1,85 @@ +#include +#include +#include +#include "simdjson.h" +#include + +struct TestData { + std::string name; + std::vector numbers; + std::map metrics; + bool active; + std::optional description; +}; + +int main() { + std::cout << "⚔ Serialization Performance Benchmark\n"; + std::cout << "=====================================\n\n"; + + // Create test data + TestData data{ + .name = "Performance Test", + .numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + .metrics = {{"latency", 1.23}, {"throughput", 456.78}, {"cpu", 89.01}}, + .active = true, + .description = "Testing reflection-based serialization performance" + }; + + const int iterations = 100000; + + // Benchmark serialization + std::cout << "šŸ“¤ Benchmarking serialization (" << iterations << " iterations)...\n"; + + auto start = std::chrono::high_resolution_clock::now(); + + std::string json; + for (int i = 0; i < iterations; i++) { + auto result = simdjson::builder::to_json_string(data); + if (i == 0 && !result.error()) { + json = result.value(); + } + } + + auto end = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(end - start); + + std::cout << "\nResults:\n"; + std::cout << " • Generated JSON size: " << json.length() << " bytes\n"; + std::cout << " • Total time: " << duration.count() / 1000.0 << " ms\n"; + + double time_per_iteration_us = duration.count() / double(iterations); + double time_per_iteration_s = time_per_iteration_us / 1000000.0; + double bytes_per_second = json.length() / time_per_iteration_s; + double mb_per_second = bytes_per_second / (1024.0 * 1024.0); + + std::cout << " • Time per serialization: " << std::fixed << std::setprecision(2) << time_per_iteration_us << " μs\n"; + std::cout << " • Throughput: " << std::fixed << std::setprecision(2) << mb_per_second << " MB/s\n"; + + std::cout << "\nGenerated JSON:\n" << json << "\n\n"; + + // Benchmark deserialization for comparison + std::cout << "šŸ“„ Benchmarking deserialization (for comparison)...\n"; + + simdjson::padded_string padded_json(json); + start = std::chrono::high_resolution_clock::now(); + + for (int i = 0; i < iterations; i++) { + TestData parsed = simdjson::from(padded_json); + } + + end = std::chrono::high_resolution_clock::now(); + duration = std::chrono::duration_cast(end - start); + + std::cout << "\nResults:\n"; + time_per_iteration_us = duration.count() / double(iterations); + time_per_iteration_s = time_per_iteration_us / 1000000.0; + bytes_per_second = json.length() / time_per_iteration_s; + mb_per_second = bytes_per_second / (1024.0 * 1024.0); + + std::cout << " • Time per deserialization: " << std::fixed << std::setprecision(2) << time_per_iteration_us << " μs\n"; + std::cout << " • Throughput: " << std::fixed << std::setprecision(2) << mb_per_second << " MB/s\n"; + + std::cout << "\nāœ… Both serialization and deserialization work with reflection!\n"; + + return 0; +}