CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-flatbuffers

Memory efficient cross-platform serialization library with zero-copy deserialization supporting 15+ programming languages.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

flexbuffers.mddocs/

FlexBuffers

Schema-less variant of FlatBuffers for dynamic data structures where the schema is not known at compile time. FlexBuffers provides JSON-like flexibility with FlatBuffers efficiency, making it ideal for configuration files, dynamic APIs, and mixed-type data storage.

Capabilities

Core Concepts

FlexBuffers stores self-describing data without requiring a predefined schema, similar to JSON but with better performance and smaller size.

namespace flexbuffers {

/**
 * Type enumeration for FlexBuffer values
 */
enum Type : uint8_t {
    FBT_NULL = 0,           // Null value
    FBT_INT = 1,            // Signed integer (variable size)
    FBT_UINT = 2,           // Unsigned integer (variable size)  
    FBT_FLOAT = 3,          // Floating point (variable precision)
    
    // Container types
    FBT_KEY = 4,            // String key in maps
    FBT_STRING = 5,         // String value
    FBT_INDIRECT_INT = 6,   // Indirect integer reference
    FBT_INDIRECT_UINT = 7,  // Indirect unsigned integer reference
    FBT_INDIRECT_FLOAT = 8, // Indirect float reference
    
    // Vector types (homogeneous)
    FBT_MAP = 9,            // Key-value map (like JSON object)
    FBT_VECTOR = 10,        // Mixed-type vector (like JSON array)
    FBT_VECTOR_INT = 11,    // Vector of integers
    FBT_VECTOR_UINT = 12,   // Vector of unsigned integers
    FBT_VECTOR_FLOAT = 13,  // Vector of floats
    FBT_VECTOR_KEY = 14,    // Vector of keys (internal use)
    FBT_VECTOR_STRING = 15, // Vector of strings
    
    // Fixed-size vector types (more compact)
    FBT_VECTOR_INT2 = 16,   // Vector of 2 integers
    FBT_VECTOR_UINT2 = 17,  // Vector of 2 unsigned integers
    FBT_VECTOR_FLOAT2 = 18, // Vector of 2 floats
    FBT_VECTOR_INT3 = 19,   // Vector of 3 integers
    FBT_VECTOR_UINT3 = 20,  // Vector of 3 unsigned integers
    FBT_VECTOR_FLOAT3 = 21, // Vector of 3 floats
    FBT_VECTOR_INT4 = 22,   // Vector of 4 integers
    FBT_VECTOR_UINT4 = 23,  // Vector of 4 unsigned integers
    FBT_VECTOR_FLOAT4 = 24, // Vector of 4 floats
    
    FBT_BLOB = 25,          // Binary blob
    FBT_BOOL = 26,          // Boolean value
    FBT_VECTOR_BOOL = 36    // Vector of booleans
};

/**
 * Bit width enumeration for variable-size encoding
 */
enum BitWidth : uint8_t {
    BIT_WIDTH_8 = 0,   // 8-bit values
    BIT_WIDTH_16 = 1,  // 16-bit values  
    BIT_WIDTH_32 = 2,  // 32-bit values
    BIT_WIDTH_64 = 3   // 64-bit values
};

/**
 * Utility functions for type checking
 */
inline bool IsInline(Type t) { return t <= FBT_FLOAT || t == FBT_BOOL; }
inline bool IsTypedVector(Type t) { return (t >= FBT_VECTOR_INT && t <= FBT_VECTOR_STRING) || t == FBT_VECTOR_BOOL; }
inline bool IsFixedTypedVector(Type t) { return t >= FBT_VECTOR_INT2 && t <= FBT_VECTOR_FLOAT4; }
inline bool IsAVector(Type t) { return t >= FBT_VECTOR && t <= FBT_VECTOR_BOOL; }

} // namespace flexbuffers

Builder Class

Builder for constructing FlexBuffer data with a fluent API supporting dynamic typing.

namespace flexbuffers {

class Builder {
public:
    /**
     * Create FlexBuffer builder
     * @param initial_size Initial buffer size (default: 256)
     * @param dedup_strings Whether to deduplicate strings (default: true)
     * @param dedup_keys Whether to deduplicate keys (default: true)
     * @param dedup_key_vectors Whether to deduplicate key vectors (default: true)
     */
    explicit Builder(
        size_t initial_size = 256,
        bool dedup_strings = true,
        bool dedup_keys = true, 
        bool dedup_key_vectors = true
    );

    /// Scalar value methods
    
    /**
     * Add null value
     */
    void Null();
    
    /**
     * Add signed integer
     * @param i Integer value
     */
    void Int(int64_t i);
    
    /**
     * Add unsigned integer
     * @param u Unsigned integer value
     */
    void UInt(uint64_t u);
    
    /**
     * Add floating point value
     * @param f Float value
     */
    void Float(double f);
    
    /**
     * Add boolean value
     * @param b Boolean value
     */
    void Bool(bool b);
    
    /**
     * Add string value
     * @param str String value
     */
    void String(const char *str);
    void String(const std::string &str);
    void String(const char *str, size_t len);
    
    /**
     * Add binary blob
     * @param data Pointer to binary data
     * @param len Length of data
     */
    void Blob(const void *data, size_t len);
    void Blob(const std::vector<uint8_t> &v);

    /// Container methods
    
    /**
     * Start building a vector (JSON array equivalent)
     */
    size_t StartVector();
    
    /**
     * Start building a vector with known size
     * @param len Expected number of elements
     */
    size_t StartVector(size_t len);
    
    /**
     * End vector construction
     * @param start Return value from StartVector
     * @param typed Whether to create typed vector if possible
     * @param fixed Whether to create fixed-size vector if possible
     */
    void EndVector(size_t start, bool typed = true, bool fixed = true);
    
    /**
     * Start building a map (JSON object equivalent)
     */
    size_t StartMap();
    
    /**
     * Start building a map with known size
     * @param len Expected number of key-value pairs
     */
    size_t StartMap(size_t len);
    
    /**
     * End map construction
     * @param start Return value from StartMap
     */
    void EndMap(size_t start);
    
    /**
     * Add key for next value in map
     * @param key Key string
     */
    void Key(const char *key);
    void Key(const std::string &key);

    /// Typed vector methods (more efficient)
    
    /**
     * Create vector of integers
     * @param v Vector of integers
     */
    void Vector(const std::vector<int64_t> &v);
    
    /**
     * Create vector of unsigned integers
     * @param v Vector of unsigned integers
     */
    void Vector(const std::vector<uint64_t> &v);
    
    /**
     * Create vector of floats
     * @param v Vector of floats
     */
    void Vector(const std::vector<double> &v);
    
    /**
     * Create vector of strings
     * @param v Vector of strings
     */
    void Vector(const std::vector<std::string> &v);

    /// Fixed-size vector methods (most efficient)
    
    /**
     * Create fixed-size vector from array
     * @param v Array of values
     * @param len Number of elements (2, 3, or 4)
     */
    void FixedTypedVector(const int64_t *v, size_t len);
    void FixedTypedVector(const uint64_t *v, size_t len);
    void FixedTypedVector(const double *v, size_t len);

    /// Buffer management
    
    /**
     * Finish building and get buffer
     * @return Vector containing FlexBuffer data
     */
    std::vector<uint8_t> GetBuffer();
    
    /**
     * Clear builder for reuse
     */
    void Clear();
    
    /**
     * Get current buffer size
     * @return Size in bytes
     */
    size_t GetSize() const;
};

} // namespace flexbuffers

Builder Usage Example:

#include "flatbuffers/flexbuffers.h"

// Create JSON-like data structure
void CreateFlexBuffer() {
    flexbuffers::Builder fbb;
    
    // Create nested structure equivalent to:
    // {
    //   "name": "John",
    //   "age": 30,
    //   "scores": [95, 87, 92],
    //   "active": true,
    //   "address": {
    //     "street": "123 Main St",
    //     "city": "Anytown"
    //   }
    // }
    
    fbb.Map([&]() {
        fbb.Key("name");
        fbb.String("John");
        
        fbb.Key("age");
        fbb.Int(30);
        
        fbb.Key("scores");
        fbb.Vector([&]() {
            fbb.Int(95);
            fbb.Int(87);
            fbb.Int(92);
        });
        
        fbb.Key("active");
        fbb.Bool(true);
        
        fbb.Key("address");
        fbb.Map([&]() {
            fbb.Key("street");
            fbb.String("123 Main St");
            
            fbb.Key("city");
            fbb.String("Anytown");
        });
    });
    
    // Get buffer
    auto buffer = fbb.GetBuffer();
    
    // Buffer now contains the FlexBuffer data
    std::cout << "FlexBuffer size: " << buffer.size() << " bytes" << std::endl;
}

Reference Class

Reference class for reading FlexBuffer data with type-safe access methods.

namespace flexbuffers {

class Reference {
public:
    /**
     * Create reference from buffer
     * @param buf Buffer containing FlexBuffer data
     * @param offset Offset to reference in buffer
     */
    Reference(const uint8_t *buf, size_t offset);
    
    /**
     * Create reference from vector
     * @param buffer Vector containing FlexBuffer data
     * @param offset Offset to reference in buffer
     */
    Reference(const std::vector<uint8_t> &buffer, size_t offset = 0);

    /// Type checking
    
    /**
     * Get the type of this reference
     * @return Type enum value
     */
    Type GetType() const;
    
    /**
     * Check if reference is null
     * @return True if null
     */
    bool IsNull() const;
    
    /**
     * Check if reference is boolean
     * @return True if boolean
     */
    bool IsBool() const;
    
    /**
     * Check if reference is numeric (int, uint, float)
     * @return True if numeric
     */
    bool IsNumeric() const;
    
    /**
     * Check if reference is integer (signed or unsigned)
     * @return True if integer
     */
    bool IsIntOrUint() const;
    
    /**
     * Check if reference is float
     * @return True if float
     */
    bool IsFloat() const;
    
    /**
     * Check if reference is string
     * @return True if string
     */
    bool IsString() const;
    
    /**
     * Check if reference is vector (any type)
     * @return True if vector
     */
    bool IsVector() const;
    
    /**
     * Check if reference is typed vector
     * @return True if typed vector
     */
    bool IsTypedVector() const;
    
    /**
     * Check if reference is fixed-size vector
     * @return True if fixed-size vector
     */
    bool IsFixedTypedVector() const;
    
    /**
     * Check if reference is map
     * @return True if map
     */
    bool IsMap() const;
    
    /**
     * Check if reference is blob
     * @return True if blob
     */
    bool IsBlob() const;

    /// Value access
    
    /**
     * Get value as boolean
     * @return Boolean value (false if not boolean)
     */
    bool AsBool() const;
    
    /**
     * Get value as signed integer
     * @return Integer value (0 if not integer)
     */
    int64_t AsInt64() const;
    int32_t AsInt32() const;
    int16_t AsInt16() const;
    int8_t AsInt8() const;
    
    /**
     * Get value as unsigned integer
     * @return Unsigned integer value (0 if not integer)
     */
    uint64_t AsUInt64() const;
    uint32_t AsUInt32() const;
    uint16_t AsUInt16() const;
    uint8_t AsUInt8() const;
    
    /**
     * Get value as floating point
     * @return Float value (0.0 if not float)
     */
    double AsDouble() const;
    float AsFloat() const;
    
    /**
     * Get value as string
     * @return String value (empty if not string)
     */
    const char *AsString() const;
    std::string AsString() const;
    
    /**
     * Get value as blob
     * @return Blob data (null if not blob)
     */
    const uint8_t *AsBlob() const;

    /// Container access
    
    /**
     * Get vector/map size
     * @return Number of elements (0 if not container)
     */
    size_t size() const;
    
    /**
     * Check if container is empty
     * @return True if empty or not a container
     */
    bool empty() const;
    
    /**
     * Access vector element by index
     * @param i Element index
     * @return Reference to element
     */
    Reference operator[](size_t i) const;
    
    /**
     * Access map element by key
     * @param key Key string
     * @return Reference to element
     */
    Reference operator[](const char *key) const;
    Reference operator[](const std::string &key) const;

    /// Iteration support
    
    /**
     * Get keys for map iteration
     * @return Vector reference containing keys
     */
    Reference Keys() const;
    
    /**
     * Get values for map iteration  
     * @return Vector reference containing values
     */
    Reference Values() const;
    
    /**
     * Iterator support for C++11 range-based for loops
     */
    class iterator {
        // Implementation details
    public:
        Reference operator*() const;
        iterator& operator++();
        bool operator!=(const iterator& other) const;
    };
    
    iterator begin() const;
    iterator end() const;

    /// Conversion and output
    
    /**
     * Convert to string representation (JSON-like)
     * @return String representation
     */
    std::string ToString() const;
    
    /**
     * Convert to pretty-printed string
     * @param indent Indentation string
     * @return Formatted string
     */
    std::string ToPrettyString(const std::string &indent = "  ") const;
};

/**
 * Get root reference from FlexBuffer
 * @param buffer FlexBuffer data
 * @return Root reference
 */
Reference GetRoot(const std::vector<uint8_t> &buffer);
Reference GetRoot(const uint8_t *buffer, size_t size);

} // namespace flexbuffers

Reference Usage Example:

#include "flatbuffers/flexbuffers.h"
#include <iostream>

void ReadFlexBuffer(const std::vector<uint8_t> &buffer) {
    // Get root reference
    auto root = flexbuffers::GetRoot(buffer);
    
    // Check if root is a map
    if (root.IsMap()) {
        std::cout << "Root is a map with " << root.size() << " entries" << std::endl;
        
        // Access values by key
        auto name = root["name"];
        if (name.IsString()) {
            std::cout << "Name: " << name.AsString() << std::endl;
        }
        
        auto age = root["age"];
        if (age.IsIntOrUint()) {
            std::cout << "Age: " << age.AsInt64() << std::endl;
        }
        
        auto scores = root["scores"];
        if (scores.IsVector()) {
            std::cout << "Scores: ";
            for (size_t i = 0; i < scores.size(); i++) {
                std::cout << scores[i].AsInt64() << " ";
            }
            std::cout << std::endl;
        }
        
        auto active = root["active"];
        if (active.IsBool()) {
            std::cout << "Active: " << (active.AsBool() ? "true" : "false") << std::endl;
        }
        
        // Access nested map
        auto address = root["address"];
        if (address.IsMap()) {
            std::cout << "Address: " << address["street"].AsString() 
                     << ", " << address["city"].AsString() << std::endl;
        }
    }
    
    // Print entire structure
    std::cout << "JSON representation:" << std::endl;
    std::cout << root.ToPrettyString() << std::endl;
}

Language-Specific APIs

FlexBuffers implementations adapted for different programming languages while maintaining API consistency.

JavaScript/TypeScript:

import { flexbuffers } from 'flatbuffers';

// Builder usage
const builder = new flexbuffers.Builder();
builder.startMap();
builder.key('name');
builder.string('John');
builder.key('age');
builder.int(30);
builder.endMap();

const buffer = builder.buffer;

// Reader usage  
const root = flexbuffers.getRoot(buffer);
console.log(root.get('name').stringValue());
console.log(root.get('age').intValue());

Python:

import flatbuffers.flexbuffers as flexbuffers

# Builder usage
builder = flexbuffers.Builder()
with builder.Map():
    builder.Key("name")
    builder.String("John")
    builder.Key("age") 
    builder.Int(30)

buffer = builder.Output()

# Reader usage
root = flexbuffers.GetRoot(buffer)
print(root["name"].AsString())
print(root["age"].AsInt())

Java:

import com.google.flatbuffers.flexbuffers.*;

// Builder usage
FlexBuffersBuilder builder = new FlexBuffersBuilder();
int map = builder.startMap();
builder.key("name");
builder.string("John");
builder.key("age");
builder.int(30);
builder.endMap(map);

ByteBuffer buffer = builder.finish();

// Reader usage
Reference root = FlexBuffers.getRoot(buffer);
System.out.println(root.get("name").asString());
System.out.println(root.get("age").asLong());

Advanced Usage Patterns

Common patterns for using FlexBuffers in real-world applications.

// Configuration file handling
class ConfigManager {
private:
    flexbuffers::Reference config_;
    std::vector<uint8_t> buffer_;
    
public:
    bool LoadFromFile(const std::string &filename) {
        std::ifstream file(filename, std::ios::binary);
        if (!file) return false;
        
        buffer_.assign(std::istreambuf_iterator<char>(file), 
                      std::istreambuf_iterator<char>());
        config_ = flexbuffers::GetRoot(buffer_);
        return config_.IsMap();
    }
    
    template<typename T>
    T GetValue(const std::string &key, const T &default_value) const {
        auto ref = config_[key];
        if constexpr (std::is_same_v<T, std::string>) {
            return ref.IsString() ? ref.AsString() : default_value;
        } else if constexpr (std::is_integral_v<T>) {
            return ref.IsIntOrUint() ? static_cast<T>(ref.AsInt64()) : default_value;
        } else if constexpr (std::is_floating_point_v<T>) {
            return ref.IsFloat() ? static_cast<T>(ref.AsDouble()) : default_value;
        } else if constexpr (std::is_same_v<T, bool>) {
            return ref.IsBool() ? ref.AsBool() : default_value;
        }
        return default_value;
    }
    
    std::vector<std::string> GetStringArray(const std::string &key) const {
        std::vector<std::string> result;
        auto ref = config_[key];
        if (ref.IsVector()) {
            for (size_t i = 0; i < ref.size(); i++) {
                if (ref[i].IsString()) {
                    result.push_back(ref[i].AsString());
                }
            }
        }
        return result;
    }
};

// Dynamic API response handling
class APIResponse {
private:
    flexbuffers::Reference root_;
    
public:
    APIResponse(const std::vector<uint8_t> &data) 
        : root_(flexbuffers::GetRoot(data)) {}
    
    bool IsSuccess() const {
        auto status = root_["status"];
        return status.IsString() && status.AsString() == "success";
    }
    
    std::string GetErrorMessage() const {
        auto error = root_["error"];
        return error.IsString() ? error.AsString() : "Unknown error";
    }
    
    template<typename T>
    std::optional<T> GetData(const std::string &field) const {
        auto data = root_["data"];
        if (!data.IsMap()) return std::nullopt;
        
        auto field_ref = data[field];
        if constexpr (std::is_same_v<T, std::string>) {
            return field_ref.IsString() ? 
                std::make_optional(field_ref.AsString()) : std::nullopt;
        } else if constexpr (std::is_integral_v<T>) {
            return field_ref.IsIntOrUint() ? 
                std::make_optional(static_cast<T>(field_ref.AsInt64())) : std::nullopt;
        }
        return std::nullopt;
    }
};

// Schema evolution example
void HandleVersionedData(const std::vector<uint8_t> &buffer) {
    auto root = flexbuffers::GetRoot(buffer);
    
    // Check version for backward compatibility
    auto version = root["version"];
    int ver = version.IsIntOrUint() ? version.AsInt32() : 1;
    
    switch (ver) {
        case 1:
            // Handle v1 format
            ProcessV1Data(root);
            break;
        case 2:
            // Handle v2 format with new fields
            ProcessV2Data(root);
            break;
        default:
            // Unknown version - try to handle gracefully
            ProcessGenericData(root);
            break;
    }
}

Complete FlexBuffers Example:

#include "flatbuffers/flexbuffers.h"
#include <iostream>
#include <fstream>

int main() {
    // Create complex nested structure
    flexbuffers::Builder fbb;
    
    fbb.Map([&]() {
        fbb.Key("user_id");
        fbb.Int(12345);
        
        fbb.Key("username");
        fbb.String("johndoe");
        
        fbb.Key("profile");
        fbb.Map([&]() {
            fbb.Key("display_name");
            fbb.String("John Doe");
            
            fbb.Key("email");
            fbb.String("john@example.com");
            
            fbb.Key("preferences");
            fbb.Map([&]() {
                fbb.Key("theme");
                fbb.String("dark");
                
                fbb.Key("notifications");
                fbb.Bool(true);
                
                fbb.Key("languages");
                fbb.Vector([&]() {
                    fbb.String("en");
                    fbb.String("es");
                    fbb.String("fr");
                });
            });
        });
        
        fbb.Key("scores");
        fbb.Vector(std::vector<int64_t>{95, 87, 92, 88, 96});
        
        fbb.Key("location");
        fbb.FixedTypedVector(new double[2]{37.7749, -122.4194}, 2); // lat, lng
    });
    
    // Get buffer
    auto buffer = fbb.GetBuffer();
    
    // Save to file
    std::ofstream file("user_data.flexbuf", std::ios::binary);
    file.write(reinterpret_cast<const char*>(buffer.data()), buffer.size());
    file.close();
    
    // Read and parse
    auto root = flexbuffers::GetRoot(buffer);
    
    std::cout << "User ID: " << root["user_id"].AsInt64() << std::endl;
    std::cout << "Username: " << root["username"].AsString() << std::endl;
    std::cout << "Display Name: " << root["profile"]["display_name"].AsString() << std::endl;
    std::cout << "Theme: " << root["profile"]["preferences"]["theme"].AsString() << std::endl;
    
    auto languages = root["profile"]["preferences"]["languages"];
    std::cout << "Languages: ";
    for (size_t i = 0; i < languages.size(); i++) {
        std::cout << languages[i].AsString() << " ";
    }
    std::cout << std::endl;
    
    auto scores = root["scores"];
    std::cout << "Scores: ";
    for (size_t i = 0; i < scores.size(); i++) {
        std::cout << scores[i].AsInt64() << " ";
    }
    std::cout << std::endl;
    
    auto location = root["location"];
    std::cout << "Location: " << location[0].AsDouble() << ", " << location[1].AsDouble() << std::endl;
    
    // Pretty print entire structure
    std::cout << "\nComplete structure:" << std::endl;
    std::cout << root.ToPrettyString() << std::endl;
    
    return 0;
}

docs

cpp-core.md

flexbuffers.md

go.md

index.md

java.md

javascript.md

python.md

rust.md

schema-compiler.md

verification.md

tile.json