4.5 KiB
Serialization and Archives Internals
This document explains the internal design of the uLib serialization system, which is built on top of Boost.Serialization. It provides custom archive implementations for various formats (XML, Text, Logging) and introduces Human Readable Pairs (HRP) for metadata-rich serialization.
Architecture Overview
The uLib archive system extends the standard boost::archive templates to add domain-specific features. The main components are:
- Custom Interface Layer: Extends the default Boost archive API with additional operators and utilities.
- Specialized Archive Implementations: Specialized classes for XML, Text, and Logging.
- HRP Support: First-class support for
hrp(Human Readable Pair) wrappers, which carry units, ranges, and descriptions. - Static Registration System: Macros and explicit instantiations to handle polymorphic types and compilation isolation.
Custom Interface Layer
All uLib archives use a custom interface defined in Archives.h via uLib_interface_iarchive and uLib_interface_oarchive. These templates add several key features:
| Feature | Operator/Method | Description |
|---|---|---|
| Mapping Operator | operator== |
Aliased to operator& (Boost's standard mapping operator). |
| Trace Operator | operator!= |
Used for trace/debug output of strings during serialization. |
| Type Registration | register_type<T>() |
Registers a class type with the archive's internal serializer map. |
| Standard IO | operator<< / operator>> |
Standard redirect for saving and loading. |
These interfaces are applied to the archives using template specialization of boost::archive::detail::interface_iarchive and interface_oarchive.
Archive Variants
XML Archives (xml_iarchive, xml_oarchive)
These inherit from boost::archive::xml_iarchive_impl and xml_oarchive_impl.
- Internals: They override
load_overrideandsave_overrideto handleboost::serialization::hrp<T>specifically. - XML Mapping: When saving an
hrp, it usessave_start(name)andsave_end(name)to wrap the value in a named XML tag.
Text Archives (text_iarchive, text_oarchive)
Standard text-based archives used for compact serialization. They use StringReader to consume decorative text markers during loading.
Human Readable Text (hrt_iarchive, hrt_oarchive)
These are "naked" text archives that suppress most of Boost's internal metadata (object IDs, class IDs, versions).
- Goal: Produce text output that is easy for humans to read and edit.
- Internals: All overrides for Boost internal types (like
object_id_type,version_type, etc.) are implemented as no-ops.
Log Archive (log_archive)
An XML-based output archive specifically for debug logging.
- Internals: It forces every object into a Name-Value Pair (NVP) even if not provided by the user, and strips all technical metadata to keep the logs clean.
HRP (Human Readable Pair) Integration
hrp is a core uLib wrapper (defined in Serializable.h) that extends Boost's nvp:
// Example of HRP usage
ar & HRP2("Energy", m_energy, "MeV").range(0, 100);
Internal Handling in Archives
Archives in Archives.h provide specific save_override/load_override for hrp<T>:
- XML: Maps the
name()to an XML tag. - HRT: Formats as
name: value [units]\n. - Log: Converts it to a standard Boost
nvpfor consistent XML logging.
Registration and Polymorphism
Registration Macro
The ULIB_SERIALIZATION_REGISTER_ARCHIVE(Archive) macro is crucial for polymorphic serialization. It instantiates the necessary template machinery to link the custom Archive type with any Serializable class exported via BOOST_CLASS_EXPORT.
Explicit Instantiation
To reduce compilation times and provide a single point of failure for link-time issues, uLib uses explicit instantiations in src/Core/Archives.cpp. This file includes the .ipp implementation files from Boost and instantiates the archive_serializer_map and implementation classes for all uLib archive types.
Utility: StringReader
The StringReader utility is used internally by text-based archives to parse and skip literals. For example:
- When loading a string literal from a text archive,
StringReaderconsumes whitespace and ensures the stream matches the expected string, failing if there is a mismatch. - This is vital for maintaining the structure of human-readable formats.