array.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * Copyright 2021 Google Inc. All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #ifndef FLATBUFFERS_ARRAY_H_
  17. #define FLATBUFFERS_ARRAY_H_
  18. #include "flatbuffers/base.h"
  19. #include "flatbuffers/stl_emulation.h"
  20. #include "flatbuffers/vector.h"
  21. namespace flatbuffers {
  22. // This is used as a helper type for accessing arrays.
  23. template<typename T, uint16_t length> class Array {
  24. // Array<T> can carry only POD data types (scalars or structs).
  25. typedef typename flatbuffers::bool_constant<flatbuffers::is_scalar<T>::value>
  26. scalar_tag;
  27. typedef
  28. typename flatbuffers::conditional<scalar_tag::value, T, const T *>::type
  29. IndirectHelperType;
  30. public:
  31. typedef uint16_t size_type;
  32. typedef typename IndirectHelper<IndirectHelperType>::return_type return_type;
  33. typedef VectorIterator<T, return_type> const_iterator;
  34. typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
  35. // If T is a LE-scalar or a struct (!scalar_tag::value).
  36. static FLATBUFFERS_CONSTEXPR bool is_span_observable =
  37. (scalar_tag::value && (FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1)) ||
  38. !scalar_tag::value;
  39. FLATBUFFERS_CONSTEXPR uint16_t size() const { return length; }
  40. return_type Get(uoffset_t i) const {
  41. FLATBUFFERS_ASSERT(i < size());
  42. return IndirectHelper<IndirectHelperType>::Read(Data(), i);
  43. }
  44. return_type operator[](uoffset_t i) const { return Get(i); }
  45. // If this is a Vector of enums, T will be its storage type, not the enum
  46. // type. This function makes it convenient to retrieve value with enum
  47. // type E.
  48. template<typename E> E GetEnum(uoffset_t i) const {
  49. return static_cast<E>(Get(i));
  50. }
  51. const_iterator begin() const { return const_iterator(Data(), 0); }
  52. const_iterator end() const { return const_iterator(Data(), size()); }
  53. const_reverse_iterator rbegin() const {
  54. return const_reverse_iterator(end());
  55. }
  56. const_reverse_iterator rend() const {
  57. return const_reverse_iterator(begin());
  58. }
  59. const_iterator cbegin() const { return begin(); }
  60. const_iterator cend() const { return end(); }
  61. const_reverse_iterator crbegin() const { return rbegin(); }
  62. const_reverse_iterator crend() const { return rend(); }
  63. // Get a mutable pointer to elements inside this array.
  64. // This method used to mutate arrays of structs followed by a @p Mutate
  65. // operation. For primitive types use @p Mutate directly.
  66. // @warning Assignments and reads to/from the dereferenced pointer are not
  67. // automatically converted to the correct endianness.
  68. typename flatbuffers::conditional<scalar_tag::value, void, T *>::type
  69. GetMutablePointer(uoffset_t i) const {
  70. FLATBUFFERS_ASSERT(i < size());
  71. return const_cast<T *>(&data()[i]);
  72. }
  73. // Change elements if you have a non-const pointer to this object.
  74. void Mutate(uoffset_t i, const T &val) { MutateImpl(scalar_tag(), i, val); }
  75. // The raw data in little endian format. Use with care.
  76. const uint8_t *Data() const { return data_; }
  77. uint8_t *Data() { return data_; }
  78. // Similarly, but typed, much like std::vector::data
  79. const T *data() const { return reinterpret_cast<const T *>(Data()); }
  80. T *data() { return reinterpret_cast<T *>(Data()); }
  81. // Copy data from a span with endian conversion.
  82. // If this Array and the span overlap, the behavior is undefined.
  83. void CopyFromSpan(flatbuffers::span<const T, length> src) {
  84. const auto p1 = reinterpret_cast<const uint8_t *>(src.data());
  85. const auto p2 = Data();
  86. FLATBUFFERS_ASSERT(!(p1 >= p2 && p1 < (p2 + length)) &&
  87. !(p2 >= p1 && p2 < (p1 + length)));
  88. (void)p1;
  89. (void)p2;
  90. CopyFromSpanImpl(flatbuffers::bool_constant<is_span_observable>(), src);
  91. }
  92. protected:
  93. void MutateImpl(flatbuffers::true_type, uoffset_t i, const T &val) {
  94. FLATBUFFERS_ASSERT(i < size());
  95. WriteScalar(data() + i, val);
  96. }
  97. void MutateImpl(flatbuffers::false_type, uoffset_t i, const T &val) {
  98. *(GetMutablePointer(i)) = val;
  99. }
  100. void CopyFromSpanImpl(flatbuffers::true_type,
  101. flatbuffers::span<const T, length> src) {
  102. // Use std::memcpy() instead of std::copy() to avoid performance degradation
  103. // due to aliasing if T is char or unsigned char.
  104. // The size is known at compile time, so memcpy would be inlined.
  105. std::memcpy(data(), src.data(), length * sizeof(T));
  106. }
  107. // Copy data from flatbuffers::span with endian conversion.
  108. void CopyFromSpanImpl(flatbuffers::false_type,
  109. flatbuffers::span<const T, length> src) {
  110. for (size_type k = 0; k < length; k++) { Mutate(k, src[k]); }
  111. }
  112. // This class is only used to access pre-existing data. Don't ever
  113. // try to construct these manually.
  114. // 'constexpr' allows us to use 'size()' at compile time.
  115. // @note Must not use 'FLATBUFFERS_CONSTEXPR' here, as const is not allowed on
  116. // a constructor.
  117. #if defined(__cpp_constexpr)
  118. constexpr Array();
  119. #else
  120. Array();
  121. #endif
  122. uint8_t data_[length * sizeof(T)];
  123. private:
  124. // This class is a pointer. Copying will therefore create an invalid object.
  125. // Private and unimplemented copy constructor.
  126. Array(const Array &);
  127. Array &operator=(const Array &);
  128. };
  129. // Specialization for Array[struct] with access using Offset<void> pointer.
  130. // This specialization used by idl_gen_text.cpp.
  131. template<typename T, uint16_t length> class Array<Offset<T>, length> {
  132. static_assert(flatbuffers::is_same<T, void>::value, "unexpected type T");
  133. public:
  134. typedef const void *return_type;
  135. const uint8_t *Data() const { return data_; }
  136. // Make idl_gen_text.cpp::PrintContainer happy.
  137. return_type operator[](uoffset_t) const {
  138. FLATBUFFERS_ASSERT(false);
  139. return nullptr;
  140. }
  141. private:
  142. // This class is only used to access pre-existing data.
  143. Array();
  144. Array(const Array &);
  145. Array &operator=(const Array &);
  146. uint8_t data_[1];
  147. };
  148. template<class U, uint16_t N>
  149. FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U, N> make_span(Array<U, N> &arr)
  150. FLATBUFFERS_NOEXCEPT {
  151. static_assert(
  152. Array<U, N>::is_span_observable,
  153. "wrong type U, only plain struct, LE-scalar, or byte types are allowed");
  154. return span<U, N>(arr.data(), N);
  155. }
  156. template<class U, uint16_t N>
  157. FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U, N> make_span(
  158. const Array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
  159. static_assert(
  160. Array<U, N>::is_span_observable,
  161. "wrong type U, only plain struct, LE-scalar, or byte types are allowed");
  162. return span<const U, N>(arr.data(), N);
  163. }
  164. template<class U, uint16_t N>
  165. FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<uint8_t, sizeof(U) * N>
  166. make_bytes_span(Array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
  167. static_assert(Array<U, N>::is_span_observable,
  168. "internal error, Array<T> might hold only scalars or structs");
  169. return span<uint8_t, sizeof(U) * N>(arr.Data(), sizeof(U) * N);
  170. }
  171. template<class U, uint16_t N>
  172. FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const uint8_t, sizeof(U) * N>
  173. make_bytes_span(const Array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
  174. static_assert(Array<U, N>::is_span_observable,
  175. "internal error, Array<T> might hold only scalars or structs");
  176. return span<const uint8_t, sizeof(U) * N>(arr.Data(), sizeof(U) * N);
  177. }
  178. // Cast a raw T[length] to a raw flatbuffers::Array<T, length>
  179. // without endian conversion. Use with care.
  180. // TODO: move these Cast-methods to `internal` namespace.
  181. template<typename T, uint16_t length>
  182. Array<T, length> &CastToArray(T (&arr)[length]) {
  183. return *reinterpret_cast<Array<T, length> *>(arr);
  184. }
  185. template<typename T, uint16_t length>
  186. const Array<T, length> &CastToArray(const T (&arr)[length]) {
  187. return *reinterpret_cast<const Array<T, length> *>(arr);
  188. }
  189. template<typename E, typename T, uint16_t length>
  190. Array<E, length> &CastToArrayOfEnum(T (&arr)[length]) {
  191. static_assert(sizeof(E) == sizeof(T), "invalid enum type E");
  192. return *reinterpret_cast<Array<E, length> *>(arr);
  193. }
  194. template<typename E, typename T, uint16_t length>
  195. const Array<E, length> &CastToArrayOfEnum(const T (&arr)[length]) {
  196. static_assert(sizeof(E) == sizeof(T), "invalid enum type E");
  197. return *reinterpret_cast<const Array<E, length> *>(arr);
  198. }
  199. } // namespace flatbuffers
  200. #endif // FLATBUFFERS_ARRAY_H_