Object Model

Object Model & Memory Layout.

Blend2D object model is a foundation of all Blend2D objects. It was designed only for Blend2D and it's not supposed to be used as a foundation of other libraries. The object model provides runtime reflection, small size optimization (SSO), and good performance. In general, it focuses on optimizing memory footprint by taking advantage of SSO storage, however, this makes the implementation more complex compared to a traditional non-SSO model.

Blend2D object model used by BLObjectCore consists of 16 bytes that have the following layout:

void* impl;
char char_data[16];
uint8_t u8_data[16];
uint16_t u16_data[8];
uint32_t u32_data[4];
uint64_t u64_data[2];
float f32_data[4];
double f64_data[2];
struct {
uint32_t u32_data_overlap[2];
uint32_t impl_payload;
BLObjectInfo info; // 32 bits describing object type and its additional payload.
};
};

Which allows to have either static or dynamic instances:

  • Static instance stores payload in object layout, Impl is not a valid pointer and cannot be accessed.
  • Dynamic instance has a valid Impl pointer having a content, which depends on BLObjectType.

The layout was designed to provide the following properties:

  • Reflection - any Blend2D object can be casted to a generic BLObjectCore or BLVar and reflected at runtime.
  • Small string, container, and value optimization saves memory allocations (BLString, BLArray, BLBitSet).
  • No atomic reference counting operations for small containers and default constructed objects without data.
  • It's possible to store a floating point RGBA color (BLRgba) as f32_data, which uses all 16 bytes. The last value of the color, which describes alpha channel, cannot have a sign bit set (cannot be negative and cannot be NaN with sign).

32-bit Floating Point is represented the following way (32 bits):

[--------+--------+--------+--------]
[31....24|23....16|15.....8|7......0] (32-bit integer layout)
[--------+--------+--------+--------]
[Seeeeeee|eQ......|........|........] (32-bit floating point)
[--------+--------+--------+--------]

Where:

  • 'S' - Sign bit
  • 'e' - Exponent bits (all bits must be '1' to form NaN).
  • 'Q' - Fraction bit that can be used to describe quiet and signaling NaNs, the value is not standardized (X86 and ARM use '1' for quiet NaN and '0' for signaling NaN).
  • '.' - Fraction bits.

Blend2D uses a sign bit to determine whether the data is BLRgba or object compatible. This design has been chosen, because we don't allow alpha values to be negative. When the sign bit is set it means that it's a type inherited from BLObjectCore. When the sign bit is not set the whole payload represents 128-bit BLRgba color, where alpha is not a negative number. It's designed in a way that 31 bits out of 32 can be used as payload that represents object type, object info flags, and additional type-dependent payload.

Object info value looks like this (also compared with floating point):

[--------+--------+--------+--------]
[31....24|23....16|15.....8|7......0] (32-bit integer layout)
[--------+--------+--------+--------]
[Seeeeeee|eQ......|........|........] (32-bit floating point) (\ref BLRgba case, 'S' bit (sign bit) set to zero).
[MDTVtttt|ttaaaabb|bbccccpp|pppppXIR] (object info fields view) (\ref BLObjectCore case, 'M' bit set to one).
[--------+--------+--------+--------]
[1D00tttt|ttaaaabb|bbccccpp|pppppXIR] (BLArray SSO layout - 'a' is an array size, 'bbbb' is capacity)
[1D001000|00aaaabb|bbccccpp|pppppXIR] (BLString SSO layout - 'a' is a string size ^ SSO Capacity, the rest can be used as characters)
[1D10tttt|ttaaaabb|bbccccpp|pppppXIR] (BLBitSet SSO layout - 'ttt|ttaaaabb|bbccccpp|pppppXIR' is a word start or SSO range sentinel)
[--------+--------+--------+--------]

Where:

  • 'M' - Object marker, forms a valid BLObject signature when set to '1'.
  • 'T' - Object type MSB bit - when set all other 't' bits are implied to be zero, only used by BLBitSet to make it possible to index all possible BitWords in SSO mode - this should be considered a special case.
  • 'V' - Virtual table flag (implies 'D' == 1) - when set it means that Impl pointer has a virtual function table. This flag cannot be used in SSO mode as a payload. It can only be set when 'D' == 1. Objects that provide virtual function table are never SSO, so such objects always have both 'D' and 'V' set to '1'.
  • 't' - Object type LSB bits - 'TVtttttt' forms an 8-bit type having possible values from 0 to 128, see BLObjectType.
  • 'D' - Dynamic flag - when set the Impl pointer is valid. When 'D' == '0' it means the object is in SSO mode, when 'D' == '1' it means it's in Dynamic mode.
  • 'X' - External flag (with 'D' == 1) - used by allocator, when set the Impl holds external data. In SSO mode 'X' flag can be used as a payload.
  • 'I' - Immutable flag (with 'D' == 1) - if set the Impl is immutable - could be an ethernal built-in instance. In SSO mode 'I' flag can be used as a payload.
  • 'R' - Reference counted. Must be '1' if the the Impl is reference counted. The reference count still has to be provided even when 'R' == '0'. In SSO mode 'R' flag can be used as a payload.
  • 'a' - Object 'a' payload (4 bits) - available in SSO mode, used by Impl allocator if 'D' is 1.
  • 'b' - Object 'b' payload (4 bits) - available in both SSO and Dynamic modes.
  • 'c' - Object 'c' payload (4 bits) - available in both SSO and Dynamic modes.
  • 'p' - Object 'p' payload (7 bits) - available in both SSO and Dynamic modes.

Common meaning of payload fields:

  • 'a' - If the object is a container (BLArray, BLString) 'a' field always represents its size in SSO mode. If the object is a BLBitSet, 'a' field is combined with other fields to store a start word index or to mark a BitSet, which contains an SSO range instead of dense words.
  • 'b' - If the object is a container (BLArray) 'b' field always represents its capacity in SSO mode except BLString, which doesn't store capacity in 'b' field and uses it as an additional SSO content byte on little endian targets (SSO capacity is then either 13 on little endian targets or 11 on big endian ones). This is possible as BL_OBJECT_TYPE_STRING must be identifier that has 2 low bits zero, which then makes it possible to use 'ttIRaaaa' as null terminator when the string length is 14 characters.
  • 'c' - Used freely.
  • 'p' - Used freely.

If the 'D' flag is '1' the following payload fields are used by the allocator (and thus cannot be used by the object):

  • 'a' - Allocation adjustment (4 bits) - At the moment the field describes how many bytes (shifted) to subtract from Impl to get the real pointer returned by Impl allocator. Object deallocation relies on this offset.

Not all object support all defined flags, here is an overview:

+---------------------+---+---+---+---+---+---+
| Type |SSO|Dyn|Ext|Imm|Vft|Ref|
+---------------------+---+---+---+---+---+---|
| BLVar {Null} | 1 | 0 | 0 | 0 | 0 | 0 | 'SSO' - Small size optimization support
| BLVar {Bool} | 1 | 0 | 0 | 0 | 0 | 0 | 'Dyn' - Dynamic Impl support
| BLVar {Int64} | 1 | 0 | 0 | 0 | 0 | 0 | 'Ext' - External data support
| BLVar {UInt64} | 1 | 0 | 0 | 0 | 0 | 0 | 'Imm' - Immutable data support.
| BLVar {Double} | 1 | 0 | 0 | 0 | 0 | 0 | 'Vft' - Object provides virtual function table.
| BLVar {Rgba} | 1 | 0 | 0 | 0 | 0 | 0 | 'Ref' - Reference counting support.
| BLArray<T> | x | x | x | x | 0 | x |
| BLBitSet | x | x | 0 | 0 | 0 | x |
| BLContext | 0 | 1 | 0 | 0 | 1 | x |
| BLString | x | x | 0 | 0 | 0 | x |
| BLPattern | 0 | 1 | 0 | 0 | 0 | x |
| BLGradient | 0 | 1 | 0 | 0 | 0 | x |
| BLPath | 0 | 1 | 0 | x | 0 | x |
| BLImage | 0 | 1 | x | x | 0 | x |
| BLImageCodec | 0 | 1 | 0 | x | 1 | x |
| BLImageDecoder | 0 | 1 | 0 | 0 | 1 | x |
| BLImageEncoder | 0 | 1 | 0 | 0 | 1 | x |
| BLFont | 0 | 1 | 0 | 0 | 0 | x |
| BLFontFace | 0 | 1 | 0 | x | 1 | x |
| BLFontData | 0 | 1 | x | x | 1 | x |
| BLFontManager | 0 | 1 | 0 | x | 1 | x |
+---------------------+---+---+---+---+---+---+

Classes

Macros

BLObject - Constants

BLObject - External Data

BLObject - C API

Macro Definition Documentation

#define BL_DEFINE_OBJECT_PROPERTY_API

Value:
\
BL_INLINE BLResult getProperty(const char* name, BLVarCore& valueOut) const noexcept { \
return blObjectGetProperty(this, name, SIZE_MAX, &valueOut); \
} \
\ \
BL_INLINE BLResult getProperty(const BLStringView& name, BLVarCore& valueOut) const noexcept { \
return blObjectGetProperty(this, name.data, name.size, &valueOut); \
} \
\ \
BL_INLINE BLResult setProperty(const char* name, const BLObjectCore& value) noexcept { \
return blObjectSetProperty(this, name, SIZE_MAX, &value); \
} \
\ \
BL_INLINE BLResult setProperty(const BLStringView& name, const BLObjectCore& value) noexcept { \
return blObjectSetProperty(this, name.data, name.size, &value); \
}

Typedef Documentation

typedef void(* BLDestroyExternalDataFunc)(void* impl, void* externalData, void* userData)

A function callback that is called when an Impl that holds external data is going to be destroyed. It's often used as a notification that a data passed to a certain Impl is no longer in use by Blend2D.

Enumeration Type Documentation

BLObjectInfoBits : uint32_tenum

Defines a mask of each field of the object info.

Note
This is part of the official documentation, however, users should not use these enumerations in any context.
ConstantDescription
BL_OBJECT_INFO_REF_COUNTED_FLAG 

Flag describing a reference counted object, which means it has a valid reference count that must be increased/decreased.

BL_OBJECT_INFO_IMMUTABLE_FLAG 

Flag describing an immutable object, which holds immutable data (immutable data is always external).

BL_OBJECT_INFO_X_FLAG 

Flag describing 'X' payload value (it's a payload that has a single bit).

BL_OBJECT_INFO_P_MASK 

Mask describing 'P' payload (7 bits).

BL_OBJECT_INFO_C_MASK 

Mask describing 'C' payload (4 bits).

BL_OBJECT_INFO_B_MASK 

Mask describing 'B' payload (4 bits).

BL_OBJECT_INFO_A_MASK 

Mask describing 'A' payload (4 bits).

BL_OBJECT_INFO_TYPE_MASK 

Mask describing object type (8 bits), see BLObjectType.

BL_OBJECT_INFO_VIRTUAL_FLAG 

Flag describing a virtual object.

BL_OBJECT_INFO_T_MSB_FLAG 

Flag describing the first most significant bit of BLObjectType.

BL_OBJECT_INFO_DYNAMIC_FLAG 

Flag describing a dynamic object - if this flag is not set, it means the object is in SSO mode.

BL_OBJECT_INFO_MARKER_FLAG 

Flag describing a valid object compatible with BLObjectCore interface (otherwise it's most likely BLRgba).

BL_OBJECT_INFO_RC_INIT_MASK 

Reference count initializer (combines BL_OBJECT_INFO_REF_COUNTED_FLAG and BL_OBJECT_INFO_IMMUTABLE_FLAG).

BLObjectType : uint32_tenum

Object type identifier.

ConstantDescription
BL_OBJECT_TYPE_RGBA 

Object represents a RGBA value stored as 4 32-bit floating point components (can be used as style).

BL_OBJECT_TYPE_NULL 

Object is Null (can be used as style).

BL_OBJECT_TYPE_PATTERN 

Object is BLPattern (style compatible).

BL_OBJECT_TYPE_GRADIENT 

Object is BLGradient (style compatible).

BL_OBJECT_TYPE_IMAGE 

Object is BLImage.

BL_OBJECT_TYPE_PATH 

Object is BLPath.

BL_OBJECT_TYPE_FONT 

Object is BLFont.

BL_OBJECT_TYPE_FONT_FEATURE_OPTIONS 

Object is BLFontFeatureOptions.

BL_OBJECT_TYPE_FONT_VARIATION_OPTIONS 

Object is BLFontVariationOptions.

BL_OBJECT_TYPE_BOOL 

Object represents a boolean value.

BL_OBJECT_TYPE_INT64 

Object represents a 64-bit signed integer value.

BL_OBJECT_TYPE_UINT64 

Object represents a 64-bit unsigned integer value.

BL_OBJECT_TYPE_DOUBLE 

Object represents a 64-bit floating point value.

BL_OBJECT_TYPE_STRING 

Object is BLString.

BL_OBJECT_TYPE_ARRAY_OBJECT 

Object is BLArray<T> where T is a BLObject compatible type.

BL_OBJECT_TYPE_ARRAY_INT8 

Object is BLArray<T> where T matches 8-bit signed integral type.

BL_OBJECT_TYPE_ARRAY_UINT8 

Object is BLArray<T> where T matches 8-bit unsigned integral type.

BL_OBJECT_TYPE_ARRAY_INT16 

Object is BLArray<T> where T matches 16-bit signed integral type.

BL_OBJECT_TYPE_ARRAY_UINT16 

Object is BLArray<T> where T matches 16-bit unsigned integral type.

BL_OBJECT_TYPE_ARRAY_INT32 

Object is BLArray<T> where T matches 32-bit signed integral type.

BL_OBJECT_TYPE_ARRAY_UINT32 

Object is BLArray<T> where T matches 32-bit unsigned integral type.

BL_OBJECT_TYPE_ARRAY_INT64 

Object is BLArray<T> where T matches 64-bit signed integral type.

BL_OBJECT_TYPE_ARRAY_UINT64 

Object is BLArray<T> where T matches 64-bit unsigned integral type.

BL_OBJECT_TYPE_ARRAY_FLOAT32 

Object is BLArray<T> where T matches 32-bit floating point type.

BL_OBJECT_TYPE_ARRAY_FLOAT64 

Object is BLArray<T> where T matches 64-bit floating point type.

BL_OBJECT_TYPE_ARRAY_STRUCT_1 

Object is BLArray<T> where T is a struct of size 1.

BL_OBJECT_TYPE_ARRAY_STRUCT_2 

Object is BLArray<T> where T is a struct of size 2.

BL_OBJECT_TYPE_ARRAY_STRUCT_3 

Object is BLArray<T> where T is a struct of size 3.

BL_OBJECT_TYPE_ARRAY_STRUCT_4 

Object is BLArray<T> where T is a struct of size 4.

BL_OBJECT_TYPE_ARRAY_STRUCT_6 

Object is BLArray<T> where T is a struct of size 6.

BL_OBJECT_TYPE_ARRAY_STRUCT_8 

Object is BLArray<T> where T is a struct of size 8.

BL_OBJECT_TYPE_ARRAY_STRUCT_10 

Object is BLArray<T> where T is a struct of size 10.

BL_OBJECT_TYPE_ARRAY_STRUCT_12 

Object is BLArray<T> where T is a struct of size 12.

BL_OBJECT_TYPE_ARRAY_STRUCT_16 

Object is BLArray<T> where T is a struct of size 16.

BL_OBJECT_TYPE_ARRAY_STRUCT_20 

Object is BLArray<T> where T is a struct of size 20.

BL_OBJECT_TYPE_ARRAY_STRUCT_24 

Object is BLArray<T> where T is a struct of size 24.

BL_OBJECT_TYPE_ARRAY_STRUCT_32 

Object is BLArray<T> where T is a struct of size 32.

BL_OBJECT_TYPE_CONTEXT 

Object is BLContext.

BL_OBJECT_TYPE_IMAGE_CODEC 

Object is BLImageCodec.

BL_OBJECT_TYPE_IMAGE_DECODER 

Object is BLImageDecoder.

BL_OBJECT_TYPE_IMAGE_ENCODER 

Object is BLImageEncoder.

BL_OBJECT_TYPE_FONT_FACE 

Object is BLFontFace.

BL_OBJECT_TYPE_FONT_DATA 

Object is BLFontData.

BL_OBJECT_TYPE_FONT_MANAGER 

Object is BLFontManager.

BL_OBJECT_TYPE_BIT_SET 

Object is BLBitSet.

BL_OBJECT_TYPE_MAX_STYLE_VALUE 

Maximum object type identifier that can be used as a style.

BL_OBJECT_TYPE_MAX_VALUE 

Maximum possible value of an object type, including identifiers reserved for the future.