/srv/osrm/osrm-backend/third_party/flatbuffers/include/flatbuffers
Edit: /srv/osrm/osrm-backend/third_party/flatbuffers/include/flatbuffers/flatbuffers.h (99000B)
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FLATBUFFERS_H_
#define FLATBUFFERS_H_
#include "flatbuffers/base.h"
#if defined(FLATBUFFERS_NAN_DEFAULTS)
#include
#endif
namespace flatbuffers {
// Generic 'operator==' with conditional specialisations.
// T e - new value of a scalar field.
// T def - default of scalar (is known at compile-time).
template inline bool IsTheSameAs(T e, T def) { return e == def; }
#if defined(FLATBUFFERS_NAN_DEFAULTS) && \
defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0)
// Like `operator==(e, def)` with weak NaN if T=(float|double).
template inline bool IsFloatTheSameAs(T e, T def) {
return (e == def) || ((def != def) && (e != e));
}
template<> inline bool IsTheSameAs(float e, float def) {
return IsFloatTheSameAs(e, def);
}
template<> inline bool IsTheSameAs(double e, double def) {
return IsFloatTheSameAs(e, def);
}
#endif
// Wrapper for uoffset_t to allow safe template specialization.
// Value is allowed to be 0 to indicate a null object (see e.g. AddOffset).
template struct Offset {
uoffset_t o;
Offset() : o(0) {}
Offset(uoffset_t _o) : o(_o) {}
Offset Union() const { return Offset(o); }
bool IsNull() const { return !o; }
};
inline void EndianCheck() {
int endiantest = 1;
// If this fails, see FLATBUFFERS_LITTLEENDIAN above.
FLATBUFFERS_ASSERT(*reinterpret_cast(&endiantest) ==
FLATBUFFERS_LITTLEENDIAN);
(void)endiantest;
}
template FLATBUFFERS_CONSTEXPR size_t AlignOf() {
// clang-format off
#ifdef _MSC_VER
return __alignof(T);
#else
#ifndef alignof
return __alignof__(T);
#else
return alignof(T);
#endif
#endif
// clang-format on
}
// When we read serialized data from memory, in the case of most scalars,
// we want to just read T, but in the case of Offset, we want to actually
// perform the indirection and return a pointer.
// The template specialization below does just that.
// It is wrapped in a struct since function templates can't overload on the
// return type like this.
// The typedef is for the convenience of callers of this function
// (avoiding the need for a trailing return decltype)
template struct IndirectHelper {
typedef T return_type;
typedef T mutable_return_type;
static const size_t element_stride = sizeof(T);
static return_type Read(const uint8_t *p, uoffset_t i) {
return EndianScalar((reinterpret_cast(p))[i]);
}
};
template struct IndirectHelper> {
typedef const T *return_type;
typedef T *mutable_return_type;
static const size_t element_stride = sizeof(uoffset_t);
static return_type Read(const uint8_t *p, uoffset_t i) {
p += i * sizeof(uoffset_t);
return reinterpret_cast(p + ReadScalar(p));
}
};
template struct IndirectHelper {
typedef const T *return_type;
typedef T *mutable_return_type;
static const size_t element_stride = sizeof(T);
static return_type Read(const uint8_t *p, uoffset_t i) {
return reinterpret_cast(p + i * sizeof(T));
}
};
// An STL compatible iterator implementation for Vector below, effectively
// calling Get() for every element.
template struct VectorIterator {
typedef std::random_access_iterator_tag iterator_category;
typedef IT value_type;
typedef ptrdiff_t difference_type;
typedef IT *pointer;
typedef IT &reference;
VectorIterator(const uint8_t *data, uoffset_t i)
: data_(data + IndirectHelper::element_stride * i) {}
VectorIterator(const VectorIterator &other) : data_(other.data_) {}
VectorIterator() : data_(nullptr) {}
VectorIterator &operator=(const VectorIterator &other) {
data_ = other.data_;
return *this;
}
// clang-format off
#if !defined(FLATBUFFERS_CPP98_STL)
VectorIterator &operator=(VectorIterator &&other) {
data_ = other.data_;
return *this;
}
#endif // !defined(FLATBUFFERS_CPP98_STL)
// clang-format on
bool operator==(const VectorIterator &other) const {
return data_ == other.data_;
}
bool operator<(const VectorIterator &other) const {
return data_ < other.data_;
}
bool operator!=(const VectorIterator &other) const {
return data_ != other.data_;
}
difference_type operator-(const VectorIterator &other) const {
return (data_ - other.data_) / IndirectHelper::element_stride;
}
IT operator*() const { return IndirectHelper::Read(data_, 0); }
IT operator->() const { return IndirectHelper::Read(data_, 0); }
VectorIterator &operator++() {
data_ += IndirectHelper::element_stride;
return *this;
}
VectorIterator operator++(int) {
VectorIterator temp(data_, 0);
data_ += IndirectHelper::element_stride;
return temp;
}
VectorIterator operator+(const uoffset_t &offset) const {
return VectorIterator(data_ + offset * IndirectHelper::element_stride,
0);
}
VectorIterator &operator+=(const uoffset_t &offset) {
data_ += offset * IndirectHelper::element_stride;
return *this;
}
VectorIterator &operator--() {
data_ -= IndirectHelper::element_stride;
return *this;
}
VectorIterator operator--(int) {
VectorIterator temp(data_, 0);
data_ -= IndirectHelper::element_stride;
return temp;
}
VectorIterator operator-(const uoffset_t &offset) const {
return VectorIterator(data_ - offset * IndirectHelper::element_stride,
0);
}
VectorIterator &operator-=(const uoffset_t &offset) {
data_ -= offset * IndirectHelper::element_stride;
return *this;
}
private:
const uint8_t *data_;
};
template struct VectorReverseIterator :
public std::reverse_iterator {
explicit VectorReverseIterator(Iterator iter) :
std::reverse_iterator(iter) {}
typename Iterator::value_type operator*() const {
return *(std::reverse_iterator::current);
}
typename Iterator::value_type operator->() const {
return *(std::reverse_iterator::current);
}
};
struct String;
// This is used as a helper type for accessing vectors.
// Vector::data() assumes the vector elements start after the length field.
template class Vector {
public:
typedef VectorIterator::mutable_return_type>
iterator;
typedef VectorIterator::return_type>
const_iterator;
typedef VectorReverseIterator reverse_iterator;
typedef VectorReverseIterator const_reverse_iterator;
uoffset_t size() const { return EndianScalar(length_); }
// Deprecated: use size(). Here for backwards compatibility.
FLATBUFFERS_ATTRIBUTE(deprecated("use size() instead"))
uoffset_t Length() const { return size(); }
typedef typename IndirectHelper::return_type return_type;
typedef typename IndirectHelper::mutable_return_type mutable_return_type;
return_type Get(uoffset_t i) const {
FLATBUFFERS_ASSERT(i < size());
return IndirectHelper::Read(Data(), i);
}
return_type operator[](uoffset_t i) const { return Get(i); }
// If this is a Vector of enums, T will be its storage type, not the enum
// type. This function makes it convenient to retrieve value with enum
// type E.
template E GetEnum(uoffset_t i) const {
return static_cast(Get(i));
}
// If this a vector of unions, this does the cast for you. There's no check
// to make sure this is the right type!
template const U *GetAs(uoffset_t i) const {
return reinterpret_cast(Get(i));
}
// If this a vector of unions, this does the cast for you. There's no check
// to make sure this is actually a string!
const String *GetAsString(uoffset_t i) const {
return reinterpret_cast(Get(i));
}
const void *GetStructFromOffset(size_t o) const {
return reinterpret_cast(Data() + o);
}
iterator begin() { return iterator(Data(), 0); }
const_iterator begin() const { return const_iterator(Data(), 0); }
iterator end() { return iterator(Data(), size()); }
const_iterator end() const { return const_iterator(Data(), size()); }
reverse_iterator rbegin() { return reverse_iterator(end() - 1); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(end() - 1); }
reverse_iterator rend() { return reverse_iterator(begin() - 1); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin() - 1); }
const_iterator cbegin() const { return begin(); }
const_iterator cend() const { return end(); }
const_reverse_iterator crbegin() const { return rbegin(); }
const_reverse_iterator crend() const { return rend(); }
// Change elements if you have a non-const pointer to this object.
// Scalars only. See reflection.h, and the documentation.
void Mutate(uoffset_t i, const T &val) {
FLATBUFFERS_ASSERT(i < size());
WriteScalar(data() + i, val);
}
// Change an element of a vector of tables (or strings).
// "val" points to the new table/string, as you can obtain from
// e.g. reflection::AddFlatBuffer().
void MutateOffset(uoffset_t i, const uint8_t *val) {
FLATBUFFERS_ASSERT(i < size());
static_assert(sizeof(T) == sizeof(uoffset_t), "Unrelated types");
WriteScalar(data() + i,
static_cast(val - (Data() + i * sizeof(uoffset_t))));
}
// Get a mutable pointer to tables/strings inside this vector.
mutable_return_type GetMutableObject(uoffset_t i) const {
FLATBUFFERS_ASSERT(i < size());
return const_cast(IndirectHelper::Read(Data(), i));
}
// The raw data in little endian format. Use with care.
const uint8_t *Data() const {
return reinterpret_cast(&length_ + 1);
}
uint8_t *Data() { return reinterpret_cast(&length_ + 1); }
// Similarly, but typed, much like std::vector::data
const T *data() const { return reinterpret_cast(Data()); }
T *data() { return reinterpret_cast(Data()); }
template return_type LookupByKey(K key) const {
void *search_result = std::bsearch(
&key, Data(), size(), IndirectHelper::element_stride, KeyCompare);
if (!search_result) {
return nullptr; // Key not found.
}
const uint8_t *element = reinterpret_cast(search_result);
return IndirectHelper::Read(element, 0);
}
protected:
// This class is only used to access pre-existing data. Don't ever
// try to construct these manually.
Vector();
uoffset_t length_;
private:
// This class is a pointer. Copying will therefore create an invalid object.
// Private and unimplemented copy constructor.
Vector(const Vector &);
template static int KeyCompare(const void *ap, const void *bp) {
const K *key = reinterpret_cast(ap);
const uint8_t *data = reinterpret_cast(bp);
auto table = IndirectHelper::Read(data, 0);
// std::bsearch compares with the operands transposed, so we negate the
// result here.
return -table->KeyCompareWithValue(*key);
}
};
// Represent a vector much like the template above, but in this case we
// don't know what the element types are (used with reflection.h).
class VectorOfAny {
public:
uoffset_t size() const { return EndianScalar(length_); }
const uint8_t *Data() const {
return reinterpret_cast(&length_ + 1);
}
uint8_t *Data() { return reinterpret_cast(&length_ + 1); }
protected:
VectorOfAny();
uoffset_t length_;
private:
VectorOfAny(const VectorOfAny &);
};
#ifndef FLATBUFFERS_CPP98_STL
template
Vector> *VectorCast(Vector> *ptr) {
static_assert(std::is_base_of::value, "Unrelated types");
return reinterpret_cast> *>(ptr);
}
template
const Vector> *VectorCast(const Vector> *ptr) {
static_assert(std::is_base_of::value, "Unrelated types");
return reinterpret_cast> *>(ptr);
}
#endif
// Convenient helper function to get the length of any vector, regardless
// of whether it is null or not (the field is not set).
template static inline size_t VectorLength(const Vector *v) {
return v ? v->size() : 0;
}
// This is used as a helper type for accessing arrays.
template class Array {
public:
typedef VectorIterator::return_type>
const_iterator;
typedef VectorReverseIterator const_reverse_iterator;
typedef typename IndirectHelper::return_type return_type;
FLATBUFFERS_CONSTEXPR uint16_t size() const { return length; }
return_type Get(uoffset_t i) const {
FLATBUFFERS_ASSERT(i < size());
return IndirectHelper::Read(Data(), i);
}
return_type operator[](uoffset_t i) const { return Get(i); }
const_iterator begin() const { return const_iterator(Data(), 0); }
const_iterator end() const { return const_iterator(Data(), size()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const { return const_reverse_iterator(end()); }
const_iterator cbegin() const { return begin(); }
const_iterator cend() const { return end(); }
const_reverse_iterator crbegin() const { return rbegin(); }
const_reverse_iterator crend() const { return rend(); }
// Change elements if you have a non-const pointer to this object.
void Mutate(uoffset_t i, const T &val) {
FLATBUFFERS_ASSERT(i < size());
WriteScalar(data() + i, val);
}
// Get a mutable pointer to elements inside this array.
// @note This method should be only used to mutate arrays of structs followed
// by a @p Mutate operation. For primitive types use @p Mutate directly.
// @warning Assignments and reads to/from the dereferenced pointer are not
// automatically converted to the correct endianness.
T *GetMutablePointer(uoffset_t i) const {
FLATBUFFERS_ASSERT(i < size());
return const_cast(&data()[i]);
}
// The raw data in little endian format. Use with care.
const uint8_t *Data() const { return data_; }
uint8_t *Data() { return data_; }
// Similarly, but typed, much like std::vector::data
const T *data() const { return reinterpret_cast(Data()); }
T *data() { return reinterpret_cast(Data()); }
protected:
// This class is only used to access pre-existing data. Don't ever
// try to construct these manually.
// 'constexpr' allows us to use 'size()' at compile time.
// @note Must not use 'FLATBUFFERS_CONSTEXPR' here, as const is not allowed on
// a constructor.
#if defined(__cpp_constexpr)
constexpr Array();
#else
Array();
#endif
uint8_t data_[length * sizeof(T)];
private:
// This class is a pointer. Copying will therefore create an invalid object.
// Private and unimplemented copy constructor.
Array(const Array &);
};
// Lexicographically compare two strings (possibly containing nulls), and
// return true if the first is less than the second.
static inline bool StringLessThan(const char *a_data, uoffset_t a_size,
const char *b_data, uoffset_t b_size) {
const auto cmp = memcmp(a_data, b_data, (std::min)(a_size, b_size));
return cmp == 0 ? a_size < b_size : cmp < 0;
}
struct String : public Vector {
const char *c_str() const { return reinterpret_cast(Data()); }
std::string str() const { return std::string(c_str(), size()); }
// clang-format off
#ifdef FLATBUFFERS_HAS_STRING_VIEW
flatbuffers::string_view string_view() const {
return flatbuffers::string_view(c_str(), size());
}
#endif // FLATBUFFERS_HAS_STRING_VIEW
// clang-format on
bool operator<(const String &o) const {
return StringLessThan(this->data(), this->size(), o.data(), o.size());
}
};
// Convenience function to get std::string from a String returning an empty
// string on null pointer.
static inline std::string GetString(const String * str) {
return str ? str->str() : "";
}
// Convenience function to get char* from a String returning an empty string on
// null pointer.
static inline const char * GetCstring(const String * str) {
return str ? str->c_str() : "";
}
// Allocator interface. This is flatbuffers-specific and meant only for
// `vector_downward` usage.
class Allocator {
public:
virtual ~Allocator() {}
// Allocate `size` bytes of memory.
virtual uint8_t *allocate(size_t size) = 0;
// Deallocate `size` bytes of memory at `p` allocated by this allocator.
virtual void deallocate(uint8_t *p, size_t size) = 0;
// Reallocate `new_size` bytes of memory, replacing the old region of size
// `old_size` at `p`. In contrast to a normal realloc, this grows downwards,
// and is intended specifcally for `vector_downward` use.
// `in_use_back` and `in_use_front` indicate how much of `old_size` is
// actually in use at each end, and needs to be copied.
virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
size_t new_size, size_t in_use_back,
size_t in_use_front) {
FLATBUFFERS_ASSERT(new_size > old_size); // vector_downward only grows
uint8_t *new_p = allocate(new_size);
memcpy_downward(old_p, old_size, new_p, new_size, in_use_back,
in_use_front);
deallocate(old_p, old_size);
return new_p;
}
protected:
// Called by `reallocate_downward` to copy memory from `old_p` of `old_size`
// to `new_p` of `new_size`. Only memory of size `in_use_front` and
// `in_use_back` will be copied from the front and back of the old memory
// allocation.
void memcpy_downward(uint8_t *old_p, size_t old_size,
uint8_t *new_p, size_t new_size,
size_t in_use_back, size_t in_use_front) {
memcpy(new_p + new_size - in_use_back, old_p + old_size - in_use_back,
in_use_back);
memcpy(new_p, old_p, in_use_front);
}
};
// DefaultAllocator uses new/delete to allocate memory regions
class DefaultAllocator : public Allocator {
public:
uint8_t *allocate(size_t size) FLATBUFFERS_OVERRIDE {
return new uint8_t[size];
}
void deallocate(uint8_t *p, size_t) FLATBUFFERS_OVERRIDE {
delete[] p;
}
static void dealloc(void *p, size_t) {
delete[] static_cast(p);
}
};
// These functions allow for a null allocator to mean use the default allocator,
// as used by DetachedBuffer and vector_downward below.
// This is to avoid having a statically or dynamically allocated default
// allocator, or having to move it between the classes that may own it.
inline uint8_t *Allocate(Allocator *allocator, size_t size) {
return allocator ? allocator->allocate(size)
: DefaultAllocator().allocate(size);
}
inline void Deallocate(Allocator *allocator, uint8_t *p, size_t size) {
if (allocator) allocator->deallocate(p, size);
else DefaultAllocator().deallocate(p, size);
}
inline uint8_t *ReallocateDownward(Allocator *allocator, uint8_t *old_p,
size_t old_size, size_t new_size,
size_t in_use_back, size_t in_use_front) {
return allocator
? allocator->reallocate_downward(old_p, old_size, new_size,
in_use_back, in_use_front)
: DefaultAllocator().reallocate_downward(old_p, old_size, new_size,
in_use_back, in_use_front);
}
// DetachedBuffer is a finished flatbuffer memory region, detached from its
// builder. The original memory region and allocator are also stored so that
// the DetachedBuffer can manage the memory lifetime.
class DetachedBuffer {
public:
DetachedBuffer()
: allocator_(nullptr),
own_allocator_(false),
buf_(nullptr),
reserved_(0),
cur_(nullptr),
size_(0) {}
DetachedBuffer(Allocator *allocator, bool own_allocator, uint8_t *buf,
size_t reserved, uint8_t *cur, size_t sz)
: allocator_(allocator),
own_allocator_(own_allocator),
buf_(buf),
reserved_(reserved),
cur_(cur),
size_(sz) {}
// clang-format off
#if !defined(FLATBUFFERS_CPP98_STL)
// clang-format on
DetachedBuffer(DetachedBuffer &&other)
: allocator_(other.allocator_),
own_allocator_(other.own_allocator_),
buf_(other.buf_),
reserved_(other.reserved_),
cur_(other.cur_),
size_(other.size_) {
other.reset();
}
// clang-format off
#endif // !defined(FLATBUFFERS_CPP98_STL)
// clang-format on
// clang-format off
#if !defined(FLATBUFFERS_CPP98_STL)
// clang-format on
DetachedBuffer &operator=(DetachedBuffer &&other) {
destroy();
allocator_ = other.allocator_;
own_allocator_ = other.own_allocator_;
buf_ = other.buf_;
reserved_ = other.reserved_;
cur_ = other.cur_;
size_ = other.size_;
other.reset();
return *this;
}
// clang-format off
#endif // !defined(FLATBUFFERS_CPP98_STL)
// clang-format on
~DetachedBuffer() { destroy(); }
const uint8_t *data() const { return cur_; }
uint8_t *data() { return cur_; }
size_t size() const { return size_; }
// clang-format off
#if 0 // disabled for now due to the ordering of classes in this header
template
bool Verify() const {
Verifier verifier(data(), size());
return verifier.Verify(nullptr);
}
template
const T* GetRoot() const {
return flatbuffers::GetRoot(data());
}
template
T* GetRoot() {
return flatbuffers::GetRoot(data());
}
#endif
// clang-format on
// clang-format off
#if !defined(FLATBUFFERS_CPP98_STL)
// clang-format on
// These may change access mode, leave these at end of public section
FLATBUFFERS_DELETE_FUNC(DetachedBuffer(const DetachedBuffer &other))
FLATBUFFERS_DELETE_FUNC(
DetachedBuffer &operator=(const DetachedBuffer &other))
// clang-format off
#endif // !defined(FLATBUFFERS_CPP98_STL)
// clang-format on
protected:
Allocator *allocator_;
bool own_allocator_;
uint8_t *buf_;
size_t reserved_;
uint8_t *cur_;
size_t size_;
inline void destroy() {
if (buf_) Deallocate(allocator_, buf_, reserved_);
if (own_allocator_ && allocator_) { delete allocator_; }
reset();
}
inline void reset() {
allocator_ = nullptr;
own_allocator_ = false;
buf_ = nullptr;
reserved_ = 0;
cur_ = nullptr;
size_ = 0;
}
};
// This is a minimal replication of std::vector functionality,
// except growing from higher to lower addresses. i.e push_back() inserts data
// in the lowest address in the vector.
// Since this vector leaves the lower part unused, we support a "scratch-pad"
// that can be stored there for temporary data, to share the allocated space.
// Essentially, this supports 2 std::vectors in a single buffer.
class vector_downward {
public:
explicit vector_downward(size_t initial_size,
Allocator *allocator,
bool own_allocator,
size_t buffer_minalign)
: allocator_(allocator),
own_allocator_(own_allocator),
initial_size_(initial_size),
buffer_minalign_(buffer_minalign),
reserved_(0),
buf_(nullptr),
cur_(nullptr),
scratch_(nullptr) {}
// clang-format off
#if !defined(FLATBUFFERS_CPP98_STL)
vector_downward(vector_downward &&other)
#else
vector_downward(vector_downward &other)
#endif // defined(FLATBUFFERS_CPP98_STL)
// clang-format on
: allocator_(other.allocator_),
own_allocator_(other.own_allocator_),
initial_size_(other.initial_size_),
buffer_minalign_(other.buffer_minalign_),
reserved_(other.reserved_),
buf_(other.buf_),
cur_(other.cur_),
scratch_(other.scratch_) {
// No change in other.allocator_
// No change in other.initial_size_
// No change in other.buffer_minalign_
other.own_allocator_ = false;
other.reserved_ = 0;
other.buf_ = nullptr;
other.cur_ = nullptr;
other.scratch_ = nullptr;
}
// clang-format off
#if !defined(FLATBUFFERS_CPP98_STL)
// clang-format on
vector_downward &operator=(vector_downward &&other) {
// Move construct a temporary and swap idiom
vector_downward temp(std::move(other));
swap(temp);
return *this;
}
// clang-format off
#endif // defined(FLATBUFFERS_CPP98_STL)
// clang-format on
~vector_downward() {
clear_buffer();
clear_allocator();
}
void reset() {
clear_buffer();
clear();
}
void clear() {
if (buf_) {
cur_ = buf_ + reserved_;
} else {
reserved_ = 0;
cur_ = nullptr;
}
clear_scratch();
}
void clear_scratch() {
scratch_ = buf_;
}
void clear_allocator() {
if (own_allocator_ && allocator_) { delete allocator_; }
allocator_ = nullptr;
own_allocator_ = false;
}
void clear_buffer() {
if (buf_) Deallocate(allocator_, buf_, reserved_);
buf_ = nullptr;
}
// Relinquish the pointer to the caller.
uint8_t *release_raw(size_t &allocated_bytes, size_t &offset) {
auto *buf = buf_;
allocated_bytes = reserved_;
offset = static_cast(cur_ - buf_);
// release_raw only relinquishes the buffer ownership.
// Does not deallocate or reset the allocator. Destructor will do that.
buf_ = nullptr;
clear();
return buf;
}
// Relinquish the pointer to the caller.
DetachedBuffer release() {
// allocator ownership (if any) is transferred to DetachedBuffer.
DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
size());
if (own_allocator_) {
allocator_ = nullptr;
own_allocator_ = false;
}
buf_ = nullptr;
clear();
return fb;
}
size_t ensure_space(size_t len) {
FLATBUFFERS_ASSERT(cur_ >= scratch_ && scratch_ >= buf_);
if (len > static_cast(cur_ - scratch_)) { reallocate(len); }
// Beyond this, signed offsets may not have enough range:
// (FlatBuffers > 2GB not supported).
FLATBUFFERS_ASSERT(size() < FLATBUFFERS_MAX_BUFFER_SIZE);
return len;
}
inline uint8_t *make_space(size_t len) {
size_t space = ensure_space(len);
cur_ -= space;
return cur_;
}
// Returns nullptr if using the DefaultAllocator.
Allocator *get_custom_allocator() { return allocator_; }
uoffset_t size() const {
return static_cast(reserved_ - (cur_ - buf_));
}
uoffset_t scratch_size() const {
return static_cast(scratch_ - buf_);
}
size_t capacity() const { return reserved_; }
uint8_t *data() const {
FLATBUFFERS_ASSERT(cur_);
return cur_;
}
uint8_t *scratch_data() const {
FLATBUFFERS_ASSERT(buf_);
return buf_;
}
uint8_t *scratch_end() const {
FLATBUFFERS_ASSERT(scratch_);
return scratch_;
}
uint8_t *data_at(size_t offset) const { return buf_ + reserved_ - offset; }
void push(const uint8_t *bytes, size_t num) {
if (num > 0) { memcpy(make_space(num), bytes, num); }
}
// Specialized version of push() that avoids memcpy call for small data.
template void push_small(const T &little_endian_t) {
make_space(sizeof(T));
*reinterpret_cast(cur_) = little_endian_t;
}
template void scratch_push_small(const T &t) {
ensure_space(sizeof(T));
*reinterpret_cast(scratch_) = t;
scratch_ += sizeof(T);
}
// fill() is most frequently called with small byte counts (<= 4),
// which is why we're using loops rather than calling memset.
void fill(size_t zero_pad_bytes) {
make_space(zero_pad_bytes);
for (size_t i = 0; i < zero_pad_bytes; i++) cur_[i] = 0;
}
// Version for when we know the size is larger.
// Precondition: zero_pad_bytes > 0
void fill_big(size_t zero_pad_bytes) {
memset(make_space(zero_pad_bytes), 0, zero_pad_bytes);
}
void pop(size_t bytes_to_remove) { cur_ += bytes_to_remove; }
void scratch_pop(size_t bytes_to_remove) { scratch_ -= bytes_to_remove; }
void swap(vector_downward &other) {
using std::swap;
swap(allocator_, other.allocator_);
swap(own_allocator_, other.own_allocator_);
swap(initial_size_, other.initial_size_);
swap(buffer_minalign_, other.buffer_minalign_);
swap(reserved_, other.reserved_);
swap(buf_, other.buf_);
swap(cur_, other.cur_);
swap(scratch_, other.scratch_);
}
void swap_allocator(vector_downward &other) {
using std::swap;
swap(allocator_, other.allocator_);
swap(own_allocator_, other.own_allocator_);
}
private:
// You shouldn't really be copying instances of this class.
FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &))
FLATBUFFERS_DELETE_FUNC(vector_downward &operator=(const vector_downward &))
Allocator *allocator_;
bool own_allocator_;
size_t initial_size_;
size_t buffer_minalign_;
size_t reserved_;
uint8_t *buf_;
uint8_t *cur_; // Points at location between empty (below) and used (above).
uint8_t *scratch_; // Points to the end of the scratchpad in use.
void reallocate(size_t len) {
auto old_reserved = reserved_;
auto old_size = size();
auto old_scratch_size = scratch_size();
reserved_ += (std::max)(len,
old_reserved ? old_reserved / 2 : initial_size_);
reserved_ = (reserved_ + buffer_minalign_ - 1) & ~(buffer_minalign_ - 1);
if (buf_) {
buf_ = ReallocateDownward(allocator_, buf_, old_reserved, reserved_,
old_size, old_scratch_size);
} else {
buf_ = Allocate(allocator_, reserved_);
}
cur_ = buf_ + reserved_ - old_size;
scratch_ = buf_ + old_scratch_size;
}
};
// Converts a Field ID to a virtual table offset.
inline voffset_t FieldIndexToOffset(voffset_t field_id) {
// Should correspond to what EndTable() below builds up.
const int fixed_fields = 2; // Vtable size and Object Size.
return static_cast((field_id + fixed_fields) * sizeof(voffset_t));
}
template
const T *data(const std::vector &v) {
// Eventually the returned pointer gets passed down to memcpy, so
// we need it to be non-null to avoid undefined behavior.
static uint8_t t;
return v.empty() ? reinterpret_cast(&t) : &v.front();
}
template T *data(std::vector &v) {
// Eventually the returned pointer gets passed down to memcpy, so
// we need it to be non-null to avoid undefined behavior.
static uint8_t t;
return v.empty() ? reinterpret_cast(&t) : &v.front();
}
/// @endcond
/// @addtogroup flatbuffers_cpp_api
/// @{
/// @class FlatBufferBuilder
/// @brief Helper class to hold data needed in creation of a FlatBuffer.
/// To serialize data, you typically call one of the `Create*()` functions in
/// the generated code, which in turn call a sequence of `StartTable`/
/// `PushElement`/`AddElement`/`EndTable`, or the builtin `CreateString`/
/// `CreateVector` functions. Do this is depth-first order to build up a tree to
/// the root. `Finish()` wraps up the buffer ready for transport.
class FlatBufferBuilder {
public:
/// @brief Default constructor for FlatBufferBuilder.
/// @param[in] initial_size The initial size of the buffer, in bytes. Defaults
/// to `1024`.
/// @param[in] allocator An `Allocator` to use. If null will use
/// `DefaultAllocator`.
/// @param[in] own_allocator Whether the builder/vector should own the
/// allocator. Defaults to / `false`.
/// @param[in] buffer_minalign Force the buffer to be aligned to the given
/// minimum alignment upon reallocation. Only needed if you intend to store
/// types with custom alignment AND you wish to read the buffer in-place
/// directly after creation.
explicit FlatBufferBuilder(size_t initial_size = 1024,
Allocator *allocator = nullptr,
bool own_allocator = false,
size_t buffer_minalign =
AlignOf())
: buf_(initial_size, allocator, own_allocator, buffer_minalign),
num_field_loc(0),
max_voffset_(0),
nested(false),
finished(false),
minalign_(1),
force_defaults_(false),
dedup_vtables_(true),
string_pool(nullptr) {
EndianCheck();
}
// clang-format off
/// @brief Move constructor for FlatBufferBuilder.
#if !defined(FLATBUFFERS_CPP98_STL)
FlatBufferBuilder(FlatBufferBuilder &&other)
#else
FlatBufferBuilder(FlatBufferBuilder &other)
#endif // #if !defined(FLATBUFFERS_CPP98_STL)
: buf_(1024, nullptr, false, AlignOf()),
num_field_loc(0),
max_voffset_(0),
nested(false),
finished(false),
minalign_(1),
force_defaults_(false),
dedup_vtables_(true),
string_pool(nullptr) {
EndianCheck();
// Default construct and swap idiom.
// Lack of delegating constructors in vs2010 makes it more verbose than needed.
Swap(other);
}
// clang-format on
// clang-format off
#if !defined(FLATBUFFERS_CPP98_STL)
// clang-format on
/// @brief Move assignment operator for FlatBufferBuilder.
FlatBufferBuilder &operator=(FlatBufferBuilder &&other) {
// Move construct a temporary and swap idiom
FlatBufferBuilder temp(std::move(other));
Swap(temp);
return *this;
}
// clang-format off
#endif // defined(FLATBUFFERS_CPP98_STL)
// clang-format on
void Swap(FlatBufferBuilder &other) {
using std::swap;
buf_.swap(other.buf_);
swap(num_field_loc, other.num_field_loc);
swap(max_voffset_, other.max_voffset_);
swap(nested, other.nested);
swap(finished, other.finished);
swap(minalign_, other.minalign_);
swap(force_defaults_, other.force_defaults_);
swap(dedup_vtables_, other.dedup_vtables_);
swap(string_pool, other.string_pool);
}
~FlatBufferBuilder() {
if (string_pool) delete string_pool;
}
void Reset() {
Clear(); // clear builder state
buf_.reset(); // deallocate buffer
}
/// @brief Reset all the state in this FlatBufferBuilder so it can be reused
/// to construct another buffer.
void Clear() {
ClearOffsets();
buf_.clear();
nested = false;
finished = false;
minalign_ = 1;
if (string_pool) string_pool->clear();
}
/// @brief The current size of the serialized buffer, counting from the end.
/// @return Returns an `uoffset_t` with the current size of the buffer.
uoffset_t GetSize() const { return buf_.size(); }
/// @brief Get the serialized buffer (after you call `Finish()`).
/// @return Returns an `uint8_t` pointer to the FlatBuffer data inside the
/// buffer.
uint8_t *GetBufferPointer() const {
Finished();
return buf_.data();
}
/// @brief Get a pointer to an unfinished buffer.
/// @return Returns a `uint8_t` pointer to the unfinished buffer.
uint8_t *GetCurrentBufferPointer() const { return buf_.data(); }
/// @brief Get the released pointer to the serialized buffer.
/// @warning Do NOT attempt to use this FlatBufferBuilder afterwards!
/// @return A `FlatBuffer` that owns the buffer and its allocator and
/// behaves similar to a `unique_ptr` with a deleter.
FLATBUFFERS_ATTRIBUTE(deprecated("use Release() instead")) DetachedBuffer
ReleaseBufferPointer() {
Finished();
return buf_.release();
}
/// @brief Get the released DetachedBuffer.
/// @return A `DetachedBuffer` that owns the buffer and its allocator.
DetachedBuffer Release() {
Finished();
return buf_.release();
}
/// @brief Get the released pointer to the serialized buffer.
/// @param The size of the memory block containing
/// the serialized `FlatBuffer`.
/// @param The offset from the released pointer where the finished
/// `FlatBuffer` starts.
/// @return A raw pointer to the start of the memory block containing
/// the serialized `FlatBuffer`.
/// @remark If the allocator is owned, it gets deleted when the destructor is called..
uint8_t *ReleaseRaw(size_t &size, size_t &offset) {
Finished();
return buf_.release_raw(size, offset);
}
/// @brief get the minimum alignment this buffer needs to be accessed
/// properly. This is only known once all elements have been written (after
/// you call Finish()). You can use this information if you need to embed
/// a FlatBuffer in some other buffer, such that you can later read it
/// without first having to copy it into its own buffer.
size_t GetBufferMinAlignment() {
Finished();
return minalign_;
}
/// @cond FLATBUFFERS_INTERNAL
void Finished() const {
// If you get this assert, you're attempting to get access a buffer
// which hasn't been finished yet. Be sure to call
// FlatBufferBuilder::Finish with your root table.
// If you really need to access an unfinished buffer, call
// GetCurrentBufferPointer instead.
FLATBUFFERS_ASSERT(finished);
}
/// @endcond
/// @brief In order to save space, fields that are set to their default value
/// don't get serialized into the buffer.
/// @param[in] bool fd When set to `true`, always serializes default values that are set.
/// Optional fields which are not set explicitly, will still not be serialized.
void ForceDefaults(bool fd) { force_defaults_ = fd; }
/// @brief By default vtables are deduped in order to save space.
/// @param[in] bool dedup When set to `true`, dedup vtables.
void DedupVtables(bool dedup) { dedup_vtables_ = dedup; }
/// @cond FLATBUFFERS_INTERNAL
void Pad(size_t num_bytes) { buf_.fill(num_bytes); }
void TrackMinAlign(size_t elem_size) {
if (elem_size > minalign_) minalign_ = elem_size;
}
void Align(size_t elem_size) {
TrackMinAlign(elem_size);
buf_.fill(PaddingBytes(buf_.size(), elem_size));
}
void PushFlatBuffer(const uint8_t *bytes, size_t size) {
PushBytes(bytes, size);
finished = true;
}
void PushBytes(const uint8_t *bytes, size_t size) { buf_.push(bytes, size); }
void PopBytes(size_t amount) { buf_.pop(amount); }
template void AssertScalarT() {
// The code assumes power of 2 sizes and endian-swap-ability.
static_assert(flatbuffers::is_scalar::value, "T must be a scalar type");
}
// Write a single aligned scalar to the buffer
template uoffset_t PushElement(T element) {
AssertScalarT();
T litle_endian_element = EndianScalar(element);
Align(sizeof(T));
buf_.push_small(litle_endian_element);
return GetSize();
}
template uoffset_t PushElement(Offset off) {
// Special case for offsets: see ReferTo below.
return PushElement(ReferTo(off.o));
}
// When writing fields, we track where they are, so we can create correct
// vtables later.
void TrackField(voffset_t field, uoffset_t off) {
FieldLoc fl = { off, field };
buf_.scratch_push_small(fl);
num_field_loc++;
max_voffset_ = (std::max)(max_voffset_, field);
}
// Like PushElement, but additionally tracks the field this represents.
template void AddElement(voffset_t field, T e, T def) {
// We don't serialize values equal to the default.
if (IsTheSameAs(e, def) && !force_defaults_) return;
auto off = PushElement(e);
TrackField(field, off);
}
template void AddOffset(voffset_t field, Offset off) {
if (off.IsNull()) return; // Don't store.
AddElement(field, ReferTo(off.o), static_cast(0));
}
template void AddStruct(voffset_t field, const T *structptr) {
if (!structptr) return; // Default, don't store.
Align(AlignOf());
buf_.push_small(*structptr);
TrackField(field, GetSize());
}
void AddStructOffset(voffset_t field, uoffset_t off) {
TrackField(field, off);
}
// Offsets initially are relative to the end of the buffer (downwards).
// This function converts them to be relative to the current location
// in the buffer (when stored here), pointing upwards.
uoffset_t ReferTo(uoffset_t off) {
// Align to ensure GetSize() below is correct.
Align(sizeof(uoffset_t));
// Offset must refer to something already in buffer.
FLATBUFFERS_ASSERT(off && off <= GetSize());
return GetSize() - off + static_cast(sizeof(uoffset_t));
}
void NotNested() {
// If you hit this, you're trying to construct a Table/Vector/String
// during the construction of its parent table (between the MyTableBuilder
// and table.Finish().
// Move the creation of these sub-objects to above the MyTableBuilder to
// not get this assert.
// Ignoring this assert may appear to work in simple cases, but the reason
// it is here is that storing objects in-line may cause vtable offsets
// to not fit anymore. It also leads to vtable duplication.
FLATBUFFERS_ASSERT(!nested);
// If you hit this, fields were added outside the scope of a table.
FLATBUFFERS_ASSERT(!num_field_loc);
}
// From generated code (or from the parser), we call StartTable/EndTable
// with a sequence of AddElement calls in between.
uoffset_t StartTable() {
NotNested();
nested = true;
return GetSize();
}
// This finishes one serialized object by generating the vtable if it's a
// table, comparing it against existing vtables, and writing the
// resulting vtable offset.
uoffset_t EndTable(uoffset_t start) {
// If you get this assert, a corresponding StartTable wasn't called.
FLATBUFFERS_ASSERT(nested);
// Write the vtable offset, which is the start of any Table.
// We fill it's value later.
auto vtableoffsetloc = PushElement(0);
// Write a vtable, which consists entirely of voffset_t elements.
// It starts with the number of offsets, followed by a type id, followed
// by the offsets themselves. In reverse:
// Include space for the last offset and ensure empty tables have a
// minimum size.
max_voffset_ =
(std::max)(static_cast(max_voffset_ + sizeof(voffset_t)),
FieldIndexToOffset(0));
buf_.fill_big(max_voffset_);
auto table_object_size = vtableoffsetloc - start;
// Vtable use 16bit offsets.
FLATBUFFERS_ASSERT(table_object_size < 0x10000);
WriteScalar(buf_.data() + sizeof(voffset_t),
static_cast(table_object_size));
WriteScalar(buf_.data(), max_voffset_);
// Write the offsets into the table
for (auto it = buf_.scratch_end() - num_field_loc * sizeof(FieldLoc);
it < buf_.scratch_end(); it += sizeof(FieldLoc)) {
auto field_location = reinterpret_cast(it);
auto pos = static_cast(vtableoffsetloc - field_location->off);
// If this asserts, it means you've set a field twice.
FLATBUFFERS_ASSERT(
!ReadScalar(buf_.data() + field_location->id));
WriteScalar(buf_.data() + field_location->id, pos);
}
ClearOffsets();
auto vt1 = reinterpret_cast(buf_.data());
auto vt1_size = ReadScalar(vt1);
auto vt_use = GetSize();
// See if we already have generated a vtable with this exact same
// layout before. If so, make it point to the old one, remove this one.
if (dedup_vtables_) {
for (auto it = buf_.scratch_data(); it < buf_.scratch_end();
it += sizeof(uoffset_t)) {
auto vt_offset_ptr = reinterpret_cast(it);
auto vt2 = reinterpret_cast(buf_.data_at(*vt_offset_ptr));
auto vt2_size = *vt2;
if (vt1_size != vt2_size || 0 != memcmp(vt2, vt1, vt1_size)) continue;
vt_use = *vt_offset_ptr;
buf_.pop(GetSize() - vtableoffsetloc);
break;
}
}
// If this is a new vtable, remember it.
if (vt_use == GetSize()) { buf_.scratch_push_small(vt_use); }
// Fill the vtable offset we created above.
// The offset points from the beginning of the object to where the
// vtable is stored.
// Offsets default direction is downward in memory for future format
// flexibility (storing all vtables at the start of the file).
WriteScalar(buf_.data_at(vtableoffsetloc),
static_cast(vt_use) -
static_cast(vtableoffsetloc));
nested = false;
return vtableoffsetloc;
}
FLATBUFFERS_ATTRIBUTE(deprecated("call the version above instead"))
uoffset_t EndTable(uoffset_t start, voffset_t /*numfields*/) {
return EndTable(start);
}
// This checks a required field has been set in a given table that has
// just been constructed.
template void Required(Offset table, voffset_t field);
uoffset_t StartStruct(size_t alignment) {
Align(alignment);
return GetSize();
}
uoffset_t EndStruct() { return GetSize(); }
void ClearOffsets() {
buf_.scratch_pop(num_field_loc * sizeof(FieldLoc));
num_field_loc = 0;
max_voffset_ = 0;
}
// Aligns such that when "len" bytes are written, an object can be written
// after it with "alignment" without padding.
void PreAlign(size_t len, size_t alignment) {
TrackMinAlign(alignment);
buf_.fill(PaddingBytes(GetSize() + len, alignment));
}
template void PreAlign(size_t len) {
AssertScalarT();
PreAlign(len, sizeof(T));
}
/// @endcond
/// @brief Store a string in the buffer, which can contain any binary data.
/// @param[in] str A const char pointer to the data to be stored as a string.
/// @param[in] len The number of bytes that should be stored from `str`.
/// @return Returns the offset in the buffer where the string starts.
Offset CreateString(const char *str, size_t len) {
NotNested();
PreAlign(len + 1); // Always 0-terminated.
buf_.fill(1);
PushBytes(reinterpret_cast(str), len);
PushElement(static_cast(len));
return Offset(GetSize());
}
/// @brief Store a string in the buffer, which is null-terminated.
/// @param[in] str A const char pointer to a C-string to add to the buffer.
/// @return Returns the offset in the buffer where the string starts.
Offset CreateString(const char *str) {
return CreateString(str, strlen(str));
}
/// @brief Store a string in the buffer, which is null-terminated.
/// @param[in] str A char pointer to a C-string to add to the buffer.
/// @return Returns the offset in the buffer where the string starts.
Offset CreateString(char *str) {
return CreateString(str, strlen(str));
}
/// @brief Store a string in the buffer, which can contain any binary data.
/// @param[in] str A const reference to a std::string to store in the buffer.
/// @return Returns the offset in the buffer where the string starts.
Offset CreateString(const std::string &str) {
return CreateString(str.c_str(), str.length());
}
// clang-format off
#ifdef FLATBUFFERS_HAS_STRING_VIEW
/// @brief Store a string in the buffer, which can contain any binary data.
/// @param[in] str A const string_view to copy in to the buffer.
/// @return Returns the offset in the buffer where the string starts.
Offset CreateString(flatbuffers::string_view str) {
return CreateString(str.data(), str.size());
}
#endif // FLATBUFFERS_HAS_STRING_VIEW
// clang-format on
/// @brief Store a string in the buffer, which can contain any binary data.
/// @param[in] str A const pointer to a `String` struct to add to the buffer.
/// @return Returns the offset in the buffer where the string starts
Offset CreateString(const String *str) {
return str ? CreateString(str->c_str(), str->size()) : 0;
}
/// @brief Store a string in the buffer, which can contain any binary data.
/// @param[in] str A const reference to a std::string like type with support
/// of T::c_str() and T::length() to store in the buffer.
/// @return Returns the offset in the buffer where the string starts.
template Offset CreateString(const T &str) {
return CreateString(str.c_str(), str.length());
}
/// @brief Store a string in the buffer, which can contain any binary data.
/// If a string with this exact contents has already been serialized before,
/// instead simply returns the offset of the existing string.
/// @param[in] str A const char pointer to the data to be stored as a string.
/// @param[in] len The number of bytes that should be stored from `str`.
/// @return Returns the offset in the buffer where the string starts.
Offset CreateSharedString(const char *str, size_t len) {
if (!string_pool)
string_pool = new StringOffsetMap(StringOffsetCompare(buf_));
auto size_before_string = buf_.size();
// Must first serialize the string, since the set is all offsets into
// buffer.
auto off = CreateString(str, len);
auto it = string_pool->find(off);
// If it exists we reuse existing serialized data!
if (it != string_pool->end()) {
// We can remove the string we serialized.
buf_.pop(buf_.size() - size_before_string);
return *it;
}
// Record this string for future use.
string_pool->insert(off);
return off;
}
/// @brief Store a string in the buffer, which null-terminated.
/// If a string with this exact contents has already been serialized before,
/// instead simply returns the offset of the existing string.
/// @param[in] str A const char pointer to a C-string to add to the buffer.
/// @return Returns the offset in the buffer where the string starts.
Offset CreateSharedString(const char *str) {
return CreateSharedString(str, strlen(str));
}
/// @brief Store a string in the buffer, which can contain any binary data.
/// If a string with this exact contents has already been serialized before,
/// instead simply returns the offset of the existing string.
/// @param[in] str A const reference to a std::string to store in the buffer.
/// @return Returns the offset in the buffer where the string starts.
Offset CreateSharedString(const std::string &str) {
return CreateSharedString(str.c_str(), str.length());
}
/// @brief Store a string in the buffer, which can contain any binary data.
/// If a string with this exact contents has already been serialized before,
/// instead simply returns the offset of the existing string.
/// @param[in] str A const pointer to a `String` struct to add to the buffer.
/// @return Returns the offset in the buffer where the string starts
Offset CreateSharedString(const String *str) {
return CreateSharedString(str->c_str(), str->size());
}
/// @cond FLATBUFFERS_INTERNAL
uoffset_t EndVector(size_t len) {
FLATBUFFERS_ASSERT(nested); // Hit if no corresponding StartVector.
nested = false;
return PushElement(static_cast(len));
}
void StartVector(size_t len, size_t elemsize) {
NotNested();
nested = true;
PreAlign(len * elemsize);
PreAlign(len * elemsize, elemsize); // Just in case elemsize > uoffset_t.
}
// Call this right before StartVector/CreateVector if you want to force the
// alignment to be something different than what the element size would
// normally dictate.
// This is useful when storing a nested_flatbuffer in a vector of bytes,
// or when storing SIMD floats, etc.
void ForceVectorAlignment(size_t len, size_t elemsize, size_t alignment) {
PreAlign(len * elemsize, alignment);
}
// Similar to ForceVectorAlignment but for String fields.
void ForceStringAlignment(size_t len, size_t alignment) {
PreAlign((len + 1) * sizeof(char), alignment);
}
/// @endcond
/// @brief Serialize an array into a FlatBuffer `vector`.
/// @tparam T The data type of the array elements.
/// @param[in] v A pointer to the array of type `T` to serialize into the
/// buffer as a `vector`.
/// @param[in] len The number of elements to serialize.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template Offset> CreateVector(const T *v, size_t len) {
// If this assert hits, you're specifying a template argument that is
// causing the wrong overload to be selected, remove it.
AssertScalarT();
StartVector(len, sizeof(T));
// clang-format off
#if FLATBUFFERS_LITTLEENDIAN
PushBytes(reinterpret_cast(v), len * sizeof(T));
#else
if (sizeof(T) == 1) {
PushBytes(reinterpret_cast(v), len);
} else {
for (auto i = len; i > 0; ) {
PushElement(v[--i]);
}
}
#endif
// clang-format on
return Offset>(EndVector(len));
}
template
Offset>> CreateVector(const Offset *v, size_t len) {
StartVector(len, sizeof(Offset));
for (auto i = len; i > 0;) { PushElement(v[--i]); }
return Offset>>(EndVector(len));
}
/// @brief Serialize a `std::vector` into a FlatBuffer `vector`.
/// @tparam T The data type of the `std::vector` elements.
/// @param v A const reference to the `std::vector` to serialize into the
/// buffer as a `vector`.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template Offset> CreateVector(const std::vector &v) {
return CreateVector(data(v), v.size());
}
// vector may be implemented using a bit-set, so we can't access it as
// an array. Instead, read elements manually.
// Background: https://isocpp.org/blog/2012/11/on-vectorbool
Offset> CreateVector(const std::vector &v) {
StartVector(v.size(), sizeof(uint8_t));
for (auto i = v.size(); i > 0;) {
PushElement(static_cast(v[--i]));
}
return Offset>(EndVector(v.size()));
}
// clang-format off
#ifndef FLATBUFFERS_CPP98_STL
/// @brief Serialize values returned by a function into a FlatBuffer `vector`.
/// This is a convenience function that takes care of iteration for you.
/// @tparam T The data type of the `std::vector` elements.
/// @param f A function that takes the current iteration 0..vector_size-1 and
/// returns any type that you can construct a FlatBuffers vector out of.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template Offset> CreateVector(size_t vector_size,
const std::function &f) {
std::vector elems(vector_size);
for (size_t i = 0; i < vector_size; i++) elems[i] = f(i);
return CreateVector(elems);
}
#endif
// clang-format on
/// @brief Serialize values returned by a function into a FlatBuffer `vector`.
/// This is a convenience function that takes care of iteration for you.
/// @tparam T The data type of the `std::vector` elements.
/// @param f A function that takes the current iteration 0..vector_size-1,
/// and the state parameter returning any type that you can construct a
/// FlatBuffers vector out of.
/// @param state State passed to f.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template
Offset> CreateVector(size_t vector_size, F f, S *state) {
std::vector elems(vector_size);
for (size_t i = 0; i < vector_size; i++) elems[i] = f(i, state);
return CreateVector(elems);
}
/// @brief Serialize a `std::vector` into a FlatBuffer `vector`.
/// This is a convenience function for a common case.
/// @param v A const reference to the `std::vector` to serialize into the
/// buffer as a `vector`.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
Offset>> CreateVectorOfStrings(
const std::vector &v) {
std::vector> offsets(v.size());
for (size_t i = 0; i < v.size(); i++) offsets[i] = CreateString(v[i]);
return CreateVector(offsets);
}
/// @brief Serialize an array of structs into a FlatBuffer `vector`.
/// @tparam T The data type of the struct array elements.
/// @param[in] v A pointer to the array of type `T` to serialize into the
/// buffer as a `vector`.
/// @param[in] len The number of elements to serialize.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template
Offset> CreateVectorOfStructs(const T *v, size_t len) {
StartVector(len * sizeof(T) / AlignOf(), AlignOf());
PushBytes(reinterpret_cast(v), sizeof(T) * len);
return Offset>(EndVector(len));
}
/// @brief Serialize an array of native structs into a FlatBuffer `vector`.
/// @tparam T The data type of the struct array elements.
/// @tparam S The data type of the native struct array elements.
/// @param[in] v A pointer to the array of type `S` to serialize into the
/// buffer as a `vector`.
/// @param[in] len The number of elements to serialize.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template
Offset> CreateVectorOfNativeStructs(const S *v,
size_t len) {
extern T Pack(const S &);
std::vector vv(len);
std::transform(v, v + len, vv.begin(), Pack);
return CreateVectorOfStructs(vv.data(), vv.size());
}
// clang-format off
#ifndef FLATBUFFERS_CPP98_STL
/// @brief Serialize an array of structs into a FlatBuffer `vector`.
/// @tparam T The data type of the struct array elements.
/// @param[in] f A function that takes the current iteration 0..vector_size-1
/// and a pointer to the struct that must be filled.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
/// This is mostly useful when flatbuffers are generated with mutation
/// accessors.
template Offset> CreateVectorOfStructs(
size_t vector_size, const std::function &filler) {
T* structs = StartVectorOfStructs(vector_size);
for (size_t i = 0; i < vector_size; i++) {
filler(i, structs);
structs++;
}
return EndVectorOfStructs(vector_size);
}
#endif
// clang-format on
/// @brief Serialize an array of structs into a FlatBuffer `vector`.
/// @tparam T The data type of the struct array elements.
/// @param[in] f A function that takes the current iteration 0..vector_size-1,
/// a pointer to the struct that must be filled and the state argument.
/// @param[in] state Arbitrary state to pass to f.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
/// This is mostly useful when flatbuffers are generated with mutation
/// accessors.
template
Offset> CreateVectorOfStructs(size_t vector_size, F f,
S *state) {
T *structs = StartVectorOfStructs(vector_size);
for (size_t i = 0; i < vector_size; i++) {
f(i, structs, state);
structs++;
}
return EndVectorOfStructs(vector_size);
}
/// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`.
/// @tparam T The data type of the `std::vector` struct elements.
/// @param[in]] v A const reference to the `std::vector` of structs to
/// serialize into the buffer as a `vector`.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template
Offset> CreateVectorOfStructs(
const std::vector &v) {
return CreateVectorOfStructs(data(v), v.size());
}
/// @brief Serialize a `std::vector` of native structs into a FlatBuffer
/// `vector`.
/// @tparam T The data type of the `std::vector` struct elements.
/// @tparam S The data type of the `std::vector` native struct elements.
/// @param[in]] v A const reference to the `std::vector` of structs to
/// serialize into the buffer as a `vector`.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template
Offset> CreateVectorOfNativeStructs(
const std::vector &v) {
return CreateVectorOfNativeStructs(data(v), v.size());
}
/// @cond FLATBUFFERS_INTERNAL
template struct StructKeyComparator {
bool operator()(const T &a, const T &b) const {
return a.KeyCompareLessThan(&b);
}
private:
StructKeyComparator &operator=(const StructKeyComparator &);
};
/// @endcond
/// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`
/// in sorted order.
/// @tparam T The data type of the `std::vector` struct elements.
/// @param[in]] v A const reference to the `std::vector` of structs to
/// serialize into the buffer as a `vector`.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template
Offset> CreateVectorOfSortedStructs(std::vector *v) {
return CreateVectorOfSortedStructs(data(*v), v->size());
}
/// @brief Serialize a `std::vector` of native structs into a FlatBuffer
/// `vector` in sorted order.
/// @tparam T The data type of the `std::vector` struct elements.
/// @tparam S The data type of the `std::vector` native struct elements.
/// @param[in]] v A const reference to the `std::vector` of structs to
/// serialize into the buffer as a `vector`.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template
Offset> CreateVectorOfSortedNativeStructs(
std::vector *v) {
return CreateVectorOfSortedNativeStructs(data(*v), v->size());
}
/// @brief Serialize an array of structs into a FlatBuffer `vector` in sorted
/// order.
/// @tparam T The data type of the struct array elements.
/// @param[in] v A pointer to the array of type `T` to serialize into the
/// buffer as a `vector`.
/// @param[in] len The number of elements to serialize.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template
Offset> CreateVectorOfSortedStructs(T *v, size_t len) {
std::sort(v, v + len, StructKeyComparator());
return CreateVectorOfStructs(v, len);
}
/// @brief Serialize an array of native structs into a FlatBuffer `vector` in
/// sorted order.
/// @tparam T The data type of the struct array elements.
/// @tparam S The data type of the native struct array elements.
/// @param[in] v A pointer to the array of type `S` to serialize into the
/// buffer as a `vector`.
/// @param[in] len The number of elements to serialize.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template
Offset> CreateVectorOfSortedNativeStructs(S *v,
size_t len) {
extern T Pack(const S &);
typedef T (*Pack_t)(const S &);
std::vector vv(len);
std::transform(v, v + len, vv.begin(), static_cast(Pack));
return CreateVectorOfSortedStructs(vv, len);
}
/// @cond FLATBUFFERS_INTERNAL
template struct TableKeyComparator {
TableKeyComparator(vector_downward &buf) : buf_(buf) {}
bool operator()(const Offset &a, const Offset &b) const {
auto table_a = reinterpret_cast(buf_.data_at(a.o));
auto table_b = reinterpret_cast(buf_.data_at(b.o));
return table_a->KeyCompareLessThan(table_b);
}
vector_downward &buf_;
private:
TableKeyComparator &operator=(const TableKeyComparator &);
};
/// @endcond
/// @brief Serialize an array of `table` offsets as a `vector` in the buffer
/// in sorted order.
/// @tparam T The data type that the offset refers to.
/// @param[in] v An array of type `Offset` that contains the `table`
/// offsets to store in the buffer in sorted order.
/// @param[in] len The number of elements to store in the `vector`.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template
Offset>> CreateVectorOfSortedTables(Offset *v,
size_t len) {
std::sort(v, v + len, TableKeyComparator(buf_));
return CreateVector(v, len);
}
/// @brief Serialize an array of `table` offsets as a `vector` in the buffer
/// in sorted order.
/// @tparam T The data type that the offset refers to.
/// @param[in] v An array of type `Offset` that contains the `table`
/// offsets to store in the buffer in sorted order.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template
Offset>> CreateVectorOfSortedTables(
std::vector> *v) {
return CreateVectorOfSortedTables(data(*v), v->size());
}
/// @brief Specialized version of `CreateVector` for non-copying use cases.
/// Write the data any time later to the returned buffer pointer `buf`.
/// @param[in] len The number of elements to store in the `vector`.
/// @param[in] elemsize The size of each element in the `vector`.
/// @param[out] buf A pointer to a `uint8_t` pointer that can be
/// written to at a later time to serialize the data into a `vector`
/// in the buffer.
uoffset_t CreateUninitializedVector(size_t len, size_t elemsize,
uint8_t **buf) {
NotNested();
StartVector(len, elemsize);
buf_.make_space(len * elemsize);
auto vec_start = GetSize();
auto vec_end = EndVector(len);
*buf = buf_.data_at(vec_start);
return vec_end;
}
/// @brief Specialized version of `CreateVector` for non-copying use cases.
/// Write the data any time later to the returned buffer pointer `buf`.
/// @tparam T The data type of the data that will be stored in the buffer
/// as a `vector`.
/// @param[in] len The number of elements to store in the `vector`.
/// @param[out] buf A pointer to a pointer of type `T` that can be
/// written to at a later time to serialize the data into a `vector`
/// in the buffer.
template
Offset