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