1FlexBuffers    {#flexbuffers}
2==========
3
4FlatBuffers was designed around schemas, because when you want maximum
5performance and data consistency, strong typing is helpful.
6
7There are however times when you want to store data that doesn't fit a
8schema, because you can't know ahead of time what all needs to be stored.
9
10For this, FlatBuffers has a dedicated format, called FlexBuffers.
11This is a binary format that can be used in conjunction
12with FlatBuffers (by storing a part of a buffer in FlexBuffers
13format), or also as its own independent serialization format.
14
15While it loses the strong typing, you retain the most unique advantage
16FlatBuffers has over other serialization formats (schema-based or not):
17FlexBuffers can also be accessed without parsing / copying / object allocation.
18This is a huge win in efficiency / memory friendly-ness, and allows unique
19use cases such as mmap-ing large amounts of free-form data.
20
21FlexBuffers' design and implementation allows for a very compact encoding,
22combining automatic pooling of strings with automatic sizing of containers to
23their smallest possible representation (8/16/32/64 bits). Many values and
24offsets can be encoded in just 8 bits. While a schema-less representation is
25usually more bulky because of the need to be self-descriptive, FlexBuffers
26generates smaller binaries for many cases than regular FlatBuffers.
27
28FlexBuffers is still slower than regular FlatBuffers though, so we recommend to
29only use it if you need it.
30
31
32# Usage
33
34This is for C++, other languages may follow.
35
36Include the header `flexbuffers.h`, which in turn depends on `flatbuffers.h`
37and `util.h`.
38
39To create a buffer:
40
41~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
42flexbuffers::Builder fbb;
43fbb.Int(13);
44fbb.Finish();
45~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
46
47You create any value, followed by `Finish`. Unlike FlatBuffers which requires
48the root value to be a table, here any value can be the root, including a lonely
49int value.
50
51You can now access the `std::vector<uint8_t>` that contains the encoded value
52as `fbb.GetBuffer()`. Write it, send it, or store it in a parent FlatBuffer. In
53this case, the buffer is just 3 bytes in size.
54
55To read this value back, you could just say:
56
57~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
58auto root = flexbuffers::GetRoot(my_buffer);
59int64_t i = root.AsInt64();
60~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
61
62FlexBuffers stores ints only as big as needed, so it doesn't differentiate
63between different sizes of ints. You can ask for the 64 bit version,
64regardless of what you put in. In fact, since you demand to read the root
65as an int, if you supply a buffer that actually contains a float, or a
66string with numbers in it, it will convert it for you on the fly as well,
67or return 0 if it can't. If instead you actually want to know what is inside
68the buffer before you access it, you can call `root.GetType()` or `root.IsInt()`
69etc.
70
71Here's a slightly more complex value you could write instead of `fbb.Int` above:
72
73~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
74fbb.Map([&]() {
75  fbb.Vector("vec", [&]() {
76    fbb.Int(-100);
77    fbb.String("Fred");
78    fbb.IndirectFloat(4.0f);
79  });
80  fbb.UInt("foo", 100);
81});
82~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
83
84This stores the equivalent of the JSON value
85`{ vec: [ -100, "Fred", 4.0 ], foo: 100 }`. The root is a dictionary that has
86just two key-value pairs, with keys `vec` and `foo`. Unlike FlatBuffers, it
87actually has to store these keys in the buffer (which it does only once if
88you store multiple such objects, by pooling key values), but also unlike
89FlatBuffers it has no restriction on the keys (fields) that you use.
90
91The map constructor uses a C++11 Lambda to group its children, but you can
92also use more conventional start/end calls if you prefer.
93
94The first value in the map is a vector. You'll notice that unlike FlatBuffers,
95you can use mixed types. There is also a `TypedVector` variant that only
96allows a single type, and uses a bit less memory.
97
98`IndirectFloat` is an interesting feature that allows you to store values
99by offset rather than inline. Though that doesn't make any visible change
100to the user, the consequence is that large values (especially doubles or
10164 bit ints) that occur more than once can be shared. Another use case is
102inside of vectors, where the largest element makes up the size of all elements
103(e.g. a single double forces all elements to 64bit), so storing a lot of small
104integers together with a double is more efficient if the double is indirect.
105
106Accessing it:
107
108~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
109auto map = flexbuffers::GetRoot(my_buffer).AsMap();
110map.size();  // 2
111auto vec = map["vec"].AsVector();
112vec.size();  // 3
113vec[0].AsInt64();  // -100;
114vec[1].AsString().c_str();  // "Fred";
115vec[1].AsInt64();  // 0 (Number parsing failed).
116vec[2].AsDouble();  // 4.0
117vec[2].AsString().IsTheEmptyString();  // true (Wrong Type).
118vec[2].AsString().c_str();  // "" (This still works though).
119vec[2].ToString().c_str();  // "4" (Or have it converted).
120map["foo"].AsUInt8();  // 100
121map["unknown"].IsNull();  // true
122~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123
124
125# Binary encoding
126
127A description of how FlexBuffers are encoded is in the
128[internals](@ref flatbuffers_internals) document.
129
130
131# Nesting inside a FlatBuffer
132
133You can mark a field as containing a FlexBuffer, e.g.
134
135    a:[ubyte] (flexbuffer);
136
137A special accessor will be generated that allows you to access the root value
138directly, e.g. `a_flexbuffer_root().AsInt64()`.
139
140
141# Efficiency tips
142
143* Vectors generally are a lot more efficient than maps, so prefer them over maps
144  when possible for small objects. Instead of a map with keys `x`, `y` and `z`,
145  use a vector. Better yet, use a typed vector. Or even better, use a fixed
146  size typed vector.
147* Maps are backwards compatible with vectors, and can be iterated as such.
148  You can iterate either just the values (`map.Values()`), or in parallel with
149  the keys vector (`map.Keys()`). If you intend
150  to access most or all elements, this is faster than looking up each element
151  by key, since that involves a binary search of the key vector.
152* When possible, don't mix values that require a big bit width (such as double)
153  in a large vector of smaller values, since all elements will take on this
154  width. Use `IndirectDouble` when this is a possibility. Note that
155  integers automatically use the smallest width possible, i.e. if you ask
156  to serialize an int64_t whose value is actually small, you will use less
157  bits. Doubles are represented as floats whenever possible losslessly, but
158  this is only possible for few values.
159  Since nested vectors/maps are stored over offsets, they typically don't
160  affect the vector width.
161* To store large arrays of byte data, use a blob. If you'd use a typed
162  vector, the bit width of the size field may make it use more space than
163  expected, and may not be compatible with `memcpy`.
164  Similarly, large arrays of (u)int16_t may be better off stored as a
165  binary blob if their size could exceed 64k elements.
166  Construction and use are otherwise similar to strings.
167