Mutable FlatBuffers: in-place updates.

This commit contains the first step in providing mutable FlatBuffers,
non-const accessors and mutation functions for existing fields generated
from --gen-mutable.

Change-Id: Iebee3975f05c1001f8e22824725edeaa6d85fbee
Tested: on Linux.
Bug: 15777024
This commit is contained in:
Wouter van Oortmerssen
2015-04-27 16:25:06 -07:00
parent a8d6962ac2
commit 3ec5dddb00
10 changed files with 225 additions and 22 deletions

View File

@@ -289,11 +289,21 @@ public:
iterator end() { return iterator(Data(), length_); }
const_iterator end() const { return const_iterator(Data(), length_); }
// Change elements if you have a non-const pointer to this object.
void Mutate(uoffset_t i, T val) {
assert(i < size());
WriteScalar(Data() + i * sizeof(T), val);
}
// The raw data in little endian format. Use with care.
const uint8_t *Data() const {
return reinterpret_cast<const uint8_t *>(&length_ + 1);
}
uint8_t *Data() {
return reinterpret_cast<uint8_t *>(&length_ + 1);
}
template<typename K> return_type LookupByKey(K key) const {
auto span = size();
uoffset_t start = 0;
@@ -806,11 +816,15 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
bool force_defaults_; // Serialize values equal to their defaults anyway.
};
// Helper to get a typed pointer to the root object contained in the buffer.
template<typename T> const T *GetRoot(const void *buf) {
// Helpers to get a typed pointer to the root object contained in the buffer.
template<typename T> T *GetMutableRoot(void *buf) {
EndianCheck();
return reinterpret_cast<const T *>(reinterpret_cast<const uint8_t *>(buf) +
EndianScalar(*reinterpret_cast<const uoffset_t *>(buf)));
return reinterpret_cast<T *>(reinterpret_cast<uint8_t *>(buf) +
EndianScalar(*reinterpret_cast<uoffset_t *>(buf)));
}
template<typename T> const T *GetRoot(const void *buf) {
return GetMutableRoot<T>(const_cast<void *>(buf));
}
// Helper to see if the identifier in a buffer has the expected value.
@@ -978,7 +992,7 @@ class Table {
return field_offset ? ReadScalar<T>(data_ + field_offset) : defaultval;
}
template<typename P> P GetPointer(voffset_t field) const {
template<typename P> P GetPointer(voffset_t field) {
auto field_offset = GetOptionalFieldOffset(field);
auto p = data_ + field_offset;
return field_offset
@@ -986,18 +1000,21 @@ class Table {
: nullptr;
}
template<typename P> P GetStruct(voffset_t field) const {
auto field_offset = GetOptionalFieldOffset(field);
return field_offset ? reinterpret_cast<P>(data_ + field_offset) : nullptr;
template<typename P> P GetPointer(voffset_t field) const {
return const_cast<Table *>(this)->GetPointer<P>(field);
}
template<typename T> void SetField(voffset_t field, T val) {
template<typename P> P GetStruct(voffset_t field) const {
auto field_offset = GetOptionalFieldOffset(field);
// If this asserts, you're trying to set a field that's not there
// (or should we return a bool instead?).
// check if it exists first using CheckField()
assert(field_offset);
auto p = const_cast<u_int8_t *>(data_ + field_offset);
return field_offset ? reinterpret_cast<P>(p) : nullptr;
}
template<typename T> bool SetField(voffset_t field, T val) {
auto field_offset = GetOptionalFieldOffset(field);
if (!field_offset) return false;
WriteScalar(data_ + field_offset, val);
return true;
}
bool CheckField(voffset_t field) const {

View File

@@ -395,6 +395,7 @@ struct GeneratorOptions {
bool output_enum_identifiers;
bool prefixed_enums;
bool include_dependence_headers;
bool mutable_buffer;
// Possible options for the more general generator below.
enum Language { kJava, kCSharp, kGo, kMAX };
@@ -404,6 +405,7 @@ struct GeneratorOptions {
GeneratorOptions() : strict_json(false), indent_step(2),
output_enum_identifiers(true), prefixed_enums(true),
include_dependence_headers(false),
mutable_buffer(false),
lang(GeneratorOptions::kJava) {}
};