C++: Add default value handling to mutation/SetField code (#4230)

* Add default value handling to mutation/SetField code

* Shorten reflection SetField impl

* Modify impl to work with C++03

* Add more mutation tests

* Fail SetField if non-scalar

* Add IsScalar/IsInteger/IsFloat for reflection::BaseType

* Use new IsScalar/IsInteger/IsFloat in reflection SetField

* Assume scalar is either int or float
This commit is contained in:
Lawrence Chan
2017-03-20 19:36:27 -05:00
committed by Wouter van Oortmerssen
parent b8f5f84437
commit 1a27c7017a
9 changed files with 81 additions and 33 deletions

View File

@@ -1646,9 +1646,9 @@ class Table {
return field_offset ? reinterpret_cast<P>(p) : nullptr;
}
template<typename T> bool SetField(voffset_t field, T val) {
template<typename T> bool SetField(voffset_t field, T val, T def) {
auto field_offset = GetOptionalFieldOffset(field);
if (!field_offset) return false;
if (!field_offset) return val == def;
WriteScalar(data_ + field_offset, val);
return true;
}

View File

@@ -30,6 +30,15 @@ namespace flatbuffers {
// ------------------------- GETTERS -------------------------
inline bool IsScalar (reflection::BaseType t) { return t >= reflection::UType &&
t <= reflection::Double; }
inline bool IsInteger(reflection::BaseType t) { return t >= reflection::UType &&
t <= reflection::ULong; }
inline bool IsFloat (reflection::BaseType t) { return t == reflection::Float ||
t == reflection::Double; }
inline bool IsLong (reflection::BaseType t) { return t == reflection::Long ||
t == reflection::ULong; }
// Size of a basic type, don't use with structs.
inline size_t GetTypeSize(reflection::BaseType base_type) {
// This needs to correspond to the BaseType enum.
@@ -58,6 +67,18 @@ inline const Table *GetAnyRoot(const uint8_t *flatbuf) {
return GetRoot<Table>(flatbuf);
}
// Get a field's default, if you know it's an integer, and its exact type.
template<typename T> T GetFieldDefaultI(const reflection::Field &field) {
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
return static_cast<T>(field.default_integer());
}
// Get a field's default, if you know it's floating point and its exact type.
template<typename T> T GetFieldDefaultF(const reflection::Field &field) {
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
return static_cast<T>(field.default_real());
}
// Get a field, if you know it's an integer, and its exact type.
template<typename T> T GetFieldI(const Table &table,
const reflection::Field &field) {
@@ -242,8 +263,19 @@ template<typename T> T *GetAnyFieldAddressOf(const Struct &st,
// Set any scalar field, if you know its exact type.
template<typename T> bool SetField(Table *table, const reflection::Field &field,
T val) {
assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
return table->SetField(field.offset(), val);
reflection::BaseType type = field.type()->base_type();
if (!IsScalar(type)) {
return false;
}
assert(sizeof(T) == GetTypeSize(type));
T def;
if (IsInteger(type)) {
def = GetFieldDefaultI<T>(field);
} else {
assert(IsFloat(type));
def = GetFieldDefaultF<T>(field);
}
return table->SetField(field.offset(), val, def);
}
// Raw helper functions used below: set any value in memory as a 64bit int, a
@@ -258,7 +290,7 @@ void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val);
inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
int64_t val) {
auto field_ptr = table->GetAddressOf(field.offset());
if (!field_ptr) return false;
if (!field_ptr) return val == GetFieldDefaultI<int64_t>(field);
SetAnyValueI(field.type()->base_type(), field_ptr, val);
return true;
}
@@ -267,7 +299,7 @@ inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
double val) {
auto field_ptr = table->GetAddressOf(field.offset());
if (!field_ptr) return false;
if (!field_ptr) return val == GetFieldDefaultF<double>(field);
SetAnyValueF(field.type()->base_type(), field_ptr, val);
return true;
}