Added support for custom allocators and uninitialized vectors.

This is helpful working with zero-copy use cases.

Bug: 15779698
Change-Id: I7097651ca9a432b5021b4e024da86398d1413ec7
Tested: on Linux and Windows.
parent 4cdf3eb1
...@@ -293,19 +293,29 @@ struct String : public Vector<char> { ...@@ -293,19 +293,29 @@ struct String : public Vector<char> {
const char *c_str() const { return reinterpret_cast<const char *>(Data()); } const char *c_str() const { return reinterpret_cast<const char *>(Data()); }
}; };
// Simple indirection for buffer allocation, to allow this to be overridden
// with custom allocation (see the FlatBufferBuilder constructor).
class simple_allocator {
public:
virtual uint8_t *allocate(size_t size) const { return new uint8_t[size]; }
virtual void deallocate(uint8_t *p) const { delete[] p; }
};
// This is a minimal replication of std::vector<uint8_t> functionality, // This is a minimal replication of std::vector<uint8_t> functionality,
// except growing from higher to lower addresses. i.e push_back() inserts data // except growing from higher to lower addresses. i.e push_back() inserts data
// in the lowest address in the vector. // in the lowest address in the vector.
class vector_downward { class vector_downward {
public: public:
explicit vector_downward(size_t initial_size) explicit vector_downward(size_t initial_size,
const simple_allocator &allocator)
: reserved_(initial_size), : reserved_(initial_size),
buf_(new uint8_t[reserved_]), buf_(allocator.allocate(reserved_)),
cur_(buf_ + reserved_) { cur_(buf_ + reserved_),
allocator_(allocator) {
assert((initial_size & (sizeof(largest_scalar_t) - 1)) == 0); assert((initial_size & (sizeof(largest_scalar_t) - 1)) == 0);
} }
~vector_downward() { delete[] buf_; } ~vector_downward() { allocator_.deallocate(buf_); }
void clear() { cur_ = buf_ + reserved_; } void clear() { cur_ = buf_ + reserved_; }
...@@ -317,11 +327,11 @@ class vector_downward { ...@@ -317,11 +327,11 @@ class vector_downward {
if (buf_ > cur_ - len) { if (buf_ > cur_ - len) {
auto old_size = size(); auto old_size = size();
reserved_ += std::max(len, growth_policy(reserved_)); reserved_ += std::max(len, growth_policy(reserved_));
auto new_buf = new uint8_t[reserved_]; auto new_buf = allocator_.allocate(reserved_);
auto new_cur = new_buf + reserved_ - old_size; auto new_cur = new_buf + reserved_ - old_size;
memcpy(new_cur, cur_, old_size); memcpy(new_cur, cur_, old_size);
cur_ = new_cur; cur_ = new_cur;
delete[] buf_; allocator_.deallocate(buf_);
buf_ = new_buf; buf_ = new_buf;
} }
cur_ -= len; cur_ -= len;
...@@ -361,6 +371,7 @@ class vector_downward { ...@@ -361,6 +371,7 @@ class vector_downward {
size_t reserved_; size_t reserved_;
uint8_t *buf_; uint8_t *buf_;
uint8_t *cur_; // Points at location between empty (below) and used (above). uint8_t *cur_; // Points at location between empty (below) and used (above).
const simple_allocator &allocator_;
}; };
// Converts a Field ID to a virtual table offset. // Converts a Field ID to a virtual table offset.
...@@ -385,8 +396,10 @@ inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) { ...@@ -385,8 +396,10 @@ inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) {
// Finish() wraps up the buffer ready for transport. // Finish() wraps up the buffer ready for transport.
class FlatBufferBuilder { class FlatBufferBuilder {
public: public:
explicit FlatBufferBuilder(uoffset_t initial_size = 1024) explicit FlatBufferBuilder(uoffset_t initial_size = 1024,
: buf_(initial_size), minalign_(1), force_defaults_(false) { const simple_allocator *allocator = nullptr)
: buf_(initial_size, allocator ? *allocator : default_allocator),
minalign_(1), force_defaults_(false) {
offsetbuf_.reserve(16); // Avoid first few reallocs. offsetbuf_.reserve(16); // Avoid first few reallocs.
vtables_.reserve(16); vtables_.reserve(16);
EndianCheck(); EndianCheck();
...@@ -617,6 +630,16 @@ class FlatBufferBuilder { ...@@ -617,6 +630,16 @@ class FlatBufferBuilder {
return Offset<Vector<T>>(EndVector(len)); return Offset<Vector<T>>(EndVector(len));
} }
// Specialized version for non-copying use cases. Data to be written later.
// After calling this function, GetBufferPointer() can be cast to the
// corresponding Vector<> type to write the data (through Data()).
template<typename T> Offset<Vector<T>> CreateUninitializedVector(size_t len) {
NotNested();
StartVector(len, sizeof(T));
buf_.make_space(len * sizeof(T));
return Offset<Vector<T>>(EndVector(len));
}
template<typename T> Offset<Vector<T>> CreateVector(const std::vector<T> &v){ template<typename T> Offset<Vector<T>> CreateVector(const std::vector<T> &v){
return CreateVector(v.data(), v.size()); return CreateVector(v.data(), v.size());
} }
...@@ -662,6 +685,8 @@ class FlatBufferBuilder { ...@@ -662,6 +685,8 @@ class FlatBufferBuilder {
voffset_t id; voffset_t id;
}; };
simple_allocator default_allocator;
vector_downward buf_; vector_downward buf_;
// Accumulating offsets of table members while it is being built. // Accumulating offsets of table members while it is being built.
......
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