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#include <string>
21#include <type_traits>
22#include <vector>
23#include <memory>
24#include <limits>
25
26#if defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
27  #define FLATBUFFERS_CPP98_STL
28#endif  // defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
29
30#if defined(FLATBUFFERS_CPP98_STL)
31  #include <cctype>
32#endif  // defined(FLATBUFFERS_CPP98_STL)
33
34// This header provides backwards compatibility for C++98 STLs like stlport.
35namespace flatbuffers {
36
37// Retrieve ::back() from a string in a way that is compatible with pre C++11
38// STLs (e.g stlport).
39inline char string_back(const std::string &value) {
40  return value[value.length() - 1];
41}
42
43// Helper method that retrieves ::data() from a vector in a way that is
44// compatible with pre C++11 STLs (e.g stlport).
45template <typename T> inline T *vector_data(std::vector<T> &vector) {
46  // In some debug environments, operator[] does bounds checking, so &vector[0]
47  // can't be used.
48  return &(*vector.begin());
49}
50
51template <typename T> inline const T *vector_data(
52    const std::vector<T> &vector) {
53  return &(*vector.begin());
54}
55
56template <typename T, typename V>
57inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
58  #if defined(FLATBUFFERS_CPP98_STL)
59    vector->push_back(data);
60  #else
61    vector->emplace_back(std::forward<V>(data));
62  #endif  // defined(FLATBUFFERS_CPP98_STL)
63}
64
65#ifndef FLATBUFFERS_CPP98_STL
66  #if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
67    template <typename T>
68    using numeric_limits = std::numeric_limits<T>;
69  #else
70    template <typename T> class numeric_limits :
71      public std::numeric_limits<T> {};
72  #endif  // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
73#else
74  template <typename T> class numeric_limits :
75      public std::numeric_limits<T> {};
76
77  template <> class numeric_limits<unsigned long long> {
78   public:
79    static unsigned long long min() { return 0ULL; }
80    static unsigned long long max() { return ~0ULL; }
81  };
82
83  template <> class numeric_limits<long long> {
84   public:
85    static long long min() {
86      return static_cast<long long>(1ULL << ((sizeof(long long) << 3) - 1));
87    }
88    static long long max() {
89      return static_cast<long long>(
90          (1ULL << ((sizeof(long long) << 3) - 1)) - 1);
91    }
92  };
93#endif  // FLATBUFFERS_CPP98_STL
94
95#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
96  #ifndef FLATBUFFERS_CPP98_STL
97    template <typename T> using is_scalar = std::is_scalar<T>;
98    template <typename T, typename U> using is_same = std::is_same<T,U>;
99    template <typename T> using is_floating_point = std::is_floating_point<T>;
100    template <typename T> using is_unsigned = std::is_unsigned<T>;
101  #else
102    // Map C++ TR1 templates defined by stlport.
103    template <typename T> using is_scalar = std::tr1::is_scalar<T>;
104    template <typename T, typename U> using is_same = std::tr1::is_same<T,U>;
105    template <typename T> using is_floating_point =
106        std::tr1::is_floating_point<T>;
107    template <typename T> using is_unsigned = std::tr1::is_unsigned<T>;
108  #endif  // !FLATBUFFERS_CPP98_STL
109#else
110  // MSVC 2010 doesn't support C++11 aliases.
111  template <typename T> struct is_scalar : public std::is_scalar<T> {};
112  template <typename T, typename U> struct is_same : public std::is_same<T,U> {};
113  template <typename T> struct is_floating_point :
114        public std::is_floating_point<T> {};
115  template <typename T> struct is_unsigned : public std::is_unsigned<T> {};
116#endif  // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
117
118#ifndef FLATBUFFERS_CPP98_STL
119  #if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
120    template <class T> using unique_ptr = std::unique_ptr<T>;
121  #else
122    // MSVC 2010 doesn't support C++11 aliases.
123    // We're manually "aliasing" the class here as we want to bring unique_ptr
124    // into the flatbuffers namespace.  We have unique_ptr in the flatbuffers
125    // namespace we have a completely independent implemenation (see below)
126    // for C++98 STL implementations.
127    template <class T> class unique_ptr : public std::unique_ptr<T> {
128     public:
129      unique_ptr() {}
130      explicit unique_ptr(T* p) : std::unique_ptr<T>(p) {}
131      unique_ptr(std::unique_ptr<T>&& u) { *this = std::move(u); }
132      unique_ptr(unique_ptr&& u) { *this = std::move(u); }
133      unique_ptr& operator=(std::unique_ptr<T>&& u) {
134        std::unique_ptr<T>::reset(u.release());
135        return *this;
136      }
137      unique_ptr& operator=(unique_ptr&& u) {
138        std::unique_ptr<T>::reset(u.release());
139        return *this;
140      }
141      unique_ptr& operator=(T* p) {
142        return std::unique_ptr<T>::operator=(p);
143      }
144    };
145  #endif  // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
146#else
147  // Very limited implementation of unique_ptr.
148  // This is provided simply to allow the C++ code generated from the default
149  // settings to function in C++98 environments with no modifications.
150  template <class T> class unique_ptr {
151   public:
152    typedef T element_type;
153
154    unique_ptr() : ptr_(nullptr) {}
155    explicit unique_ptr(T* p) : ptr_(p) {}
156    unique_ptr(unique_ptr&& u) : ptr_(nullptr) { reset(u.release()); }
157    unique_ptr(const unique_ptr& u) : ptr_(nullptr) {
158      reset(const_cast<unique_ptr*>(&u)->release());
159    }
160    ~unique_ptr() { reset(); }
161
162    unique_ptr& operator=(const unique_ptr& u) {
163      reset(const_cast<unique_ptr*>(&u)->release());
164      return *this;
165    }
166
167    unique_ptr& operator=(unique_ptr&& u) {
168      reset(u.release());
169      return *this;
170    }
171
172    unique_ptr& operator=(T* p) {
173      reset(p);
174      return *this;
175    }
176
177    const T& operator*() const { return *ptr_; }
178    T* operator->() const { return ptr_; }
179    T* get() const noexcept { return ptr_; }
180    explicit operator bool() const { return ptr_ != nullptr; }
181
182    // modifiers
183    T* release() {
184      T* value = ptr_;
185      ptr_ = nullptr;
186      return value;
187    }
188
189    void reset(T* p = nullptr) {
190      T* value = ptr_;
191      ptr_ = p;
192      if (value) delete value;
193    }
194
195    void swap(unique_ptr& u) {
196      T* temp_ptr = ptr_;
197      ptr_ = u.ptr_;
198      u.ptr_ = temp_ptr;
199    }
200
201   private:
202    T* ptr_;
203  };
204
205  template <class T> bool operator==(const unique_ptr<T>& x,
206                                     const unique_ptr<T>& y) {
207    return x.get() == y.get();
208  }
209
210  template <class T, class D> bool operator==(const unique_ptr<T>& x,
211                                              const D* y) {
212    return static_cast<D*>(x.get()) == y;
213  }
214
215  template <class T> bool operator==(const unique_ptr<T>& x, intptr_t y) {
216    return reinterpret_cast<intptr_t>(x.get()) == y;
217  }
218#endif  // !FLATBUFFERS_CPP98_STL
219
220}  // namespace flatbuffers
221
222#endif  // FLATBUFFERS_STL_EMULATION_H_
223