forked from BigfootDev/flatbuffers
- add flatbuffers::span - add new constructor for `struct` with `array` - add some test for flatbuffers::span and 'arrays_test.fbs'
This commit is contained in:
@@ -177,10 +177,9 @@ namespace flatbuffers {
|
||||
#define FLATBUFFERS_CONSTEXPR_CPP11
|
||||
#endif
|
||||
|
||||
// This macro is never used in code!
|
||||
#if (defined(__cplusplus) && __cplusplus >= 201402L) || \
|
||||
(defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
|
||||
#define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR
|
||||
#define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR_CPP11
|
||||
#else
|
||||
#define FLATBUFFERS_CONSTEXPR_CPP14
|
||||
#endif
|
||||
|
||||
@@ -435,6 +435,7 @@ template<typename T, uint16_t length> class Array {
|
||||
IndirectHelperType;
|
||||
|
||||
public:
|
||||
typedef uint16_t size_type;
|
||||
typedef typename IndirectHelper<IndirectHelperType>::return_type return_type;
|
||||
typedef VectorIterator<T, return_type> const_iterator;
|
||||
typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
|
||||
@@ -492,6 +493,22 @@ template<typename T, uint16_t length> class Array {
|
||||
const T *data() const { return reinterpret_cast<const T *>(Data()); }
|
||||
T *data() { return reinterpret_cast<T *>(Data()); }
|
||||
|
||||
// Copy data from a span with endian conversion.
|
||||
// If this Array and the span overlap, the behavior is undefined.
|
||||
void CopyFromSpan(flatbuffers::span<const T, length> src) {
|
||||
const auto p1 = reinterpret_cast<const uint8_t *>(src.data());
|
||||
const auto p2 = Data();
|
||||
FLATBUFFERS_ASSERT(!(p1 >= p2 && p1 < (p2 + length)) &&
|
||||
!(p2 >= p1 && p2 < (p1 + length)));
|
||||
(void)p1;
|
||||
(void)p2;
|
||||
|
||||
CopyFromSpanImpl(
|
||||
flatbuffers::integral_constant<bool,
|
||||
!scalar_tag::value || sizeof(T) == 1 || FLATBUFFERS_LITTLEENDIAN>(),
|
||||
src);
|
||||
}
|
||||
|
||||
protected:
|
||||
void MutateImpl(flatbuffers::integral_constant<bool, true>, uoffset_t i,
|
||||
const T &val) {
|
||||
@@ -504,6 +521,20 @@ template<typename T, uint16_t length> class Array {
|
||||
*(GetMutablePointer(i)) = val;
|
||||
}
|
||||
|
||||
void CopyFromSpanImpl(flatbuffers::integral_constant<bool, true>,
|
||||
flatbuffers::span<const T, length> src) {
|
||||
// Use std::memcpy() instead of std::copy() to avoid preformance degradation
|
||||
// due to aliasing if T is char or unsigned char.
|
||||
// The size is known at compile time, so memcpy would be inlined.
|
||||
std::memcpy(data(), src.data(), length * sizeof(T));
|
||||
}
|
||||
|
||||
// Copy data from flatbuffers::span with endian conversion.
|
||||
void CopyFromSpanImpl(flatbuffers::integral_constant<bool, false>,
|
||||
flatbuffers::span<const T, length> src) {
|
||||
for (size_type k = 0; k < length; k++) { Mutate(k, src[k]); }
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -549,6 +580,30 @@ template<typename T, uint16_t length> class Array<Offset<T>, length> {
|
||||
uint8_t data_[1];
|
||||
};
|
||||
|
||||
// Cast a raw T[length] to a raw flatbuffers::Array<T, length>
|
||||
// without endian conversion. Use with care.
|
||||
template<typename T, uint16_t length>
|
||||
Array<T, length>& CastToArray(T (&arr)[length]) {
|
||||
return *reinterpret_cast<Array<T, length> *>(arr);
|
||||
}
|
||||
|
||||
template<typename T, uint16_t length>
|
||||
const Array<T, length>& CastToArray(const T (&arr)[length]) {
|
||||
return *reinterpret_cast<const Array<T, length> *>(arr);
|
||||
}
|
||||
|
||||
template<typename E, typename T, uint16_t length>
|
||||
Array<E, length> &CastToArrayOfEnum(T (&arr)[length]) {
|
||||
static_assert(sizeof(E) == sizeof(T), "invalid enum type E");
|
||||
return *reinterpret_cast<Array<E, length> *>(arr);
|
||||
}
|
||||
|
||||
template<typename E, typename T, uint16_t length>
|
||||
const Array<E, length> &CastToArrayOfEnum(const T (&arr)[length]) {
|
||||
static_assert(sizeof(E) == sizeof(T), "invalid enum type E");
|
||||
return *reinterpret_cast<const Array<E, length> *>(arr);
|
||||
}
|
||||
|
||||
// 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,
|
||||
|
||||
@@ -26,6 +26,14 @@
|
||||
#include <memory>
|
||||
#include <limits>
|
||||
|
||||
#if defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
|
||||
#define FLATBUFFERS_CPP98_STL
|
||||
#endif // defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
|
||||
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
#include <cctype>
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
|
||||
// Detect C++17 compatible compiler.
|
||||
// __cplusplus >= 201703L - a compiler has support of 'static inline' variables.
|
||||
#if defined(FLATBUFFERS_USE_STD_OPTIONAL) \
|
||||
@@ -35,15 +43,25 @@
|
||||
#ifndef FLATBUFFERS_USE_STD_OPTIONAL
|
||||
#define FLATBUFFERS_USE_STD_OPTIONAL
|
||||
#endif
|
||||
#endif
|
||||
#endif // defined(FLATBUFFERS_USE_STD_OPTIONAL) ...
|
||||
|
||||
#if defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
|
||||
#define FLATBUFFERS_CPP98_STL
|
||||
#endif // defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
|
||||
|
||||
#if defined(FLATBUFFERS_CPP98_STL)
|
||||
#include <cctype>
|
||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
||||
// The __cpp_lib_span is the predefined feature macro.
|
||||
#if defined(FLATBUFFERS_USE_STD_SPAN)
|
||||
#include <span>
|
||||
#elif defined(__cpp_lib_span) && defined(__has_include)
|
||||
#if __has_include(<span>)
|
||||
#include <span>
|
||||
#define FLATBUFFERS_USE_STD_SPAN
|
||||
#endif
|
||||
#else
|
||||
// Disable non-trivial ctors if FLATBUFFERS_SPAN_MINIMAL defined.
|
||||
#if !defined(FLATBUFFERS_TEMPLATES_ALIASES) || defined(FLATBUFFERS_CPP98_STL)
|
||||
#define FLATBUFFERS_SPAN_MINIMAL
|
||||
#else
|
||||
// Enable implicit construction of a span<T,N> from a std::array<T,N>.
|
||||
#include <array>
|
||||
#endif
|
||||
#endif // defined(FLATBUFFERS_USE_STD_SPAN)
|
||||
|
||||
// This header provides backwards compatibility for C++98 STLs like stlport.
|
||||
namespace flatbuffers {
|
||||
@@ -444,6 +462,206 @@ FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& lhs, const Option
|
||||
}
|
||||
#endif // FLATBUFFERS_USE_STD_OPTIONAL
|
||||
|
||||
|
||||
// Very limited and naive partial implementation of C++20 std::span<T,Extent>.
|
||||
#if defined(FLATBUFFERS_USE_STD_SPAN)
|
||||
inline constexpr std::size_t dynamic_extent = std::dynamic_extent;
|
||||
template<class T, std::size_t Extent = std::dynamic_extent>
|
||||
using Span = std::span<T, Extent>;
|
||||
|
||||
#else // !defined(FLATBUFFERS_USE_STD_SPAN)
|
||||
FLATBUFFERS_CONSTEXPR std::size_t dynamic_extent = static_cast<std::size_t>(-1);
|
||||
|
||||
// Exclude this code if MSVC2010 or non-STL Android is active.
|
||||
// The non-STL Android doesn't have `std::is_convertible` required for SFINAE.
|
||||
#if !defined(FLATBUFFERS_SPAN_MINIMAL)
|
||||
namespace internal {
|
||||
// This is SFINAE helper class for checking of a common condition:
|
||||
// > This overload only participates in overload resolution
|
||||
// > Check whether a pointer to an array of U can be converted
|
||||
// > to a pointer to an array of E.
|
||||
// This helper is used for checking of 'U -> const U'.
|
||||
template<class E, std::size_t Extent, class U, std::size_t N>
|
||||
struct is_span_convertable {
|
||||
using type =
|
||||
typename std::conditional<std::is_convertible<U (*)[], E (*)[]>::value
|
||||
&& (Extent == dynamic_extent || N == Extent),
|
||||
int, void>::type;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
#endif // !defined(FLATBUFFERS_SPAN_MINIMAL)
|
||||
|
||||
// T - element type; must be a complete type that is not an abstract
|
||||
// class type.
|
||||
// Extent - the number of elements in the sequence, or dynamic.
|
||||
template<class T, std::size_t Extent = dynamic_extent>
|
||||
class span FLATBUFFERS_FINAL_CLASS {
|
||||
public:
|
||||
typedef T element_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
static FLATBUFFERS_CONSTEXPR size_type extent = Extent;
|
||||
|
||||
// Returns the number of elements in the span.
|
||||
FLATBUFFERS_CONSTEXPR_CPP11 size_type size() const FLATBUFFERS_NOEXCEPT {
|
||||
return count_;
|
||||
}
|
||||
|
||||
// Returns the size of the sequence in bytes.
|
||||
FLATBUFFERS_CONSTEXPR_CPP11
|
||||
size_type size_bytes() const FLATBUFFERS_NOEXCEPT {
|
||||
return size() * sizeof(element_type);
|
||||
}
|
||||
|
||||
// Checks if the span is empty.
|
||||
FLATBUFFERS_CONSTEXPR_CPP11 bool empty() const FLATBUFFERS_NOEXCEPT {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
// Returns a pointer to the beginning of the sequence.
|
||||
FLATBUFFERS_CONSTEXPR_CPP11 pointer data() const FLATBUFFERS_NOEXCEPT {
|
||||
return data_;
|
||||
}
|
||||
|
||||
// Returns a reference to the idx-th element of the sequence.
|
||||
// The behavior is undefined if the idx is greater than or equal to size().
|
||||
FLATBUFFERS_CONSTEXPR_CPP11 reference operator[](size_type idx) const {
|
||||
return data()[idx];
|
||||
}
|
||||
|
||||
FLATBUFFERS_CONSTEXPR_CPP11 span(const span &other) FLATBUFFERS_NOEXCEPT
|
||||
: data_(other.data_), count_(other.count_) {}
|
||||
|
||||
FLATBUFFERS_CONSTEXPR_CPP14 span &operator=(const span &other)
|
||||
FLATBUFFERS_NOEXCEPT {
|
||||
data_ = other.data_;
|
||||
count_ = other.count_;
|
||||
}
|
||||
|
||||
// Limited implementation of
|
||||
// `template <class It> constexpr std::span(It first, size_type count);`.
|
||||
//
|
||||
// Constructs a span that is a view over the range [first, first + count);
|
||||
// the resulting span has: data() == first and size() == count.
|
||||
// The behavior is undefined if [first, first + count) is not a valid range,
|
||||
// or if (extent != flatbuffers::dynamic_extent && count != extent).
|
||||
FLATBUFFERS_CONSTEXPR_CPP11
|
||||
explicit span(pointer first, size_type count) FLATBUFFERS_NOEXCEPT
|
||||
: data_ (Extent == dynamic_extent ? first : (Extent == count ? first : nullptr)),
|
||||
count_(Extent == dynamic_extent ? count : (Extent == count ? Extent : 0)) {
|
||||
// Make span empty if the count argument is incompatible with span<T,N>.
|
||||
}
|
||||
|
||||
// Exclude this code if MSVC2010 is active. The MSVC2010 isn't C++11
|
||||
// compliant, it doesn't support default template arguments for functions.
|
||||
#if defined(FLATBUFFERS_SPAN_MINIMAL)
|
||||
FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr),
|
||||
count_(0) {
|
||||
static_assert(extent == 0 || extent == dynamic_extent, "invalid span");
|
||||
}
|
||||
|
||||
#else
|
||||
// Constructs an empty span whose data() == nullptr and size() == 0.
|
||||
// This overload only participates in overload resolution if
|
||||
// extent == 0 || extent == flatbuffers::dynamic_extent.
|
||||
// A dummy template argument N is need dependency for SFINAE.
|
||||
template<std::size_t N = 0,
|
||||
typename internal::is_span_convertable<element_type, Extent, element_type, (N - N)>::type = 0>
|
||||
FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr),
|
||||
count_(0) {
|
||||
static_assert(extent == 0 || extent == dynamic_extent, "invalid span");
|
||||
}
|
||||
|
||||
// Constructs a span that is a view over the array arr; the resulting span
|
||||
// has size() == N and data() == std::data(arr). These overloads only
|
||||
// participate in overload resolution if
|
||||
// extent == std::dynamic_extent || N == extent is true and
|
||||
// std::remove_pointer_t<decltype(std::data(arr))>(*)[]
|
||||
// is convertible to element_type (*)[].
|
||||
template<std::size_t N,
|
||||
typename internal::is_span_convertable<element_type, Extent, element_type, N>::type = 0>
|
||||
FLATBUFFERS_CONSTEXPR_CPP11 span(element_type (&arr)[N]) FLATBUFFERS_NOEXCEPT
|
||||
: data_(arr), count_(N) {}
|
||||
|
||||
template<class U, std::size_t N,
|
||||
typename internal::is_span_convertable<element_type, Extent, U, N>::type = 0>
|
||||
FLATBUFFERS_CONSTEXPR_CPP11 span(std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
|
||||
: data_(arr.data()), count_(N) {}
|
||||
|
||||
//template<class U, std::size_t N,
|
||||
// int = 0>
|
||||
//FLATBUFFERS_CONSTEXPR_CPP11 span(std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
|
||||
// : data_(arr.data()), count_(N) {}
|
||||
|
||||
template<class U, std::size_t N,
|
||||
typename internal::is_span_convertable<element_type, Extent, U, N>::type = 0>
|
||||
FLATBUFFERS_CONSTEXPR_CPP11 span(const std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
|
||||
: data_(arr.data()), count_(N) {}
|
||||
|
||||
// Converting constructor from another span s;
|
||||
// the resulting span has size() == s.size() and data() == s.data().
|
||||
// This overload only participates in overload resolution
|
||||
// if extent == std::dynamic_extent || N == extent is true and U (*)[]
|
||||
// is convertible to element_type (*)[].
|
||||
template<class U, std::size_t N,
|
||||
typename internal::is_span_convertable<element_type, Extent, U, N>::type = 0>
|
||||
FLATBUFFERS_CONSTEXPR_CPP11 span(const flatbuffers::span<U, N> &s) FLATBUFFERS_NOEXCEPT
|
||||
: span(s.data(), s.size()) {
|
||||
}
|
||||
|
||||
#endif // !defined(FLATBUFFERS_SPAN_MINIMAL)
|
||||
|
||||
private:
|
||||
// This is a naive implementation with 'count_' member even if (Extent != dynamic_extent).
|
||||
pointer const data_;
|
||||
const size_type count_;
|
||||
};
|
||||
|
||||
#if !defined(FLATBUFFERS_SPAN_MINIMAL)
|
||||
template<class U, std::size_t N>
|
||||
FLATBUFFERS_CONSTEXPR_CPP11
|
||||
flatbuffers::span<U, N> make_span(U(&arr)[N]) FLATBUFFERS_NOEXCEPT {
|
||||
return span<U, N>(arr);
|
||||
}
|
||||
|
||||
template<class U, std::size_t N>
|
||||
FLATBUFFERS_CONSTEXPR_CPP11
|
||||
flatbuffers::span<const U, N> make_span(const U(&arr)[N]) FLATBUFFERS_NOEXCEPT {
|
||||
return span<const U, N>(arr);
|
||||
}
|
||||
|
||||
template<class U, std::size_t N>
|
||||
FLATBUFFERS_CONSTEXPR_CPP11
|
||||
flatbuffers::span<U, N> make_span(std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
|
||||
return span<U, N>(arr);
|
||||
}
|
||||
|
||||
template<class U, std::size_t N>
|
||||
FLATBUFFERS_CONSTEXPR_CPP11
|
||||
flatbuffers::span<const U, N> make_span(const std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
|
||||
return span<const U, N>(arr);
|
||||
}
|
||||
|
||||
template<class U, std::size_t N>
|
||||
FLATBUFFERS_CONSTEXPR_CPP11
|
||||
flatbuffers::span<U, dynamic_extent> make_span(U *first, std::size_t count) FLATBUFFERS_NOEXCEPT {
|
||||
return span<U, dynamic_extent>(first, count);
|
||||
}
|
||||
|
||||
template<class U, std::size_t N>
|
||||
FLATBUFFERS_CONSTEXPR_CPP11
|
||||
flatbuffers::span<const U, dynamic_extent> make_span(const U *first, std::size_t count) FLATBUFFERS_NOEXCEPT {
|
||||
return span<const U, dynamic_extent>(first, count);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // defined(FLATBUFFERS_USE_STD_SPAN)
|
||||
|
||||
} // namespace flatbuffers
|
||||
|
||||
#endif // FLATBUFFERS_STL_EMULATION_H_
|
||||
|
||||
@@ -72,6 +72,12 @@ namespace cpp {
|
||||
|
||||
enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 };
|
||||
|
||||
// Define a style of 'struct' constructor if it has 'Array' fields.
|
||||
enum GenArrayArgMode {
|
||||
kArrayArgModeNone, // don't generate initialization args
|
||||
kArrayArgModeSpanStatic, // generate flatbuffers::span<T,N>
|
||||
};
|
||||
|
||||
// Extension of IDLOptions for cpp-generator.
|
||||
struct IDLOptionsCpp : public IDLOptions {
|
||||
// All fields start with 'g_' prefix to distinguish from the base IDLOptions.
|
||||
@@ -820,6 +826,38 @@ class CppGenerator : public BaseGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
std::string GenTypeSpan(const Type &type, bool immutable, size_t extent) {
|
||||
// Generate "flatbuffers::span<const U, extent>".
|
||||
FLATBUFFERS_ASSERT(IsSeries(type) && "unexpected type");
|
||||
auto element_type = type.VectorType();
|
||||
std::string text = "flatbuffers::span<";
|
||||
text += immutable ? "const " : "";
|
||||
if (IsScalar(element_type.base_type)) {
|
||||
text += GenTypeBasic(element_type, IsEnum(element_type));
|
||||
} else {
|
||||
switch (element_type.base_type) {
|
||||
case BASE_TYPE_STRING: {
|
||||
text += "char";
|
||||
break;
|
||||
}
|
||||
case BASE_TYPE_STRUCT: {
|
||||
FLATBUFFERS_ASSERT(type.struct_def);
|
||||
text += WrapInNameSpace(*type.struct_def);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
FLATBUFFERS_ASSERT(false && "unexpected element's type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (extent != flatbuffers::dynamic_extent) {
|
||||
text += ", ";
|
||||
text += NumToString(extent);
|
||||
}
|
||||
text += "> ";
|
||||
return text;
|
||||
}
|
||||
|
||||
std::string GenEnumValDecl(const EnumDef &enum_def,
|
||||
const std::string &enum_val) const {
|
||||
return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
|
||||
@@ -2938,13 +2976,14 @@ class CppGenerator : public BaseGenerator {
|
||||
|
||||
static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
|
||||
(void)bits;
|
||||
if (*code_ptr != "") *code_ptr += ",\n ";
|
||||
if (!code_ptr->empty()) *code_ptr += ",\n ";
|
||||
*code_ptr += "padding" + NumToString((*id)++) + "__(0)";
|
||||
}
|
||||
|
||||
static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
|
||||
(void)bits;
|
||||
*code_ptr += " (void)padding" + NumToString((*id)++) + "__;\n";
|
||||
if (!code_ptr->empty()) *code_ptr += '\n';
|
||||
*code_ptr += " (void)padding" + NumToString((*id)++) + "__;";
|
||||
}
|
||||
|
||||
void GenStructDefaultConstructor(const StructDef &struct_def) {
|
||||
@@ -2989,58 +3028,50 @@ class CppGenerator : public BaseGenerator {
|
||||
code_ += " {}";
|
||||
} else {
|
||||
code_.SetValue("INIT_LIST", init_list);
|
||||
code_.SetValue("DEFAULT_CONSTRUCTOR_BODY", body);
|
||||
code_ += " {{STRUCT_NAME}}()";
|
||||
code_ += " : {{INIT_LIST}} {";
|
||||
code_ += "{{DEFAULT_CONSTRUCTOR_BODY}} }";
|
||||
if (!body.empty()) { code_ += body; }
|
||||
code_ += " }";
|
||||
}
|
||||
}
|
||||
|
||||
void GenStructConstructor(const StructDef &struct_def) {
|
||||
void GenStructConstructor(const StructDef &struct_def,
|
||||
GenArrayArgMode array_mode) {
|
||||
std::string arg_list;
|
||||
std::string init_list;
|
||||
int padding_id = 0;
|
||||
bool first_arg = true;
|
||||
bool first_init = true;
|
||||
auto first = struct_def.fields.vec.begin();
|
||||
// skip arrays if generate ctor without array assignment
|
||||
const auto init_arrays = (array_mode != kArrayArgModeNone);
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
const auto &field = **it;
|
||||
const auto &field_type = field.value.type;
|
||||
const auto member_name = Name(field) + "_";
|
||||
const auto &type = field.value.type;
|
||||
const auto is_array = IsArray(type);
|
||||
const auto arg_name = "_" + Name(field);
|
||||
const auto arg_type = GenTypeGet(field_type, " ", "const ", " &", true);
|
||||
|
||||
if (!IsArray(field_type)) {
|
||||
if (first_arg) {
|
||||
first_arg = false;
|
||||
} else {
|
||||
arg_list += ", ";
|
||||
}
|
||||
arg_list += arg_type;
|
||||
if (!is_array || init_arrays) {
|
||||
if (it != first && !arg_list.empty()) { arg_list += ", "; }
|
||||
arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true)
|
||||
: GenTypeSpan(type, true, type.fixed_length);
|
||||
arg_list += arg_name;
|
||||
}
|
||||
if (first_init) {
|
||||
first_init = false;
|
||||
} else {
|
||||
init_list += ",";
|
||||
init_list += "\n ";
|
||||
// skip an array with initialization from span
|
||||
if (false == (is_array && init_arrays)) {
|
||||
if (it != first && !init_list.empty()) { init_list += ",\n "; }
|
||||
init_list += Name(field) + "_";
|
||||
if (IsScalar(type.base_type)) {
|
||||
auto scalar_type = GenUnderlyingCast(field, false, arg_name);
|
||||
init_list += "(flatbuffers::EndianScalar(" + scalar_type + "))";
|
||||
} else {
|
||||
FLATBUFFERS_ASSERT((is_array && !init_arrays) || IsStruct(type));
|
||||
if (!is_array)
|
||||
init_list += "(" + arg_name + ")";
|
||||
else
|
||||
init_list += "()";
|
||||
}
|
||||
}
|
||||
init_list += member_name;
|
||||
if (IsScalar(field_type.base_type)) {
|
||||
auto type = GenUnderlyingCast(field, false, arg_name);
|
||||
init_list += "(flatbuffers::EndianScalar(" + type + "))";
|
||||
} else if (IsArray(field_type)) {
|
||||
// implicit initialization of array
|
||||
// for each object in array it:
|
||||
// * sets it as zeros for POD types (integral, floating point, etc)
|
||||
// * calls default constructor for classes/structs
|
||||
init_list += "()";
|
||||
} else {
|
||||
init_list += "(" + arg_name + ")";
|
||||
}
|
||||
if (field.padding) {
|
||||
if (field.padding)
|
||||
GenPadding(field, &init_list, &padding_id, PaddingInitializer);
|
||||
}
|
||||
}
|
||||
|
||||
if (!arg_list.empty()) {
|
||||
@@ -3052,10 +3083,55 @@ class CppGenerator : public BaseGenerator {
|
||||
} else {
|
||||
code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
|
||||
}
|
||||
padding_id = 0;
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
const auto &field = **it;
|
||||
const auto &type = field.value.type;
|
||||
if (IsArray(type) && init_arrays) {
|
||||
const auto &element_type = type.VectorType();
|
||||
const auto is_enum = IsEnum(element_type);
|
||||
FLATBUFFERS_ASSERT(
|
||||
(IsScalar(element_type.base_type) || IsStruct(element_type)) &&
|
||||
"invalid declaration");
|
||||
const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
|
||||
std::string get_array =
|
||||
is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
|
||||
const auto field_name = Name(field) + "_";
|
||||
const auto arg_name = "_" + Name(field);
|
||||
code_ += " flatbuffers::" + get_array + "(" + field_name +
|
||||
").CopyFromSpan(" + arg_name + ");";
|
||||
}
|
||||
if (field.padding) {
|
||||
std::string padding;
|
||||
GenPadding(field, &padding, &padding_id, PaddingNoop);
|
||||
code_ += padding;
|
||||
}
|
||||
}
|
||||
code_ += " }";
|
||||
}
|
||||
}
|
||||
|
||||
void GenArrayAccessor(const Type &type, bool mutable_accessor) {
|
||||
FLATBUFFERS_ASSERT(IsArray(type));
|
||||
const auto is_enum = IsEnum(type.VectorType());
|
||||
// The Array<bool,N> is a tricky case, like std::vector<bool>.
|
||||
// It requires a specialization of Array class.
|
||||
// Generate Array<uint8_t> for Array<bool>.
|
||||
const auto face_type = GenTypeGet(type, " ", "", "", is_enum);
|
||||
std::string ret_type = "flatbuffers::Array<" + face_type + ", " +
|
||||
NumToString(type.fixed_length) + ">";
|
||||
if (mutable_accessor)
|
||||
code_ += " " + ret_type + " *mutable_{{FIELD_NAME}}() {";
|
||||
else
|
||||
code_ += " const " + ret_type + " *{{FIELD_NAME}}() const {";
|
||||
|
||||
std::string get_array =
|
||||
is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray";
|
||||
code_ += " return &flatbuffers::" + get_array + "({{FIELD_VALUE}});";
|
||||
code_ += " }";
|
||||
}
|
||||
|
||||
// Generate an accessor struct with constructor for a flatbuffers struct.
|
||||
void GenStruct(const StructDef &struct_def) {
|
||||
// Generate an accessor struct, with private variables of the form:
|
||||
@@ -3110,19 +3186,29 @@ class CppGenerator : public BaseGenerator {
|
||||
GenStructDefaultConstructor(struct_def);
|
||||
|
||||
// Generate a constructor that takes all fields as arguments,
|
||||
// excluding arrays
|
||||
GenStructConstructor(struct_def);
|
||||
// excluding arrays.
|
||||
GenStructConstructor(struct_def, kArrayArgModeNone);
|
||||
|
||||
auto arrays_num = std::count_if(struct_def.fields.vec.begin(),
|
||||
struct_def.fields.vec.end(),
|
||||
[](const flatbuffers::FieldDef *fd) {
|
||||
return IsArray(fd->value.type);
|
||||
});
|
||||
if (arrays_num > 0) {
|
||||
GenStructConstructor(struct_def, kArrayArgModeSpanStatic);
|
||||
}
|
||||
|
||||
// Generate accessor methods of the form:
|
||||
// type name() const { return flatbuffers::EndianScalar(name_); }
|
||||
for (auto it = struct_def.fields.vec.begin();
|
||||
it != struct_def.fields.vec.end(); ++it) {
|
||||
const auto &field = **it;
|
||||
const auto &type = field.value.type;
|
||||
const auto is_scalar = IsScalar(type.base_type);
|
||||
const auto is_array = IsArray(type);
|
||||
|
||||
auto field_type = GenTypeGet(field.value.type, " ",
|
||||
IsArray(field.value.type) ? "" : "const ",
|
||||
IsArray(field.value.type) ? "" : " &", true);
|
||||
auto is_scalar = IsScalar(field.value.type.base_type);
|
||||
const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ",
|
||||
is_array ? "" : " &", true);
|
||||
auto member = Name(field) + "_";
|
||||
auto value =
|
||||
is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
|
||||
@@ -3134,16 +3220,8 @@ class CppGenerator : public BaseGenerator {
|
||||
GenComment(field.doc_comment, " ");
|
||||
|
||||
// Generate a const accessor function.
|
||||
if (IsArray(field.value.type)) {
|
||||
auto underlying = GenTypeGet(field.value.type, "", "", "", false);
|
||||
code_ += " const flatbuffers::Array<" + field_type + ", " +
|
||||
NumToString(field.value.type.fixed_length) + "> *" +
|
||||
"{{FIELD_NAME}}() const {";
|
||||
code_ += " return reinterpret_cast<const flatbuffers::Array<" +
|
||||
field_type + ", " +
|
||||
NumToString(field.value.type.fixed_length) +
|
||||
"> *>({{FIELD_VALUE}});";
|
||||
code_ += " }";
|
||||
if (is_array) {
|
||||
GenArrayAccessor(type, false);
|
||||
} else {
|
||||
code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
|
||||
code_ += " return {{FIELD_VALUE}};";
|
||||
@@ -3153,11 +3231,10 @@ class CppGenerator : public BaseGenerator {
|
||||
// Generate a mutable accessor function.
|
||||
if (opts_.mutable_buffer) {
|
||||
auto mut_field_type =
|
||||
GenTypeGet(field.value.type, " ", "",
|
||||
IsArray(field.value.type) ? "" : " &", true);
|
||||
GenTypeGet(type, " ", "", is_array ? "" : " &", true);
|
||||
code_.SetValue("FIELD_TYPE", mut_field_type);
|
||||
if (is_scalar) {
|
||||
code_.SetValue("ARG", GenTypeBasic(field.value.type, true));
|
||||
code_.SetValue("ARG", GenTypeBasic(type, true));
|
||||
code_.SetValue("FIELD_VALUE",
|
||||
GenUnderlyingCast(field, false, "_" + Name(field)));
|
||||
|
||||
@@ -3166,16 +3243,8 @@ class CppGenerator : public BaseGenerator {
|
||||
" flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
|
||||
"{{FIELD_VALUE}});";
|
||||
code_ += " }";
|
||||
} else if (IsArray(field.value.type)) {
|
||||
auto underlying = GenTypeGet(field.value.type, "", "", "", false);
|
||||
code_ += " flatbuffers::Array<" + mut_field_type + ", " +
|
||||
NumToString(field.value.type.fixed_length) + "> *" +
|
||||
"mutable_{{FIELD_NAME}}() {";
|
||||
code_ += " return reinterpret_cast<flatbuffers::Array<" +
|
||||
mut_field_type + ", " +
|
||||
NumToString(field.value.type.fixed_length) +
|
||||
"> *>({{FIELD_VALUE}});";
|
||||
code_ += " }";
|
||||
} else if (is_array) {
|
||||
GenArrayAccessor(type, true);
|
||||
} else {
|
||||
code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
|
||||
code_ += " return {{FIELD_VALUE}};";
|
||||
|
||||
@@ -92,12 +92,24 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) NestedStruct FLATBUFFERS_FINAL_CLASS {
|
||||
padding0__(0),
|
||||
padding1__(0),
|
||||
d_() {
|
||||
(void)padding0__;
|
||||
(void)padding1__;
|
||||
}
|
||||
NestedStruct(flatbuffers::span<const int32_t, 2> _a, MyGame::Example::TestEnum _b, flatbuffers::span<const MyGame::Example::TestEnum, 2> _c, flatbuffers::span<const int64_t, 2> _d)
|
||||
: b_(flatbuffers::EndianScalar(static_cast<int8_t>(_b))),
|
||||
padding0__(0),
|
||||
padding1__(0) {
|
||||
flatbuffers::CastToArray(a_).CopyFromSpan(_a);
|
||||
flatbuffers::CastToArrayOfEnum<MyGame::Example::TestEnum>(c_).CopyFromSpan(_c);
|
||||
(void)padding0__;
|
||||
(void)padding1__;
|
||||
flatbuffers::CastToArray(d_).CopyFromSpan(_d);
|
||||
}
|
||||
const flatbuffers::Array<int32_t, 2> *a() const {
|
||||
return reinterpret_cast<const flatbuffers::Array<int32_t, 2> *>(a_);
|
||||
return &flatbuffers::CastToArray(a_);
|
||||
}
|
||||
flatbuffers::Array<int32_t, 2> *mutable_a() {
|
||||
return reinterpret_cast<flatbuffers::Array<int32_t, 2> *>(a_);
|
||||
return &flatbuffers::CastToArray(a_);
|
||||
}
|
||||
MyGame::Example::TestEnum b() const {
|
||||
return static_cast<MyGame::Example::TestEnum>(flatbuffers::EndianScalar(b_));
|
||||
@@ -106,16 +118,16 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) NestedStruct FLATBUFFERS_FINAL_CLASS {
|
||||
flatbuffers::WriteScalar(&b_, static_cast<int8_t>(_b));
|
||||
}
|
||||
const flatbuffers::Array<MyGame::Example::TestEnum, 2> *c() const {
|
||||
return reinterpret_cast<const flatbuffers::Array<MyGame::Example::TestEnum, 2> *>(c_);
|
||||
return &flatbuffers::CastToArrayOfEnum<MyGame::Example::TestEnum>(c_);
|
||||
}
|
||||
flatbuffers::Array<MyGame::Example::TestEnum, 2> *mutable_c() {
|
||||
return reinterpret_cast<flatbuffers::Array<MyGame::Example::TestEnum, 2> *>(c_);
|
||||
return &flatbuffers::CastToArrayOfEnum<MyGame::Example::TestEnum>(c_);
|
||||
}
|
||||
const flatbuffers::Array<int64_t, 2> *d() const {
|
||||
return reinterpret_cast<const flatbuffers::Array<int64_t, 2> *>(d_);
|
||||
return &flatbuffers::CastToArray(d_);
|
||||
}
|
||||
flatbuffers::Array<int64_t, 2> *mutable_d() {
|
||||
return reinterpret_cast<flatbuffers::Array<int64_t, 2> *>(d_);
|
||||
return &flatbuffers::CastToArray(d_);
|
||||
}
|
||||
};
|
||||
FLATBUFFERS_STRUCT_END(NestedStruct, 32);
|
||||
@@ -175,6 +187,26 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) ArrayStruct FLATBUFFERS_FINAL_CLASS {
|
||||
e_(flatbuffers::EndianScalar(_e)),
|
||||
padding3__(0),
|
||||
f_() {
|
||||
(void)padding0__;
|
||||
(void)padding1__;
|
||||
(void)padding2__;
|
||||
(void)padding3__;
|
||||
}
|
||||
ArrayStruct(float _a, flatbuffers::span<const int32_t, 15> _b, int8_t _c, flatbuffers::span<const MyGame::Example::NestedStruct, 2> _d, int32_t _e, flatbuffers::span<const int64_t, 2> _f)
|
||||
: a_(flatbuffers::EndianScalar(_a)),
|
||||
c_(flatbuffers::EndianScalar(_c)),
|
||||
padding0__(0),
|
||||
padding1__(0),
|
||||
padding2__(0),
|
||||
e_(flatbuffers::EndianScalar(_e)),
|
||||
padding3__(0) {
|
||||
flatbuffers::CastToArray(b_).CopyFromSpan(_b);
|
||||
(void)padding0__;
|
||||
(void)padding1__;
|
||||
(void)padding2__;
|
||||
flatbuffers::CastToArray(d_).CopyFromSpan(_d);
|
||||
(void)padding3__;
|
||||
flatbuffers::CastToArray(f_).CopyFromSpan(_f);
|
||||
}
|
||||
float a() const {
|
||||
return flatbuffers::EndianScalar(a_);
|
||||
@@ -183,10 +215,10 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) ArrayStruct FLATBUFFERS_FINAL_CLASS {
|
||||
flatbuffers::WriteScalar(&a_, _a);
|
||||
}
|
||||
const flatbuffers::Array<int32_t, 15> *b() const {
|
||||
return reinterpret_cast<const flatbuffers::Array<int32_t, 15> *>(b_);
|
||||
return &flatbuffers::CastToArray(b_);
|
||||
}
|
||||
flatbuffers::Array<int32_t, 15> *mutable_b() {
|
||||
return reinterpret_cast<flatbuffers::Array<int32_t, 15> *>(b_);
|
||||
return &flatbuffers::CastToArray(b_);
|
||||
}
|
||||
int8_t c() const {
|
||||
return flatbuffers::EndianScalar(c_);
|
||||
@@ -195,10 +227,10 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) ArrayStruct FLATBUFFERS_FINAL_CLASS {
|
||||
flatbuffers::WriteScalar(&c_, _c);
|
||||
}
|
||||
const flatbuffers::Array<MyGame::Example::NestedStruct, 2> *d() const {
|
||||
return reinterpret_cast<const flatbuffers::Array<MyGame::Example::NestedStruct, 2> *>(d_);
|
||||
return &flatbuffers::CastToArray(d_);
|
||||
}
|
||||
flatbuffers::Array<MyGame::Example::NestedStruct, 2> *mutable_d() {
|
||||
return reinterpret_cast<flatbuffers::Array<MyGame::Example::NestedStruct, 2> *>(d_);
|
||||
return &flatbuffers::CastToArray(d_);
|
||||
}
|
||||
int32_t e() const {
|
||||
return flatbuffers::EndianScalar(e_);
|
||||
@@ -207,10 +239,10 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) ArrayStruct FLATBUFFERS_FINAL_CLASS {
|
||||
flatbuffers::WriteScalar(&e_, _e);
|
||||
}
|
||||
const flatbuffers::Array<int64_t, 2> *f() const {
|
||||
return reinterpret_cast<const flatbuffers::Array<int64_t, 2> *>(f_);
|
||||
return &flatbuffers::CastToArray(f_);
|
||||
}
|
||||
flatbuffers::Array<int64_t, 2> *mutable_f() {
|
||||
return reinterpret_cast<flatbuffers::Array<int64_t, 2> *>(f_);
|
||||
return &flatbuffers::CastToArray(f_);
|
||||
}
|
||||
};
|
||||
FLATBUFFERS_STRUCT_END(ArrayStruct, 160);
|
||||
|
||||
@@ -487,6 +487,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS {
|
||||
: a_(flatbuffers::EndianScalar(_a)),
|
||||
b_(flatbuffers::EndianScalar(_b)),
|
||||
padding0__(0) {
|
||||
(void)padding0__;
|
||||
}
|
||||
int16_t a() const {
|
||||
return flatbuffers::EndianScalar(a_);
|
||||
@@ -543,6 +544,9 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Vec3 FLATBUFFERS_FINAL_CLASS {
|
||||
padding1__(0),
|
||||
test3_(_test3),
|
||||
padding2__(0) {
|
||||
(void)padding0__;
|
||||
(void)padding1__;
|
||||
(void)padding2__;
|
||||
}
|
||||
float x() const {
|
||||
return flatbuffers::EndianScalar(x_);
|
||||
|
||||
@@ -115,6 +115,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Struct FLATBUFFERS_FINAL_CLASS {
|
||||
: a_(flatbuffers::EndianScalar(_a)),
|
||||
padding0__(0),
|
||||
b_(flatbuffers::EndianScalar(_b)) {
|
||||
(void)padding0__;
|
||||
}
|
||||
int32_t a() const {
|
||||
return flatbuffers::EndianScalar(a_);
|
||||
|
||||
@@ -131,6 +131,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Struct FLATBUFFERS_FINAL_CLASS {
|
||||
: a_(flatbuffers::EndianScalar(_a)),
|
||||
padding0__(0),
|
||||
b_(flatbuffers::EndianScalar(_b)) {
|
||||
(void)padding0__;
|
||||
}
|
||||
int32_t a() const {
|
||||
return flatbuffers::EndianScalar(a_);
|
||||
|
||||
@@ -602,6 +602,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS {
|
||||
: a_(flatbuffers::EndianScalar(_a)),
|
||||
b_(flatbuffers::EndianScalar(_b)),
|
||||
padding0__(0) {
|
||||
(void)padding0__;
|
||||
}
|
||||
int16_t a() const {
|
||||
return flatbuffers::EndianScalar(a_);
|
||||
@@ -669,6 +670,9 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Vec3 FLATBUFFERS_FINAL_CLASS {
|
||||
padding1__(0),
|
||||
test3_(_test3),
|
||||
padding2__(0) {
|
||||
(void)padding0__;
|
||||
(void)padding1__;
|
||||
(void)padding2__;
|
||||
}
|
||||
float x() const {
|
||||
return flatbuffers::EndianScalar(x_);
|
||||
|
||||
136
tests/test.cpp
136
tests/test.cpp
@@ -3214,6 +3214,89 @@ void CreateSharedStringTest() {
|
||||
TEST_EQ((*a[6]) < (*a[5]), true);
|
||||
}
|
||||
|
||||
#if !defined(FLATBUFFERS_SPAN_MINIMAL)
|
||||
void FlatbuffersSpanTest() {
|
||||
// Compile-time checking of non-const [] to const [] conversions.
|
||||
using flatbuffers::internal::is_span_convertable;
|
||||
(void)is_span_convertable<int, 1, int, 1>::type(123);
|
||||
(void)is_span_convertable<const int, 1, int, 1>::type(123);
|
||||
(void)is_span_convertable<const int64_t, 1, int64_t, 1>::type(123);
|
||||
(void)is_span_convertable<const uint64_t, 1, uint64_t, 1>::type(123);
|
||||
(void)is_span_convertable<const int, 1, const int, 1>::type(123);
|
||||
(void)is_span_convertable<const int64_t, 1, const int64_t, 1>::type(123);
|
||||
(void)is_span_convertable<const uint64_t, 1, const uint64_t, 1>::type(123);
|
||||
|
||||
using flatbuffers::span;
|
||||
span<char, 0> c1;
|
||||
TEST_EQ(c1.size(), 0);
|
||||
span<char, flatbuffers::dynamic_extent> c2;
|
||||
TEST_EQ(c2.size(), 0);
|
||||
span<char> c3;
|
||||
TEST_EQ(c3.size(), 0);
|
||||
TEST_ASSERT(c1.empty() && c2.empty() && c3.empty());
|
||||
|
||||
int i_data7[7] = { 0, 1, 2, 3, 4, 5, 6 };
|
||||
span<int, 7> i1(&i_data7[0], 7);
|
||||
span<int> i2(i1); // make dynamic from static
|
||||
TEST_EQ(i1.size(), 7);
|
||||
TEST_EQ(i1.empty(), false);
|
||||
TEST_EQ(i1.size(), i2.size());
|
||||
TEST_EQ(i1.data(), i_data7);
|
||||
TEST_EQ(i1[2], 2);
|
||||
// Make const span from a non-const one.
|
||||
span<const int, 7> i3(i1);
|
||||
// Construct from a C-array.
|
||||
span<int, 7> i4(i_data7);
|
||||
span<const int, 7> i5(i_data7);
|
||||
span<int> i6(i_data7);
|
||||
span<const int> i7(i_data7);
|
||||
TEST_EQ(i7.size(), 7);
|
||||
// Check construction from a const array.
|
||||
const int i_cdata5[5] = { 4, 3, 2, 1, 0 };
|
||||
span<const int, 5> i8(i_cdata5);
|
||||
span<const int> i9(i_cdata5);
|
||||
TEST_EQ(i9.size(), 5);
|
||||
// Construction from a (ptr, size) pair.
|
||||
span<int, 7> i10(i_data7, 7);
|
||||
span<int> i11(i_data7, 7);
|
||||
TEST_EQ(i11.size(), 7);
|
||||
span<const int, 5> i12(i_cdata5, 5);
|
||||
span<const int> i13(i_cdata5, 5);
|
||||
TEST_EQ(i13.size(), 5);
|
||||
// Construction from std::array.
|
||||
std::array<int, 6> i_arr6 = { { 0, 1, 2, 3, 4, 5 } };
|
||||
span<int, 6> i14(i_arr6);
|
||||
span<const int, 6> i15(i_arr6);
|
||||
span<int> i16(i_arr6);
|
||||
span<const int> i17(i_arr6);
|
||||
TEST_EQ(i17.size(), 6);
|
||||
const std::array<int, 8> i_carr8 = { { 0, 1, 2, 3, 4, 5, 6, 7 } };
|
||||
span<const int, 8> i18(i_carr8);
|
||||
span<const int> i19(i_carr8);
|
||||
TEST_EQ(i18.size(), 8);
|
||||
TEST_EQ(i19.size(), 8);
|
||||
TEST_EQ(i19[7], 7);
|
||||
// Check compatibility with flatbuffers::Array.
|
||||
int fbs_int3_underlaying[3] = { 0 };
|
||||
int fbs_int3_data[3] = { 1, 2, 3 };
|
||||
auto &fbs_int3 = flatbuffers::CastToArray(fbs_int3_underlaying);
|
||||
fbs_int3.CopyFromSpan(fbs_int3_data);
|
||||
TEST_EQ(fbs_int3.Get(1), 2);
|
||||
const int fbs_cint3_data[3] = { 2, 3, 4 };
|
||||
fbs_int3.CopyFromSpan(fbs_cint3_data);
|
||||
TEST_EQ(fbs_int3.Get(1), 3);
|
||||
// Check with Array<Enum, N>
|
||||
enum class Dummy : uint16_t { Zero = 0, One, Two };
|
||||
Dummy fbs_dummy3_underlaying[3] = {};
|
||||
Dummy fbs_dummy3_data[3] = { Dummy::One, Dummy::Two, Dummy::Two };
|
||||
auto &fbs_dummy3 = flatbuffers::CastToArray(fbs_dummy3_underlaying);
|
||||
fbs_dummy3.CopyFromSpan(fbs_dummy3_data);
|
||||
TEST_EQ(fbs_dummy3.Get(1), Dummy::Two);
|
||||
}
|
||||
#else
|
||||
void FlatbuffersSpanTest() {}
|
||||
#endif
|
||||
|
||||
void FixedLengthArrayTest() {
|
||||
// VS10 does not support typed enums, exclude from tests
|
||||
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
||||
@@ -3322,6 +3405,57 @@ void FixedLengthArrayTest() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(FLATBUFFERS_SPAN_MINIMAL) && (!defined(_MSC_VER) || _MSC_VER >= 1700)
|
||||
void FixedLengthArrayConstructorTest() {
|
||||
const int32_t nested_a[2] = { 1, 2 };
|
||||
MyGame::Example::TestEnum nested_c[2] = { MyGame::Example::TestEnum::A,
|
||||
MyGame::Example::TestEnum::B };
|
||||
const int64_t int64_2[2] = { -2, -1 };
|
||||
|
||||
std::array<MyGame::Example::NestedStruct, 2> init_d = {
|
||||
{ MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::B,
|
||||
nested_c, int64_2),
|
||||
MyGame::Example::NestedStruct(nested_a, MyGame::Example::TestEnum::A,
|
||||
nested_c,
|
||||
std::array<int64_t, 2>{ { 12, 13 } }) }
|
||||
};
|
||||
|
||||
MyGame::Example::ArrayStruct arr_struct(
|
||||
8.125,
|
||||
std::array<int32_t, 0xF>{
|
||||
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } },
|
||||
-17, init_d, 10, int64_2);
|
||||
TEST_EQ(arr_struct.a(), 8.125);
|
||||
TEST_EQ(arr_struct.b()->Get(2), 3);
|
||||
TEST_EQ(arr_struct.c(), -17);
|
||||
|
||||
TEST_NOTNULL(arr_struct.d());
|
||||
const auto &arr_d_0 = *arr_struct.d()->Get(0);
|
||||
TEST_EQ(arr_d_0.a()->Get(0), 1);
|
||||
TEST_EQ(arr_d_0.a()->Get(1), 2);
|
||||
TEST_EQ(arr_d_0.b(), MyGame::Example::TestEnum::B);
|
||||
TEST_EQ(arr_d_0.c()->Get(0), MyGame::Example::TestEnum::A);
|
||||
TEST_EQ(arr_d_0.c()->Get(1), MyGame::Example::TestEnum::B);
|
||||
TEST_EQ(arr_d_0.d()->Get(0), -2);
|
||||
TEST_EQ(arr_d_0.d()->Get(1), -1);
|
||||
const auto &arr_d_1 = *arr_struct.d()->Get(1);
|
||||
TEST_EQ(arr_d_1.a()->Get(0), 1);
|
||||
TEST_EQ(arr_d_1.a()->Get(1), 2);
|
||||
TEST_EQ(arr_d_1.b(), MyGame::Example::TestEnum::A);
|
||||
TEST_EQ(arr_d_1.c()->Get(0), MyGame::Example::TestEnum::A);
|
||||
TEST_EQ(arr_d_1.c()->Get(1), MyGame::Example::TestEnum::B);
|
||||
TEST_EQ(arr_d_1.d()->Get(0), 12);
|
||||
TEST_EQ(arr_d_1.d()->Get(1), 13);
|
||||
|
||||
TEST_EQ(arr_struct.e(), 10);
|
||||
TEST_EQ(arr_struct.f()->Get(0), -2);
|
||||
TEST_EQ(arr_struct.f()->Get(1), -1);
|
||||
}
|
||||
#else
|
||||
void FixedLengthArrayConstructorTest() {
|
||||
}
|
||||
#endif
|
||||
|
||||
void NativeTypeTest() {
|
||||
const int N = 3;
|
||||
|
||||
@@ -3666,6 +3800,8 @@ int FlatBufferTests() {
|
||||
NativeTypeTest();
|
||||
OptionalScalarsTest();
|
||||
ParseFlexbuffersFromJsonWithNullTest();
|
||||
FlatbuffersSpanTest();
|
||||
FixedLengthArrayConstructorTest();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user