Apache Fory™ is a blazing fast multi-language serialization framework powered by JIT compilation and zero-copy techniques, providing up to ultra-fast performance while maintaining ease of use and type safety.
The C++ implementation provides high-performance serialization with compile-time type safety through template metaprogramming and zero-copy row format for analytics workloads.
- Blazingly Fast: Fast serialization and optimized binary protocols
- Cross-Language: Seamlessly serialize/deserialize data across Java, Python, C++, Go, JavaScript, and Rust
- Type-Safe: Compile-time type checking with template specialization
- Shared References: Automatic tracking of shared and circular references
- Schema Evolution: Compatible mode for independent schema changes
- Two Formats: Object graph serialization and zero-copy row-based format
- Modern C++17: Clean API using modern C++ features
Fory C++ demonstrates competitive performance compared to protobuf c++ serialization framework.
For more detailed benchmarks and methodology, see C++ Benchmarks.
#include "fory/serialization/fory.h"
// Define your class with FORY_STRUCT macro (struct works the same way).
// Place it after all fields.
// When used inside a class, it must be placed in a public: section.
struct Person {
std::string name;
int32_t age;
std::string email;
FORY_STRUCT(Person, name, age, email);
};
int main() {
// Create Fory instance
auto fory = apache::fory::ForyBuilder()
.xlang(true)
.track_ref(true)
.build();
// Register type
fory->register_struct<Person>(1);
// Create object
Person person{"Alice", 30, "alice@example.com"};
// Serialize
auto result = fory->serialize(person);
if (!result.ok()) {
std::cerr << "Serialization failed: " << result.error().message() << std::endl;
return 1;
}
std::vector<uint8_t> bytes = std::move(result.value());
// Deserialize
auto decoded = fory->deserialize<Person>(bytes);
if (!decoded.ok()) {
std::cerr << "Deserialization failed: " << decoded.error().message() << std::endl;
return 1;
}
Person restored = decoded.value();
assert(restored.name == "Alice");
assert(restored.age == 30);
return 0;
}Apache Fory™ provides automatic serialization of complex object graphs, preserving the structure and relationships between objects. The FORY_STRUCT macro enables compile-time reflection without runtime overhead.
Key capabilities:
- Nested struct serialization with arbitrary depth
- Collection types (vector, set, unordered_set)
- Map types (map, unordered_map)
- Optional fields with
std::optional<T> - Smart pointers (shared_ptr, unique_ptr, weak_ptr)
- Efficient binary encoding with variable-length integers
#include "fory/serialization/fory.h"
class Address {
public:
std::string street;
std::string city;
std::string country;
FORY_STRUCT(Address, street, city, country);
};
class Person {
public:
std::string name;
int32_t age;
Address address;
std::vector<std::string> hobbies;
std::map<std::string, std::string> metadata;
FORY_STRUCT(Person, name, age, address, hobbies, metadata);
};
auto fory = apache::fory::ForyBuilder().build();
fory->register_struct<Address>(100);
fory->register_struct<Person>(200);
Person person{
"John Doe",
30,
Address{"123 Main St", "New York", "USA"},
{"reading", "coding"},
{{"role", "developer"}}
};
auto bytes = fory->serialize(person).value();
auto decoded = fory->deserialize<Person>(bytes).value();For third-party types where you cannot modify the class definition, use
FORY_STRUCT at namespace scope. This works for public fields only.
namespace thirdparty {
struct Foo {
int32_t id;
std::string name;
};
FORY_STRUCT(Foo, id, name);
} // namespace thirdparty
auto fory = apache::fory::ForyBuilder().build();
fory->register_struct<thirdparty::Foo>(1);To include base-class fields in a derived type, use FORY_BASE(Base) inside
FORY_STRUCT. The base must define its own FORY_STRUCT so its fields can be
referenced.
struct Base {
int32_t id;
FORY_STRUCT(Base, id);
};
struct Derived : Base {
std::string name;
FORY_STRUCT(Derived, FORY_BASE(Base), name);
};Apache Fory™ automatically tracks and preserves reference identity for shared objects using std::shared_ptr<T>. When the same object is referenced multiple times, Fory serializes it only once and uses reference IDs for subsequent occurrences.
auto fory = apache::fory::ForyBuilder()
.track_ref(true)
.build();
// Create a shared value
auto shared = std::make_shared<std::string>("shared_value");
// Reference it multiple times
std::vector<std::shared_ptr<std::string>> data = {shared, shared, shared};
// The shared value is serialized only once
auto bytes = fory->serialize(data).value();
auto decoded = fory->deserialize<std::vector<std::shared_ptr<std::string>>>(bytes).value();
// Verify reference identity is preserved
assert(decoded[0].get() == decoded[1].get());
assert(decoded[1].get() == decoded[2].get());Apache Fory™ supports schema evolution in Compatible mode, allowing serialization and deserialization peers to have different type definitions.
// Version 1
struct PersonV1 {
std::string name;
int32_t age;
std::string address;
FORY_STRUCT(PersonV1, name, age, address);
};
// Version 2 - address removed, phone added
struct PersonV2 {
std::string name;
int32_t age;
std::optional<std::string> phone;
FORY_STRUCT(PersonV2, name, age, phone);
};
auto fory1 = apache::fory::ForyBuilder()
.compatible(true)
.build();
fory1->register_struct<PersonV1>(1);
auto fory2 = apache::fory::ForyBuilder()
.compatible(true)
.build();
fory2->register_struct<PersonV2>(1);
PersonV1 v1{"Alice", 30, "123 Main St"};
auto bytes = fory1->serialize(v1).value();
// Deserialize with V2 - missing fields get default values
auto v2 = fory2->deserialize<PersonV2>(bytes).value();
assert(v2.name == "Alice");
assert(v2.phone == std::nullopt);Apache Fory™ supports enum serialization with automatic ordinal mapping:
// Continuous enum - works automatically
enum class Color { Red, Green, Blue };
// Non-continuous enum - needs FORY_ENUM
enum class LegacyStatus { Active = 1, Inactive = 5, Pending = 10 };
FORY_ENUM(LegacyStatus, Active, Inactive, Pending);
// FORY_ENUM must be defined at namespace scope.
struct Item {
std::string name;
Color color;
LegacyStatus status;
FORY_STRUCT(Item, name, color, status);
};Apache Fory™ supports std::variant for type-safe union types:
using Value = std::variant<std::monostate, bool, int32_t, std::string>;
struct Config {
std::string key;
Value value;
FORY_STRUCT(Config, key, value);
};
Config config{"timeout", 30};
auto bytes = fory->serialize(config).value();Apache Fory™ provides a high-performance row format for zero-copy deserialization, enabling random access to fields directly from binary data.
#include "fory/encoder/row_encoder.h"
struct UserProfile {
int64_t id;
std::string username;
std::string email;
std::vector<int32_t> scores;
bool is_active;
FORY_STRUCT(UserProfile, id, username, email, scores, is_active);
};
apache::fory::RowEncoder<UserProfile> encoder;
UserProfile profile{12345, "alice", "alice@example.com", {95, 87, 92}, true};
// encode to row format
encoder.encode(profile);
auto& writer = encoder.get_writer();
// Access fields directly without full deserialization
auto row = writer.to_row();
assert(row.get_int64(0) == 12345); // id
assert(row.get_string(1) == "alice"); // username
assert(row.get_bool(4) == true); // is_activeApache Fory™ supports seamless data exchange across multiple languages:
// Enable cross-language mode
auto fory = apache::fory::ForyBuilder()
.xlang(true)
.compatible(true)
.build();
// Register types with consistent IDs across languages
fory->register_struct<MyStruct>(1);See xlang_type_mapping.md for type mapping across languages.
// Single-threaded (fastest performance)
auto fory = apache::fory::ForyBuilder().build();
// Thread-safe with internal Fory pool
auto fory = apache::fory::ForyBuilder().build_thread_safe();The C++ implementation consists of these main components:
cpp/fory/
├── serialization/ # Object graph serialization
│ ├── fory.h # Main entry point (Fory, ThreadSafeFory)
│ ├── config.h # Configuration options
│ ├── serializer.h # Core serializer API
│ ├── basic_serializer.h # Primitive type serializers
│ ├── string_serializer.h # String type serializers
│ ├── struct_serializer.h # Struct serialization with FORY_STRUCT
│ ├── collection_serializer.h # vector, set serializers
│ ├── map_serializer.h # map serializers
│ ├── smart_ptr_serializers.h # optional, shared_ptr, unique_ptr
│ ├── temporal_serializers.h # Duration, Timestamp, Date
│ ├── variant_serializer.h # std::variant support
│ ├── type_resolver.h # Type resolution and registration
│ └── context.h # Read/write context
├── encoder/ # Row format encoding
│ ├── row_encoder.h # Row format encoder
│ └── row_encode_trait.h # Encoding traits
├── row/ # Row format data structures
│ ├── row.h # Row, ArrayData, MapData
│ ├── writer.h # RowWriter, ArrayWriter
│ ├── schema.h # Schema definitions
│ └── type.h # Type definitions
├── meta/ # Compile-time reflection
│ ├── field_info.h # Field metadata extraction
│ └── type_traits.h # Type traits utilities
└── util/ # Common utilities
├── buffer.h # Binary buffer management
├── error.h # Error handling
└── status.h # Status codes
- C++ Standard: C++17 or later
- Build System: Bazel 8.2.1+ or CMake 3.16+
# Build all projects
bazel build //cpp/...
# Run all tests
bazel test $(bazel query //cpp/...)
# Run serialization tests
bazel test $(bazel query //cpp/fory/serialization/...)mkdir build && cd build
cmake ..
make -j$(nproc)# Format code
clang-format -i <file>
# Or use the CI script
bash ci/format.sh --cpp- User Guide - Comprehensive user documentation
- Protocol Specification - Serialization protocol details
- Type Mapping - Cross-language type mappings
- Source - Documentation source
- Complex data structures with nested objects and references
- Cross-language communication in microservices
- General-purpose serialization with full type safety
- Schema evolution with compatible mode
- High-throughput data processing
- Analytics workloads requiring fast field access
- Memory-constrained environments
- Zero-copy scenarios
Licensed under the Apache License, Version 2.0. See LICENSE for details.
We welcome contributions! Please see our Contributing Guide for details.
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Slack: Apache Fory Slack
Apache Fory™ - Blazingly fast multi-language serialization framework.
