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