• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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_STL_EMULATION_H_
18 #define FLATBUFFERS_STL_EMULATION_H_
19 
20 // clang-format off
21 #include "flatbuffers/base.h"
22 
23 #include <string>
24 #include <type_traits>
25 #include <vector>
26 #include <memory>
27 #include <limits>
28 
29 #ifndef FLATBUFFERS_USE_STD_OPTIONAL
30   // Detect C++17 compatible compiler.
31   // __cplusplus >= 201703L - a compiler has support of 'static inline' variables.
32   #if (defined(__cplusplus) && __cplusplus >= 201703L) \
33       || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
34     #define FLATBUFFERS_USE_STD_OPTIONAL 1
35   #else
36     #define FLATBUFFERS_USE_STD_OPTIONAL 0
37   #endif // (defined(__cplusplus) && __cplusplus >= 201703L) ...
38 #endif // FLATBUFFERS_USE_STD_OPTIONAL
39 
40 #if FLATBUFFERS_USE_STD_OPTIONAL
41   #include <optional>
42 #endif
43 
44 // The __cpp_lib_span is the predefined feature macro.
45 #if defined(FLATBUFFERS_USE_STD_SPAN)
46     #include <span>
47 #elif defined(__cpp_lib_span) && defined(__has_include)
48   #if __has_include(<span>)
49     #include <span>
50     #define FLATBUFFERS_USE_STD_SPAN
51   #endif
52 #else
53   // Disable non-trivial ctors if FLATBUFFERS_SPAN_MINIMAL defined.
54   #if !defined(FLATBUFFERS_TEMPLATES_ALIASES)
55     #define FLATBUFFERS_SPAN_MINIMAL
56   #else
57     // Enable implicit construction of a span<T,N> from a std::array<T,N>.
58     #include <array>
59   #endif
60 #endif // defined(FLATBUFFERS_USE_STD_SPAN)
61 
62 // This header provides backwards compatibility for older versions of the STL.
63 namespace flatbuffers {
64 
65 #if defined(FLATBUFFERS_TEMPLATES_ALIASES)
66   template <typename T>
67   using numeric_limits = std::numeric_limits<T>;
68 #else
69   template <typename T> class numeric_limits :
70     public std::numeric_limits<T> {};
71 #endif  // defined(FLATBUFFERS_TEMPLATES_ALIASES)
72 
73 #if defined(FLATBUFFERS_TEMPLATES_ALIASES)
74   template <typename T> using is_scalar = std::is_scalar<T>;
75   template <typename T, typename U> using is_same = std::is_same<T,U>;
76   template <typename T> using is_floating_point = std::is_floating_point<T>;
77   template <typename T> using is_unsigned = std::is_unsigned<T>;
78   template <typename T> using is_enum = std::is_enum<T>;
79   template <typename T> using make_unsigned = std::make_unsigned<T>;
80   template<bool B, class T, class F>
81   using conditional = std::conditional<B, T, F>;
82   template<class T, T v>
83   using integral_constant = std::integral_constant<T, v>;
84   template <bool B>
85   using bool_constant = integral_constant<bool, B>;
86   using true_type  = std::true_type;
87   using false_type = std::false_type;
88 #else
89   // MSVC 2010 doesn't support C++11 aliases.
90   template <typename T> struct is_scalar : public std::is_scalar<T> {};
91   template <typename T, typename U> struct is_same : public std::is_same<T,U> {};
92   template <typename T> struct is_floating_point :
93         public std::is_floating_point<T> {};
94   template <typename T> struct is_unsigned : public std::is_unsigned<T> {};
95   template <typename T> struct is_enum : public std::is_enum<T> {};
96   template <typename T> struct make_unsigned : public std::make_unsigned<T> {};
97   template<bool B, class T, class F>
98   struct conditional : public std::conditional<B, T, F> {};
99   template<class T, T v>
100   struct integral_constant : public std::integral_constant<T, v> {};
101   template <bool B>
102   struct bool_constant : public integral_constant<bool, B> {};
103   typedef bool_constant<true>  true_type;
104   typedef bool_constant<false> false_type;
105 #endif  // defined(FLATBUFFERS_TEMPLATES_ALIASES)
106 
107 #if defined(FLATBUFFERS_TEMPLATES_ALIASES)
108   template <class T> using unique_ptr = std::unique_ptr<T>;
109 #else
110   // MSVC 2010 doesn't support C++11 aliases.
111   // We're manually "aliasing" the class here as we want to bring unique_ptr
112   // into the flatbuffers namespace.  We have unique_ptr in the flatbuffers
113   // namespace we have a completely independent implementation (see below)
114   // for C++98 STL implementations.
115   template <class T> class unique_ptr : public std::unique_ptr<T> {
116     public:
unique_ptr()117     unique_ptr() {}
unique_ptr(T * p)118     explicit unique_ptr(T* p) : std::unique_ptr<T>(p) {}
unique_ptr(std::unique_ptr<T> && u)119     unique_ptr(std::unique_ptr<T>&& u) { *this = std::move(u); }
unique_ptr(unique_ptr && u)120     unique_ptr(unique_ptr&& u) { *this = std::move(u); }
121     unique_ptr& operator=(std::unique_ptr<T>&& u) {
122       std::unique_ptr<T>::reset(u.release());
123       return *this;
124     }
125     unique_ptr& operator=(unique_ptr&& u) {
126       std::unique_ptr<T>::reset(u.release());
127       return *this;
128     }
129     unique_ptr& operator=(T* p) {
130       return std::unique_ptr<T>::operator=(p);
131     }
132   };
133 #endif  // defined(FLATBUFFERS_TEMPLATES_ALIASES)
134 
135 #if FLATBUFFERS_USE_STD_OPTIONAL
136 template<class T>
137 using Optional = std::optional<T>;
138 using nullopt_t = std::nullopt_t;
139 inline constexpr nullopt_t nullopt = std::nullopt;
140 
141 #else
142 // Limited implementation of Optional<T> type for a scalar T.
143 // This implementation limited by trivial types compatible with
144 // std::is_arithmetic<T> or std::is_enum<T> type traits.
145 
146 // A tag to indicate an empty flatbuffers::optional<T>.
147 struct nullopt_t {
nullopt_tnullopt_t148   explicit FLATBUFFERS_CONSTEXPR_CPP11 nullopt_t(int) {}
149 };
150 
151 #if defined(FLATBUFFERS_CONSTEXPR_DEFINED)
152   namespace internal {
153     template <class> struct nullopt_holder {
154       static constexpr nullopt_t instance_ = nullopt_t(0);
155     };
156     template<class Dummy>
157     constexpr nullopt_t nullopt_holder<Dummy>::instance_;
158   }
159   static constexpr const nullopt_t &nullopt = internal::nullopt_holder<void>::instance_;
160 
161 #else
162   namespace internal {
163     template <class> struct nullopt_holder {
164       static const nullopt_t instance_;
165     };
166     template<class Dummy>
167     const nullopt_t nullopt_holder<Dummy>::instance_  = nullopt_t(0);
168   }
169   static const nullopt_t &nullopt = internal::nullopt_holder<void>::instance_;
170 
171 #endif
172 
173 template<class T>
174 class Optional FLATBUFFERS_FINAL_CLASS {
175   // Non-scalar 'T' would extremely complicated Optional<T>.
176   // Use is_scalar<T> checking because flatbuffers flatbuffers::is_arithmetic<T>
177   // isn't implemented.
178   static_assert(flatbuffers::is_scalar<T>::value, "unexpected type T");
179 
180  public:
~Optional()181   ~Optional() {}
182 
Optional()183   FLATBUFFERS_CONSTEXPR_CPP11 Optional() FLATBUFFERS_NOEXCEPT
184     : value_(), has_value_(false) {}
185 
Optional(nullopt_t)186   FLATBUFFERS_CONSTEXPR_CPP11 Optional(nullopt_t) FLATBUFFERS_NOEXCEPT
187     : value_(), has_value_(false) {}
188 
Optional(T val)189   FLATBUFFERS_CONSTEXPR_CPP11 Optional(T val) FLATBUFFERS_NOEXCEPT
190     : value_(val), has_value_(true) {}
191 
Optional(const Optional & other)192   FLATBUFFERS_CONSTEXPR_CPP11 Optional(const Optional &other) FLATBUFFERS_NOEXCEPT
193     : value_(other.value_), has_value_(other.has_value_) {}
194 
195   FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(const Optional &other) FLATBUFFERS_NOEXCEPT {
196     value_ = other.value_;
197     has_value_ = other.has_value_;
198     return *this;
199   }
200 
201   FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(nullopt_t) FLATBUFFERS_NOEXCEPT {
202     value_ = T();
203     has_value_ = false;
204     return *this;
205   }
206 
207   FLATBUFFERS_CONSTEXPR_CPP14 Optional &operator=(T val) FLATBUFFERS_NOEXCEPT {
208     value_ = val;
209     has_value_ = true;
210     return *this;
211   }
212 
reset()213   void reset() FLATBUFFERS_NOEXCEPT {
214     *this = nullopt;
215   }
216 
swap(Optional & other)217   void swap(Optional &other) FLATBUFFERS_NOEXCEPT {
218     std::swap(value_, other.value_);
219     std::swap(has_value_, other.has_value_);
220   }
221 
222   FLATBUFFERS_CONSTEXPR_CPP11 FLATBUFFERS_EXPLICIT_CPP11 operator bool() const FLATBUFFERS_NOEXCEPT {
223     return has_value_;
224   }
225 
has_value()226   FLATBUFFERS_CONSTEXPR_CPP11 bool has_value() const FLATBUFFERS_NOEXCEPT {
227     return has_value_;
228   }
229 
230   FLATBUFFERS_CONSTEXPR_CPP11 const T& operator*() const FLATBUFFERS_NOEXCEPT {
231     return value_;
232   }
233 
value()234   const T& value() const {
235     FLATBUFFERS_ASSERT(has_value());
236     return value_;
237   }
238 
value_or(T default_value)239   T value_or(T default_value) const FLATBUFFERS_NOEXCEPT {
240     return has_value() ? value_ : default_value;
241   }
242 
243  private:
244   T value_;
245   bool has_value_;
246 };
247 
248 template<class T>
249 FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& opt, nullopt_t) FLATBUFFERS_NOEXCEPT {
250   return !opt;
251 }
252 template<class T>
253 FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(nullopt_t, const Optional<T>& opt) FLATBUFFERS_NOEXCEPT {
254   return !opt;
255 }
256 
257 template<class T, class U>
258 FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& lhs, const U& rhs) FLATBUFFERS_NOEXCEPT {
259   return static_cast<bool>(lhs) && (*lhs == rhs);
260 }
261 
262 template<class T, class U>
263 FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const T& lhs, const Optional<U>& rhs) FLATBUFFERS_NOEXCEPT {
264   return static_cast<bool>(rhs) && (lhs == *rhs);
265 }
266 
267 template<class T, class U>
268 FLATBUFFERS_CONSTEXPR_CPP11 bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) FLATBUFFERS_NOEXCEPT {
269   return static_cast<bool>(lhs) != static_cast<bool>(rhs)
270               ? false
271               : !static_cast<bool>(lhs) ? false : (*lhs == *rhs);
272 }
273 #endif // FLATBUFFERS_USE_STD_OPTIONAL
274 
275 
276 // Very limited and naive partial implementation of C++20 std::span<T,Extent>.
277 #if defined(FLATBUFFERS_USE_STD_SPAN)
278   inline constexpr std::size_t dynamic_extent = std::dynamic_extent;
279   template<class T, std::size_t Extent = std::dynamic_extent>
280   using span = std::span<T, Extent>;
281 
282 #else // !defined(FLATBUFFERS_USE_STD_SPAN)
283 FLATBUFFERS_CONSTEXPR std::size_t dynamic_extent = static_cast<std::size_t>(-1);
284 
285 // Exclude this code if MSVC2010 or non-STL Android is active.
286 // The non-STL Android doesn't have `std::is_convertible` required for SFINAE.
287 #if !defined(FLATBUFFERS_SPAN_MINIMAL)
288 namespace internal {
289   // This is SFINAE helper class for checking of a common condition:
290   // > This overload only participates in overload resolution
291   // > Check whether a pointer to an array of From can be converted
292   // > to a pointer to an array of To.
293   // This helper is used for checking of 'From -> const From'.
294   template<class To, std::size_t Extent, class From, std::size_t N>
295   struct is_span_convertable {
296     using type =
297       typename std::conditional<std::is_convertible<From (*)[], To (*)[]>::value
298                                 && (Extent == dynamic_extent || N == Extent),
299                                 int, void>::type;
300   };
301 
302   template<typename T>
303   struct SpanIterator {
304     // TODO: upgrade to std::random_access_iterator_tag.
305     using iterator_category = std::forward_iterator_tag;
306     using difference_type  = std::ptrdiff_t;
307     using value_type = typename std::remove_cv<T>::type;
308     using reference = T&;
309     using pointer   = T*;
310 
311     // Convince MSVC compiler that this iterator is trusted (it is verified).
312     #ifdef _MSC_VER
313       using _Unchecked_type = pointer;
314     #endif // _MSC_VER
315 
SpanIteratorSpanIterator316     SpanIterator(pointer ptr) : ptr_(ptr) {}
317     reference operator*() const { return *ptr_; }
318     pointer operator->() { return ptr_; }
319     SpanIterator& operator++() { ptr_++; return *this; }
320     SpanIterator  operator++(int) { auto tmp = *this; ++(*this); return tmp; }
321 
322     friend bool operator== (const SpanIterator& lhs, const SpanIterator& rhs) { return lhs.ptr_ == rhs.ptr_; }
323     friend bool operator!= (const SpanIterator& lhs, const SpanIterator& rhs) { return lhs.ptr_ != rhs.ptr_; }
324 
325    private:
326     pointer ptr_;
327   };
328 }  // namespace internal
329 #endif  // !defined(FLATBUFFERS_SPAN_MINIMAL)
330 
331 // T - element type; must be a complete type that is not an abstract
332 // class type.
333 // Extent - the number of elements in the sequence, or dynamic.
334 template<class T, std::size_t Extent = dynamic_extent>
335 class span FLATBUFFERS_FINAL_CLASS {
336  public:
337   typedef T element_type;
338   typedef T& reference;
339   typedef const T& const_reference;
340   typedef T* pointer;
341   typedef const T* const_pointer;
342   typedef std::size_t size_type;
343 
344   static FLATBUFFERS_CONSTEXPR size_type extent = Extent;
345 
346   // Returns the number of elements in the span.
size()347   FLATBUFFERS_CONSTEXPR_CPP11 size_type size() const FLATBUFFERS_NOEXCEPT {
348     return count_;
349   }
350 
351   // Returns the size of the sequence in bytes.
352   FLATBUFFERS_CONSTEXPR_CPP11
size_bytes()353   size_type size_bytes() const FLATBUFFERS_NOEXCEPT {
354     return size() * sizeof(element_type);
355   }
356 
357   // Checks if the span is empty.
empty()358   FLATBUFFERS_CONSTEXPR_CPP11 bool empty() const FLATBUFFERS_NOEXCEPT {
359     return size() == 0;
360   }
361 
362   // Returns a pointer to the beginning of the sequence.
data()363   FLATBUFFERS_CONSTEXPR_CPP11 pointer data() const FLATBUFFERS_NOEXCEPT {
364     return data_;
365   }
366 
367   #if !defined(FLATBUFFERS_SPAN_MINIMAL)
368     using Iterator = internal::SpanIterator<T>;
369 
begin()370     Iterator begin() const { return Iterator(data()); }
end()371     Iterator end() const   { return Iterator(data() + size()); }
372   #endif
373 
374   // Returns a reference to the idx-th element of the sequence.
375   // The behavior is undefined if the idx is greater than or equal to size().
376   FLATBUFFERS_CONSTEXPR_CPP11 reference operator[](size_type idx) const {
377     return data()[idx];
378   }
379 
span(const span & other)380   FLATBUFFERS_CONSTEXPR_CPP11 span(const span &other) FLATBUFFERS_NOEXCEPT
381       : data_(other.data_), count_(other.count_) {}
382 
383   FLATBUFFERS_CONSTEXPR_CPP14 span &operator=(const span &other)
384       FLATBUFFERS_NOEXCEPT {
385     data_ = other.data_;
386     count_ = other.count_;
387   }
388 
389   // Limited implementation of
390   // `template <class It> constexpr std::span(It first, size_type count);`.
391   //
392   // Constructs a span that is a view over the range [first, first + count);
393   // the resulting span has: data() == first and size() == count.
394   // The behavior is undefined if [first, first + count) is not a valid range,
395   // or if (extent != flatbuffers::dynamic_extent && count != extent).
396   FLATBUFFERS_CONSTEXPR_CPP11
span(pointer first,size_type count)397   explicit span(pointer first, size_type count) FLATBUFFERS_NOEXCEPT
398     : data_ (Extent == dynamic_extent ? first : (Extent == count ? first : nullptr)),
399       count_(Extent == dynamic_extent ? count : (Extent == count ? Extent : 0)) {
400       // Make span empty if the count argument is incompatible with span<T,N>.
401   }
402 
403   // Exclude this code if MSVC2010 is active. The MSVC2010 isn't C++11
404   // compliant, it doesn't support default template arguments for functions.
405   #if defined(FLATBUFFERS_SPAN_MINIMAL)
span()406   FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr),
407                                                             count_(0) {
408     static_assert(extent == 0 || extent == dynamic_extent, "invalid span");
409   }
410 
411   #else
412   // Constructs an empty span whose data() == nullptr and size() == 0.
413   // This overload only participates in overload resolution if
414   // extent == 0 || extent == flatbuffers::dynamic_extent.
415   // A dummy template argument N is need dependency for SFINAE.
416   template<std::size_t N = 0,
417     typename internal::is_span_convertable<element_type, Extent, element_type, (N - N)>::type = 0>
span()418   FLATBUFFERS_CONSTEXPR_CPP11 span() FLATBUFFERS_NOEXCEPT : data_(nullptr),
419                                                             count_(0) {
420     static_assert(extent == 0 || extent == dynamic_extent, "invalid span");
421   }
422 
423   // Constructs a span that is a view over the array arr; the resulting span
424   // has size() == N and data() == std::data(arr). These overloads only
425   // participate in overload resolution if
426   // extent == std::dynamic_extent || N == extent is true and
427   // std::remove_pointer_t<decltype(std::data(arr))>(*)[]
428   // is convertible to element_type (*)[].
429   template<std::size_t N,
430     typename internal::is_span_convertable<element_type, Extent, element_type, N>::type = 0>
span(element_type (& arr)[N])431   FLATBUFFERS_CONSTEXPR_CPP11 span(element_type (&arr)[N]) FLATBUFFERS_NOEXCEPT
432       : data_(arr), count_(N) {}
433 
434   template<class U, std::size_t N,
435     typename internal::is_span_convertable<element_type, Extent, U, N>::type = 0>
span(std::array<U,N> & arr)436   FLATBUFFERS_CONSTEXPR_CPP11 span(std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
437      : data_(arr.data()), count_(N) {}
438 
439   //template<class U, std::size_t N,
440   //  int = 0>
441   //FLATBUFFERS_CONSTEXPR_CPP11 span(std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
442   //   : data_(arr.data()), count_(N) {}
443 
444   template<class U, std::size_t N,
445     typename internal::is_span_convertable<element_type, Extent, U, N>::type = 0>
span(const std::array<U,N> & arr)446   FLATBUFFERS_CONSTEXPR_CPP11 span(const std::array<U, N> &arr) FLATBUFFERS_NOEXCEPT
447     : data_(arr.data()), count_(N) {}
448 
449   // Converting constructor from another span s;
450   // the resulting span has size() == s.size() and data() == s.data().
451   // This overload only participates in overload resolution
452   // if extent == std::dynamic_extent || N == extent is true and U (*)[]
453   // is convertible to element_type (*)[].
454   template<class U, std::size_t N,
455     typename internal::is_span_convertable<element_type, Extent, U, N>::type = 0>
span(const flatbuffers::span<U,N> & s)456   FLATBUFFERS_CONSTEXPR_CPP11 span(const flatbuffers::span<U, N> &s) FLATBUFFERS_NOEXCEPT
457       : span(s.data(), s.size()) {
458   }
459 
460   #endif  // !defined(FLATBUFFERS_SPAN_MINIMAL)
461 
462  private:
463   // This is a naive implementation with 'count_' member even if (Extent != dynamic_extent).
464   pointer const data_;
465   size_type count_;
466 };
467 #endif  // defined(FLATBUFFERS_USE_STD_SPAN)
468 
469 #if !defined(FLATBUFFERS_SPAN_MINIMAL)
470 template<class ElementType, std::size_t Extent>
471 FLATBUFFERS_CONSTEXPR_CPP11
make_span(ElementType (& arr)[Extent])472 flatbuffers::span<ElementType, Extent> make_span(ElementType(&arr)[Extent]) FLATBUFFERS_NOEXCEPT {
473   return span<ElementType, Extent>(arr);
474 }
475 
476 template<class ElementType, std::size_t Extent>
477 FLATBUFFERS_CONSTEXPR_CPP11
make_span(const ElementType (& arr)[Extent])478 flatbuffers::span<const ElementType, Extent> make_span(const ElementType(&arr)[Extent]) FLATBUFFERS_NOEXCEPT {
479   return span<const ElementType, Extent>(arr);
480 }
481 
482 template<class ElementType, std::size_t Extent>
483 FLATBUFFERS_CONSTEXPR_CPP11
make_span(std::array<ElementType,Extent> & arr)484 flatbuffers::span<ElementType, Extent> make_span(std::array<ElementType, Extent> &arr) FLATBUFFERS_NOEXCEPT {
485   return span<ElementType, Extent>(arr);
486 }
487 
488 template<class ElementType, std::size_t Extent>
489 FLATBUFFERS_CONSTEXPR_CPP11
make_span(const std::array<ElementType,Extent> & arr)490 flatbuffers::span<const ElementType, Extent> make_span(const std::array<ElementType, Extent> &arr) FLATBUFFERS_NOEXCEPT {
491   return span<const ElementType, Extent>(arr);
492 }
493 
494 template<class ElementType, std::size_t Extent>
495 FLATBUFFERS_CONSTEXPR_CPP11
make_span(ElementType * first,std::size_t count)496 flatbuffers::span<ElementType, dynamic_extent> make_span(ElementType *first, std::size_t count) FLATBUFFERS_NOEXCEPT {
497   return span<ElementType, dynamic_extent>(first, count);
498 }
499 
500 template<class ElementType, std::size_t Extent>
501 FLATBUFFERS_CONSTEXPR_CPP11
make_span(const ElementType * first,std::size_t count)502 flatbuffers::span<const ElementType, dynamic_extent> make_span(const ElementType *first, std::size_t count) FLATBUFFERS_NOEXCEPT {
503   return span<const ElementType, dynamic_extent>(first, count);
504 }
505 #endif // !defined(FLATBUFFERS_SPAN_MINIMAL)
506 
507 }  // namespace flatbuffers
508 
509 #endif  // FLATBUFFERS_STL_EMULATION_H_
510