mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-28 08:18:05 +00:00
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.
This commit is contained in:
@@ -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 {
|
|||||||
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 {
|
|||||||
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) {
|
|||||||
// 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 {
|
|||||||
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 {
|
|||||||
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user