Jsonpp is a modern, header-only C++17 JSON library built around a configurable basic_json template.
It focuses on:
- Type-safe JSON value handling via
std::variant. - Flexible container customization (
std::maporstd::unordered_map, etc.). - Generic stream-based parsing and serialization.
- A fast path for contiguous input (
std::string_view).
- Why jsonpp
- Requirements
- Quick Start
- Integration
- Core Types and Design
- Implemented API (v0.1.4)
- Parsing and Serialization
- Error Handling
- Performance Notes
- Known Limitations and Roadmap
- Testing
- Project Layout
- License
- Header-only: Include and use without building a static/shared library.
- Template-first architecture:
basic_jsonlets you customize object/array/string/number types. - IO abstraction: Works with
std::string_view,std::istream, and custom streams. - Round-trip tested: Parse/serialize consistency is covered by the test suite.
- C++17 or newer.
- CMake 3.24+ (for building/running tests in this repository).
#include "jsonpp.hpp"
#include <iostream>
int main() {
using jsonpp::json;
json j = json::parse(R"({"name":"Mikami","age":25,"tags":["cpp","json"]})");
std::cout << j.at("name").as_string() << "\n"; // Mikami
std::cout << j["age"].as_int() << "\n"; // 25
j["active"] = true;
j["score"] = 98.5;
std::cout << j.stringify() << "\n";
std::cout << j.pretty(" ") << "\n";
}Add this repository's src/ to your include path, then:
#include "jsonpp.hpp"Use single_include/jsonpp.hpp when a single-file drop-in is preferred.
cmake_minimum_required(VERSION 3.16)
project(my_app)
add_executable(my_app main.cpp)
target_include_directories(my_app PRIVATE /path/to/jsonpp/src)Primary aliases:
jsonpp::json=basic_json<>jsonpp::unordered_json=basic_json<std::unordered_map>jsonpp::null= JSON null value
The core value type is implemented with std::variant and supports:
- empty (default-constructed state)
- null
- bool
- int64
- double
- string
- array
- object
json(map-based object): deterministic key order in serialization.unordered_json(hash-map object): typically faster lookup, but key order is not stable.
This section lists APIs that are implemented in the current codebase.
- Constructors from null/bool/integer/floating/string/array/object.
type(),empty(),is_null(),is_bool(),is_number(),is_int(),is_float(),is_string(),is_array(),is_object().set_type<Type::...>(clear_content = false)andset_type(Type, clear_content = false).size().
- Array access:
operator[](size_t),at(size_t). - Object access:
operator[](const std::string&),at(const std::string&). - Object lookup:
find(const std::string&),count(const std::string&),contains(const std::string&). - Safe pointers:
get_if_bool/int/float/string/array/object(). - Checked conversion:
as_bool/int/float/string/array/object().
Behavior notes:
operator[](size_t)uses an internal assertion for bounds checking in debug builds; useat(size_t)when you need checked access with exceptions.- Non-const
operator[](const std::string&)converts an empty/null value to an object before insertion. - Const
operator[](const std::string&)delegates toat(...)and throws if the key does not exist. find/count/containsare object-only and throwJsonTypeErrorfor non-object values.
- Iterators:
begin/end/cbegin/cend/rbegin/rend/crbegin/crend. - Type-dependent range behavior:
empty=> empty rangenull/bool/int/float/string=> single-element rangearray=> iterate array elementsobject=> iterate values (JSON references), object key is available viait.key()
- Reverse iteration is available when both underlying array/object iterators support bidirectional traversal.
push_back(...),emplace_back(...)for arrays.insert(std::pair<string, json>),emplace(...)for objects.insert(const_iterator pos, const json&)for arrays.erase(const std::string&),erase(size_t),erase(const_iterator),erase(const_iterator, const_iterator).update(const json&, merge_objects),update(const_iterator, const_iterator, merge_objects).swap(...)and ADLswap.
parse(std::string_view)parse(std::istream&)parse(StreamT&)for custom stream types satisfying JSON stream traits.dump(std::string&, pretty = false, indent = "\t")dump(std::ostream&, pretty = false, indent = "\t")dump(SerializeHandlerT&, pretty = false, indent = "\t")stringify()andpretty(indent)
operator==,operator!=operator<<
auto j = jsonpp::json::parse(R"({"k":1,"arr":[1,2,3]})");Note: parsing an empty/whitespace-only document returns the library's empty JSON state.
#include <sstream>
std::stringstream ss(R"({"ok":true})");
auto j = jsonpp::json::parse(ss);std::string compact = j.stringify();
std::string pretty = j.pretty(" ");
j.dump(std::cout, true, " ");To be accepted by parse(StreamT&), a stream type must provide:
int peek()int advance()std::size_t tell_pos()bool eof()
Optional capabilities (size, seek, get_chunk, read_chunk_until) enable optimized parsing paths.
To be accepted by dump(SerializeHandlerT&), a handler must provide:
append(char)append(std::string_view)append(const char*, std::size_t)
Jsonpp defines dedicated exception types:
JsonParseError: malformed JSON, invalid escapes, number parse errors, trailing tokens, etc.JsonTypeError: invalid typed access (for exampleas_int()on a string).JsonOutOfRange: array index out-of-range or missing object key viaat(...).JsonDepthLimitExceeded: nesting exceedsMAX_NESTING_DEPTH(default1024).
Example:
try {
auto j = jsonpp::json::parse("{bad json}");
} catch (const jsonpp::JsonParseError& e) {
// handle parse failure
}parse(std::string_view)uses a contiguous-stream path (StringViewStream) with chunk reads, reducing per-character overhead.parse(std::istream&)uses a generic stream adapter (IStreamStream) suitable for large input sources.- Number parsing uses
std::from_charsfor both integer and floating-point conversion. - Serializer emits floating numbers with a decimal suffix when needed (for example
1.0).
The following are currently declared in headers but not fully implemented in v0.1.4:
- Several STL-like helpers/modifiers such as
max_size,capacity,reserve,shrink_to_fit,front,back,value,clear,pop_back,resize,insert(InputIt, InputIt),insert(initializer_list), andtry_emplace. - Iterator-based APIs for modifiers are partially implemented (core insert/erase/update paths are available, while some declared overloads are still pending).
- Stateful allocator instance storage in
basic_json. - Planned extension points noted in code comments (such as ADL serializer customization and binary type support).
If you need a method listed above, check implementation status before use.
This repository includes:
- correctness tests
- usage tests
- round-trip tests (multiple JSON fixtures)
- spot-check tests for realistic nested data
Run tests:
cmake -B build -S .
cmake --build build
cd build
ctest --output-on-failureKey test files:
tests/gtest_correctness.cpptests/gtest_usage.cpptests/gtest_roundtrip.cpptests/gtest_spotcheck.cpp
src/- main headerssrc/detail/- parser, serializer, traits, stream adapters, core implementationsingle_include/- amalgamated single-header distributiontests/- GoogleTest-based test suite and test data
Apache License 2.0. See LICENSE for details.