Skip to content
 
 

Repository files navigation

cpplibv/vide - A C++26 serialization library

Vide is a header-only C++11 serialization library.

Vide takes arbitrary data types and reversibly turns them into different representations, such as compact binary encodings, XML, or JSON. Vide was designed to be fast, light-weight, and easy to extend - it has no external dependencies and can be easily bundled with other code or used standalone.

Vide is easy to use

Installation and use of Vide is easy, but this is a quick and dirty version:

  • Download Vide and place the headers somewhere your code can see them
  • Write serialization functions for your custom types or use the built-in support for the standard library Vide provides
  • Use the serialization archives to save and load data
#include <vide/archives/binary.hpp>
#include <vide/types/memory.hpp>
#include <vide/types/std_unordered_map.hpp>
#include <fstream>

struct MyRecord {
	uint8_t x;
	float y;

	template <class Archive> void serialize(Archive& ar) {
		ar(x);
		ar(y);
	}
};

class SomeData {
	std::shared_ptr<std::unordered_map<uint32_t, MyRecord>> data;
	int cachedSize = 0;

public:
	template <class Archive> void save(Archive& ar) const {
		ar(data);
	}

	template <class Archive> void load(Archive& ar) {
		ar(data);
		cachedSize = data ? data->size() : 0;
	}
};

int main() {
	std::ofstream os("out.bin", std::ios::binary | std::ios::out);

	SomeData myData;
	{
		vide::BinaryOutputArchive archive(os);
		archive(myData);
	}

	return 0;
}

Forked from Cereal:

Originally started as a fork from USCiLab/cereal

Compared to the original project the most notable changes are:

  • Fixed numerous security vulnerabilities
  • New features and utilities: ProxyArchives, Validations, Reflection
  • Improved API flexibility and composability
  • Significantly improved compile time
  • Modernized and simplify the codebase

Since compared to USCiLab/cereal multiple core functionality has been changed and therefore the two are not compatible! Bugfixes from the upstream are manually ported (and currently in sync with 2026.07.24 22a1b369).

Since v3.0.0 the data representation is considered STABLE! Hurray!

Planned / Upcoming new features:

The library is considered production ready and almost feature complete. Additional nice to have extras may arrive in the future.

  • reflection: Comprehensive reflection based serialization
  • reflection: Comprehensive rework of metaprogramming to utilize reflection
  • reflection: Rework enum validation to rely more on reflection
    • Replace unbounded_enumerator, end_value_enumerator and max_value_enumerator validation with attribute reflection
  • Comprehensive serialization error reporting. Additional stack information and archive position in error
    • Both during normal serialization and during validation
  • Foreach iteration/visitor algorithms
  • Archive level global version: const auto version_guard = ar.archive_version(config_version); and ar.archive_version()
  • Scoped versions and version guards: const auto version_guard = ar.scope_version(config_version); and ar.scope_version()
  • Maybe: Context variables passed as additional function arguments
  • Maybe: Versioned<->type selector

Change log:

  • Change name to vide to indicate the incompatibility with upstream
    • vide comes from the latin word serial
    • Name change was necessary due to incompatibilities
  • Remove some legacy compiler support
  • Bump required versions to C++23, GCC 11.2, CMake 3.20
  • Fixes and breaks some minor stuff
  • Remove VIDE_SETUP_ARCHIVE_TRAITS (Input and output archives are no longer linked)
    • Pro: Enables archives to be template types
    • Pro: One less macro that has to be called
    • Pro: Allows single in or out direction archives or type supports
    • Con: load_minimal type deduction is now done with the input archives on the save_minimal function (never called, only instantiated for type deduction)
    • Con: No check if save_minimal and load_minimal are correctly using different types
    • Note: Cons could be negated with a single typedef inside the input archive to the output archive
  • New archive flag vide::IgnoreNVP: Add support for specifying if archives ignores name from NVPs (previously this was hardcoded for the built-in binary archive only)
  • Move NVP into its own header
  • Move vide::access into its own header and add access_fwd.hpp header for forward declaration only
  • Move BinaryData, SizeTag, MapItem and construct into their own header
  • Rework type serializers to only include what is required
  • Remove load_and_construct
  • Remove pointer to derived in archive bases (just use this with CRTP)
  • Make archives movable
  • Remove the experimental UserDataAdapter (A better solution will come)
  • Remove the ability to call the archives with multiple member at the same times as ar(member0, member1, member2). Chaining is still possible prefer that syntax ar(member0)(member1)(member2) or just use multiple calls
    • Pro: Enables some future shenanigans
    • Pro: Alternative syntax are more clear and has same number of character, and has better auto formatting
    • Pro: More clear evaluation order, less variadic template
    • Con: More breakage
  • Add proxy archives (A way to inject context information into the serialization chain)
    • NOTE: polymorphic serialization will fall back to the underlying archives and not use the proxy
  • Add process_as customization point for archives to handle special types
  • Remove prologue and epilogue function support (process_as can take care of it)
  • Add ar.nvp("var", var) syntax to allow option to not include any header file and rely on dependent names only
  • Bump version to 2.1.0 and start versioning Vide
  • Version 2.2.0:
    • Remove specialize/specialization feature that could disambiguate in duplicate serialization methods. (For now serialization methods consistency is required in inheritance hierarchies)
    • Remove string/arithmetic type restriction from load_minimal/save_minimal
    • Add support for const reference return type during minimal serialization
    • Add support for recursive minimal serialization (But it is recommended to only use it with primitive/trivial types)
  • Version 2.2.1:
    • Add support for move reference parameter type for load_minimal function
  • Version 2.3.0:
    • Breaking change: Serialized data format changed breaking compatibility with data generated before this version
    • Sync with upstream 2024.05.02 d1fcec807
    • Security: Fix vulnerability where invalid data could allocate unbounded amount of memory during deserialization
      • Add ar.safe_to_reserve<T>() to check and clamp the amount of memory reserved
      • Add ar.validate_read_size<T>() to check if the archive has enough data for binary deserialization
      • Add ar.maximumBinaryReadSize() to report how much data could be extracted during binary deserialization
    • Refactor and modernize type traits
    • Add ar.size_tag() as a dependent name for vide::make_size_tag
    • Add Archive::is_binary_archive
    • Add Archive::size_type as a dependent name for vide::size_type
    • Add Archive::supports_binary<T> to test if the archive can binary serialize T
    • Remove Archive::could_serialize<T>
    • Improve compile time performance
    • Improve and modernize meta programming practices and techniques
    • Improve ar.nvp() to respect IgnoreNVP flag
    • Cleanup compiler warnings
  • Version 2.4.0:
    • Security: Fix vulnerability where binary bool would allow loading non 0 or 1 as value which could result in UB
    • Add support for static member serialize_class_version-ing which is serialized regardless if it is used in serializers or not
    • Add VIDE_CLASS_VERSION_TAG_NAME as a customization macro for vide_class_version
    • Improve CMAKE_BUILD_TYPE to be case-insensitive
    • Rename VIDE_XML_STRING_VALUE to VIDE_XML_ROOT_TAG_NAME
    • Move out exception.hpp header from details
    • Remove compatibility operator>>, operator<< and operator&
  • Version 2.5.0:
    • Add enum value verifications system: If an 'enum value set' is specified it will be verified during serialization and deserialization. This feature resolves the last known security concern. The 'enum value set' can be specified for EnumType by:
      • Defining an enumerator serialize_unbounded inside the EnumType with any value. Valid values: every underlying representation.
      • Defining an enumerator serialize_end_value inside the EnumType with the max value. Valid values: [0..end_value).
      • Defining an enumerator serialize_max_value inside the EnumType with the max value. Valid values: [0..max_value].
      • Defining a free function serialize_enum_unbounded(EnumType) : void reachable by ADL. Valid values every underlying representation.
      • Defining a free function serialize_enum_end_value(EnumType) : EnumType reachable by ADL returning the max value. Valid values: [0..end_value).
      • Defining a free function serialize_enum_end_value(EnumType) : Underlying reachable by ADL returning the max value. Valid values: [0..end_value).
      • Defining a free function serialize_enum_max_value(EnumType) : EnumType reachable by ADL returning with the max value. Valid values: [0..max_value].
      • Defining a free function serialize_enum_max_value(EnumType) : Underlying reachable by ADL returning with the max value. Valid values: [0..max_value].
      • Defining a free function serialize_enum_verify(EnumType) : bool reachable by ADL returning the value's validity. Valid values will those which return true.
      • As soon as C++ reflection are implemented additional (better) definition ways will be added
    • Add VIDE_STRICT_ENUM_VALUE_SET macro to specify whether vide should enforce enum value set specification. Should be defined to 0 or 1. Defaults to (0) disabled.
    • Add static_assert message for incomplete types
    • Add ar.ignore<T>() and ar.nvp_ignore<T>(name) to load and discard a value from an input archive. Does nothing for output archives. Useful for ignoring variables from data serialized by old versions.
      template <class Archive> void serialize(Archive& ar, uint32_t version) {
          if (version < 2) {
              ar.template nvp_ignore<int>("removedVarNamed");
              ar.template nvp_ignore<int>(); // removedVarUnnamed
          }
      }
    • Add ar.load<T>() : T and ar.nvp_load<T>(name) : T to direct load a value from an input archive. Does not exist for output archives. Useful shorthand if the deserialized value is not directly assigned to a final object.
      template <class Archive> void serialize(Archive& ar, uint32_t version) {
          if constexpr (Archive::is_input) {
              var0 = ar.template nvp_load<int>("var0") * 100;
              var1 = ar.template nvp_load<int>() * 100;
          } else {
              ar(var0 / 100);
              ar(var1 / 100);
          }
      }
    • Add API for value validations:
      ar.nvp("pointer", pointer, ar.notnull);
      ar.nvp("vector", vector, ar.notempty, ar.maxsize(10));
    • ar.operator(), ar.nvp, ar.load, ar.nvp_load, ar.ignore, ar.nvp_ignore now accepts a variadic set of validation objects.
    • ar.verify(bool, string) can be used to throw exception if the is enforcing validation.
    • vide::notnull or ar.notnull: A var bool testing validation object.
    • vide::notempty or ar.notempty: A !var.empty() testing validation object.
    • vide::maxsize(limit) or ar.maxsize(limit): A var.size() <= limit testing validation object.
    • Proxy archives can opt-out of validation tests with declaring a static constexpr bool enforce_validation = false; member.
    • Sync with upstream 2025.01.20 a56bad8bb
    • Sync, review and merge most upstream PRs up until 2025.09.14 872
    • Update RapidJSON and RapidXML
  • Version 3.0.0:
    • Breaking changes in the serialized archive data format. These changes are expected to be the last and final breaking changes:
      • Change shared_ptr representation
      • Change polymorphic representation
      • Remove unnecessary empty node in text archives when serializing the same virtual base multiple times
    • Rework polymorphic serialization logic
    • Security: Fix vulnerability where shared_ptrs could be manipulated to point to an incorrect type after loading. Type mismatches are now detected for both polymorphic and non-polymorphic shared_ptrs.
    • Implement support for generic smart_ptr serialization
    • Overhaul test and types code structure. Most std type's serializer file now received std_ prefix.
    • Move set and unordered_set serializer implementations into a separate file
    • Extend validator support for NVPs
    • Add element check for notnull when used with non-bool convertible ranges
    • Add notnullrange validator (which can be used if the range is bool convertible)
    • Add validation check for duplicate key loading for types with unique key constraints
    • Add T& serialize_minimal() customization point as an alternative shorthand for load_minimal/save_minimal syntax
      struct StructMemberSerializeMinimal {
        std::int32_t x;
      
        template <typename Archive>
        std::int32_t& serialize_minimal(Archive&) {
          return x;
        }
      };
      The new customization point is available as usual in global/member and versioned/non-versioned format.
    • Add boost flat_set and flat_map serializers
    • Add dependent name accessors for: ar.template base_class<Base>(this) and ar.template virtual_base_class<Base>(this)
    • Add VIDE_POLYMORPHIC_ID_TYPE macro that determines the data type used for polymorphic_id. Defaults to uint16_t.
  • Version 3.0.1:
    • Add base_class/virtual_base_class dependent names to ProxyArchives
  • Version 3.0.2:
    • Move vide/types/base_class.hpp to vide/base_class.hpp
    • Fix missing base_class include
  • Version 3.1.0:
    • Bump required CMake version to 3.24
    • Remove pkgconfig file generation
    • Remove AllowEmptyClassElision
    • Change duration and time_point serialization to be minimal
    • Improve the CMake scripts
    • Enable and cleanup additional warnings and VERIFY_INTERFACE_HEADER_SETS
    • Add vide::indirect(base_validator) or ar.indirect(base_validator) as a validator for !var || base_validator(*var) testing.
    • Add vide::indirect_maxsize(limit) or ar.indirect_maxsize(limit) as a validator for !var || var->size() <= limit testing.
    • Add vide::ranged(base_validator) or ar.ranged(base_validator) as a validator for for (item : var) base_validator(var) testing.
    • Add types/reflection.hpp to support initial reflection based serialization
      • Enabled by defining using T::serialize_enable_reflection = void inside the target type.
      • Member validators can be assigned with annotations on the member
      • Example:
         struct MyType {
           using serialize_enable_reflection = void;
           static constexpr std::uint32_t serialize_class_version = 166;
           [[=vide::notnull]]
           int a = 1;
        };
        
    • Add vide::minsize(limit) or ar.minsize(limit): A var.size() >= limit testing validation object.
    • Fix multi-container deserialization order for equal keys (Upstream PR USCiLab/cereal#874
    • Sync, review and resolve upstream commits, PRs, and issues up to and including 2026.07.24 22a1b369

Known Issues:

KNOWN_ISSUES.md

License

Vide is licensed under the permissive BSD license.

About

C++26 serialization library

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages