mirror of
https://github.com/google/flatbuffers.git
synced 2026-07-04 10:31:11 +00:00
- 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
|
#define FLATBUFFERS_CONSTEXPR_CPP11
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This macro is never used in code!
|
|
||||||
#if (defined(__cplusplus) && __cplusplus >= 201402L) || \
|
#if (defined(__cplusplus) && __cplusplus >= 201402L) || \
|
||||||
(defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
|
(defined(__cpp_constexpr) && __cpp_constexpr >= 201304)
|
||||||
#define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR
|
#define FLATBUFFERS_CONSTEXPR_CPP14 FLATBUFFERS_CONSTEXPR_CPP11
|
||||||
#else
|
#else
|
||||||
#define FLATBUFFERS_CONSTEXPR_CPP14
|
#define FLATBUFFERS_CONSTEXPR_CPP14
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -435,6 +435,7 @@ template<typename T, uint16_t length> class Array {
|
|||||||
IndirectHelperType;
|
IndirectHelperType;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef uint16_t size_type;
|
||||||
typedef typename IndirectHelper<IndirectHelperType>::return_type return_type;
|
typedef typename IndirectHelper<IndirectHelperType>::return_type return_type;
|
||||||
typedef VectorIterator<T, return_type> const_iterator;
|
typedef VectorIterator<T, return_type> const_iterator;
|
||||||
typedef VectorReverseIterator<const_iterator> const_reverse_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()); }
|
const T *data() const { return reinterpret_cast<const T *>(Data()); }
|
||||||
T *data() { return reinterpret_cast<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:
|
protected:
|
||||||
void MutateImpl(flatbuffers::integral_constant<bool, true>, uoffset_t i,
|
void MutateImpl(flatbuffers::integral_constant<bool, true>, uoffset_t i,
|
||||||
const T &val) {
|
const T &val) {
|
||||||
@@ -504,6 +521,20 @@ template<typename T, uint16_t length> class Array {
|
|||||||
*(GetMutablePointer(i)) = val;
|
*(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
|
// This class is only used to access pre-existing data. Don't ever
|
||||||
// try to construct these manually.
|
// try to construct these manually.
|
||||||
// 'constexpr' allows us to use 'size()' at compile time.
|
// '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];
|
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
|
// Lexicographically compare two strings (possibly containing nulls), and
|
||||||
// return true if the first is less than the second.
|
// return true if the first is less than the second.
|
||||||
static inline bool StringLessThan(const char *a_data, uoffset_t a_size,
|
static inline bool StringLessThan(const char *a_data, uoffset_t a_size,
|
||||||
|
|||||||
@@ -26,6 +26,14 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <limits>
|
#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.
|
// Detect C++17 compatible compiler.
|
||||||
// __cplusplus >= 201703L - a compiler has support of 'static inline' variables.
|
// __cplusplus >= 201703L - a compiler has support of 'static inline' variables.
|
||||||
#if defined(FLATBUFFERS_USE_STD_OPTIONAL) \
|
#if defined(FLATBUFFERS_USE_STD_OPTIONAL) \
|
||||||
@@ -35,15 +43,25 @@
|
|||||||
#ifndef FLATBUFFERS_USE_STD_OPTIONAL
|
#ifndef FLATBUFFERS_USE_STD_OPTIONAL
|
||||||
#define FLATBUFFERS_USE_STD_OPTIONAL
|
#define FLATBUFFERS_USE_STD_OPTIONAL
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif // defined(FLATBUFFERS_USE_STD_OPTIONAL) ...
|
||||||
|
|
||||||
#if defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
|
// The __cpp_lib_span is the predefined feature macro.
|
||||||
#define FLATBUFFERS_CPP98_STL
|
#if defined(FLATBUFFERS_USE_STD_SPAN)
|
||||||
#endif // defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
|
#include <span>
|
||||||
|
#elif defined(__cpp_lib_span) && defined(__has_include)
|
||||||
#if defined(FLATBUFFERS_CPP98_STL)
|
#if __has_include(<span>)
|
||||||
#include <cctype>
|
#include <span>
|
||||||
#endif // defined(FLATBUFFERS_CPP98_STL)
|
#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.
|
// This header provides backwards compatibility for C++98 STLs like stlport.
|
||||||
namespace flatbuffers {
|
namespace flatbuffers {
|
||||||
@@ -444,6 +462,206 @@ FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& lhs, const Option
|
|||||||
}
|
}
|
||||||
#endif // FLATBUFFERS_USE_STD_OPTIONAL
|
#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
|
} // namespace flatbuffers
|
||||||
|
|
||||||
#endif // FLATBUFFERS_STL_EMULATION_H_
|
#endif // FLATBUFFERS_STL_EMULATION_H_
|
||||||
|
|||||||
@@ -72,6 +72,12 @@ namespace cpp {
|
|||||||
|
|
||||||
enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 };
|
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.
|
// Extension of IDLOptions for cpp-generator.
|
||||||
struct IDLOptionsCpp : public IDLOptions {
|
struct IDLOptionsCpp : public IDLOptions {
|
||||||
// All fields start with 'g_' prefix to distinguish from the base 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,
|
std::string GenEnumValDecl(const EnumDef &enum_def,
|
||||||
const std::string &enum_val) const {
|
const std::string &enum_val) const {
|
||||||
return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
|
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) {
|
static void PaddingInitializer(int bits, std::string *code_ptr, int *id) {
|
||||||
(void)bits;
|
(void)bits;
|
||||||
if (*code_ptr != "") *code_ptr += ",\n ";
|
if (!code_ptr->empty()) *code_ptr += ",\n ";
|
||||||
*code_ptr += "padding" + NumToString((*id)++) + "__(0)";
|
*code_ptr += "padding" + NumToString((*id)++) + "__(0)";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
|
static void PaddingNoop(int bits, std::string *code_ptr, int *id) {
|
||||||
(void)bits;
|
(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) {
|
void GenStructDefaultConstructor(const StructDef &struct_def) {
|
||||||
@@ -2989,58 +3028,50 @@ class CppGenerator : public BaseGenerator {
|
|||||||
code_ += " {}";
|
code_ += " {}";
|
||||||
} else {
|
} else {
|
||||||
code_.SetValue("INIT_LIST", init_list);
|
code_.SetValue("INIT_LIST", init_list);
|
||||||
code_.SetValue("DEFAULT_CONSTRUCTOR_BODY", body);
|
|
||||||
code_ += " {{STRUCT_NAME}}()";
|
code_ += " {{STRUCT_NAME}}()";
|
||||||
code_ += " : {{INIT_LIST}} {";
|
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 arg_list;
|
||||||
std::string init_list;
|
std::string init_list;
|
||||||
int padding_id = 0;
|
int padding_id = 0;
|
||||||
bool first_arg = true;
|
auto first = struct_def.fields.vec.begin();
|
||||||
bool first_init = true;
|
// skip arrays if generate ctor without array assignment
|
||||||
|
const auto init_arrays = (array_mode != kArrayArgModeNone);
|
||||||
for (auto it = struct_def.fields.vec.begin();
|
for (auto it = struct_def.fields.vec.begin();
|
||||||
it != struct_def.fields.vec.end(); ++it) {
|
it != struct_def.fields.vec.end(); ++it) {
|
||||||
const auto &field = **it;
|
const auto &field = **it;
|
||||||
const auto &field_type = field.value.type;
|
const auto &type = field.value.type;
|
||||||
const auto member_name = Name(field) + "_";
|
const auto is_array = IsArray(type);
|
||||||
const auto arg_name = "_" + Name(field);
|
const auto arg_name = "_" + Name(field);
|
||||||
const auto arg_type = GenTypeGet(field_type, " ", "const ", " &", true);
|
if (!is_array || init_arrays) {
|
||||||
|
if (it != first && !arg_list.empty()) { arg_list += ", "; }
|
||||||
if (!IsArray(field_type)) {
|
arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true)
|
||||||
if (first_arg) {
|
: GenTypeSpan(type, true, type.fixed_length);
|
||||||
first_arg = false;
|
|
||||||
} else {
|
|
||||||
arg_list += ", ";
|
|
||||||
}
|
|
||||||
arg_list += arg_type;
|
|
||||||
arg_list += arg_name;
|
arg_list += arg_name;
|
||||||
}
|
}
|
||||||
if (first_init) {
|
// skip an array with initialization from span
|
||||||
first_init = false;
|
if (false == (is_array && init_arrays)) {
|
||||||
} else {
|
if (it != first && !init_list.empty()) { init_list += ",\n "; }
|
||||||
init_list += ",";
|
init_list += Name(field) + "_";
|
||||||
init_list += "\n ";
|
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 (field.padding)
|
||||||
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) {
|
|
||||||
GenPadding(field, &init_list, &padding_id, PaddingInitializer);
|
GenPadding(field, &init_list, &padding_id, PaddingInitializer);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!arg_list.empty()) {
|
if (!arg_list.empty()) {
|
||||||
@@ -3052,10 +3083,55 @@ class CppGenerator : public BaseGenerator {
|
|||||||
} else {
|
} else {
|
||||||
code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {";
|
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_ += " }";
|
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.
|
// Generate an accessor struct with constructor for a flatbuffers struct.
|
||||||
void GenStruct(const StructDef &struct_def) {
|
void GenStruct(const StructDef &struct_def) {
|
||||||
// Generate an accessor struct, with private variables of the form:
|
// Generate an accessor struct, with private variables of the form:
|
||||||
@@ -3110,19 +3186,29 @@ class CppGenerator : public BaseGenerator {
|
|||||||
GenStructDefaultConstructor(struct_def);
|
GenStructDefaultConstructor(struct_def);
|
||||||
|
|
||||||
// Generate a constructor that takes all fields as arguments,
|
// Generate a constructor that takes all fields as arguments,
|
||||||
// excluding arrays
|
// excluding arrays.
|
||||||
GenStructConstructor(struct_def);
|
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:
|
// Generate accessor methods of the form:
|
||||||
// type name() const { return flatbuffers::EndianScalar(name_); }
|
// type name() const { return flatbuffers::EndianScalar(name_); }
|
||||||
for (auto it = struct_def.fields.vec.begin();
|
for (auto it = struct_def.fields.vec.begin();
|
||||||
it != struct_def.fields.vec.end(); ++it) {
|
it != struct_def.fields.vec.end(); ++it) {
|
||||||
const auto &field = **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, " ",
|
const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ",
|
||||||
IsArray(field.value.type) ? "" : "const ",
|
is_array ? "" : " &", true);
|
||||||
IsArray(field.value.type) ? "" : " &", true);
|
|
||||||
auto is_scalar = IsScalar(field.value.type.base_type);
|
|
||||||
auto member = Name(field) + "_";
|
auto member = Name(field) + "_";
|
||||||
auto value =
|
auto value =
|
||||||
is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
|
is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member;
|
||||||
@@ -3134,16 +3220,8 @@ class CppGenerator : public BaseGenerator {
|
|||||||
GenComment(field.doc_comment, " ");
|
GenComment(field.doc_comment, " ");
|
||||||
|
|
||||||
// Generate a const accessor function.
|
// Generate a const accessor function.
|
||||||
if (IsArray(field.value.type)) {
|
if (is_array) {
|
||||||
auto underlying = GenTypeGet(field.value.type, "", "", "", false);
|
GenArrayAccessor(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_ += " }";
|
|
||||||
} else {
|
} else {
|
||||||
code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
|
code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
|
||||||
code_ += " return {{FIELD_VALUE}};";
|
code_ += " return {{FIELD_VALUE}};";
|
||||||
@@ -3153,11 +3231,10 @@ class CppGenerator : public BaseGenerator {
|
|||||||
// Generate a mutable accessor function.
|
// Generate a mutable accessor function.
|
||||||
if (opts_.mutable_buffer) {
|
if (opts_.mutable_buffer) {
|
||||||
auto mut_field_type =
|
auto mut_field_type =
|
||||||
GenTypeGet(field.value.type, " ", "",
|
GenTypeGet(type, " ", "", is_array ? "" : " &", true);
|
||||||
IsArray(field.value.type) ? "" : " &", true);
|
|
||||||
code_.SetValue("FIELD_TYPE", mut_field_type);
|
code_.SetValue("FIELD_TYPE", mut_field_type);
|
||||||
if (is_scalar) {
|
if (is_scalar) {
|
||||||
code_.SetValue("ARG", GenTypeBasic(field.value.type, true));
|
code_.SetValue("ARG", GenTypeBasic(type, true));
|
||||||
code_.SetValue("FIELD_VALUE",
|
code_.SetValue("FIELD_VALUE",
|
||||||
GenUnderlyingCast(field, false, "_" + Name(field)));
|
GenUnderlyingCast(field, false, "_" + Name(field)));
|
||||||
|
|
||||||
@@ -3166,16 +3243,8 @@ class CppGenerator : public BaseGenerator {
|
|||||||
" flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
|
" flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
|
||||||
"{{FIELD_VALUE}});";
|
"{{FIELD_VALUE}});";
|
||||||
code_ += " }";
|
code_ += " }";
|
||||||
} else if (IsArray(field.value.type)) {
|
} else if (is_array) {
|
||||||
auto underlying = GenTypeGet(field.value.type, "", "", "", false);
|
GenArrayAccessor(type, true);
|
||||||
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 {
|
} else {
|
||||||
code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
|
code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
|
||||||
code_ += " return {{FIELD_VALUE}};";
|
code_ += " return {{FIELD_VALUE}};";
|
||||||
|
|||||||
@@ -92,12 +92,24 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) NestedStruct FLATBUFFERS_FINAL_CLASS {
|
|||||||
padding0__(0),
|
padding0__(0),
|
||||||
padding1__(0),
|
padding1__(0),
|
||||||
d_() {
|
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 {
|
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() {
|
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 {
|
MyGame::Example::TestEnum b() const {
|
||||||
return static_cast<MyGame::Example::TestEnum>(flatbuffers::EndianScalar(b_));
|
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));
|
flatbuffers::WriteScalar(&b_, static_cast<int8_t>(_b));
|
||||||
}
|
}
|
||||||
const flatbuffers::Array<MyGame::Example::TestEnum, 2> *c() const {
|
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() {
|
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 {
|
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() {
|
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);
|
FLATBUFFERS_STRUCT_END(NestedStruct, 32);
|
||||||
@@ -175,6 +187,26 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) ArrayStruct FLATBUFFERS_FINAL_CLASS {
|
|||||||
e_(flatbuffers::EndianScalar(_e)),
|
e_(flatbuffers::EndianScalar(_e)),
|
||||||
padding3__(0),
|
padding3__(0),
|
||||||
f_() {
|
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 {
|
float a() const {
|
||||||
return flatbuffers::EndianScalar(a_);
|
return flatbuffers::EndianScalar(a_);
|
||||||
@@ -183,10 +215,10 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) ArrayStruct FLATBUFFERS_FINAL_CLASS {
|
|||||||
flatbuffers::WriteScalar(&a_, _a);
|
flatbuffers::WriteScalar(&a_, _a);
|
||||||
}
|
}
|
||||||
const flatbuffers::Array<int32_t, 15> *b() const {
|
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() {
|
flatbuffers::Array<int32_t, 15> *mutable_b() {
|
||||||
return reinterpret_cast<flatbuffers::Array<int32_t, 15> *>(b_);
|
return &flatbuffers::CastToArray(b_);
|
||||||
}
|
}
|
||||||
int8_t c() const {
|
int8_t c() const {
|
||||||
return flatbuffers::EndianScalar(c_);
|
return flatbuffers::EndianScalar(c_);
|
||||||
@@ -195,10 +227,10 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) ArrayStruct FLATBUFFERS_FINAL_CLASS {
|
|||||||
flatbuffers::WriteScalar(&c_, _c);
|
flatbuffers::WriteScalar(&c_, _c);
|
||||||
}
|
}
|
||||||
const flatbuffers::Array<MyGame::Example::NestedStruct, 2> *d() const {
|
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() {
|
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 {
|
int32_t e() const {
|
||||||
return flatbuffers::EndianScalar(e_);
|
return flatbuffers::EndianScalar(e_);
|
||||||
@@ -207,10 +239,10 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) ArrayStruct FLATBUFFERS_FINAL_CLASS {
|
|||||||
flatbuffers::WriteScalar(&e_, _e);
|
flatbuffers::WriteScalar(&e_, _e);
|
||||||
}
|
}
|
||||||
const flatbuffers::Array<int64_t, 2> *f() const {
|
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() {
|
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);
|
FLATBUFFERS_STRUCT_END(ArrayStruct, 160);
|
||||||
|
|||||||
@@ -487,6 +487,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS {
|
|||||||
: a_(flatbuffers::EndianScalar(_a)),
|
: a_(flatbuffers::EndianScalar(_a)),
|
||||||
b_(flatbuffers::EndianScalar(_b)),
|
b_(flatbuffers::EndianScalar(_b)),
|
||||||
padding0__(0) {
|
padding0__(0) {
|
||||||
|
(void)padding0__;
|
||||||
}
|
}
|
||||||
int16_t a() const {
|
int16_t a() const {
|
||||||
return flatbuffers::EndianScalar(a_);
|
return flatbuffers::EndianScalar(a_);
|
||||||
@@ -543,6 +544,9 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Vec3 FLATBUFFERS_FINAL_CLASS {
|
|||||||
padding1__(0),
|
padding1__(0),
|
||||||
test3_(_test3),
|
test3_(_test3),
|
||||||
padding2__(0) {
|
padding2__(0) {
|
||||||
|
(void)padding0__;
|
||||||
|
(void)padding1__;
|
||||||
|
(void)padding2__;
|
||||||
}
|
}
|
||||||
float x() const {
|
float x() const {
|
||||||
return flatbuffers::EndianScalar(x_);
|
return flatbuffers::EndianScalar(x_);
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Struct FLATBUFFERS_FINAL_CLASS {
|
|||||||
: a_(flatbuffers::EndianScalar(_a)),
|
: a_(flatbuffers::EndianScalar(_a)),
|
||||||
padding0__(0),
|
padding0__(0),
|
||||||
b_(flatbuffers::EndianScalar(_b)) {
|
b_(flatbuffers::EndianScalar(_b)) {
|
||||||
|
(void)padding0__;
|
||||||
}
|
}
|
||||||
int32_t a() const {
|
int32_t a() const {
|
||||||
return flatbuffers::EndianScalar(a_);
|
return flatbuffers::EndianScalar(a_);
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Struct FLATBUFFERS_FINAL_CLASS {
|
|||||||
: a_(flatbuffers::EndianScalar(_a)),
|
: a_(flatbuffers::EndianScalar(_a)),
|
||||||
padding0__(0),
|
padding0__(0),
|
||||||
b_(flatbuffers::EndianScalar(_b)) {
|
b_(flatbuffers::EndianScalar(_b)) {
|
||||||
|
(void)padding0__;
|
||||||
}
|
}
|
||||||
int32_t a() const {
|
int32_t a() const {
|
||||||
return flatbuffers::EndianScalar(a_);
|
return flatbuffers::EndianScalar(a_);
|
||||||
|
|||||||
@@ -602,6 +602,7 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(2) Test FLATBUFFERS_FINAL_CLASS {
|
|||||||
: a_(flatbuffers::EndianScalar(_a)),
|
: a_(flatbuffers::EndianScalar(_a)),
|
||||||
b_(flatbuffers::EndianScalar(_b)),
|
b_(flatbuffers::EndianScalar(_b)),
|
||||||
padding0__(0) {
|
padding0__(0) {
|
||||||
|
(void)padding0__;
|
||||||
}
|
}
|
||||||
int16_t a() const {
|
int16_t a() const {
|
||||||
return flatbuffers::EndianScalar(a_);
|
return flatbuffers::EndianScalar(a_);
|
||||||
@@ -669,6 +670,9 @@ FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Vec3 FLATBUFFERS_FINAL_CLASS {
|
|||||||
padding1__(0),
|
padding1__(0),
|
||||||
test3_(_test3),
|
test3_(_test3),
|
||||||
padding2__(0) {
|
padding2__(0) {
|
||||||
|
(void)padding0__;
|
||||||
|
(void)padding1__;
|
||||||
|
(void)padding2__;
|
||||||
}
|
}
|
||||||
float x() const {
|
float x() const {
|
||||||
return flatbuffers::EndianScalar(x_);
|
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);
|
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() {
|
void FixedLengthArrayTest() {
|
||||||
// VS10 does not support typed enums, exclude from tests
|
// VS10 does not support typed enums, exclude from tests
|
||||||
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
#if !defined(_MSC_VER) || _MSC_VER >= 1700
|
||||||
@@ -3322,6 +3405,57 @@ void FixedLengthArrayTest() {
|
|||||||
#endif
|
#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() {
|
void NativeTypeTest() {
|
||||||
const int N = 3;
|
const int N = 3;
|
||||||
|
|
||||||
@@ -3666,6 +3800,8 @@ int FlatBufferTests() {
|
|||||||
NativeTypeTest();
|
NativeTypeTest();
|
||||||
OptionalScalarsTest();
|
OptionalScalarsTest();
|
||||||
ParseFlexbuffersFromJsonWithNullTest();
|
ParseFlexbuffersFromJsonWithNullTest();
|
||||||
|
FlatbuffersSpanTest();
|
||||||
|
FixedLengthArrayConstructorTest();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user