github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/executor/_include/flatbuffers/array.h (about)

     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  
    17  #ifndef FLATBUFFERS_ARRAY_H_
    18  #define FLATBUFFERS_ARRAY_H_
    19  
    20  #include <cstdint>
    21  #include <memory>
    22  
    23  #include "flatbuffers/base.h"
    24  #include "flatbuffers/stl_emulation.h"
    25  #include "flatbuffers/vector.h"
    26  
    27  namespace flatbuffers {
    28  
    29  // This is used as a helper type for accessing arrays.
    30  template<typename T, uint16_t length> class Array {
    31    // Array<T> can carry only POD data types (scalars or structs).
    32    typedef typename flatbuffers::bool_constant<flatbuffers::is_scalar<T>::value>
    33        scalar_tag;
    34    typedef
    35        typename flatbuffers::conditional<scalar_tag::value, T, const T *>::type
    36            IndirectHelperType;
    37  
    38   public:
    39    typedef uint16_t size_type;
    40    typedef typename IndirectHelper<IndirectHelperType>::return_type return_type;
    41    typedef VectorConstIterator<T, return_type, uoffset_t> const_iterator;
    42    typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
    43  
    44    // If T is a LE-scalar or a struct (!scalar_tag::value).
    45    static FLATBUFFERS_CONSTEXPR bool is_span_observable =
    46        (scalar_tag::value && (FLATBUFFERS_LITTLEENDIAN || sizeof(T) == 1)) ||
    47        !scalar_tag::value;
    48  
    49    FLATBUFFERS_CONSTEXPR uint16_t size() const { return length; }
    50  
    51    return_type Get(uoffset_t i) const {
    52      FLATBUFFERS_ASSERT(i < size());
    53      return IndirectHelper<IndirectHelperType>::Read(Data(), i);
    54    }
    55  
    56    return_type operator[](uoffset_t i) const { return Get(i); }
    57  
    58    // If this is a Vector of enums, T will be its storage type, not the enum
    59    // type. This function makes it convenient to retrieve value with enum
    60    // type E.
    61    template<typename E> E GetEnum(uoffset_t i) const {
    62      return static_cast<E>(Get(i));
    63    }
    64  
    65    const_iterator begin() const { return const_iterator(Data(), 0); }
    66    const_iterator end() const { return const_iterator(Data(), size()); }
    67  
    68    const_reverse_iterator rbegin() const {
    69      return const_reverse_iterator(end());
    70    }
    71    const_reverse_iterator rend() const {
    72      return const_reverse_iterator(begin());
    73    }
    74  
    75    const_iterator cbegin() const { return begin(); }
    76    const_iterator cend() const { return end(); }
    77  
    78    const_reverse_iterator crbegin() const { return rbegin(); }
    79    const_reverse_iterator crend() const { return rend(); }
    80  
    81    // Get a mutable pointer to elements inside this array.
    82    // This method used to mutate arrays of structs followed by a @p Mutate
    83    // operation. For primitive types use @p Mutate directly.
    84    // @warning Assignments and reads to/from the dereferenced pointer are not
    85    //  automatically converted to the correct endianness.
    86    typename flatbuffers::conditional<scalar_tag::value, void, T *>::type
    87    GetMutablePointer(uoffset_t i) const {
    88      FLATBUFFERS_ASSERT(i < size());
    89      return const_cast<T *>(&data()[i]);
    90    }
    91  
    92    // Change elements if you have a non-const pointer to this object.
    93    void Mutate(uoffset_t i, const T &val) { MutateImpl(scalar_tag(), i, val); }
    94  
    95    // The raw data in little endian format. Use with care.
    96    const uint8_t *Data() const { return data_; }
    97  
    98    uint8_t *Data() { return data_; }
    99  
   100    // Similarly, but typed, much like std::vector::data
   101    const T *data() const { return reinterpret_cast<const T *>(Data()); }
   102    T *data() { return reinterpret_cast<T *>(Data()); }
   103  
   104    // Copy data from a span with endian conversion.
   105    // If this Array and the span overlap, the behavior is undefined.
   106    void CopyFromSpan(flatbuffers::span<const T, length> src) {
   107      const auto p1 = reinterpret_cast<const uint8_t *>(src.data());
   108      const auto p2 = Data();
   109      FLATBUFFERS_ASSERT(!(p1 >= p2 && p1 < (p2 + length)) &&
   110                         !(p2 >= p1 && p2 < (p1 + length)));
   111      (void)p1;
   112      (void)p2;
   113      CopyFromSpanImpl(flatbuffers::bool_constant<is_span_observable>(), src);
   114    }
   115  
   116   protected:
   117    void MutateImpl(flatbuffers::true_type, uoffset_t i, const T &val) {
   118      FLATBUFFERS_ASSERT(i < size());
   119      WriteScalar(data() + i, val);
   120    }
   121  
   122    void MutateImpl(flatbuffers::false_type, uoffset_t i, const T &val) {
   123      *(GetMutablePointer(i)) = val;
   124    }
   125  
   126    void CopyFromSpanImpl(flatbuffers::true_type,
   127                          flatbuffers::span<const T, length> src) {
   128      // Use std::memcpy() instead of std::copy() to avoid performance degradation
   129      // due to aliasing if T is char or unsigned char.
   130      // The size is known at compile time, so memcpy would be inlined.
   131      std::memcpy(data(), src.data(), length * sizeof(T));
   132    }
   133  
   134    // Copy data from flatbuffers::span with endian conversion.
   135    void CopyFromSpanImpl(flatbuffers::false_type,
   136                          flatbuffers::span<const T, length> src) {
   137      for (size_type k = 0; k < length; k++) { Mutate(k, src[k]); }
   138    }
   139  
   140    // This class is only used to access pre-existing data. Don't ever
   141    // try to construct these manually.
   142    // 'constexpr' allows us to use 'size()' at compile time.
   143    // @note Must not use 'FLATBUFFERS_CONSTEXPR' here, as const is not allowed on
   144    //  a constructor.
   145  #if defined(__cpp_constexpr)
   146    constexpr Array();
   147  #else
   148    Array();
   149  #endif
   150  
   151    uint8_t data_[length * sizeof(T)];
   152  
   153   private:
   154    // This class is a pointer. Copying will therefore create an invalid object.
   155    // Private and unimplemented copy constructor.
   156    Array(const Array &);
   157    Array &operator=(const Array &);
   158  };
   159  
   160  // Specialization for Array[struct] with access using Offset<void> pointer.
   161  // This specialization used by idl_gen_text.cpp.
   162  template<typename T, uint16_t length, template<typename> class OffsetT>
   163  class Array<OffsetT<T>, length> {
   164    static_assert(flatbuffers::is_same<T, void>::value, "unexpected type T");
   165  
   166   public:
   167    typedef const void *return_type;
   168    typedef uint16_t size_type;
   169  
   170    const uint8_t *Data() const { return data_; }
   171  
   172    // Make idl_gen_text.cpp::PrintContainer happy.
   173    return_type operator[](uoffset_t) const {
   174      FLATBUFFERS_ASSERT(false);
   175      return nullptr;
   176    }
   177  
   178   private:
   179    // This class is only used to access pre-existing data.
   180    Array();
   181    Array(const Array &);
   182    Array &operator=(const Array &);
   183  
   184    uint8_t data_[1];
   185  };
   186  
   187  template<class U, uint16_t N>
   188  FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<U, N> make_span(Array<U, N> &arr)
   189      FLATBUFFERS_NOEXCEPT {
   190    static_assert(
   191        Array<U, N>::is_span_observable,
   192        "wrong type U, only plain struct, LE-scalar, or byte types are allowed");
   193    return span<U, N>(arr.data(), N);
   194  }
   195  
   196  template<class U, uint16_t N>
   197  FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const U, N> make_span(
   198      const Array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
   199    static_assert(
   200        Array<U, N>::is_span_observable,
   201        "wrong type U, only plain struct, LE-scalar, or byte types are allowed");
   202    return span<const U, N>(arr.data(), N);
   203  }
   204  
   205  template<class U, uint16_t N>
   206  FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<uint8_t, sizeof(U) * N>
   207  make_bytes_span(Array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
   208    static_assert(Array<U, N>::is_span_observable,
   209                  "internal error, Array<T> might hold only scalars or structs");
   210    return span<uint8_t, sizeof(U) * N>(arr.Data(), sizeof(U) * N);
   211  }
   212  
   213  template<class U, uint16_t N>
   214  FLATBUFFERS_CONSTEXPR_CPP11 flatbuffers::span<const uint8_t, sizeof(U) * N>
   215  make_bytes_span(const Array<U, N> &arr) FLATBUFFERS_NOEXCEPT {
   216    static_assert(Array<U, N>::is_span_observable,
   217                  "internal error, Array<T> might hold only scalars or structs");
   218    return span<const uint8_t, sizeof(U) * N>(arr.Data(), sizeof(U) * N);
   219  }
   220  
   221  // Cast a raw T[length] to a raw flatbuffers::Array<T, length>
   222  // without endian conversion. Use with care.
   223  // TODO: move these Cast-methods to `internal` namespace.
   224  template<typename T, uint16_t length>
   225  Array<T, length> &CastToArray(T (&arr)[length]) {
   226    return *reinterpret_cast<Array<T, length> *>(arr);
   227  }
   228  
   229  template<typename T, uint16_t length>
   230  const Array<T, length> &CastToArray(const T (&arr)[length]) {
   231    return *reinterpret_cast<const Array<T, length> *>(arr);
   232  }
   233  
   234  template<typename E, typename T, uint16_t length>
   235  Array<E, length> &CastToArrayOfEnum(T (&arr)[length]) {
   236    static_assert(sizeof(E) == sizeof(T), "invalid enum type E");
   237    return *reinterpret_cast<Array<E, length> *>(arr);
   238  }
   239  
   240  template<typename E, typename T, uint16_t length>
   241  const Array<E, length> &CastToArrayOfEnum(const T (&arr)[length]) {
   242    static_assert(sizeof(E) == sizeof(T), "invalid enum type E");
   243    return *reinterpret_cast<const Array<E, length> *>(arr);
   244  }
   245  
   246  template<typename T, uint16_t length>
   247  bool operator==(const Array<T, length> &lhs,
   248                  const Array<T, length> &rhs) noexcept {
   249    return std::addressof(lhs) == std::addressof(rhs) ||
   250           (lhs.size() == rhs.size() &&
   251            std::memcmp(lhs.Data(), rhs.Data(), rhs.size() * sizeof(T)) == 0);
   252  }
   253  
   254  }  // namespace flatbuffers
   255  
   256  #endif  // FLATBUFFERS_ARRAY_H_