Sane C++ Libraries
C++ Platform Abstraction Libraries
Loading...
Searching...
No Matches
Containers Reflection

🟨 Opt-in reflection and serialization adapters for SC containers and owning memory types.

SaneCppContainersReflection.h connects the generic Reflection, Serialization Binary, and Serialization Text machinery to SC's owning containers. Include its adapters where a reflected object graph contains types such as SC::Vector, SC::Array, SC::VectorMap, SC::Buffer, or SC::String.

Dependencies

Dependency Graph

What Containers Reflection Is For

Reflection can describe structures and primitive values without knowing about growable storage. Serialization can walk that description without choosing which container library an application uses. Containers Reflection supplies the missing, opt-in knowledge for SC's own containers.

This separation matters because SC libraries do not acquire dependencies merely for convenience. Reflection and the serialization libraries remain usable without Containers or Memory; an application pays for these adapters only when its reflected types need them.

Use this library when:

  • a reflected structure contains an SC::Array, SC::Vector, SC::VectorMap, SC::Buffer, or SC::String;
  • binary or text serialization must resize an owning SC container while reading;
  • you want the standard SC representation of these types rather than writing application-specific reflection traits.

It is usually not something an application calls directly. Its public surface consists of template specializations selected by the compiler after the appropriate header is included.

Choose The Adapter Header

The library keeps container and memory adapters separate, and keeps reflection-only use separate from serialization:

Include Adds support for
ContainersReflection.h Reflecting SC::Array, SC::Vector, and SC::VectorMap
MemoryReflection.h Reflecting SC::Buffer, SC::String, and SC::StringEncoding
ContainersSerialization.h Binary and text serialization of SC::Array and SC::Vector
MemorySerialization.h Binary serialization of SC::Buffer and text serialization of SC::String

The serialization headers include their corresponding reflection headers. Include only the layer the translation unit uses; there is no initialization function or object to retain.

Mental Model

Reflection treats SC::Array and SC::Vector as vector-like values: it can obtain their size and data, identify their element type, and ask them to resize. A fixed-capacity SC::Array<T, N> clamps adapter resize requests to N; a SC::Vector<T> can grow as far as its allocator permits. SC::Buffer follows the same vector-like model for bytes. That clamp is a capacity boundary, not a general promise that oversized exact-format input is accepted: input sizes still need to match the guarantees of the serializer being used.

SC::VectorMap is different. Its reflection describes the map through its items storage, preserving the container's actual representation instead of inventing a separate wire-level map abstraction. SC::String is reflected through its encoding and data members, while text serialization has direct string handling.

The adapters contain no per-object state and perform growth only through the adapted object. Deserializing a vector, buffer, or string may therefore allocate through that object's configured allocator. A failed resize makes the surrounding serialization operation fail; existing contents should not be treated as a transactionally preserved value unless the selected serializer explicitly provides that guarantee.

Nested Containers Need No Per-Field Adapter

Once ContainersReflection.h is included, ordinary reflection declarations can contain nested vectors. The following compiled test reflects both Vector<int> and Vector<SimpleStructure> fields:

struct TestNamespace::IntermediateStructure
{
SC::Vector<int> vectorOfInt;
SimpleStructure simpleStructure;
};
SC_REFLECT_STRUCT_VISIT(TestNamespace::IntermediateStructure)
SC_REFLECT_STRUCT_FIELD(1, vectorOfInt)
SC_REFLECT_STRUCT_FIELD(0, simpleStructure)
SC_REFLECT_STRUCT_LEAVE()
struct TestNamespace::ComplexStructure
{
SC::uint8_t f1 = 0;
SimpleStructure simpleStructure;
SimpleStructure simpleStructure2;
SC::uint16_t f4 = 0;
IntermediateStructure intermediateStructure;
SC::Vector<SimpleStructure> vectorOfStructs;
};
SC_REFLECT_STRUCT_VISIT(TestNamespace::ComplexStructure)
SC_REFLECT_STRUCT_FIELD(0, f1)
SC_REFLECT_STRUCT_FIELD(1, simpleStructure)
SC_REFLECT_STRUCT_FIELD(2, simpleStructure2)
SC_REFLECT_STRUCT_FIELD(3, f4)
SC_REFLECT_STRUCT_FIELD(4, intermediateStructure)
SC_REFLECT_STRUCT_FIELD(5, vectorOfStructs)
SC_REFLECT_STRUCT_LEAVE()

The structure still declares its own fields, but it does not explain how a vector is sized, traversed, or resized. That knowledge comes from this library's Reflect and ExtendedTypeInfo specializations.

The Same Types Flow Into Serialization

The serialization adapters reuse that model. This compiled JSON test combines a built-in fixed array, SC::String, and SC::Vector<SC::String> in one reflected object:

struct SC::Test
{
int x = 2;
float y = 1.5f;
int xy[2] = {1, 3};
String myTest = "asdf"_a8;
Vector<String> myVector = {"Str1"_a8, "Str2"_a8};
bool operator==(const Test& other) const
{
return x == other.x and y == other.y and //
xy[0] == other.xy[0] and xy[1] == other.xy[1] and //
myTest == other.myTest and myVector.size() == 2 and //
myVector.size() == other.myVector.size() and //
myVector[0] == other.myVector[0] and myVector[1] == other.myVector[1];
}
};
SC_REFLECT_STRUCT_VISIT(SC::Test)
SC_REFLECT_STRUCT_FIELD(0, x)
SC_REFLECT_STRUCT_FIELD(1, y)
SC_REFLECT_STRUCT_FIELD(2, xy)
SC_REFLECT_STRUCT_FIELD(3, myTest)
SC_REFLECT_STRUCT_FIELD(4, myVector)
SC_REFLECT_STRUCT_LEAVE()
struct SC::EscapedStringTest
{
String value;
};
SC_REFLECT_STRUCT_VISIT(SC::EscapedStringTest)
SC_REFLECT_STRUCT_FIELD(0, value)
SC_REFLECT_STRUCT_LEAVE()
struct SC::BorrowedStringTest
{
StringSpan spanValue;
StringView viewValue;
};
SC_REFLECT_STRUCT_VISIT(SC::BorrowedStringTest)
SC_REFLECT_STRUCT_FIELD(0, spanValue)
SC_REFLECT_STRUCT_FIELD(1, viewValue)
SC_REFLECT_STRUCT_LEAVE()
struct SC::VersionedVectorItem
{
int first = 0;
String second;
};
SC_REFLECT_STRUCT_VISIT(SC::VersionedVectorItem)
SC_REFLECT_STRUCT_FIELD(0, first)
SC_REFLECT_STRUCT_FIELD(1, second)
SC_REFLECT_STRUCT_LEAVE()
struct SC::VersionedVectorTest
{
Vector<VersionedVectorItem> items;
};
SC_REFLECT_STRUCT_VISIT(SC::VersionedVectorTest)
SC_REFLECT_STRUCT_FIELD(0, items)
SC_REFLECT_STRUCT_LEAVE()

Including ContainersSerialization.h and MemorySerialization.h makes those fields available to the generic text and binary serializers. The adapters do not choose an allocator, hide capacity failures, or change the lifetime rules of the objects being loaded.

Boundaries And Tradeoffs

  • Support is opt-in and compile-time. Omitting an adapter header produces a missing specialization at compilation, rather than a runtime registration failure.
  • SC::VectorMap gains reflection here, but no direct serialization specialization. Its default reflected shape is a structure with an items field; it is not serialized as a format-specific map or JSON object.
  • The standard adapters describe SC's concrete representation. If a stable external format must differ from that representation, define an explicit schema or application-level conversion instead of relying on the default shape.
  • Owning values may allocate while loading. Borrowed views and spans have different lifetime and input-buffer rules and are handled by their respective serialization facilities, not turned into owning containers here.
  • This library is intentionally coupled to both sides of the seam. Adding support for another container belongs here when doing so would otherwise force Reflection or Serialization to depend on that container library.

Status

🟩 Usable

Where To Go Next

Statistics

LOC counts exclude comments. Library counts files physically under Libraries/ContainersReflection. Single File counts SaneCppContainersReflection.h. Standalone counts SaneCppContainersReflectionStandalone.h and intentionally includes dependency payloads.

Metric Header Source Sum
Library 231 0 231
Single File 251 0 251
Standalone 4269 1340 5609