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