diff --git a/CMakeLists.txt b/CMakeLists.txt index 69bd55c3..8e21a714 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ project( option(BUILD_UNITTEST "Build unittest." ON) option(BUILD_FUZZ "Build fuzz." OFF) option(BUILD_BENCH "Build benchmark." OFF) +option(BUILD_EXAMPLE "Build examples." OFF) option(ENABLE_SVE2_128 "Build for Arm SVE2 with 128 bit vector size" OFF) option(ENABLE_RISCV_ZBB "Enable RISC-V Zbb extension for bit manipulation optimizations" OFF) @@ -26,3 +27,7 @@ endif() if(BUILD_BENCH) add_subdirectory(benchmark) endif() + +if(BUILD_EXAMPLE) + add_subdirectory(example) +endif() diff --git a/README.md b/README.md index 3d2bb960..7eb3ee8f 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,19 @@ Sonic-Cpp is a header-only library, you only need to include the directory of Sonic-Cpp header files, such as adding `-I/path/to/sonic/include/` to your compiler. +### Building the examples + +The programs under [`example/`](example/) can be built together with CMake: + +```shell +cmake -S . -B build-examples -DBUILD_UNITTEST=OFF -DBUILD_EXAMPLE=ON +cmake --build build-examples +``` + +See [`example/document_api.cpp`](example/document_api.cpp) for a complete +Document API example covering object and array construction, mutation, member +removal, and serialization. + ### Parsing and Serializing ```c++ #include "sonic/sonic.h" diff --git a/docs/usage.md b/docs/usage.md index 7b970b5b..7c3cc593 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -45,6 +45,10 @@ Document is the manager of Nodes. Sonic-Cpp organizes JSON value as a tree. Document also the root of JSON value tree. There is an allocator in Document, which you should use to allocate memory for Node and Document. +See [`example/document_api.cpp`](../example/document_api.cpp) for a complete, +runnable example that creates object and array nodes, updates and removes +members, and serializes the resulting document. + > **Note:** Re-parsing a `Document` discards the previous tree. Any raw > pointers, iterators, or `DNode*` obtained from an earlier `Parse()` become > invalid and must be re-acquired after each parse. diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index e69de29b..3975e66b 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -0,0 +1,15 @@ +file(GLOB SONIC_EXAMPLE_FILES CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") + +include("${PROJECT_SOURCE_DIR}/cmake/set_arch_flags.cmake") + +foreach(EXAMPLE_FILE IN LISTS SONIC_EXAMPLE_FILES) + get_filename_component(EXAMPLE_NAME "${EXAMPLE_FILE}" NAME_WE) + set(EXAMPLE_TARGET "sonic_example_${EXAMPLE_NAME}") + + add_executable(${EXAMPLE_TARGET} "${EXAMPLE_FILE}") + target_compile_features(${EXAMPLE_TARGET} PRIVATE cxx_std_17) + target_include_directories(${EXAMPLE_TARGET} + PRIVATE "${PROJECT_SOURCE_DIR}/include") + set_arch_flags(${EXAMPLE_TARGET} "${CMAKE_SYSTEM_PROCESSOR}") +endforeach() diff --git a/example/addmember.cpp b/example/addmember.cpp index 618c078c..5403ad6a 100644 --- a/example/addmember.cpp +++ b/example/addmember.cpp @@ -14,4 +14,4 @@ int main() { std::cout << "Add member successfully!\n"; return 0; } -// g++ -I../include/ -march=haswell --std=c++11 get_and_set.cpp -o get_and_set +// g++ -I../include/ -march=haswell --std=c++11 addmember.cpp -o addmember diff --git a/example/document_api.cpp b/example/document_api.cpp new file mode 100644 index 00000000..554dce01 --- /dev/null +++ b/example/document_api.cpp @@ -0,0 +1,67 @@ +#include +#include +#include + +#include "sonic/sonic.h" + +int main() { + using NodeType = sonic_json::Node; + + sonic_json::Document doc; + auto& allocator = doc.GetAllocator(); + doc.SetObject(); + + doc.AddMember("name", NodeType("Sonic-Cpp", allocator), allocator); + doc.AddMember("enabled", NodeType(true), allocator); + + NodeType versions; + versions.SetArray(); + versions.PushBack(NodeType(1), allocator); + versions.PushBack(NodeType(2), allocator); + versions.PushBack(NodeType(3), allocator); + doc.AddMember("versions", std::move(versions), allocator); + + NodeType metadata; + metadata.SetObject(); + metadata.AddMember("language", NodeType("C++", allocator), allocator); + metadata.AddMember("license", NodeType("Apache-2.0", allocator), allocator); + doc.AddMember("metadata", std::move(metadata), allocator); + + auto enabled = doc.FindMember("enabled"); + if (enabled == doc.MemberEnd()) { + std::cerr << "The enabled member is missing.\n"; + return 1; + } + enabled->value.SetBool(false); + + auto version_list = doc.FindMember("versions"); + if (version_list == doc.MemberEnd() || !version_list->value.IsArray()) { + std::cerr << "The versions member is not an array.\n"; + return 1; + } + version_list->value.PopBack(); + + auto metadata_object = doc.FindMember("metadata"); + if (metadata_object == doc.MemberEnd() || + !metadata_object->value.IsObject() || + !metadata_object->value.RemoveMember("license")) { + std::cerr << "The metadata member could not be updated.\n"; + return 1; + } + + sonic_json::WriteBuffer buffer; + const sonic_json::SonicError error = doc.Serialize(buffer); + if (error != sonic_json::kErrorNone) { + std::cerr << "Serialize failed: " << sonic_json::ErrorMsg(error) << '\n'; + return 1; + } + + const std::string result = buffer.ToString(); + const std::string expected = + R"({"name":"Sonic-Cpp","enabled":false,"versions":[1,2],"metadata":{"language":"C++"}})"; + std::cout << result << '\n'; + return result == expected ? 0 : 1; +} + +// g++ -I../include/ -march=haswell --std=c++11 document_api.cpp -o +// document_api