Commit 53a89773 authored by rmawatson's avatar rmawatson Committed by Wouter van Oortmerssen

this is allow custom allocator for obj-api structs/tables. (#4520)

added "native_custom_alloc" attribute to tables/structs, eg.

table parent_table( native_custom_alloc:"custom_alloc_name" ) {
...
}

with a custom allocator defined as

template <typename T> class custom_alloc_name : public std::allocator<T> {
public:

 typedef T*       pointer;

 template <class U>
 struct rebind {
  typedef custom_alloc_name<U> other;
 };

 pointer allocate(const std::size_t n) {
      return ....;
 }

 void deallocate(T* ptr, std::size_t n) {
    ...
 }

 custom_alloc_name() throw() {}
 template <class U> custom_alloc_name(const custom_alloc_name<U>&) throw() {}
};
};
parent ba08b0ec
......@@ -126,6 +126,45 @@ The following attributes are specific to the object-based API code generation:
"native_inline", the value specified with this attribute will be included
verbatim in the class constructor initializer list for this member.
- `native_custom_alloc`:"custom_allocator" (on a table or struct): When using the
object-based API all generated NativeTables that are allocated when unpacking
your flatbuffer will use "custom allocator". The allocator is also used by
any std::vector that appears in a table defined with `native_custom_alloc`.
This can be used to provide allocation from a pool for example, for faster
unpacking when using the object-based API.
Minimal Example:
schema:
table mytable(native_custom_alloc:"custom_allocator") {
...
}
with custom_allocator defined before flatbuffers.h is included, as:
template <typename T> struct custom_allocator : public std::allocator<T> {
typedef T *pointer;
template <class U>
struct rebind {
typedef custom_allocator<U> other;
};
pointer allocate(const std::size_t n) {
return std::allocator<T>::allocate(n);
}
void deallocate(T* ptr, std::size_t n) {
return std::allocator<T>::deallocate(ptr,n);
}
custom_allocator() throw() {}
template <class U>
custom_allocator(const custom_allocator<U>&) throw() {}
};
- `native_type`' "type" (on a struct): In some cases, a more optimal C++ data
type exists for a given struct. For example, the following schema:
......
......@@ -656,10 +656,10 @@ inline voffset_t FieldIndexToOffset(voffset_t field_id) {
return static_cast<voffset_t>((field_id + fixed_fields) * sizeof(voffset_t));
}
template <typename T> const T* data(const std::vector<T> &v) {
template <typename T, typename Alloc> const T* data(const std::vector<T, Alloc> &v) {
return v.empty() ? nullptr : &v.front();
}
template <typename T> T* data(std::vector<T> &v) {
template <typename T, typename Alloc> T* data(std::vector<T, Alloc> &v) {
return v.empty() ? nullptr : &v.front();
}
......@@ -1283,8 +1283,8 @@ class FlatBufferBuilder
/// serialize into the buffer as a `vector`.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T> Offset<Vector<const T *>> CreateVectorOfStructs(
const std::vector<T> &v) {
template<typename T, typename Alloc> Offset<Vector<const T *>> CreateVectorOfStructs(
const std::vector<T, Alloc> &v) {
return CreateVectorOfStructs(data(v), v.size());
}
......
......@@ -526,6 +526,7 @@ class Parser : public ParserState {
known_attributes_["cpp_ptr_type"] = true;
known_attributes_["cpp_str_type"] = true;
known_attributes_["native_inline"] = true;
known_attributes_["native_custom_alloc"] = true;
known_attributes_["native_type"] = true;
known_attributes_["native_default"] = true;
known_attributes_["flexbuffer"] = true;
......
......@@ -479,7 +479,11 @@ class CppGenerator : public BaseGenerator {
}
case BASE_TYPE_VECTOR: {
const auto type_name = GenTypeNative(type.VectorType(), true, field);
return "std::vector<" + type_name + ">";
if (type.struct_def && type.struct_def->attributes.Lookup("native_custom_alloc")) {
auto native_custom_alloc = type.struct_def->attributes.Lookup("native_custom_alloc");
return "std::vector<" + type_name + "," + native_custom_alloc->constant + "<" + type_name + ">>";
} else
return "std::vector<" + type_name + ">";
}
case BASE_TYPE_STRUCT: {
auto type_name = WrapInNameSpace(*type.struct_def);
......@@ -1323,6 +1327,17 @@ class CppGenerator : public BaseGenerator {
code_ += " }";
}
void GenOperatorNewDelete(const StructDef & struct_def) {
if (auto native_custom_alloc = struct_def.attributes.Lookup("native_custom_alloc")) {
code_ += " inline void *operator new (std::size_t count) {";
code_ += " return " + native_custom_alloc->constant + "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
code_ += " }";
code_ += " inline void operator delete (void *ptr) {";
code_ += " return " + native_custom_alloc->constant + "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>(ptr),1);";
code_ += " }";
}
}
void GenNativeTable(const StructDef &struct_def) {
const auto native_name = NativeName(Name(struct_def), &struct_def, parser_.opts);
code_.SetValue("STRUCT_NAME", Name(struct_def));
......@@ -1336,6 +1351,7 @@ class CppGenerator : public BaseGenerator {
it != struct_def.fields.vec.end(); ++it) {
GenMember(**it);
}
GenOperatorNewDelete(struct_def);
GenDefaultConstructor(struct_def);
code_ += "};";
code_ += "";
......@@ -2388,6 +2404,8 @@ class CppGenerator : public BaseGenerator {
code_ += " }";
}
}
code_.SetValue("NATIVE_NAME", Name(struct_def));
GenOperatorNewDelete(struct_def);
code_ += "};";
code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
......
......@@ -676,6 +676,10 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
}
}
auto field_native_custom_alloc = field->attributes.Lookup("native_custom_alloc");
if (field_native_custom_alloc)
return Error("native_custom_alloc can only be used with a table or struct definition");
field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
if (field->native_inline && !IsStruct(field->value.type))
return Error("native_inline can only be defined on structs'");
......
No preview for this file type
// automatically generated by the FlatBuffers compiler, do not modify
import * as NS9459827973991502386 from "./namespace_test1_generated";
import * as NS11563891686210618450 from "./namespace_test1_generated";
/**
* @constructor
*/
......@@ -39,24 +39,24 @@ static getRootAsTableInFirstNS(bb:flatbuffers.ByteBuffer, obj?:TableInFirstNS):T
* @param {NamespaceA.NamespaceB.TableInNestedNS=} obj
* @returns {NamespaceA.NamespaceB.TableInNestedNS|null}
*/
fooTable(obj?:NS9459827973991502386.NamespaceA.NamespaceB.TableInNestedNS):NS9459827973991502386.NamespaceA.NamespaceB.TableInNestedNS|null {
fooTable(obj?:NS11563891686210618450.NamespaceA.NamespaceB.TableInNestedNS):NS11563891686210618450.NamespaceA.NamespaceB.TableInNestedNS|null {
var offset = this.bb.__offset(this.bb_pos, 4);
return offset ? (obj || new NS9459827973991502386.NamespaceA.NamespaceB.TableInNestedNS).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
return offset ? (obj || new NS11563891686210618450.NamespaceA.NamespaceB.TableInNestedNS).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
};
/**
* @returns {NamespaceA.NamespaceB.EnumInNestedNS}
*/
fooEnum():NS9459827973991502386.NamespaceA.NamespaceB.EnumInNestedNS {
fooEnum():NS11563891686210618450.NamespaceA.NamespaceB.EnumInNestedNS {
var offset = this.bb.__offset(this.bb_pos, 6);
return offset ? /** @type {NamespaceA.NamespaceB.EnumInNestedNS} */ (this.bb.readInt8(this.bb_pos + offset)) : NS9459827973991502386.NamespaceA.NamespaceB.EnumInNestedNS.A;
return offset ? /** @type {NamespaceA.NamespaceB.EnumInNestedNS} */ (this.bb.readInt8(this.bb_pos + offset)) : NS11563891686210618450.NamespaceA.NamespaceB.EnumInNestedNS.A;
};
/**
* @param {NamespaceA.NamespaceB.EnumInNestedNS} value
* @returns {boolean}
*/
mutate_foo_enum(value:NS9459827973991502386.NamespaceA.NamespaceB.EnumInNestedNS):boolean {
mutate_foo_enum(value:NS11563891686210618450.NamespaceA.NamespaceB.EnumInNestedNS):boolean {
var offset = this.bb.__offset(this.bb_pos, 6);
if (offset === 0) {
......@@ -71,9 +71,9 @@ mutate_foo_enum(value:NS9459827973991502386.NamespaceA.NamespaceB.EnumInNestedNS
* @param {NamespaceA.NamespaceB.StructInNestedNS=} obj
* @returns {NamespaceA.NamespaceB.StructInNestedNS|null}
*/
fooStruct(obj?:NS9459827973991502386.NamespaceA.NamespaceB.StructInNestedNS):NS9459827973991502386.NamespaceA.NamespaceB.StructInNestedNS|null {
fooStruct(obj?:NS11563891686210618450.NamespaceA.NamespaceB.StructInNestedNS):NS11563891686210618450.NamespaceA.NamespaceB.StructInNestedNS|null {
var offset = this.bb.__offset(this.bb_pos, 8);
return offset ? (obj || new NS9459827973991502386.NamespaceA.NamespaceB.StructInNestedNS).__init(this.bb_pos + offset, this.bb) : null;
return offset ? (obj || new NS11563891686210618450.NamespaceA.NamespaceB.StructInNestedNS).__init(this.bb_pos + offset, this.bb) : null;
};
/**
......@@ -95,8 +95,8 @@ static addFooTable(builder:flatbuffers.Builder, fooTableOffset:flatbuffers.Offse
* @param {flatbuffers.Builder} builder
* @param {NamespaceA.NamespaceB.EnumInNestedNS} fooEnum
*/
static addFooEnum(builder:flatbuffers.Builder, fooEnum:NS9459827973991502386.NamespaceA.NamespaceB.EnumInNestedNS) {
builder.addFieldInt8(1, fooEnum, NS9459827973991502386.NamespaceA.NamespaceB.EnumInNestedNS.A);
static addFooEnum(builder:flatbuffers.Builder, fooEnum:NS11563891686210618450.NamespaceA.NamespaceB.EnumInNestedNS) {
builder.addFieldInt8(1, fooEnum, NS11563891686210618450.NamespaceA.NamespaceB.EnumInNestedNS.A);
};
/**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment