// ============================================================================ // // = LIBRARY // ULib - c++ library // // = FILENAME // flatbuffers.h // // = AUTHOR // Stefano Casazza // // ============================================================================ #ifndef ULIB_FLAT_BUFFERS_H #define ULIB_FLAT_BUFFERS_H #include /** * @see http://google.github.io/flatbuffers/index.html * * All data is accessed over offsets, all scalars are aligned to their own size, and all data is always stored in little endian format. * Buffers are built front to back, so children are stored before parents, and the root of the data starts at the last byte. * * The scalar data is stored with a variable number of bits (8/16/32/64). The current width is always determined by the *parent*, i.e. * if the scalar sits in a vector, the vector determines the bit width for all elements at once. Selecting the minimum bit width for a * particular vector is something the encoder does automatically and thus is typically of no concern to the user, though being aware of * this feature (and not sticking a double in the same vector as a bunch of byte sized elements) is helpful for efficiency. * * There is only one kind of offset, and that is an unsigned integer indicating the number of bytes in a negative direction from the * address of itself (where the offset is stored). The root starts at the end of the buffer. The last uint8_t is the width in bytes of * the root (normally the parent determines the width, but the root has no parent). The uint8_t before this is the type of the root, and * the bytes before that are the root value (of the number of bytes specified by the last byte) * * Vectors * * The representation of the vector is at the core of how UFlatBuffer works (since maps are really just a combination of 2 vectors). * A vector is governed by a single bit width (supplied by its parent). This includes the size field. For example, a vector that * stores the integer values `1, 2, 3` is encoded as follows: * * uint8_t 3, 1, 2, 3, 4, 4, 4 * * The first `3` is the size field, and is placed before the vector (an offset from the parent to this vector points to the first * element, not the size field, so the size field is effectively at index -1). Since this is an untyped vector `TYPE_VECTOR`, it * is followed by 3 type bytes (one per element of the vector), which are always following the vector, and are always a uint8_t * even if the vector is made up of bigger scalars. There are also the Typed Vectors that omit the type bytes. The type is instead * determined by the vector type supplied by the parent. Typed vectors are only available for a subset of types for which these * savings can be significant, namely inline signed/unsigned integers (`TYPE_VECTOR_INT` / `TYPE_VECTOR_UINT`), floats (`TYPE_VECTOR_FLOAT`), * string (`TYPE_VECTOR_STRING`) and bool (`TYPE_VECTOR_BOOL`). Additionally, for scalars, there are fixed length vectors of sizes 2 / 3 / 4 * that don't store the size (`TYPE_VECTOR_INT2` etc.), for an additional savings in space when storing common vector or color data. * * Scalars * * UFlatBuffer supports integers (`TYPE_INT` and `TYPE_UINT`) and floats (`TYPE_FLOAT`), available in the bit-widths mentioned above. * They can be stored both inline and over an offset (`TYPE_INDIRECT_*`). The offset version is useful to encode costly 64bit (or even * 32bit) quantities into vectors / maps of smaller sizes, and to share / repeat a value multiple times. * * Booleans and Nulls * * Booleans (`TYPE_BOOL`) and nulls (`TYPE_NULL`) are encoded as inlined unsigned integers. * * Maps * * A map (`TYPE_MAP`) is like an (untyped) vector, but with 2 prefixes before the size field: * * | index | field | * | ----: | :-------------------------------------------------------| * | -3 | An offset to the keys vector | * | -2 | Byte width of the keys vector | * | -1 | Size (from here on it is compatible with `TYPE_VECTOR`) | * | 0 | Elements | * | Size | Types | * * Since a map is otherwise the same as a vector, it can be iterated like a vector (which is probably faster than lookup by key). * The keys vector is a typed vector of strings. The reason the key vector is a seperate structure from the value vector is such that * to allow it to be treated as its own individual vector in code. An example map { foo: 13, bar: 14 } would be encoded as: * * "\003foo\003bar\002\b\005\002\001\002\r\016\004\004\004$\001" * 0 4 8 9 11 13 14 16 19 * * 0 : uint8_t 3, 'f', 'o', 'o' * 4 : uint8_t 3, 'b', 'a', 'r' * 8 : uint8_t 2 // key vector of size 2 * <-------------------------------------> key vector offset points here * 9 : uint8_t 8, 5 // offsets to foo_key and bar_key * 11: uint8_t 2, 1 // offset to key vector, and its byte width * 13: uint8_t 2 // value vector of size * <-------------------------------------> value vector offset points here * 14: uint8_t 13, 14 // values * 16: uint8_t 4, 4 // types * 19: uint8_t 40 // root type * * The root * * The root starts at the end of the buffer. The last uint8_t is the width in bytes of the root (normally the parent determines * the width, but the root has no parent). The uint8_t before this is the type of the root, and the bytes before that are the * root value (of the number of bytes specified by the last byte). So for example, the integer value `13` as root would be: * * uint8_t 13, 4, 1 // root value, type and byte width */ class UFlatBuffer; template class UFlatBufferTypeHandler; class U_EXPORT UFlatBufferValue { public: /** * A type byte is made up of 2 components: * * 2 lower bits representing the bit-width of the child (8, 16, 32, 64). * This is only used if the child is accessed over an offset, such as a child vector. It is ignored for inline types */ enum BitWidth { BIT_WIDTH_8 = 0, BIT_WIDTH_16 = 1, BIT_WIDTH_32 = 2, BIT_WIDTH_64 = 3 }; /** * 6 bits representing the actual type * * for example 4 (100) means 8 bit child (value 0, unused, since the value is in-line), type `TYPE_INT` (value 1) */ enum Type { TYPE_NULL = 0, TYPE_INT = 1, TYPE_UINT = 2, TYPE_FLOAT = 3, TYPE_BOOL = 4, // Types above stored inline, types below store an offset TYPE_STRING = 5, TYPE_INDIRECT_INT = 6, TYPE_INDIRECT_UINT = 7, TYPE_INDIRECT_FLOAT = 8, TYPE_MAP = 9, TYPE_VECTOR = 10, // Untyped TYPE_VECTOR_INT = 11, // Typed any size (stores no type table) TYPE_VECTOR_UINT = 12, TYPE_VECTOR_FLOAT = 13, TYPE_VECTOR_BOOL = 14, // To Allow the same type of conversion of type to vector type TYPE_VECTOR_STRING = 15, TYPE_VECTOR_INT2 = 16, // Typed tuple (no type table, no size field) TYPE_VECTOR_UINT2 = 17, TYPE_VECTOR_FLOAT2 = 18, TYPE_VECTOR_INT3 = 19, // Typed triple (no type table, no size field) TYPE_VECTOR_UINT3 = 20, TYPE_VECTOR_FLOAT3 = 21, TYPE_VECTOR_INT4 = 22, // Typed quad (no type table, no size field) TYPE_VECTOR_UINT4 = 23, TYPE_VECTOR_FLOAT4 = 24 }; static uint32_t size() { return sizeof(double)+(sizeof(uint8_t)*2); } protected: union { uint32_t l_; int64_t i_; uint64_t u_; double f_; }; uint8_t type_, min_bit_width_; // For scalars: of itself, for vector: of its elements, for string: length void reset() { U_TRACE_NO_PARAM(0, "UFlatBufferValue::reset()") u_ = 0ULL; type_ = TYPE_NULL; min_bit_width_ = BIT_WIDTH_8; } void set(uint64_t u = 0ULL, uint8_t type = TYPE_NULL, uint8_t min_bit_width = BIT_WIDTH_8) { U_TRACE(0, "UFlatBufferValue::set(%llu,%u,%u)", u, type, min_bit_width) u_ = u; type_ = type; min_bit_width_ = min_bit_width; } void set(float f) { U_TRACE(0, "UFlatBufferValue::set(%g)", f) f_ = f; type_ = TYPE_FLOAT; min_bit_width_ = BIT_WIDTH_32; } void set(double f) { U_TRACE(0, "UFlatBufferValue::set(%g)", f) f_ = f; type_ = TYPE_FLOAT; min_bit_width_ = WidthF(f); } uint8_t StoredWidth(uint8_t parent_bit_width) const { U_TRACE(0, "UFlatBufferValue::StoredWidth(%u)", parent_bit_width) if (IsInline(type_) && min_bit_width_ < parent_bit_width) { U_RETURN(parent_bit_width); } U_RETURN(min_bit_width_); } uint8_t StoredPackedType(uint8_t parent_bit_width) const { U_TRACE(0, "UFlatBufferValue::StoredPackedType(%u)", parent_bit_width) uint8_t bit_width = PackedType(StoredWidth(parent_bit_width), type_); U_RETURN(bit_width); } __pure uint8_t ElemWidth(uint32_t buf_size, uint32_t elem_index) const { U_TRACE(0, "UFlatBufferValue::ElemWidth(%u,%u)", buf_size, elem_index) if (IsInline(type_)) U_RETURN(min_bit_width_); // We have an absolute offset, but want to store a relative offset elem_index elements beyond // the current buffer end. Since whether the relative offset fits in a certain byte_width depends // on the size of the elements before it (and their alignment), we have to test for each size in turn uint8_t bit_width; uint32_t offset_loc, offset; for (uint8_t byte_width = 1; byte_width <= sizeof(uint32_t); byte_width *= 2) { // Where are we going to write this offset? offset_loc = buf_size + PaddingBytes(buf_size, byte_width) + elem_index * byte_width; // Compute relative offset offset = offset_loc - l_; // Does it fit? bit_width = WidthL(offset); U_INTERNAL_DUMP("bit_width = %u byte_width = %u offset = %u offset_loc = %u", bit_width, byte_width, offset, offset_loc) if ((1U << bit_width) == byte_width) U_RETURN(bit_width); } U_INTERNAL_ASSERT(false) // Must match one of the sizes above U_RETURN(BIT_WIDTH_64); } static uint8_t WidthB(uint32_t byte_width) { U_TRACE(0, "UFlatBufferValue::WidthB(%u)", byte_width) switch (byte_width) { case 1: U_RETURN(BIT_WIDTH_8); case 2: U_RETURN(BIT_WIDTH_16); case 4: U_RETURN(BIT_WIDTH_32); case 8: U_RETURN(BIT_WIDTH_64); default: U_INTERNAL_ASSERT(false); } U_RETURN(BIT_WIDTH_64); } static uint8_t WidthL(uint32_t u) { U_TRACE(0, "UFlatBufferValue::WidthL(%u)", u) if ((u & ~((1U << 8) - 1U)) == 0) U_RETURN(BIT_WIDTH_8); if ((u & ~((1U << 16) - 1U)) == 0) U_RETURN(BIT_WIDTH_16); U_RETURN(BIT_WIDTH_32); } static uint8_t WidthU(uint64_t u) { U_TRACE(0, "UFlatBufferValue::WidthU(%llu)", u) if ((u & ~((1ULL << 8) - 1ULL)) == 0) U_RETURN(BIT_WIDTH_8); if ((u & ~((1ULL << 16) - 1ULL)) == 0) U_RETURN(BIT_WIDTH_16); if ((u & ~((1ULL << 32) - 1ULL)) == 0) U_RETURN(BIT_WIDTH_32); U_RETURN(BIT_WIDTH_64); } static uint8_t WidthI(int64_t i) { U_TRACE(0, "UFlatBufferValue::WidthI(%lld)", i) U_INTERNAL_ASSERT_MINOR(i, 0) return WidthU(-i); } static uint8_t WidthF(double f) { U_TRACE(0, "UFlatBufferValue::WidthF(%g)", f) U_RETURN((double)((float)f) == f ? BIT_WIDTH_32 : BIT_WIDTH_64); } static bool IsInline(uint8_t t) { U_TRACE(0, "UFlatBufferValue::IsInline(%u)", t) if (t <= TYPE_BOOL) U_RETURN(true); U_RETURN(false); } static uint8_t PackedType(uint8_t bit_width, uint8_t type) { U_TRACE(0, "UFlatBufferValue::PackedType(%u,%u)", bit_width, type) return (bit_width | (type << 2)); } // Computes how many bytes you'd have to pad to be able to write an // "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in memory) static uint32_t PaddingBytes(uint32_t buf_size, uint32_t scalar_size) { U_TRACE(0, "UFlatBufferValue::PaddingBytes(%u,%u)", buf_size, scalar_size) U_RETURN(((~buf_size)+1) & (scalar_size-1)); } private: UFlatBufferValue() {} friend class UFlatBuffer; U_DISALLOW_COPY_AND_ASSIGN(UFlatBufferValue) }; class U_EXPORT UFlatBuffer { public: // Check for memory error U_MEMORY_TEST // Allocator e Deallocator U_MEMORY_ALLOCATOR U_MEMORY_DEALLOCATOR UFlatBuffer() { U_TRACE_REGISTER_OBJECT(0, UFlatBuffer, "", 0) // coverity[uninit_ctor] # ifdef U_COVERITY_FALSE_POSITIVE reset(); # endif } ~UFlatBuffer() { U_TRACE_UNREGISTER_OBJECT(0, UFlatBuffer) } // SERVICES void reset() { U_TRACE_NO_PARAM(0, "UFlatBuffer::reset()") data_ = U_NULLPTR; buffer_idx = 0; type_ = UFlatBufferValue::TYPE_NULL; byte_width_ = parent_width_ = UFlatBufferValue::BIT_WIDTH_8; } uint8_t GetType() const { return type_; } static bool IsBool(uint8_t type) { return type == UFlatBufferValue::TYPE_BOOL; } static bool IsInt(uint8_t type) { return (type == UFlatBufferValue::TYPE_INT || type == UFlatBufferValue::TYPE_INDIRECT_INT); } static bool IsUInt(uint8_t type) { return (type == UFlatBufferValue::TYPE_UINT || type == UFlatBufferValue::TYPE_INDIRECT_UINT); } static bool IsIntOrUint(uint8_t type) { return (IsInt(type) || IsUInt(type)); } static bool IsFloat(uint8_t type) { return (type == UFlatBufferValue::TYPE_FLOAT || type == UFlatBufferValue::TYPE_INDIRECT_FLOAT); } static bool IsVector(uint8_t type) { return type == UFlatBufferValue::TYPE_VECTOR; } static bool IsNumeric(uint8_t type) { return (IsIntOrUint(type) || IsFloat(type)); } static bool IsScalar(uint8_t type) { return (IsNumeric(type) || IsBool(type)); } bool IsNull() const { return type_ == UFlatBufferValue::TYPE_NULL; } bool IsString() const { return type_ == UFlatBufferValue::TYPE_STRING; } bool IsMap() const { return type_ == UFlatBufferValue::TYPE_MAP; } bool IsBool() const { return IsBool(type_); } bool IsInt() const { return IsInt(type_); } bool IsUInt() const { return IsUInt(type_); } bool IsIntOrUint() const { return IsIntOrUint(type_); } bool IsFloat() const { return IsFloat(type_); } bool IsNumeric() const { return IsNumeric(type_); } bool IsVector() const { return IsVector(type_); } // Maps can be viewed as vectors too bool IsTypedVector() const { return (type_ >= UFlatBufferValue::TYPE_VECTOR_INT && type_ <= UFlatBufferValue::TYPE_VECTOR_STRING); } bool IsFixedTypedVector() const { return (type_ >= UFlatBufferValue::TYPE_VECTOR_INT2 && type_ <= UFlatBufferValue::TYPE_VECTOR_FLOAT4); } // All value constructing functions below have two versions: one that takes a key // (for placement inside a map) and one that doesn't (for inside vectors and elsewhere) static void Null() { pushOnStack(); } static void Bool(bool b) { pushOnStack((uint64_t)b, UFlatBufferValue::TYPE_BOOL, UFlatBufferValue::BIT_WIDTH_8); } static void Int( int64_t i) { pushOnStack(-i, UFlatBufferValue::TYPE_INT, UFlatBufferValue::WidthI(i)); } static void UInt(uint64_t u) { pushOnStack(u, UFlatBufferValue::TYPE_UINT, UFlatBufferValue::WidthU(u)); } static void Float(float f) { pushOnStack(f); } static void Double(double d) { pushOnStack(d); } static void setNumber(int64_t l) { U_TRACE(0, "UFlatBuffer::setNumber(%lld)", l) if (l < 0) Int(l); else UInt(l); } void IndirectInt( int64_t i) { PushIndirect((uint64_t)i, UFlatBufferValue::TYPE_INDIRECT_INT, UFlatBufferValue::WidthU((uint64_t)i)); } void IndirectUInt(uint64_t u) { PushIndirect(u, UFlatBufferValue::TYPE_INDIRECT_UINT, UFlatBufferValue::WidthU(u)); } void IndirectFloat(float f) { PushIndirectFloat(f); } void IndirectDouble(double f) { PushIndirect(f, UFlatBufferValue::TYPE_INDIRECT_FLOAT, UFlatBufferValue::WidthF(f)); } void String(const char* str, uint32_t len) { CreateString(str, len); } void Null( const char* key, uint32_t len) { Key(key, len); Null(); } void Bool( const char* key, uint32_t len, bool b) { Key(key, len); Bool(b); } void Int( const char* key, uint32_t len, int64_t i) { Key(key, len); Int(i); } void UInt( const char* key, uint32_t len, uint64_t u) { Key(key, len); UInt(u); } void Float( const char* key, uint32_t len, float f) { Key(key, len); Float(f); } void Double(const char* key, uint32_t len, double d) { Key(key, len); Double(d); } void IndirectInt( const char* key, uint32_t len, int64_t i) { Key(key, len); IndirectInt(i); } void IndirectUInt( const char* key, uint32_t len, uint64_t u) { Key(key, len); IndirectUInt(u); } void IndirectFloat( const char* key, uint32_t len, float f) { Key(key, len); IndirectFloat(f); } void IndirectDouble(const char* key, uint32_t len, double d) { Key(key, len); IndirectDouble(d); } void String(const char* key, uint32_t len1, const char* str, uint32_t len2) { Key(key, len1); CreateString(str, len2); } // Overloaded Add that tries to call the correct function above static void Add() { Null(); } static void Add(bool b) { Bool(b); } static void Add( int64_t i) { Int(i); } static void Add(uint64_t u) { UInt(u); } static void Add(float f) { Float(f); } static void Add(double d) { Double(d); } void Add(const char* str, uint32_t len) { CreateString(str, len); } void Key(const char* key, uint32_t len) { CreateString(key, len); } void Add(const char* key, uint32_t len, bool b) { Key(key, len); Bool(b); } void Add(const char* key, uint32_t len, int64_t i) { Key(key, len); Int(i); } void Add(const char* key, uint32_t len, uint64_t u) { Key(key, len); UInt(u); } void Add(const char* key, uint32_t len, float f) { Key(key, len); Float(f); } void Add(const char* key, uint32_t len, double d) { Key(key, len); Double(d); } void Add(const char* key, uint32_t len1, const char* str, uint32_t len2) { Key(key, len1); CreateString(str, len2); } static uint32_t StartVector() { U_TRACE_NO_PARAM(0, "UFlatBuffer::StartVector()") U_RETURN(stack_idx); } uint32_t StartVector(const char* key, uint32_t len) { U_TRACE(0, "UFlatBuffer::StartVector(%.*S,%u)", len, key, len) Key(key, len); U_RETURN(stack_idx); } static uint32_t StartMap() { U_TRACE_NO_PARAM(0, "UFlatBuffer::StartMap()") U_RETURN(stack_idx); } uint32_t StartMap(const char* key, uint32_t len) { U_TRACE(0, "UFlatBuffer::StartMap(%.*S,%u)", len, key, len) uint32_t start = stack_idx; Key(key, len); U_RETURN(start); } void EndMap( uint32_t start); void EndVector(uint32_t start, bool typed = true, bool fixed = false) { U_TRACE(0, "UFlatBuffer::EndVector(%u,%b,%b)", start, typed, fixed) CreateVector(start, stack_idx-start, 1, typed, fixed, U_NULLPTR); } template void TypedVector(const T* elems, uint32_t len) { U_TRACE(0, "UFlatBuffer::TypedVector(%p,%u)", elems, len) uint32_t start = StartVector(); for (uint32_t i = 0; i < len; ++i) Add(elems[i]); EndVector(start); } template void TypedVector(const char* key, uint32_t klen, const T* elems, uint32_t len) { U_TRACE(0, "UFlatBuffer::TypedVector(%.*S,%u,%p,%u)", klen, key, klen, elems, len) uint32_t start = StartVector(key, klen); for (uint32_t i = 0; i < len; ++i) Add(elems[i]); EndVector(start); } template void FixedTypedVector(const T* elems, uint32_t len, uint8_t vector_type = UFlatBufferValue::TYPE_UINT) // only scalar values { U_TRACE(0, "UFlatBuffer::FixedTypedVector(%p,%u,%u)", elems, len, vector_type) U_INTERNAL_ASSERT_RANGE(2, len, 4) // We only support a few fixed vector lengths. Anything bigger use a regular typed vector ScalarVector(elems, len, vector_type, true); } template void FixedTypedVector(const char* key, uint32_t klen, const T* elems, uint32_t len, uint8_t vector_type = UFlatBufferValue::TYPE_UINT) // only scalar values { U_TRACE(0, "UFlatBuffer::FixedTypedVector(%.*S,%u,%p,%u,%u)", klen, key, klen, elems, len, vector_type) U_INTERNAL_ASSERT_RANGE(2, len, 4) // We only support a few fixed vector lengths. Anything bigger use a regular typed vector Key(key, klen); ScalarVector(elems, len, vector_type, true); } template void ScalarVector(const T* elems, uint32_t len, uint8_t vector_type = UFlatBufferValue::TYPE_UINT, bool fixed = true) { U_TRACE(0, "UFlatBuffer::ScalarVector(%p,%u,%u,%b)", elems, len, vector_type, fixed) U_INTERNAL_ASSERT(IsScalar(vector_type)) uint8_t byte_width = sizeof(T), bit_width = UFlatBufferValue::WidthB(byte_width); // If you get this assert, you're trying to write a vector with a size field that is bigger than the scalars // you're trying to write (e.g. a byte vector > 255 elements). For such types, write a "string" instead U_INTERNAL_ASSERT(UFlatBufferValue::WidthU(len) <= bit_width) if (fixed == false) WriteScalar(len, byte_width); # ifdef DEBUG else { U_INTERNAL_ASSERT(IsNumeric(vector_type)) } # endif uint32_t vloc = buffer_idx; for (uint32_t i = 0; i < len; ++i) WriteScalar(elems[i], byte_width); pushOnStack(vloc, ToTypedVector(vector_type, fixed ? len : 0), bit_width); } template void Vector(F f, bool typed = false, bool fixed = false) { U_TRACE(0, "UFlatBuffer::Vector(%p,%b,%b)", f, typed, fixed) uint32_t start = StartVector(); f(); EndVector(start, typed, fixed); } template void Vector(const char* key, uint32_t len, F f, bool typed = false, bool fixed = false) { U_TRACE(0, "UFlatBuffer::Vector(%.*S,%u,%p,%b,%b)", len, key, len, f, typed, fixed) uint32_t start = StartVector(key, len); f(); EndVector(start, typed, fixed); } template void Map(F f) { U_TRACE(0, "UFlatBuffer::Map(%p)", f) uint32_t start = StartMap(); f(); EndMap(start); } template void Map(const char* key, uint32_t len, F f) { U_TRACE(0, "UFlatBuffer::Map(%.*S,%u,%p)", len, key, len, f) uint32_t start = StartMap(key, len); f(); EndMap(start); } // manage object <=> FlatBuffer representation template void toFlatBuffer(UFlatBufferTypeHandler member) { U_TRACE(0, "UFlatBuffer::toFlatBuffer(%p)", &member) member.toFlatBuffer(*this); } template void toFlatBuffer(const UString& key, UFlatBufferTypeHandler member) { U_TRACE(0, "UFlatBuffer::toFlatBuffer(%V, %p)", key.rep, &member) Key(U_STRING_TO_PARAM(key)); member.toFlatBuffer(*this); } template void fromFlatBuffer(uint32_t i, UFlatBufferTypeHandler member) { U_TRACE(0, "UFlatBuffer::fromFlatBuffer(%u,%p)", i, &member) UFlatBuffer fb; AsVectorGet(i, fb); member.fromFlatBuffer(fb); } template void toObject(T& obj); template void fromObject(T& obj); // INIT static void setStack(uint8_t* ptr, uint32_t len) { U_TRACE(0, "UFlatBuffer::setStack(%p,%u)", ptr, len) stack_str = ptr; stack_max = len / UFlatBufferValue::size(); } static void setBuffer(uint8_t* ptr, uint32_t len) { U_TRACE(0, "UFlatBuffer::setBuffer(%p,%u)", ptr, len) buffer_str = ptr; buffer_max = len; } UString getResult() const { return UString(buffer_str, buffer_idx); } uint8_t* getPointer() const { return buffer_str+buffer_idx; } uint32_t getBufferSize() const { return buffer_idx; } static uint8_t* getStack() { return stack_str; } static uint8_t* getBuffer() { return buffer_str; } static uint32_t getStackMax() { return stack_max * UFlatBufferValue::size(); } static uint32_t getBufferMax() { return buffer_max; } // BUILD void StartBuild() { U_TRACE_NO_PARAM(0, "UFlatBuffer::StartBuild()") U_INTERNAL_ASSERT_POINTER(stack_str) U_INTERNAL_ASSERT_POINTER(buffer_str) // Reset all state so we can re-use the buffers reset(); setStackPointer((stack_idx = 0)); pvalue->reset(); } uint32_t EndBuild() { U_TRACE_NO_PARAM(0, "UFlatBuffer::EndBuild()") // If you hit this assert, you likely have objects that were never included in a parent. // You need to have exactly one root to finish a buffer. Check your Start/End calls are // matched, and all objects are inside some other object U_INTERNAL_ASSERT_EQUALS(stack_idx, 1) U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) uint8_t byte_width = Align(((UFlatBufferValue*)stack_str)->ElemWidth(buffer_idx, 0)); WriteAny(byte_width); // Write root value WriteScalar8(((UFlatBufferValue*)stack_str)->StoredPackedType(UFlatBufferValue::BIT_WIDTH_8)); // Write root type WriteScalar8(byte_width); // Write root size. Normally determined by parent, but root has no parent :) U_INTERNAL_DUMP("buffer(%u) = %#.*S", buffer_idx, buffer_idx, buffer_str) U_RETURN(buffer_idx); } template uint32_t encode(F f) { U_TRACE(0, "UFlatBuffer::encode(%p)", f) StartBuild(); f(); return EndBuild(); } template uint32_t encodeVector(F f, bool typed = false, bool fixed = false) { U_TRACE(0, "UFlatBuffer::encodeVector(%p,%b,%b)", f, typed, fixed) StartBuild(); (void) StartVector(); f(); EndVector(0, typed, fixed); return EndBuild(); } template uint32_t encodeMap(F f) { U_TRACE(0, "UFlatBuffer::encodeMap(%p)", f) StartBuild(); (void) StartMap(); f(); EndMap(0); return EndBuild(); } void AddVectorEmpty() { U_TRACE_NO_PARAM(0, "UFlatBuffer::AddVectorEmpty()") buffer_str[buffer_idx++] = 0; U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) pushOnStack(buffer_idx, UFlatBufferValue::TYPE_VECTOR_BOOL, UFlatBufferValue::BIT_WIDTH_8); } void AddMapEmpty() { U_TRACE_NO_PARAM(0, "UFlatBuffer::AddMapEmpty()") u_put_unalignedp32(buffer_str+buffer_idx, U_MULTICHAR_CONSTANT32(0,1,1,0)); pushOnStack((buffer_idx += 4), UFlatBufferValue::TYPE_MAP, UFlatBufferValue::BIT_WIDTH_8); U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) } // PARSE void setRoot(const uint8_t* ptr, uint32_t len) // See EndBuild() below for the serialization counterpart of this { U_TRACE(0, "UFlatBuffer::setRoot(%p,%u)", ptr, len) data_ = (buffer_str = (uint8_t*)ptr) + len; // The root starts at the end of the buffer, so we parse backwards from there parent_width_ = *--data_; setTypeAndWidth(*--data_); data_ -= parent_width_; // The root data item U_DUMP("type_ = (%u,%S) byte_width_ = %u parent_width_ = %u data_(%u) = %#.*S", type_, getTypeDescription(type_), byte_width_, parent_width_, 2+byte_width_, 2+byte_width_, data_) } void setRoot() { setRoot(buffer_str, buffer_idx); } bool AsBool() const { return AsBool(data_); } int64_t AsInt64() const { return AsInt64(data_); } uint64_t AsUInt64() const { return AsUInt64(data_); } float AsFloat() const { return AsFloat(data_); } double AsDouble() const { return AsDouble(data_); } UString AsString() const { return AsString(data_); } int8_t AsInt8() const { return (int8_t) AsInt64(data_); } int16_t AsInt16() const { return (int16_t)AsInt64(data_); } int32_t AsInt32() const { return (int32_t)AsInt64(data_); } int64_t AsIndirectInt64() const { return AsIndirectInt64(data_); } uint64_t AsIndirectUInt64() const { return AsIndirectUInt64(data_); } float AsIndirectFloat() const { return AsIndirectFloat(data_); } double AsIndirectDouble() const { return AsIndirectDouble(data_); } int8_t AsIndirectInt8() const { return (int8_t) AsIndirectInt64(data_); } int16_t AsIndirectInt16() const { return (int16_t)AsIndirectInt64(data_); } int32_t AsIndirectInt32() const { return (int32_t)AsIndirectInt64(data_); } int64_t AsNumber() const { U_TRACE_NO_PARAM(0, "UFlatBuffer::AsNumber()") if (type_ == UFlatBufferValue::TYPE_INT) return AsInt64(); U_INTERNAL_ASSERT_EQUALS(type_, UFlatBufferValue::TYPE_UINT) return AsUInt64(); } int64_t AsIndirectNumber() const { U_TRACE_NO_PARAM(0, "UFlatBuffer::AsIndirectNumber()") if (type_ == UFlatBufferValue::TYPE_INDIRECT_INT) return AsIndirectInt64(); U_INTERNAL_ASSERT_EQUALS(type_, UFlatBufferValue::TYPE_INDIRECT_UINT) return AsIndirectUInt64(); } uint32_t GetSize() const { U_TRACE_NO_PARAM(0, "UFlatBuffer::GetSize()") U_RETURN(buffer_idx); } // VECTOR void AsVector(UFlatBuffer& fb) const { AsVector(data_, fb); } void AsTypedVector(UFlatBuffer& fb) const { AsTypedVector(data_, fb); } void AsFixedTypedVector(UFlatBuffer& fb) const { AsFixedTypedVector(data_, fb); } template T AsVectorGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsVectorGet(%u)", i) T value = Get(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_VECTOR; return value; } template T AsVectorGetIndirect(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsVectorGetIndirect(%u)", i) T value = GetIndirect(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_VECTOR; return value; } template T AsTypedOrFixedVectorGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGet(%u)", i) return Get(AsTypedOrFixedVectorSetIndex(i)); } template T AsTypedOrFixedVectorGetIndirect(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGetIndirect(%u)", i) return GetIndirect(AsTypedOrFixedVectorSetIndex(i)); } template bool AsVectorIsEqual(const T* elems, uint32_t len) { U_TRACE(0, "UFlatBuffer::AsVectorIsEqual(%p,%u)", elems, len) for (uint32_t i = 0; i < len; ++i) { if (AsVectorGet(i) != elems[i]) U_RETURN(false); } U_RETURN(true); } template bool AsTypedOrFixedVectorIsEqual(const T* elems, uint32_t len) { U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorIsEqual(%p,%u)", elems, len) for (uint32_t i = 0; i < len; ++i) { if (AsTypedOrFixedVectorGet(i) != elems[i]) U_RETURN(false); } U_RETURN(true); } // MAP void AsMap(UFlatBuffer& fb) const { AsMap(data_, fb); } void AsMapGetKeys(UFlatBuffer& fb) const { AsMapGetKeys(data_, fb); } void AsMapGetValues(UFlatBuffer& fb) const { AsMapGetValues(data_, fb); } uint32_t AsMapGetKeys(UVector& members) const; template T AsMapGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsMapGet(%u)", i) U_INTERNAL_ASSERT(IsMap()) T value = Get(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_MAP; return value; } template T AsMapGetIndirect(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsMapGetIndirect(%u)", i) U_INTERNAL_ASSERT(IsMap()) T value = GetIndirect(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_MAP; return value; } template T AsMapGet(const char* key, uint32_t len) { U_TRACE(0, "UFlatBuffer::AsMapGet(%.*S,%u)", len, key, len) U_INTERNAL_ASSERT(IsMap()) T value = Get(AsMapSetIndex(key, len)); type_ = UFlatBufferValue::TYPE_MAP; return value; } template T AsMapGetIndirect(const char* key, uint32_t len) { U_TRACE(0, "UFlatBuffer::AsMapGetIndirect(%.*S,%u)", len, key, len) U_INTERNAL_ASSERT(IsMap()) T value = GetIndirect(AsMapSetIndex(key, len)); type_ = UFlatBufferValue::TYPE_MAP; return value; } // VECTOR <=> MAP void AsVectorGetVector(uint32_t i, UFlatBuffer& fb) { U_TRACE(0, "UFlatBuffer::AsVectorGetVector(%u,%p)", i, &fb) U_INTERNAL_ASSERT(IsVector()) AsVector(AsVectorSetIndex(i), fb); byte_width_ = parent_width_; type_ = UFlatBufferValue::TYPE_VECTOR; } void AsVectorGetTypedVector(uint32_t i, UFlatBuffer& fb) { U_TRACE(0, "UFlatBuffer::AsVectorGetTypedVector(%u,%p)", i, &fb) U_INTERNAL_ASSERT(IsVector()) AsTypedVector(AsVectorSetIndex(i), fb); byte_width_ = parent_width_; type_ = UFlatBufferValue::TYPE_VECTOR; } void AsVectorGetFixedTypedVector(uint32_t i, UFlatBuffer& fb) { U_TRACE(0, "UFlatBuffer::AsVectorGetFixedTypedVector(%u,%p)", i, &fb) U_INTERNAL_ASSERT(IsVector()) AsFixedTypedVector(AsVectorSetIndex(i), fb); byte_width_ = parent_width_; type_ = UFlatBufferValue::TYPE_VECTOR; } void AsVectorGetMap(uint32_t i, UFlatBuffer& fb) { U_TRACE(0, "UFlatBuffer::AsVectorGetMap(%u,%p)", i, &fb) U_INTERNAL_ASSERT(IsVector()) AsMap(AsVectorSetIndex(i), fb); byte_width_ = parent_width_; type_ = UFlatBufferValue::TYPE_VECTOR; } void AsTypedOrFixedVectorGetMap(uint32_t i, UFlatBuffer& fb) { U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGetMap(%u,%p)", i, &fb) U_INTERNAL_ASSERT(IsTypedVector() || IsTypedVectorElementType()) AsMap(AsVectorSetIndex(i), fb); byte_width_ = parent_width_; } void AsMapGetVector(uint32_t i, UFlatBuffer& fb) { U_TRACE(0, "UFlatBuffer::AsMapGetVector(%u,%p)", i, &fb) U_INTERNAL_ASSERT(IsMap()) AsVector(AsVectorSetIndex(i), fb); byte_width_ = parent_width_; type_ = UFlatBufferValue::TYPE_MAP; } void AsMapGetVector(const char* key, uint32_t len, UFlatBuffer& fb) { U_TRACE(0, "UFlatBuffer::AsMapGetVector(%.*S,%u,%p)", len, key, len, &fb) U_INTERNAL_ASSERT(IsMap()) AsVector(AsMapSetIndex(key, len), fb); byte_width_ = parent_width_; type_ = UFlatBufferValue::TYPE_MAP; } void AsMapGetTypedVector(uint32_t i, UFlatBuffer& fb) { U_TRACE(0, "UFlatBuffer::AsMapGetTypedVector(%u,%p)", i, &fb) U_INTERNAL_ASSERT(IsMap()) AsTypedVector(AsVectorSetIndex(i), fb); byte_width_ = parent_width_; type_ = UFlatBufferValue::TYPE_MAP; } void AsMapGetTypedVector(const char* key, uint32_t len, UFlatBuffer& fb) { U_TRACE(0, "UFlatBuffer::AsMapGetTypedVector(%.*S,%u,%p)", len, key, len, &fb) U_INTERNAL_ASSERT(IsMap()) AsTypedVector(AsMapSetIndex(key, len), fb); byte_width_ = parent_width_; type_ = UFlatBufferValue::TYPE_MAP; } void AsMapGetFixedTypedVector(uint32_t i, UFlatBuffer& fb) { U_TRACE(0, "UFlatBuffer::AsMapGetFixedTypedVector(%u,%p)", i, &fb) U_INTERNAL_ASSERT(IsMap()) AsFixedTypedVector(AsVectorSetIndex(i), fb); byte_width_ = parent_width_; type_ = UFlatBufferValue::TYPE_MAP; } void AsMapGetFixedTypedVector(const char* key, uint32_t len, UFlatBuffer& fb) { U_TRACE(0, "UFlatBuffer::AsMapGetFixedTypedVector(%.*S,%u,%p)", len, key, len, &fb) U_INTERNAL_ASSERT(IsMap()) AsFixedTypedVector(AsMapSetIndex(key, len), fb); byte_width_ = parent_width_; type_ = UFlatBufferValue::TYPE_MAP; } void AsMapGetMap(uint32_t i, UFlatBuffer& fb) { U_TRACE(0, "UFlatBuffer::AsMapGetMap(%u,%p)", i, &fb) U_INTERNAL_ASSERT(IsMap()) AsMap(AsVectorSetIndex(i), fb); byte_width_ = parent_width_; type_ = UFlatBufferValue::TYPE_MAP; } void AsMapGetMap(const char* key, uint32_t len, UFlatBuffer& fb) { U_TRACE(0, "UFlatBuffer::AsMapGetMap(%.*S,%u,%p)", len, key, len, &fb) U_INTERNAL_ASSERT(IsMap()) AsMap(AsMapSetIndex(key, len), fb); byte_width_ = parent_width_; type_ = UFlatBufferValue::TYPE_MAP; } #ifdef DEBUG const char* dump(bool reset) const; static const char* getTypeDescription(uint8_t type); #else static const char* getTypeDescription(uint8_t) { return ""; } #endif protected: uint8_t* data_; uint32_t buffer_idx; uint8_t type_, byte_width_, parent_width_; static uint8_t* stack_str; static uint8_t* buffer_str; static uint32_t stack_idx, stack_max, buffer_max; static UFlatBufferValue* pkeys; static UFlatBufferValue* pvalue; static void setStackPointer(uint32_t idx) { U_TRACE(0, "UFlatBuffer::setStackPointer(%u)", idx) U_INTERNAL_DUMP("stack_idx = %u stack_max = %u", stack_idx, stack_max) U_INTERNAL_ASSERT_MINOR(idx, stack_max) pvalue = (UFlatBufferValue*)(stack_str + (idx * UFlatBufferValue::size())); } #ifdef DEBUG static void checkStackPointer() { U_TRACE_NO_PARAM(0, "UFlatBuffer::checkStackPointer()") U_INTERNAL_DUMP("idx = %u stack_max = %u", ((uint8_t*)pvalue - stack_str) / UFlatBufferValue::size(), stack_max) U_INTERNAL_ASSERT_MINOR(((uint8_t*)pvalue - stack_str) / UFlatBufferValue::size(), stack_max) } #endif static void nextStackPointer() { U_TRACE_NO_PARAM(0+256, "UFlatBuffer::nextStackPointer()") pvalue = (UFlatBufferValue*)((uint8_t*)pvalue + UFlatBufferValue::size()); # ifdef DEBUG checkStackPointer(); # endif } static void next2StackPointer() { U_TRACE_NO_PARAM(0+256, "UFlatBuffer::next2StackPointer()") pvalue = (UFlatBufferValue*)((uint8_t*)pvalue + (UFlatBufferValue::size()*2)); # ifdef DEBUG checkStackPointer(); # endif } static void pushOnStack(uint64_t u = 0ULL, uint8_t type = UFlatBufferValue::TYPE_NULL, uint8_t min_bit_width = UFlatBufferValue::BIT_WIDTH_8) { U_TRACE(0, "UFlatBuffer::pushOnStack(%llu,%u,%u)", u, type, min_bit_width) setStackPointer(stack_idx++); pvalue->set(u, type, min_bit_width); } static void pushOnStack(float f) { U_TRACE(0, "UFlatBufferValue::pushOnStack(%g)", f) setStackPointer(stack_idx++); pvalue->set(f); } static void pushOnStack(double f) { U_TRACE(0, "UFlatBufferValue::pushOnStack(%g)", f) setStackPointer(stack_idx++); pvalue->set(f); } static uint8_t GetByteWidth(uint32_t len) { U_TRACE(0, "UFlatBuffer::GetByteWidth(%u)", len) uint8_t bit_width = UFlatBufferValue::WidthL(len); U_RETURN(Align(bit_width)); } void CreateString(const char* data, uint32_t len) { U_TRACE(0, "UFlatBuffer::CreateString(%.*S,%u)", len, data, len) uint8_t bit_width = UFlatBufferValue::WidthL(len); WriteScalar(len, Align(bit_width)); uint32_t sloc = buffer_idx; WriteBytes(data, len); pushOnStack(sloc, UFlatBufferValue::TYPE_STRING, bit_width); } void CreateVector(uint32_t start, uint32_t vec_len, uint32_t step, bool typed, bool fixed, UFlatBufferValue* pval); uint8_t ToTypedVectorElementType() const { U_TRACE_NO_PARAM(0, "UFlatBuffer::ToTypedVectorElementType()") U_INTERNAL_ASSERT(IsTypedVector()) U_RETURN(type_ - UFlatBufferValue::TYPE_VECTOR_INT + UFlatBufferValue::TYPE_INT); } uint8_t ToFixedTypedVectorElementType(UFlatBuffer& fb) const { U_TRACE(0, "UFlatBuffer::ToFixedTypedVectorElementType(%p)", &fb) uint8_t fixed_type = type_ - UFlatBufferValue::TYPE_VECTOR_INT2; fb.buffer_idx = (uint8_t)(fixed_type / 3 + 2); // 3 types each, starting from length 2 U_RETURN(fixed_type % 3 + UFlatBufferValue::TYPE_INT); } static bool IsTypedVectorElementType(uint8_t t) { U_TRACE(0, "UFlatBuffer::IsTypedVectorElementType(%u)", t) U_DUMP("t = %S", getTypeDescription(t)) if (t >= UFlatBufferValue::TYPE_INT && t <= UFlatBufferValue::TYPE_STRING) U_RETURN(true); U_RETURN(false); } static uint8_t ToTypedVector(uint8_t t, uint8_t fixed_len) { U_TRACE(0, "UFlatBuffer::ToTypedVector(%u,%u)", t, fixed_len) U_INTERNAL_ASSERT(IsVector(t) || IsTypedVectorElementType(t)) if (fixed_len == 0) U_RETURN(t - UFlatBufferValue::TYPE_INT + UFlatBufferValue::TYPE_VECTOR_INT); if (fixed_len == 2) U_RETURN(t - UFlatBufferValue::TYPE_INT + UFlatBufferValue::TYPE_VECTOR_INT2); if (fixed_len == 3) U_RETURN(t - UFlatBufferValue::TYPE_INT + UFlatBufferValue::TYPE_VECTOR_INT3); U_INTERNAL_ASSERT_EQUALS(fixed_len, 4) U_RETURN(t - UFlatBufferValue::TYPE_INT + UFlatBufferValue::TYPE_VECTOR_INT4); } bool IsTypedVectorElementType() const { return IsTypedVectorElementType(type_); } // WRITE void WriteBytes(const void* val, uint32_t len) { U_TRACE(0, "UFlatBuffer::WriteBytes(%#.*S,%u)", len, val, len) (void) memcpy(getPointer(), val, len); buffer_idx += len; U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) } void WriteScalar8(uint8_t i) { U_TRACE(0, "UFlatBuffer::WriteScalar8(%u)", i) buffer_str[buffer_idx++] = i; U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) } void WriteScalar16(uint16_t i) { U_TRACE(0, "UFlatBuffer::WriteScalar16(%u)", i) # if __BYTE_ORDER == __LITTLE_ENDIAN u_put_unalignedp16(getPointer(), i); # else u_put_unalignedp16(getPointer(), U_BYTESWAP16(i)); # endif buffer_idx += sizeof(uint16_t); U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) } void WriteScalar32(uint32_t i) { U_TRACE(0, "UFlatBuffer::WriteScalar32(%u)", i) # if __BYTE_ORDER == __LITTLE_ENDIAN u_put_unalignedp32(getPointer(), i); # else u_put_unalignedp32(getPointer(), U_BYTESWAP32(i)); # endif buffer_idx += sizeof(uint32_t); U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) } void WriteScalar64(uint64_t i) { U_TRACE(0, "UFlatBuffer::WriteScalar64(%llu)", i) # if __BYTE_ORDER == __LITTLE_ENDIAN u_put_unalignedp64(getPointer(), i); # else u_put_unalignedp64(getPointer(), U_BYTESWAP64(i)); # endif buffer_idx += sizeof(uint64_t); U_INTERNAL_DUMP("buffer_idx = %u buffer_max = %u", buffer_idx, buffer_max) U_INTERNAL_ASSERT_MINOR(buffer_idx, buffer_max) } template void WriteScalar(T val, uint8_t byte_width) { U_TRACE(0, "UFlatBuffer::WriteScalar(%p,%u)", &val, byte_width) if (byte_width < 4) { if (byte_width < 2) WriteScalar8(val); else WriteScalar16(val); } else if (byte_width < 8) WriteScalar32(val); else WriteScalar64(val); } void WriteFloat(float f) { U_TRACE(0, "UFlatBuffer::WriteFloat(%g)", f) char* p = (char*)&f; WriteScalar32(*(uint32_t*)p); U_INTERNAL_DUMP("writeFloat = %#.4S", getPointer()-4) } void WriteDouble(double f, uint8_t byte_width) { U_TRACE(0, "UFlatBuffer::WriteDouble(%g,%u)", f, byte_width) if (byte_width == 4) WriteFloat(f); else { U_INTERNAL_ASSERT_EQUALS(byte_width, 8) char* p = (char*)&f; WriteScalar64(*(uint64_t*)p); U_INTERNAL_DUMP("writeDouble = %#.8S", getPointer()-8) } } void WriteAny(uint8_t byte_width); void WriteOffset(uint32_t o, uint8_t byte_width) { U_TRACE(0, "UFlatBuffer::WriteOffset(%u,%u)", o, byte_width) uint32_t reloff = buffer_idx - o; U_INTERNAL_DUMP("buffer_idx = %u reloff(%u) = %#.4S", buffer_idx, reloff, buffer_str + o) U_INTERNAL_ASSERT(byte_width == 8 || reloff < (1ULL << (byte_width * 8))) WriteScalar(reloff, byte_width); } static uint8_t Align(uint8_t alignment) { return (1U << alignment); } // Align to prepare for writing a scalar with a certain size // READ static uint8_t ReadScalar8(const void* p) { U_TRACE(0, "UFlatBuffer::ReadScalar8(%p)", p) return *(const uint8_t*)p; } static uint16_t ReadScalar16(const void* p) { U_TRACE(0, "UFlatBuffer::ReadScalar16(%p)", p) # if __BYTE_ORDER == __LITTLE_ENDIAN return u_get_unalignedp16(p); # else return U_BYTESWAP16(u_get_unalignedp16(p)); # endif } static uint32_t ReadScalar32(const void* p) { U_TRACE(0, "UFlatBuffer::ReadScalar32(%p)", p) # if __BYTE_ORDER == __LITTLE_ENDIAN return u_get_unalignedp32(p); # else return U_BYTESWAP32(u_get_unalignedp32(p)); # endif } static uint64_t ReadScalar64(const void* p) { U_TRACE(0, "UFlatBuffer::ReadScalar64(%p)", p) # if __BYTE_ORDER == __LITTLE_ENDIAN return u_get_unalignedp64(p); # else return U_BYTESWAP64(u_get_unalignedp64(p)); # endif } template static T ReadScalar(const void* p, uint8_t byte_width) { U_TRACE(0, "UFlatBuffer::ReadScalar(%#.*S,%u)", sizeof(T), p, byte_width) if (byte_width < 4) { if (byte_width < 2) return ReadScalar8(p); return ReadScalar16(p); } if (byte_width < 8) return ReadScalar32(p); return ReadScalar64(p); } static int64_t ReadInt64( const uint8_t* data, uint8_t byte_width) { return -ReadScalar(data, byte_width); } static uint32_t ReadUInt32(const uint8_t* data, uint8_t byte_width) { return ReadScalar(data, byte_width); } static uint64_t ReadUInt64(const uint8_t* data, uint8_t byte_width) { return ReadScalar(data, byte_width); } static float ReadFloat(const void* p) { U_TRACE(0, "UFlatBuffer::ReadFloat(%p)", p) # if __BYTE_ORDER == __LITTLE_ENDIAN return *(float*)p; # else return U_BYTESWAP32(*(float*)p); # endif } static double ReadDouble(const void* p) { U_TRACE(0, "UFlatBuffer::ReadDouble(%p)", p) # if __BYTE_ORDER == __LITTLE_ENDIAN return *(double*)p; # else return U_BYTESWAP64(*(double*)p); # endif } static double ReadDouble(const uint8_t* data, uint8_t byte_width) { U_TRACE(0, "UFlatBuffer::ReadDouble(%#.8S,%u)", data, byte_width) if (byte_width == 4) return ReadFloat(data); U_INTERNAL_ASSERT_EQUALS(byte_width, 8) return ReadDouble(data); } static uint8_t* Indirect(const uint8_t* data, uint8_t parent_width) { U_TRACE(0, "UFlatBuffer::Indirect(%#.12S,%u)", data, parent_width) U_INTERNAL_DUMP("data-buffer_str = %u", data-buffer_str) uint32_t o = ReadUInt32(data, parent_width); U_INTERNAL_DUMP("o = %u", o) U_INTERNAL_DUMP("Indirect = %#.4S", (uint8_t*)data-o) return ((uint8_t*)data - o); } uint8_t* Indirect() { return Indirect(data_, parent_width_); } template void PushIndirect(T val, uint8_t type, uint8_t bit_width) { U_TRACE(0, "UFlatBuffer::PushIndirect(%p,%u,%u)", &val, type, bit_width) uint32_t iloc = buffer_idx; uint8_t byte_width = Align(bit_width); WriteScalar(val, byte_width); pushOnStack(iloc, type, bit_width); } void PushIndirectFloat(float f) { U_TRACE(0, "UFlatBuffer::PushIndirectFloat(%g)", f) uint32_t iloc = buffer_idx; WriteFloat(f); pushOnStack(iloc, UFlatBufferValue::TYPE_INDIRECT_FLOAT, UFlatBufferValue::BIT_WIDTH_32); } uint32_t getSize(const uint8_t* data) const { U_TRACE(0, "UFlatBuffer::getSize(%#.4S)", data) U_INTERNAL_DUMP("byte_width_ = %u", byte_width_) uint32_t o = ReadUInt32(data - byte_width_, byte_width_); U_RETURN(o); } void setIndirect(uint8_t* ptr, UFlatBuffer& fb, uint8_t type) const { U_TRACE(0, "UFlatBuffer::setIndirect(%p,%p,%u)", ptr, &fb, type) U_INTERNAL_DUMP("type_ = %u byte_width_ = %u parent_width_ = %u", type_, byte_width_, parent_width_) fb.byte_width_ = fb.parent_width_ = byte_width_; fb.type_ = type; fb.buffer_idx = fb.getSize((fb.data_ = Indirect(ptr, parent_width_))); U_INTERNAL_DUMP("fb.data(%u) = %#.*S", fb.buffer_idx, fb.buffer_idx, fb.data_) } void AsVector(uint8_t* ptr, UFlatBuffer& fb) const { U_TRACE(0, "UFlatBuffer::AsVector(%p,%p)", ptr, &fb) U_INTERNAL_ASSERT(IsVector()) setIndirect(ptr, fb, UFlatBufferValue::TYPE_VECTOR); } void AsTypedVector(uint8_t* ptr, UFlatBuffer& fb) const { U_TRACE(0, "UFlatBuffer::AsTypedVector(%p,%p)", ptr, &fb) U_INTERNAL_ASSERT(IsTypedVector()) setIndirect(ptr, fb, ToTypedVectorElementType()); } void AsFixedTypedVector(uint8_t* ptr, UFlatBuffer& fb) const { U_TRACE(0, "UFlatBuffer::AsFixedTypedVector(%p,%p)", ptr, &fb) U_INTERNAL_ASSERT(IsFixedTypedVector()) fb.data_ = Indirect(ptr, parent_width_); fb.byte_width_ = fb.parent_width_ = byte_width_; fb.type_ = ToFixedTypedVectorElementType(fb); U_INTERNAL_DUMP("fb.data(%u) = %#.*S", fb.buffer_idx, fb.buffer_idx, fb.data_) } void AsMap(uint8_t* ptr, UFlatBuffer& fb) const { U_TRACE(0, "UFlatBuffer::AsMap(%p,%p)", ptr, &fb) U_INTERNAL_ASSERT(IsMap()) setIndirect(ptr, fb, UFlatBufferValue::TYPE_MAP); } void AsMapGetKeys(uint8_t* ptr, UFlatBuffer& fb) const { U_TRACE(0, "UFlatBuffer::AsMapGetKeys(%p,%p)", ptr, &fb) U_DUMP("type_ = (%u,%S) byte_width_ = %u parent_width_ = %u", type_, getTypeDescription(type_), byte_width_, parent_width_) U_INTERNAL_ASSERT(IsMap()) uint8_t* keys_offset = ptr - (byte_width_ * 3); fb.byte_width_ = fb.parent_width_ = ReadUInt32(keys_offset + byte_width_, byte_width_); fb.type_ = UFlatBufferValue::TYPE_STRING; fb.buffer_idx = fb.getSize((fb.data_ = Indirect(keys_offset, byte_width_))); U_INTERNAL_DUMP("fb.data(%u) = %#.*S", fb.buffer_idx, fb.buffer_idx, fb.data_) } void AsMapGetValues(uint8_t* ptr, UFlatBuffer& fb) const { U_TRACE(0, "UFlatBuffer::AsMapGetValues(%p,%p)", ptr, &fb) U_DUMP("type_ = (%u,%S) byte_width_ = %u parent_width_ = %u", type_, getTypeDescription(type_), byte_width_, parent_width_) U_INTERNAL_ASSERT(IsMap()) fb.byte_width_ = fb.parent_width_ = byte_width_; fb.type_ = UFlatBufferValue::TYPE_VECTOR; fb.buffer_idx = fb.getSize((fb.data_ = ptr)); U_INTERNAL_DUMP("fb.data(%u) = %#.*S", fb.buffer_idx, fb.buffer_idx, fb.data_) } void setTypeAndWidth(uint8_t packed_type) { U_TRACE(0, "UFlatBuffer::setTypeAndWidth(%u)", packed_type) byte_width_ = 1U << (packed_type & 3); type_ = packed_type >> 2; U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S) packed_type = %u", parent_width_, byte_width_, type_, getTypeDescription(type_), packed_type) } uint8_t* AsVectorSetIndex(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsVectorSetIndex(%u)", i) U_DUMP("type_ = (%u,%S)", type_, getTypeDescription(type_)) U_ASSERT_MINOR(i, buffer_idx) U_INTERNAL_ASSERT(IsVector() || IsMap()) uint8_t* ptr = data_; uint32_t offset = i * (parent_width_ = byte_width_); setTypeAndWidth(ptr[(buffer_idx * byte_width_) + i]); return (ptr + offset); } uint8_t* AsTypedOrFixedVectorSetIndex(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorSetIndex(%u)", i) U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) U_ASSERT_MINOR(i, buffer_idx) U_INTERNAL_ASSERT(IsTypedVector() || IsTypedVectorElementType()) uint8_t* ptr = (data_ + i * (parent_width_ = byte_width_)); byte_width_ = 1; return ptr; } uint8_t* AsMapSetIndex(const char* key, uint32_t len); void AsVectorGet(uint32_t i, UFlatBuffer& fb) const { U_TRACE(0, "UFlatBuffer::AsVectorGet(%u,%p)", i, &fb) U_ASSERT_MINOR(i, buffer_idx) U_INTERNAL_ASSERT(IsVector()) fb.data_ = data_ + (i * byte_width_); fb.parent_width_ = parent_width_; fb.setTypeAndWidth(data_[(buffer_idx * byte_width_) + i]); fb.buffer_idx = fb.byte_width_; U_INTERNAL_DUMP("fb.data(%u) = %#.*S", fb.buffer_idx, fb.buffer_idx, fb.data_) } void AsTypedOrFixedVectorGet(uint32_t i, UFlatBuffer& fb) const { U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGet(%u,%p)", i, &fb) U_ASSERT_MINOR(i, buffer_idx) U_INTERNAL_ASSERT(IsTypedVector() || IsTypedVectorElementType()) fb.buffer_idx = fb.byte_width_ = 1; fb.data_ = data_ + (i * byte_width_); fb.parent_width_ = parent_width_; U_INTERNAL_DUMP("fb.data(%u) = %#.*S", fb.buffer_idx, fb.buffer_idx, fb.data_) } bool AsBool(const uint8_t* ptr) const { U_TRACE(0, "UFlatBuffer::AsBool(%p)", ptr) U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) U_INTERNAL_ASSERT(IsBool()) if (ReadUInt64(ptr, parent_width_)) U_RETURN(true); U_RETURN(false); } uint64_t AsUInt64(const uint8_t* ptr) const { U_TRACE(0, "UFlatBuffer::AsUInt64(%p)", ptr) U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) U_INTERNAL_ASSERT(IsIntOrUint()) return ReadUInt64(ptr, parent_width_); } uint64_t AsIndirectUInt64(const uint8_t* ptr) const { U_TRACE(0, "UFlatBuffer::AsIndirectUInt64(%p)", ptr) U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) U_INTERNAL_ASSERT(IsIntOrUint()) return ReadUInt64(Indirect(ptr, parent_width_), byte_width_); } int64_t AsInt64(const uint8_t* ptr) const { U_TRACE(0, "UFlatBuffer::AsInt64(%p)", ptr) U_INTERNAL_ASSERT(IsInt()) return ReadInt64(ptr, parent_width_); } int64_t AsIndirectInt64(const uint8_t* ptr) const { U_TRACE(0, "UFlatBuffer::AsIndirectInt64(%p)", ptr) U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) U_INTERNAL_ASSERT(IsInt()) return ReadInt64(Indirect(ptr, parent_width_), byte_width_); } float AsFloat(const uint8_t* ptr) const { U_TRACE(0, "UFlatBuffer::AsFloat(%p)", ptr) U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) U_INTERNAL_ASSERT(IsFloat()) U_INTERNAL_ASSERT_EQUALS(parent_width_, 4) return *(float*)ptr; } double AsIndirectFloat(const uint8_t* ptr) const { U_TRACE(0, "UFlatBuffer::AsIndirectFloat(%p)", ptr) U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) U_INTERNAL_ASSERT(IsFloat()) U_INTERNAL_ASSERT_EQUALS(byte_width_, 4) return *(float*)Indirect(ptr, parent_width_); } double AsDouble(const uint8_t* ptr) const { U_TRACE(0, "UFlatBuffer::AsDouble(%p)", ptr) U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) U_INTERNAL_ASSERT(IsFloat()) return ReadDouble(ptr, parent_width_); } double AsIndirectDouble(const uint8_t* ptr) const { U_TRACE(0, "UFlatBuffer::AsIndirectDouble(%p)", ptr) U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) U_INTERNAL_ASSERT(IsFloat()) return ReadDouble(Indirect(ptr, parent_width_), byte_width_); } bool GetBool(const uint8_t* ptr) { U_TRACE(0, "UFlatBuffer::GetBool(%p)", ptr) bool value = AsBool(ptr); byte_width_ = parent_width_; U_RETURN(value); } uint64_t GetUInt64(const uint8_t* ptr) { U_TRACE(0, "UFlatBuffer::GetUInt64(%p)", ptr) uint64_t value = AsUInt64(ptr); byte_width_ = parent_width_; U_RETURN(value); } uint64_t GetIndirectUInt64(const uint8_t* ptr) { U_TRACE(0, "UFlatBuffer::GetIndirectUInt64(%p)", ptr) uint64_t value = AsIndirectUInt64(ptr); byte_width_ = parent_width_; U_RETURN(value); } float GetFloat(const uint8_t* ptr) { U_TRACE(0, "UFlatBuffer::GetFloat(%p)", ptr) float value = AsFloat(ptr); byte_width_ = parent_width_; U_RETURN(value); } float GetIndirectFloat(const uint8_t* ptr) { U_TRACE(0, "UFlatBuffer::GetIndirectFloat(%p)", ptr) float value = AsIndirectFloat(ptr); byte_width_ = parent_width_; U_RETURN(value); } double GetDouble(const uint8_t* ptr) { U_TRACE(0, "UFlatBuffer::GetDouble(%p)", ptr) double value = AsDouble(ptr); byte_width_ = parent_width_; U_RETURN(value); } double GetIndirectDouble(const uint8_t* ptr) { U_TRACE(0, "UFlatBuffer::GetIndirectDouble(%p)", ptr) double value = AsIndirectDouble(ptr); byte_width_ = parent_width_; U_RETURN(value); } UString AsString(const uint8_t* ptr) const { U_TRACE(0, "UFlatBuffer::AsString(%p)", ptr) U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) U_INTERNAL_ASSERT(IsString()) uint8_t* str = Indirect(ptr, parent_width_); UString x((const char*)str, getSize(str)); U_RETURN_STRING(x); } UString GetString(const uint8_t* ptr) { U_TRACE(0, "UFlatBuffer::GetString(%p)", ptr) UString x = AsString(ptr); byte_width_ = parent_width_; U_RETURN_STRING(x); } template T As(const uint8_t* ptr) { U_TRACE(0, "UFlatBuffer::As(%p)", ptr) U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) return ReadUInt64(ptr, parent_width_); } template T AsIndirect(const uint8_t* ptr) { U_TRACE(0, "UFlatBuffer::AsIndirect(%p)", ptr) U_DUMP("parent_width_ = %u byte_width_ = %u type_ = (%u,%S)", parent_width_, byte_width_, type_, getTypeDescription(type_)) return ReadUInt64(Indirect(ptr, parent_width_), byte_width_); } template T Get(const uint8_t* ptr) { U_TRACE(0, "UFlatBuffer::Get(%p)", ptr) T value = As(ptr); byte_width_ = parent_width_; return value; } template T GetIndirect(const uint8_t* ptr) { U_TRACE(0, "UFlatBuffer::GetIndirect(%p)", ptr) T value = AsIndirect(ptr); byte_width_ = parent_width_; return value; } private: U_DISALLOW_COPY_AND_ASSIGN(UFlatBuffer) friend class UValue; template friend class UFlatBufferTypeHandler; }; // Template specialization template<> inline bool UFlatBuffer::As( const uint8_t* ptr) { return AsBool(ptr); } template<> inline uint64_t UFlatBuffer::As(const uint8_t* ptr) { return AsUInt64(ptr); } template<> inline float UFlatBuffer::As( const uint8_t* ptr) { return AsFloat(ptr); } template<> inline double UFlatBuffer::As( const uint8_t* ptr) { return AsDouble(ptr); } template<> inline UString UFlatBuffer::As( const uint8_t* ptr) { return AsString(ptr); } template<> inline uint64_t UFlatBuffer::AsIndirect(const uint8_t* ptr) { return AsIndirectUInt64(ptr); } template<> inline float UFlatBuffer::AsIndirect( const uint8_t* ptr) { return AsIndirectFloat(ptr); } template<> inline double UFlatBuffer::AsIndirect( const uint8_t* ptr) { return AsIndirectDouble(ptr); } template<> inline bool UFlatBuffer::Get( const uint8_t* ptr) { return GetBool(ptr); } template<> inline uint64_t UFlatBuffer::Get(const uint8_t* ptr) { return GetUInt64(ptr); } template<> inline float UFlatBuffer::Get( const uint8_t* ptr) { return GetFloat(ptr); } template<> inline double UFlatBuffer::Get( const uint8_t* ptr) { return GetDouble(ptr); } template<> inline UString UFlatBuffer::Get( const uint8_t* ptr) { return GetString(ptr); } template<> inline uint64_t UFlatBuffer::GetIndirect(const uint8_t* ptr) { return GetIndirectUInt64(ptr); } template<> inline float UFlatBuffer::GetIndirect( const uint8_t* ptr) { return GetIndirectFloat(ptr); } template<> inline double UFlatBuffer::GetIndirect( const uint8_t* ptr) { return GetIndirectDouble(ptr); } // VECTOR template<> inline bool UFlatBuffer::AsVectorGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsVectorGet(%u)", i) bool value = Get(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_VECTOR; U_RETURN(value); } template<> inline bool UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGet(%u)", i) return Get(AsTypedOrFixedVectorSetIndex(i)); } template<> inline uint64_t UFlatBuffer::AsVectorGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsVectorGet(%u)", i) uint64_t value = Get(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_VECTOR; U_RETURN(value); } template<> inline uint64_t UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGet(%u)", i) return Get(AsTypedOrFixedVectorSetIndex(i)); } template<> inline int8_t UFlatBuffer::AsVectorGet( uint32_t i) { return -(int8_t) AsVectorGet(i); } template<> inline int16_t UFlatBuffer::AsVectorGet(uint32_t i) { return -(int16_t)AsVectorGet(i); } template<> inline int32_t UFlatBuffer::AsVectorGet(uint32_t i) { return -(int32_t)AsVectorGet(i); } template<> inline int64_t UFlatBuffer::AsVectorGet(uint32_t i) { return -(int64_t)AsVectorGet(i); } template<> inline uint64_t UFlatBuffer::AsVectorGetIndirect(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsVectorGetIndirect(%u)", i) uint64_t value = GetIndirect(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_VECTOR; U_RETURN(value); } template<> inline uint64_t UFlatBuffer::AsTypedOrFixedVectorGetIndirect(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGetIndirect(%u)", i) return GetIndirectUInt64(AsTypedOrFixedVectorSetIndex(i)); } template<> inline int8_t UFlatBuffer::AsVectorGetIndirect( uint32_t i) { return -(int8_t) AsVectorGetIndirect(i); } template<> inline int16_t UFlatBuffer::AsVectorGetIndirect(uint32_t i) { return -(int16_t)AsVectorGetIndirect(i); } template<> inline int32_t UFlatBuffer::AsVectorGetIndirect(uint32_t i) { return -(int32_t)AsVectorGetIndirect(i); } template<> inline int64_t UFlatBuffer::AsVectorGetIndirect(uint32_t i) { return -(int64_t)AsVectorGetIndirect(i); } template<> inline int8_t UFlatBuffer::AsTypedOrFixedVectorGet( uint32_t i) { return -(int8_t) AsTypedOrFixedVectorGet(i); } template<> inline int16_t UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) { return -(int16_t)AsTypedOrFixedVectorGet(i); } template<> inline int32_t UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) { return -(int32_t)AsTypedOrFixedVectorGet(i); } template<> inline int64_t UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) { return -(int64_t)AsTypedOrFixedVectorGet(i); } template<> inline int8_t UFlatBuffer::AsTypedOrFixedVectorGetIndirect( uint32_t i) { return -(int8_t) AsTypedOrFixedVectorGetIndirect(i); } template<> inline int16_t UFlatBuffer::AsTypedOrFixedVectorGetIndirect(uint32_t i) { return -(int16_t)AsTypedOrFixedVectorGetIndirect(i); } template<> inline int32_t UFlatBuffer::AsTypedOrFixedVectorGetIndirect(uint32_t i) { return -(int32_t)AsTypedOrFixedVectorGetIndirect(i); } template<> inline int64_t UFlatBuffer::AsTypedOrFixedVectorGetIndirect(uint32_t i) { return -(int64_t)AsTypedOrFixedVectorGetIndirect(i); } template<> inline double UFlatBuffer::AsVectorGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsVectorGet(%u)", i) double value = Get(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_VECTOR; U_RETURN(value); } template<> inline double UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGet(%u)", i) return Get(AsTypedOrFixedVectorSetIndex(i)); } template<> inline double UFlatBuffer::AsVectorGetIndirect(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsVectorGetIndirect(%u)", i) double value = GetIndirect(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_VECTOR; U_RETURN(value); } template<> inline double UFlatBuffer::AsTypedOrFixedVectorGetIndirect(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGetIndirect(%u)", i) return GetIndirect(AsTypedOrFixedVectorSetIndex(i)); } template<> inline UString UFlatBuffer::AsVectorGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsVectorGet(%u)", i) UString value = Get(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_VECTOR; U_RETURN_STRING(value); } template<> inline UString UFlatBuffer::AsTypedOrFixedVectorGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsTypedOrFixedVectorGet(%u)", i) return Get(AsTypedOrFixedVectorSetIndex(i)); } // MAP template<> inline bool UFlatBuffer::AsMapGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsMapGet(%u)", i) U_INTERNAL_ASSERT(IsMap()) bool value = Get(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_MAP; U_RETURN(value); } template<> inline bool UFlatBuffer::AsMapGet(const char* key, uint32_t len) { U_TRACE(0, "UFlatBuffer::AsMapGet(%.*S,%u)", len, key, len) U_INTERNAL_ASSERT(IsMap()) bool value = Get(AsMapSetIndex(key, len)); type_ = UFlatBufferValue::TYPE_MAP; U_RETURN(value); } template<> inline uint64_t UFlatBuffer::AsMapGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsMapGet(%u)", i) U_INTERNAL_ASSERT(IsMap()) uint64_t value = Get(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_MAP; U_RETURN(value); } template<> inline uint64_t UFlatBuffer::AsMapGet(const char* key, uint32_t len) { U_TRACE(0, "UFlatBuffer::AsMapGet(%.*S,%u)", len, key, len) U_INTERNAL_ASSERT(IsMap()) uint64_t value = Get(AsMapSetIndex(key, len)); type_ = UFlatBufferValue::TYPE_MAP; U_RETURN(value); } template<> inline int8_t UFlatBuffer::AsMapGet( uint32_t i) { return -(int8_t) AsMapGet(i); } template<> inline int16_t UFlatBuffer::AsMapGet(uint32_t i) { return -(int16_t)AsMapGet(i); } template<> inline int32_t UFlatBuffer::AsMapGet(uint32_t i) { return -(int32_t)AsMapGet(i); } template<> inline int64_t UFlatBuffer::AsMapGet(uint32_t i) { return -(int64_t)AsMapGet(i); } template<> inline int8_t UFlatBuffer::AsMapGet( const char* key, uint32_t len) { return -(int8_t) AsMapGet(key, len); } template<> inline int16_t UFlatBuffer::AsMapGet(const char* key, uint32_t len) { return -(int16_t)AsMapGet(key, len); } template<> inline int32_t UFlatBuffer::AsMapGet(const char* key, uint32_t len) { return -(int32_t)AsMapGet(key, len); } template<> inline int64_t UFlatBuffer::AsMapGet(const char* key, uint32_t len) { return -(int64_t)AsMapGet(key, len); } template<> inline uint64_t UFlatBuffer::AsMapGetIndirect(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsMapGetIndirect(%u)", i) U_INTERNAL_ASSERT(IsMap()) uint64_t value = GetIndirect(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_MAP; U_RETURN(value); } template<> inline uint64_t UFlatBuffer::AsMapGetIndirect(const char* key, uint32_t len) { U_TRACE(0, "UFlatBuffer::AsMapGetIndirect(%.*S,%u)", len, key, len) U_INTERNAL_ASSERT(IsMap()) uint64_t value = GetIndirect(AsMapSetIndex(key, len)); type_ = UFlatBufferValue::TYPE_MAP; U_RETURN(value); } template<> inline int8_t UFlatBuffer::AsMapGetIndirect( uint32_t i) { return -(int8_t) AsMapGetIndirect(i); } template<> inline int16_t UFlatBuffer::AsMapGetIndirect(uint32_t i) { return -(int16_t)AsMapGetIndirect(i); } template<> inline int32_t UFlatBuffer::AsMapGetIndirect(uint32_t i) { return -(int32_t)AsMapGetIndirect(i); } template<> inline int64_t UFlatBuffer::AsMapGetIndirect(uint32_t i) { return -(int64_t)AsMapGetIndirect(i); } template<> inline int8_t UFlatBuffer::AsMapGetIndirect( const char* key, uint32_t len) { return -(int8_t) AsMapGetIndirect(key, len); } template<> inline int16_t UFlatBuffer::AsMapGetIndirect(const char* key, uint32_t len) { return -(int16_t)AsMapGetIndirect(key, len); } template<> inline int32_t UFlatBuffer::AsMapGetIndirect(const char* key, uint32_t len) { return -(int32_t)AsMapGetIndirect(key, len); } template<> inline int64_t UFlatBuffer::AsMapGetIndirect(const char* key, uint32_t len) { return -(int64_t)AsMapGetIndirect(key, len); } template<> inline double UFlatBuffer::AsMapGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsMapGet(%u)", i) U_INTERNAL_ASSERT(IsMap()) double value = Get(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_MAP; U_RETURN(value); } template<> inline double UFlatBuffer::AsMapGet(const char* key, uint32_t len) { U_TRACE(0, "UFlatBuffer::AsMapGet(%.*S,%u)", len, key, len) U_INTERNAL_ASSERT(IsMap()) double value = Get(AsMapSetIndex(key, len)); type_ = UFlatBufferValue::TYPE_MAP; U_RETURN(value); } template<> inline double UFlatBuffer::AsMapGetIndirect(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsMapGetIndirect(%u)", i) U_INTERNAL_ASSERT(IsMap()) double value = GetIndirect(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_MAP; U_RETURN(value); } template<> inline double UFlatBuffer::AsMapGetIndirect(const char* key, uint32_t len) { U_TRACE(0, "UFlatBuffer::AsMapGetIndirect(%.*S,%u)", len, key, len) U_INTERNAL_ASSERT(IsMap()) double value = GetIndirect(AsMapSetIndex(key, len)); type_ = UFlatBufferValue::TYPE_MAP; U_RETURN(value); } template<> inline UString UFlatBuffer::AsMapGet(uint32_t i) { U_TRACE(0, "UFlatBuffer::AsMapGet(%u)", i) U_INTERNAL_ASSERT(IsMap()) UString value = Get(AsVectorSetIndex(i)); type_ = UFlatBufferValue::TYPE_MAP; U_RETURN_STRING(value); } template<> inline UString UFlatBuffer::AsMapGet(const char* key, uint32_t len) { U_TRACE(0, "UFlatBuffer::AsMapGet(%.*S,%u)", len, key, len) U_INTERNAL_ASSERT(IsMap()) UString value = Get(AsMapSetIndex(key, len)); type_ = UFlatBufferValue::TYPE_MAP; U_RETURN_STRING(value); } // manage object <=> FlatBuffer representation class U_EXPORT UFlatBufferTypeHandler_Base { public: // Check for memory error U_MEMORY_TEST // Allocator e Deallocator U_MEMORY_ALLOCATOR U_MEMORY_DEALLOCATOR UFlatBufferTypeHandler_Base(const void* ptr) : pval((void*)ptr) { U_TRACE_REGISTER_OBJECT(0, UFlatBufferTypeHandler_Base, "%p", ptr) U_INTERNAL_ASSERT_POINTER(pval) } ~UFlatBufferTypeHandler_Base() { U_TRACE_UNREGISTER_OBJECT(0, UFlatBufferTypeHandler_Base) U_INTERNAL_ASSERT_POINTER(pval) } #ifdef DEBUG const char* dump(bool _reset) const; #endif protected: void* pval; private: U_DISALLOW_ASSIGN(UFlatBufferTypeHandler_Base) }; #define FLATBUFFER(name_object_member, type_object_member) UFlatBufferTypeHandler(name_object_member) /** * Provide template specializations to support your own complex types * * Take as example the following (simplified) class: * * class Person { * public: * int age; * UString lastName; * UString firstName; * }; * * add this methods to the (simplified) class: * * void Person::toFlatBuffer(UFlatBuffer& fb) * { * fb.toFlatBuffer(FLATBUFFER(age, int)); * fb.toFlatBuffer(FLATBUFFER( lastName, UString)); * fb.toFlatBuffer(FLATBUFFER(firstName, UString)); * } * * void Person::fromFlatBuffer(UFlatBuffer& fb) * { * fb.fromFlatBuffer(0, FLATBUFFER(age, int)); * fb.fromFlatBuffer(1, FLATBUFFER( lastName, UString)); * fb.fromFlatBuffer(2, FLATBUFFER(firstName, UString)); * } */ template class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(T* val) : UFlatBufferTypeHandler_Base( val) {} explicit UFlatBufferTypeHandler(T& val) : UFlatBufferTypeHandler_Base(&val) {} // SERVICES void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) uint32_t start = fb.StartVector(); ((T*)pval)->toFlatBuffer(fb); fb.EndVector(start, false); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) UFlatBuffer vec; fb.AsVector(vec); ((T*)pval)->fromFlatBuffer(vec); } private: U_DISALLOW_ASSIGN(UFlatBufferTypeHandler) }; template void UFlatBuffer::fromObject(T& obj) { U_TRACE(0, "UFlatBuffer::fromObject(%p)", &obj) StartBuild(); UFlatBufferTypeHandler(obj).toFlatBuffer(*this); setRoot(buffer_str, EndBuild()); } template void UFlatBuffer::toObject(T& obj) { U_TRACE(0, "UFlatBuffer::toObject(%p)", &obj) UFlatBufferTypeHandler(obj).fromFlatBuffer(*this); } // TEMPLATE SPECIALIZATIONS template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(null&) : UFlatBufferTypeHandler_Base(U_NULLPTR) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.Null(); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) U_VAR_UNUSED(fb) } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(bool& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.Bool(*(bool*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(bool*)pval = fb.AsBool(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(char& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.UInt(*(char*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(char*)pval = fb.AsUInt64(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(unsigned char& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.UInt(*(unsigned char*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(unsigned char*)pval = fb.AsUInt64(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(short& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.UInt(*(short*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(short*)pval = fb.AsUInt64(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(unsigned short& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.UInt(*(unsigned short*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(unsigned short*)pval = fb.AsUInt64(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(int& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.setNumber(*(int*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(int*)pval = fb.AsNumber(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(unsigned int& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.UInt(*(unsigned int*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(unsigned int*)pval = fb.AsUInt64(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(long& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.setNumber(*(long*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(long*)pval = fb.AsNumber(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(unsigned long& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.UInt(*(unsigned long*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(unsigned long*)pval = fb.AsUInt64(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(long long& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.setNumber(*(int64_t*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(long long*)pval = fb.AsNumber(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(unsigned long long& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.UInt(*(uint64_t*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(unsigned long long*)pval = fb.AsNumber(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(float& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.Double(*(float*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(float*)pval = fb.AsDouble(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(double& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.Double(*(double*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(double*)pval = fb.AsDouble(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(long double& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.Double(*(long double*)pval); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) *(long double*)pval = fb.AsDouble(); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(UStringRep& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.String(U_STRING_TO_PARAM(*(UStringRep*)pval)); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) U_ASSERT(fb.IsString()) U_ERROR("UFlatBufferTypeHandler::fromFlatBuffer(): sorry, we cannot use UStringRep type from FLATBUFFER handler..."); } }; template <> class U_EXPORT UFlatBufferTypeHandler : public UFlatBufferTypeHandler_Base { public: explicit UFlatBufferTypeHandler(UString& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) fb.String(U_STRING_TO_PARAM(*(UString*)pval)); } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) U_ASSERT(fb.IsString()) *(UString*)pval = fb.AsString(); } }; // TEMPLATE SPECIALIZATIONS FOR CONTAINERS template class U_EXPORT UFlatBufferTypeHandler > : public UFlatBufferTypeHandler_Base { public: typedef UVector uvector; explicit UFlatBufferTypeHandler(uvector& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) uvector* pvec = (uvector*)pval; if (pvec->_length == 0) fb.AddVectorEmpty(); else { const void** ptr = pvec->vec; const void** end = pvec->vec + pvec->_length; uint32_t start = fb.StartVector(); do { UFlatBufferTypeHandler(*(T*)(*ptr)).toFlatBuffer(fb); } while (++ptr < end); fb.EndVector(start, false); } } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) U_ASSERT(((uvector*)pval)->empty()) bool typed, fixed; UFlatBuffer vec, fbb; fixed = ((typed = fb.IsTypedVector()) ? false : fb.IsFixedTypedVector()); if (typed) fb.AsTypedVector(vec); else if (fixed) fb.AsFixedTypedVector(vec), typed = true; else fb.AsVector(vec); for (uint32_t i = 0, n = vec.GetSize(); i < n; ++i) { T* pitem; U_NEW(T, pitem, T); if (typed == false) vec.AsVectorGet(i, fbb); else vec.AsTypedOrFixedVectorGet(i, fbb); UFlatBufferTypeHandler(*pitem).fromFlatBuffer(fbb); ((UVector*)pval)->push_back(pitem); } } }; template <> class U_EXPORT UFlatBufferTypeHandler > : public UFlatBufferTypeHandler > { public: typedef UVector uvectorbase; explicit UFlatBufferTypeHandler(UVector& val) : UFlatBufferTypeHandler(*((uvector*)&val)) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler>::toFlatBuffer(%p)", &fb) uvectorbase* pvec = (uvectorbase*)pval; if (pvec->_length == 0) fb.AddVectorEmpty(); else { const void** ptr = pvec->vec; const void** end = pvec->vec + pvec->_length; uint32_t start = fb.StartVector(); do { fb.String(U_STRING_TO_PARAM(*(const UStringRep*)(*ptr))); } while (++ptr < end); fb.EndVector(start); } } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler>::fromFlatBuffer(%p)", &fb) U_ASSERT(((UVector*)pval)->empty()) UFlatBuffer vec; fb.AsTypedVector(vec); for (uint32_t i = 0, n = vec.GetSize(); i < n; ++i) { ((UVector*)pval)->push_back(vec.AsTypedOrFixedVectorGet(i)); } } }; template class U_EXPORT UFlatBufferTypeHandler > : public UFlatBufferTypeHandler_Base { public: typedef UHashMap uhashmap; explicit UFlatBufferTypeHandler(uhashmap& map) : UFlatBufferTypeHandler_Base(&map) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) uhashmap* pmap = (uhashmap*)pval; if (pmap->first() == false) fb.AddMapEmpty(); else { uint32_t start = fb.StartMap(); do { fb.Key(U_STRING_TO_PARAM(pmap->getKey())); UFlatBufferTypeHandler(*(pmap->elem())).toFlatBuffer(fb); } while (pmap->next()); fb.EndMap(start); } } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) U_ASSERT(((uhashmap*)pval)->empty()) UFlatBuffer map, keys, values, fbb; fb.AsMap(map); map.AsMapGetKeys(keys); map.AsMapGetValues(values); for (uint32_t i = 0, n = map.GetSize(); i < n; ++i) { T* pitem; U_NEW(T, pitem, T); values.AsVectorGet(i, fbb); UFlatBufferTypeHandler(*pitem).fromFlatBuffer(fbb); # ifndef HAVE_OLD_IOSTREAM ((uhashmap*)pval)->insert(keys.AsTypedOrFixedVectorGet(i), pitem); # endif } } }; template <> class U_EXPORT UFlatBufferTypeHandler > : public UFlatBufferTypeHandler > { public: typedef UHashMap uhashmapbase; explicit UFlatBufferTypeHandler(UHashMap& val) : UFlatBufferTypeHandler(*((uhashmap*)&val)) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler>::toFlatBuffer(%p)", &fb) UHashMap* pmap = (UHashMap*)pval; if (pmap->first() == false) fb.AddMapEmpty(); else { uint32_t start = fb.StartMap(); do { fb.Key(U_STRING_TO_PARAM(pmap->getKey())); fb.String(U_STRING_TO_PARAM(*(const UStringRep*)pmap->elem())); } while (pmap->next()); fb.EndMap(start); } } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler>::fromFlatBuffer(%p)", &fb) U_ASSERT(((UHashMap*)pval)->empty()) UFlatBuffer map, keys, values, fbb; fb.AsMap(map); map.AsMapGetKeys(keys); map.AsMapGetValues(values); for (uint32_t i = 0, n = map.GetSize(); i < n; ++i) { ((UHashMap*)pval)->insert(keys.AsTypedOrFixedVectorGet(i), values.AsVectorGet(i)); } } }; #ifdef U_STDCPP_ENABLE # include template class U_EXPORT UFlatBufferTypeHandler > : public UFlatBufferTypeHandler_Base { public: typedef std::vector stdvector; explicit UFlatBufferTypeHandler(stdvector& val) : UFlatBufferTypeHandler_Base(&val) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) stdvector* pvec = (stdvector*)pval; uint32_t n = pvec->size(); if (n == 0) fb.AddVectorEmpty(); else { uint32_t start = fb.StartVector(); for (uint32_t i = 0; i < n; ++i) UFlatBufferTypeHandler(pvec->at(i)).toFlatBuffer(fb); fb.EndVector(start); } } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) U_ASSERT(((stdvector*)pval)->empty()) bool typed, fixed; UFlatBuffer vec, fbb; fixed = ((typed = fb.IsTypedVector()) ? false : fb.IsFixedTypedVector()); if (typed) fb.AsTypedVector(vec); else if (fixed) fb.AsFixedTypedVector(vec), typed = true; else fb.AsVector(vec); for (uint32_t i = 0, n = vec.GetSize(); i < n; ++i) { T item; if (typed == false) vec.AsVectorGet(i, fbb); else vec.AsTypedOrFixedVectorGet(i, fbb); UFlatBufferTypeHandler(item).fromFlatBuffer(fbb); ((stdvector*)pval)->push_back(item); } } }; # if defined(HAVE_CXX17) && !defined(__clang__) # include template class U_EXPORT UFlatBufferTypeHandler > : public UFlatBufferTypeHandler_Base { public: typedef std::unordered_map stringtobitmaskmap; explicit UFlatBufferTypeHandler(stringtobitmaskmap& map) : UFlatBufferTypeHandler_Base(&map) {} void toFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::toFlatBuffer(%p)", &fb) stringtobitmaskmap* pmap = (stringtobitmaskmap*)pval; if (pmap->empty()) fb.AddMapEmpty(); else { uint32_t start = fb.StartMap(); // this is is C++17 vvv for (const auto & [ key, value ] : *pmap) fb.toFlatBuffer(key, UFlatBufferTypeHandler(value)); fb.EndMap(start); } } void fromFlatBuffer(UFlatBuffer& fb) { U_TRACE(0, "UFlatBufferTypeHandler::fromFlatBuffer(%p)", &fb) U_ASSERT(((stringtobitmaskmap*)pval)->empty()) UFlatBuffer map, keys, values, fbb; fb.AsMap(map); map.AsMapGetKeys(keys); map.AsMapGetValues(values); for (uint32_t i = 0, n = map.GetSize(); i < n; ++i) { T* pitem; U_NEW(T, pitem, T); values.AsVectorGet(i, fbb); UFlatBufferTypeHandler(*pitem).fromFlatBuffer(fbb); ((stringtobitmaskmap*)pval)->insert_or_assign(keys.AsTypedOrFixedVectorGet(i), pitem); // insert_or_assign is C++17 } } }; # endif #endif #endif