Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -26,3 +27,7 @@ endif()
if(BUILD_BENCH)
add_subdirectory(benchmark)
endif()

if(BUILD_EXAMPLE)
add_subdirectory(example)
endif()
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
15 changes: 15 additions & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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()
2 changes: 1 addition & 1 deletion example/addmember.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
67 changes: 67 additions & 0 deletions example/document_api.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include <iostream>
#include <string>
#include <utility>

#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();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Check that the array is nonempty before popping

If allocation fails during all three PushBack calls while the document's existing object capacity still permits adding the versions member, this lookup succeeds with an empty array and PopBack() evaluates Size() - 1; debug builds abort on its nonempty assertion, while release builds access invalid memory. Check allocator.HadOom() after the fallible construction operations or include Empty() in this guard before mutating the array.

AGENTS.md reference: AGENTS.md:L145-L151

Useful? React with 👍 / 👎.


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