diff --git a/include/flatbuffers/base.h b/include/flatbuffers/base.h index d98da1394..6e76a3f8e 100644 --- a/include/flatbuffers/base.h +++ b/include/flatbuffers/base.h @@ -330,22 +330,20 @@ template T EndianSwap(T t) { if (sizeof(T) == 1) { // Compile-time if-then's. return t; } else if (sizeof(T) == 2) { - union { T t; uint16_t i; } u; - u.t = t; + union { T t; uint16_t i; } u = { t }; u.i = FLATBUFFERS_BYTESWAP16(u.i); return u.t; } else if (sizeof(T) == 4) { - union { T t; uint32_t i; } u; - u.t = t; + union { T t; uint32_t i; } u = { t }; u.i = FLATBUFFERS_BYTESWAP32(u.i); return u.t; } else if (sizeof(T) == 8) { - union { T t; uint64_t i; } u; - u.t = t; + union { T t; uint64_t i; } u = { t }; u.i = FLATBUFFERS_BYTESWAP64(u.i); return u.t; } else { FLATBUFFERS_ASSERT(0); + return t; } } diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h index 253af1552..228c879ab 100644 --- a/include/flatbuffers/flatbuffers.h +++ b/include/flatbuffers/flatbuffers.h @@ -402,18 +402,23 @@ template static inline size_t VectorLength(const Vector *v) { // 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 flatbuffers::integral_constant::value> + scalar_tag; + typedef + typename flatbuffers::conditional::type + IndirectHelperType; - typedef typename IndirectHelper::return_type return_type; + public: + typedef typename IndirectHelper::return_type return_type; + typedef VectorIterator const_iterator; + typedef VectorReverseIterator const_reverse_iterator; 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 IndirectHelper::Read(Data(), i); } return_type operator[](uoffset_t i) const { return Get(i); } @@ -432,22 +437,22 @@ template class Array { 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. + // This method 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 { + typename flatbuffers::conditional::type + GetMutablePointer(uoffset_t i) const { FLATBUFFERS_ASSERT(i < size()); return const_cast(&data()[i]); } + // Change elements if you have a non-const pointer to this object. + void Mutate(uoffset_t i, const T &val) { + MutateImpl(scalar_tag(), i, val); + } + // The raw data in little endian format. Use with care. const uint8_t *Data() const { return data_; } @@ -458,6 +463,17 @@ template class Array { T *data() { return reinterpret_cast(Data()); } protected: + void MutateImpl(flatbuffers::integral_constant, uoffset_t i, + const T &val) { + FLATBUFFERS_ASSERT(i < size()); + WriteScalar(data() + i, val); + } + + void MutateImpl(flatbuffers::integral_constant, uoffset_t i, + const T &val) { + *(GetMutablePointer(i)) = val; + } + // 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. @@ -475,6 +491,30 @@ template class Array { // This class is a pointer. Copying will therefore create an invalid object. // Private and unimplemented copy constructor. Array(const Array &); + Array &operator=(const Array &); +}; + +// Specialization for Array[struct] with access using Offset pointer. +// This specialization used by idl_gen_text.cpp. +template class Array, length> { + static_assert(flatbuffers::is_same::value, "unexpected type T"); + + public: + const uint8_t *Data() const { return data_; } + + // Make idl_gen_text.cpp::PrintContainer happy. + const void *operator[](uoffset_t) const { + FLATBUFFERS_ASSERT(false); + return nullptr; + } + + private: + // This class is only used to access pre-existing data. + Array(); + Array(const Array &); + Array &operator=(const Array &); + + uint8_t data_[1]; }; // Lexicographically compare two strings (possibly containing nulls), and diff --git a/include/flatbuffers/stl_emulation.h b/include/flatbuffers/stl_emulation.h index 6f6e76642..e68089ff9 100644 --- a/include/flatbuffers/stl_emulation.h +++ b/include/flatbuffers/stl_emulation.h @@ -139,7 +139,11 @@ inline void vector_emplace_back(std::vector *vector, V &&data) { template using is_floating_point = std::is_floating_point; template using is_unsigned = std::is_unsigned; template using make_unsigned = std::make_unsigned; - #else + template + using conditional = std::conditional; + template + using integral_constant = std::integral_constant; +#else // Map C++ TR1 templates defined by stlport. template using is_scalar = std::tr1::is_scalar; template using is_same = std::tr1::is_same; @@ -157,7 +161,11 @@ inline void vector_emplace_back(std::vector *vector, V &&data) { template<> struct make_unsigned { using type = unsigned long; }; template<> struct make_unsigned { using type = unsigned long long; }; - #endif // !FLATBUFFERS_CPP98_STL + template + using conditional = std::tr1::conditional; + template + using integral_constant = std::tr1::integral_constant; +#endif // !FLATBUFFERS_CPP98_STL #else // MSVC 2010 doesn't support C++11 aliases. template struct is_scalar : public std::is_scalar {}; @@ -166,6 +174,10 @@ inline void vector_emplace_back(std::vector *vector, V &&data) { public std::is_floating_point {}; template struct is_unsigned : public std::is_unsigned {}; template struct make_unsigned : public std::make_unsigned {}; + template + struct conditional : public std::conditional {}; + template + struct integral_constant : public std::integral_constant {}; #endif // defined(FLATBUFFERS_TEMPLATES_ALIASES) #ifndef FLATBUFFERS_CPP98_STL diff --git a/tests/test.cpp b/tests/test.cpp index 939550db5..7762f5fa5 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -2895,35 +2895,37 @@ void FixedLengthArrayTest() { TEST_EQ(mArStruct->b()->size(), 15); TEST_EQ(mArStruct->b()->Get(aStruct.b()->size() - 1), -14); TEST_EQ(mArStruct->c(), 12); - TEST_NOTNULL(mArStruct->d()->Get(0).a()); - TEST_EQ(mArStruct->d()->Get(0).a()->Get(0), 1); - TEST_EQ(mArStruct->d()->Get(0).a()->Get(1), 2); - TEST_NOTNULL(mArStruct->d()->Get(1).a()); - TEST_EQ(mArStruct->d()->Get(1).a()->Get(0), 3); - TEST_EQ(mArStruct->d()->Get(1).a()->Get(1), 4); + TEST_NOTNULL(mArStruct->d()->Get(0)); + TEST_NOTNULL(mArStruct->d()->Get(0)->a()); + TEST_EQ(mArStruct->d()->Get(0)->a()->Get(0), 1); + TEST_EQ(mArStruct->d()->Get(0)->a()->Get(1), 2); + TEST_NOTNULL(mArStruct->d()->Get(1)); + TEST_NOTNULL(mArStruct->d()->Get(1)->a()); + TEST_EQ(mArStruct->d()->Get(1)->a()->Get(0), 3); + TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 4); TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)); TEST_NOTNULL(mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()); mArStruct->mutable_d()->GetMutablePointer(1)->mutable_a()->Mutate(1, 5); - TEST_EQ(mArStruct->d()->Get(1).a()->Get(1), 5); - TEST_EQ(mArStruct->d()->Get(0).b() == MyGame::Example::TestEnum::B, true); - TEST_NOTNULL(mArStruct->d()->Get(0).c()); - TEST_EQ(mArStruct->d()->Get(0).c()->Get(0) == MyGame::Example::TestEnum::C, + TEST_EQ(mArStruct->d()->Get(1)->a()->Get(1), 5); + TEST_EQ(mArStruct->d()->Get(0)->b() == MyGame::Example::TestEnum::B, true); + TEST_NOTNULL(mArStruct->d()->Get(0)->c()); + TEST_EQ(mArStruct->d()->Get(0)->c()->Get(0) == MyGame::Example::TestEnum::C, true); - TEST_EQ(mArStruct->d()->Get(0).c()->Get(1) == MyGame::Example::TestEnum::A, + TEST_EQ(mArStruct->d()->Get(0)->c()->Get(1) == MyGame::Example::TestEnum::A, true); - TEST_EQ(mArStruct->d()->Get(0).d()->Get(0), + TEST_EQ(mArStruct->d()->Get(0)->d()->Get(0), flatbuffers::numeric_limits::max()); - TEST_EQ(mArStruct->d()->Get(0).d()->Get(1), + TEST_EQ(mArStruct->d()->Get(0)->d()->Get(1), flatbuffers::numeric_limits::min()); - TEST_EQ(mArStruct->d()->Get(1).b() == MyGame::Example::TestEnum::C, true); - TEST_NOTNULL(mArStruct->d()->Get(1).c()); - TEST_EQ(mArStruct->d()->Get(1).c()->Get(0) == MyGame::Example::TestEnum::C, + TEST_EQ(mArStruct->d()->Get(1)->b() == MyGame::Example::TestEnum::C, true); + TEST_NOTNULL(mArStruct->d()->Get(1)->c()); + TEST_EQ(mArStruct->d()->Get(1)->c()->Get(0) == MyGame::Example::TestEnum::C, true); - TEST_EQ(mArStruct->d()->Get(1).c()->Get(1) == MyGame::Example::TestEnum::A, + TEST_EQ(mArStruct->d()->Get(1)->c()->Get(1) == MyGame::Example::TestEnum::A, true); - TEST_EQ(mArStruct->d()->Get(1).d()->Get(0), + TEST_EQ(mArStruct->d()->Get(1)->d()->Get(0), flatbuffers::numeric_limits::min()); - TEST_EQ(mArStruct->d()->Get(1).d()->Get(1), + TEST_EQ(mArStruct->d()->Get(1)->d()->Get(1), flatbuffers::numeric_limits::max()); for (int i = 0; i < mArStruct->b()->size() - 1; i++) TEST_EQ(mArStruct->b()->Get(i), i + 1);