1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 // This file does nothing functional!
24 // It test support for main C++11 features
25 // In the future, it might be extended to test also C++14, C++17, C++20 and any future standard
26 //
27 // In order to enable the tests, we have to `define ENABLE_TEST_CPP_11` (and of course, compile this file)
28 // Then it should print "Testing C++11" *during compilation*
29 // If the message is printed, and there are no compilation errors - great, C++11 is supported on this platform
30 // If there are errors, each one of the tests can be disabled, by defining the relevant DONT_TEST_*
31 // It's important to disable failing tests, because we might decide to support only specific subset of C++11
32 //
33 // Note: there are 3 warnings in my GCC run, they have no signficance
34
35 #if defined(NONSTANDARD_PORT)
36 #include "portdefs.h"
37 #endif
38
39 #if defined(HAVE_CONFIG_H)
40 #include "config.h"
41 #endif
42
43 #ifdef ENABLE_TEST_CPP_11
44 #pragma message("Testing C++11")
45 // The tests are based on https://blog.petrzemek.net/2014/12/07/improving-cpp98-code-with-cpp11/
46 // See there for further links and explanations
47 //
48 // We're not testing `nullptr` and `override`, since they're defined in common/c++11-compat.h
49
50 #include "common/array.h"
51 #include "common/hashmap.h"
52 #include "common/hash-str.h"
53 #include "common/rect.h"
54
55 #ifndef DONT_TEST_UNICODE_STRING_LITERAL
56 const char16_t *u16str = u"\u00DAnicode string";
57 const char32_t *u32str = U"\u00DAnicode string";
58 #endif
59
60 #ifndef DONT_TEST_INITIALIZIER_LIST1
61 #ifndef USE_INITIALIZIER_LIST_REPLACEMENT
62 #include <initializer_list>
63 #else
64 namespace std {
65 template<class T> class initializer_list {
66 public:
67 typedef T value_type;
68 typedef const T& reference;
69 typedef const T& const_reference;
70 typedef size_t size_type;
71 typedef const T* iterator;
72 typedef const T* const_iterator;
73
74 constexpr initializer_list() noexcept = default;
size() const75 constexpr size_t size() const noexcept { return m_size; };
begin() const76 constexpr const T* begin() const noexcept { return m_begin; };
end() const77 constexpr const T* end() const noexcept { return m_begin + m_size; }
78
79 private:
80 // Note: begin has to be first or the compiler gets very upset
81 const T* m_begin = { nullptr };
82 size_t m_size = { 0 };
83
84 // The compiler is allowed to call this constructor
initializer_list(const T * t,size_t s)85 constexpr initializer_list(const T* t, size_t s) noexcept : m_begin(t) , m_size(s) {}
86 };
87
begin(initializer_list<T> il)88 template<class T> constexpr const T* begin(initializer_list<T> il) noexcept {
89 return il.begin();
90 }
91
end(initializer_list<T> il)92 template<class T> constexpr const T* end(initializer_list<T> il) noexcept {
93 return il.end();
94 }
95 } // end namespace std
96 #endif
97 #endif
98
99 #ifndef DONT_TEST_CLASS_ENUM
100 // ----------------------------------
101 // Scoped/Strongly Typed Enumerations
102 // ----------------------------------
103 enum class MyEnum {
104 VAL1,
105 VAL2,
106 VAL3
107 };
108 #endif
109
110 #ifndef DONT_TEST_FINAL_CLASS
111 // ----------------------------------
112 // Non-Inheritable Classes (final)
113 // ----------------------------------
114 // C++11
115 class TestNewStandards final {
116 #else
117 class TestNewStandards {
118 #endif
119 private:
do_nothing(const int & i)120 void do_nothing(const int &i) {
121 // don't do anything with i
122 };
123
124 #ifndef DONT_TEST_FINAL_FUNCTION
125 // ----------------------------------
126 // Non-Overridable Member Functions (final)
127 // ----------------------------------
f()128 virtual void f() final {}
129 #endif
130
131 #ifndef DONT_TEST_VARIADIC_TEMPLATES
132 // ------------------------
133 // Variadic Templates
134 // ------------------------
135 template <typename T>
variadic_function(const T & value)136 void variadic_function(const T &value) {
137 do_nothing(value);
138 }
139
140 template <typename U, typename... T>
variadic_function(const U & head,const T &...tail)141 void variadic_function(const U &head, const T &... tail) {
142 do_nothing(head);
143 variadic_function(tail...);
144 }
145 #endif
146
147 #ifndef DONT_TEST_TYPE_ALIASES
148 // ------------------------
149 // Type Aliases
150 // * note - this test has another bunch of code below
151 // ------------------------
152 // C++98
153 template<typename T>
154 struct Dictionary_98 {
155 typedef Common::HashMap<Common::String, T, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> type;
156 };
157 // Usage:
158 Dictionary_98<int>::type d98;
159
160 // C++11
161 template <typename T>
162 using Dictionary_11 = Common::HashMap<Common::String, T, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo>;
163 // Usage:
164 Dictionary_11<int> d11;
165 #endif
166
167 #ifndef DONT_TEST_INITIALIZIER_LIST1
168 // Array with C++11 initialization list
169 template<class T> class ArrayCpp11 : public Common::Array<T> {
170 public:
ArrayCpp11(std::initializer_list<T> list)171 ArrayCpp11(std::initializer_list<T> list) {
172 if (list.size()) {
173 this->allocCapacity(list.size());
174 Common::uninitialized_copy(list.begin(), list.end(), this->_storage);
175 }
176 }
177 };
178 #endif
179
test_cpp11()180 void test_cpp11() {
181 #ifdef DONT_TEST_INITIALIZIER_LIST1
182 // ------------------------
183 // Initializer list
184 // ------------------------
185 // C++98
186 Common::Array<int> arr;
187 arr.push_back(1);
188 arr.push_back(2);
189 arr.push_back(3);
190 #else
191 // C++11
192 ArrayCpp11<int> arr = {1, 2, 3};
193 #endif
194
195 #ifndef DONT_TEST_INITIALIZIER_LIST2
196 // C++11
197 Common::Point arr3[] = {{0, 0}, {1, 1}};
198 #endif
199
200 #ifndef DONT_TEST_AUTO_TYPE_INFERENCE
201 // ------------------------
202 // Automatic Type Inference
203 // ------------------------
204 // C++98
205 for (Common::Array<int>::iterator i = arr.begin(), e = arr.end(); i != e; ++i)
206 ;
207
208 // C++11
209 for (auto i = arr.begin(), e = arr.end(); i != e; ++i)
210 ;
211 #endif
212
213 #ifndef DONT_TEST_RANGE_BASED_FOR_LOOP
214 // ------------------------
215 // Range based for loop
216 // ------------------------
217 // C++98
218 for (Common::Array<int>::iterator i = arr.begin(), e = arr.end(); i != e; ++i)
219 do_nothing(*i);
220
221 // C++11
222 for (int &i : arr)
223 do_nothing(i);
224 #endif
225
226 #ifndef DONT_TEST_LAMBDA_FUNCTIONS
227 // ------------------------
228 // Lambda functions
229 // ------------------------
230 // C++98
231 // the following isn't working in VS, but it's not really important to debug...
232 // Common::for_each(arr.begin(), arr.end(), do_nothing);
233
234 // C++11
235 Common::for_each(arr.begin(), arr.end(),
236 [](int i) {
237 // don't do anything with i
238 }
239 );
240 #endif
241
242 #ifndef DONT_TEST_VARIADIC_TEMPLATES
243 variadic_function(1, 1, 2, 3, 5, 8, 13, 21, 34);
244 #endif
245
246 #ifndef DONT_TEST_GET_RID_OF_SPACE_IN_NESTED_TEMPLATES
247 // ------------------------
248 // No Need For an Extra Space In Nested Template Declarations
249 // ------------------------
250 // C++98
251 Common::Array<Common::Array<int> > v_98;
252
253 // C++11
254 Common::Array<Common::Array<int>> v_11;
255 #endif
256
257 #ifndef DONT_TEST_TYPE_ALIASES
258 // ------------------------
259 // Type Aliases
260 // * note - this test has another bunch of code above
261 // ------------------------
262 // C++98
263 typedef void (*fp_98)(int, int);
264
265 // C++11
266 using fp_11 = void (*)(int, int);
267 #endif
268
269 };
270
271 #ifndef DONT_TEST_ALT_FUNCTION_SYNTAX
272 // ------------------------
273 // Alternative Function Syntax
274 // ------------------------
275 // C++98
f_98(int x,int y)276 int f_98(int x, int y) {return x;}
277
278 // C++11
f_11(int x,int y)279 auto f_11(int x, int y) -> int {return x;}
280 #endif
281
282 #ifndef DONT_TEST_NON_STATIC_INIT
283 // ------------------------
284 // Non-Static Data Member Initializers
285 // ------------------------
286 int j = 3;
287 Common::String s = "non static init";
288 #endif
289
290 #ifndef DONT_TEST_EXPLICIT
291 // ------------------------
292 // Explicit Conversion Operators
293 // ------------------------
operator bool() const294 explicit operator bool() const {return true;}
295 #endif
296
297
298 public:
TestNewStandards()299 TestNewStandards() {
300 test_cpp11();
301 }
302
303 #ifndef DONT_TEST_MOVE_SEMANTICS
304 // ------------------------
305 // Move semantics
306 // Note: this test hasn't been taken from the aforementioned web page
307 // ------------------------
TestNewStandards(TestNewStandards && t)308 TestNewStandards(TestNewStandards&& t) {
309 // I'm not convinced that it's a good example of move sematics, it's a complicated topic. But just checking the syntax.
310 }
311 #endif
312
313
314 #ifndef DONT_TEST_DELETED_FUNCTIONS
315 // ------------------------
316 // Explicitly Deleted Functions
317 // (useful for non copyable classes,
318 // particularly for our Singleton class)
319 // ------------------------
320 TestNewStandards &operator=(const TestNewStandards &) = delete;
321 #endif
322
323 };
324
325 static TestNewStandards test = TestNewStandards();
326
327 #endif
328