flatbuffers clib

Google FlatBuffers zero-copy binary serialization for PascalAI. Serialize and deserialize structured data with no parsing overhead — read fields directly from the buffer. Ideal for game state, IPC, networking, and mobile where allocation and parsing latency matter.

Version1.0.0
Typeclib
CategorySerialization
System reqlibflatbuffers-dev
CLib package — Ubuntu/Debian: sudo apt install libflatbuffers-dev
ppm install flatbuffers

Quick Start

Writing a message

uses flatbuffers;

var b := NewBuilder(256);

{ Create strings and vectors first (bottom-up order) }
var nameOff   := CreateString(b, 'Alice');
var tagsOff   := CreateStringVector(b, ['admin', 'user']);
var scoresOff := CreateFloatVector(b, [98.5, 87.0, 92.3]);

{ Build the table }
StartTable(b, 4);
AddInt32(b, 0, 42);           { field 0: id }
AddOffset(b, 1, nameOff);    { field 1: name }
AddBool(b, 2, True);          { field 2: active }
AddOffset(b, 3, tagsOff);    { field 3: tags }
var root := EndTable(b);

Finish(b, root);
var buf := GetBuffer(b);
FreeBuilder(b);

Reading without parsing

uses flatbuffers;

{ Verify before reading (recommended) }
if not VerifyBuffer(buf) then
  raise 'Invalid FlatBuffer';

var t := GetRoot(buf);

{ Zero-copy field access — no allocation }
var id     := ReadInt32(t, 0, 0);
var name   := ReadString(t, 1);
var active := ReadBool(t, 2, False);

var tags := ReadVector(t, 3);
for var i := 0 to VectorLen(tags) - 1 do
  WriteLn(VectorString(tags, i));

Builder API

FunctionSignatureDescription
NewBuilderNewBuilder(initialSize: Integer): TBuilderAllocate a new FlatBuffers builder with given initial buffer size in bytes.
FreeBuilderFreeBuilder(b: TBuilder)Release all memory held by the builder.
ResetBuilderResetBuilder(b: TBuilder)Clear the builder state so it can be reused without a new allocation.

String & Vector Creation

Bottom-up order: strings and vectors must be created before the table that references them. The builder works from the end of the buffer toward the beginning.
FunctionSignatureDescription
CreateStringCreateString(b: TBuilder; s: string): TOffsetSerialize a UTF-8 string into the buffer. Returns an offset for use with AddOffset.
CreateIntVectorCreateIntVector(b: TBuilder; v: array of Integer): TOffsetSerialize an integer array.
CreateFloatVectorCreateFloatVector(b: TBuilder; v: array of Double): TOffsetSerialize a float/double array.
CreateStringVectorCreateStringVector(b: TBuilder; v: array of string): TOffsetSerialize an array of strings.
CreateByteVectorCreateByteVector(b: TBuilder; data: TBytes): TOffsetSerialize raw bytes as a byte vector (useful for blobs and nested buffers).

Table Building

FunctionSignatureDescription
StartTableStartTable(b: TBuilder; numFields: Integer)Begin a new table. numFields is the total number of fields in the schema.
AddBoolAddBool(b: TBuilder; fieldIndex: Integer; value: Boolean)Write a boolean field at the given 0-based field index.
AddInt32AddInt32(b: TBuilder; fieldIndex: Integer; value: Integer)Write a 32-bit integer field.
AddInt64AddInt64(b: TBuilder; fieldIndex: Integer; value: Int64)Write a 64-bit integer field.
AddFloat32AddFloat32(b: TBuilder; fieldIndex: Integer; value: Single)Write a 32-bit float field.
AddFloat64AddFloat64(b: TBuilder; fieldIndex: Integer; value: Double)Write a 64-bit double field.
AddOffsetAddOffset(b: TBuilder; fieldIndex: Integer; offset: TOffset)Write a reference to a previously created string, vector, or nested table.
EndTableEndTable(b: TBuilder): TOffsetFinalize the current table and return its offset.

Finish & Buffer

FunctionSignatureDescription
FinishFinish(b: TBuilder; rootOffset: TOffset)Mark the root object and write the file identifier prefix. Must be called before GetBuffer.
GetBufferGetBuffer(b: TBuilder): TBytesReturn the finished byte array. Valid only after Finish.
GetBufferSizeGetBufferSize(b: TBuilder): IntegerReturn the number of bytes in the finished buffer.

Reading API

FunctionSignatureDescription
VerifyBufferVerifyBuffer(buf: TBytes): BooleanValidate the buffer for safety before reading. Always call this on untrusted data.
GetRootGetRoot(buf: TBytes): TTableGet the root table handle from a finished buffer.
ReadBoolReadBool(t: TTable; fieldIndex: Integer; default: Boolean): BooleanRead a boolean field, returning default if absent.
ReadInt32ReadInt32(t: TTable; fieldIndex: Integer; default: Integer): IntegerRead a 32-bit integer field.
ReadInt64ReadInt64(t: TTable; fieldIndex: Integer; default: Int64): Int64Read a 64-bit integer field.
ReadFloat32ReadFloat32(t: TTable; fieldIndex: Integer; default: Single): SingleRead a 32-bit float field.
ReadFloat64ReadFloat64(t: TTable; fieldIndex: Integer; default: Double): DoubleRead a 64-bit double field.
ReadStringReadString(t: TTable; fieldIndex: Integer): stringRead a UTF-8 string field. Returns empty string if absent.
ReadTableReadTable(t: TTable; fieldIndex: Integer): TTableRead a nested table field.
ReadVectorReadVector(t: TTable; fieldIndex: Integer): TVectorRead a vector field handle for further element access.

Vector Reading

FunctionSignatureDescription
VectorLenVectorLen(v: TVector): IntegerReturn the number of elements in the vector.
VectorInt32VectorInt32(v: TVector; index: Integer): IntegerRead a 32-bit integer element at index.
VectorFloat64VectorFloat64(v: TVector; index: Integer): DoubleRead a double element at index.
VectorStringVectorString(v: TVector; index: Integer): stringRead a string element at index.
VectorTableVectorTable(v: TVector; index: Integer): TTableRead a nested table element at index.
VectorToIntArrayVectorToIntArray(v: TVector): array of IntegerConvert the entire integer vector to a Pascal array.
VectorToFloatArrayVectorToFloatArray(v: TVector): array of DoubleConvert the entire float vector to a Pascal array.

Key Concepts

Zero-copy access

Unlike JSON or Protocol Buffers, FlatBuffers requires no parse step and no allocation when reading. Fields are accessed by computing a byte offset into the original buffer. The data never needs to be copied or transformed — your code reads directly from the wire bytes.

Bottom-up building

The builder constructs the buffer from end to start. Nested objects (strings, vectors, inner tables) must be fully written before the parent table that references them. Call CreateString and CreateFloatVector first, then StartTable / AddOffset / EndTable.

Field indices

Fields are identified by a 0-based integer index, not by name. The index is stable across schema versions — absent fields are represented by a default value, never an error. This allows schema evolution without breaking existing serialized data.

FlatBuffers vs Protocol Buffers vs JSON

FormatParse stepAllocationSizeSchema
FlatBuffersNoneNoneSmallRequired
Protocol BuffersFull parseFull object graphVery smallRequired
JSONFull parseFull object graphLargeOptional