multi_span_tests.cpp revision a9dcbe04ff330ef8297191d19951d4a313b2115a
1///////////////////////////////////////////////////////////////////////////////
2//
3// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
4//
5// This code is licensed under the MIT License (MIT).
6//
7// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
13// THE SOFTWARE.
14//
15///////////////////////////////////////////////////////////////////////////////
16
17#include <UnitTest++/UnitTest++.h>
18#include <array_view.h>
19#include <numeric>
20#include <array>
21#include <string>
22#include <vector>
23#include <list>
24#include <iostream>
25#include <functional>
26#include <algorithm>
27
28
29using namespace std;
30using namespace Guide;
31
32namespace
33{
34	void use(int&) {}
35	struct BaseClass {};
36	struct DerivedClass : BaseClass {};
37}
38
39SUITE(array_view_tests)
40{
41	TEST(basics)
42	{
43		auto ptr = as_array_view(new int[10], 10);
44		fill(ptr.begin(), ptr.end(), 99);
45		for (int num : ptr)
46		{
47			CHECK(num == 99);
48		}
49
50		delete[] ptr.data();
51
52
53		static_bounds<size_t, 4, dynamic_range, 2> bounds{ 3 };
54
55#ifdef CONFIRM_COMPILATION_ERRORS
56		array_view<int, 4, dynamic_range, 2> av(nullptr, bounds);
57		av.extent();
58		av.extent<2>();
59		av[8][4][3];
60#endif
61	}
62
63	TEST (array_view_convertible)
64	{
65#ifdef CONFIRM_COMPILATION_ERRORS
66		array_view<int, 7, 4, 2> av1(nullptr, b1);
67#endif
68
69		auto f = [&]() { array_view<int, 7, 4, 2> av1(nullptr); };
70		CHECK_THROW(f(), fail_fast);
71
72		array_view<int, 7, dynamic_range, 2> av1(nullptr);
73
74#ifdef CONFIRM_COMPILATION_ERRORS
75		static_bounds<size_t, 7, dynamic_range, 2> b12(b11);
76		b12 = b11;
77		b11 = b12;
78
79		array_view<int, dynamic_range> av1 = nullptr;
80		array_view<int, 7, dynamic_range, 2> av2(av1);
81		array_view<int, 7, 4, 2> av2(av1);
82#endif
83
84		array_view<DerivedClass> avd;
85#ifdef CONFIRM_COMPILATION_ERRORS
86		array_view<BaseClass> avb = avd;
87#endif
88		array_view<const DerivedClass> avcd = avd;
89	}
90
91	TEST(boundary_checks)
92	{
93		int arr[10][2];
94		auto av = as_array_view(arr);
95
96		fill(begin(av), end(av), 0);
97
98		av[2][0] = 1;
99		av[1][1] = 3;
100
101		// out of bounds
102		CHECK_THROW(av[1][3] = 3, fail_fast);
103		CHECK_THROW((av[{1, 3}] = 3), fail_fast);
104
105		CHECK_THROW(av[10][2], fail_fast);
106		CHECK_THROW((av[{10,2}]), fail_fast);
107	}
108
109	void overloaded_func(array_view<const int, dynamic_range, 3, 5> exp, int expected_value) {
110		for (auto val : exp)
111		{
112			CHECK(val == expected_value);
113		}
114	}
115
116	void overloaded_func(array_view<const char, dynamic_range, 3, 5> exp, char expected_value) {
117		for (auto val : exp)
118		{
119			CHECK(val == expected_value);
120		}
121	}
122
123	void fixed_func(array_view<int, 3, 3, 5> exp, int expected_value) {
124		for (auto val : exp)
125		{
126			CHECK(val == expected_value);
127		}
128	}
129
130	TEST(array_view_parameter_test)
131	{
132		auto data = new int[4][3][5];
133
134		auto av = as_array_view(data, 4);
135
136		CHECK(av.size() == 60);
137
138		fill(av.begin(), av.end(), 34);
139
140		int count = 0;
141		for_each(av.rbegin(), av.rend(), [&](int val) { count += val; });
142		CHECK(count == 34 * 60);
143		overloaded_func(av, 34);
144
145		overloaded_func(av.as_array_view(dim<>(4), dim<>(3), dim<>(5)), 34);
146
147		//fixed_func(av, 34);
148		delete[] data;
149	}
150
151
152	TEST(md_access)
153	{
154		unsigned int width = 5, height = 20;
155
156		unsigned int imgSize = width * height;
157		auto image_ptr = new int[imgSize][3];
158
159		// size check will be done
160		auto image_view = as_array_view(image_ptr, imgSize).as_array_view(dim<>(height), dim<>(width), dim<3>());
161
162		iota(image_view.begin(), image_view.end(), 1);
163
164		int expected = 0;
165		for (unsigned int i = 0; i < height; i++)
166		{
167			for (unsigned int j = 0; j < width; j++)
168			{
169				CHECK(expected + 1 == image_view[i][j][0]);
170				CHECK(expected + 2 == image_view[i][j][1]);
171				CHECK(expected + 3 == image_view[i][j][2]);
172
173				auto val = image_view[{i, j, 0}];
174				CHECK(expected + 1 == val);
175				val = image_view[{i, j, 1}];
176				CHECK(expected + 2 == val);
177				val = image_view[{i, j, 2}];
178				CHECK(expected + 3 == val);
179
180				expected += 3;
181			}
182		}
183	}
184
185	TEST(array_view_factory_test)
186	{
187		{
188			int * arr = new int[150];
189
190			auto av = as_array_view(arr, dim<10>(), dim<>(3), dim<5>());
191
192			fill(av.begin(), av.end(), 24);
193			overloaded_func(av, 24);
194
195			delete[] arr;
196
197
198			array<int, 15> stdarr{ 0 };
199			auto av2 = as_array_view(stdarr);
200			overloaded_func(av2.as_array_view(dim<>(1), dim<3>(), dim<5>()), 0);
201
202
203			string str = "ttttttttttttttt"; // size = 15
204			auto t = str.data();
205			auto av3 = as_array_view(str);
206			overloaded_func(av3.as_array_view(dim<>(1), dim<3>(), dim<5>()), 't');
207		}
208
209		{
210			int a[3][4][5];
211			auto av = as_array_view(a);
212			const int (*b)[4][5];
213			b = a;
214			auto bv = as_array_view(b, 3);
215
216			CHECK(av == bv);
217
218			const std::array<double, 3> arr = {0.0, 0.0, 0.0};
219			auto cv = as_array_view(arr);
220
221			vector<float> vec(3);
222			auto dv = as_array_view(vec);
223
224#ifdef CONFIRM_COMPILATION_ERRORS
225			auto dv2 = as_array_view(std::move(vec));
226#endif
227		}
228	}
229
230	TEST (array_view_reshape_test)
231	{
232		int a[3][4][5];
233		auto av = as_array_view(a);
234		auto av2 = av.as_array_view(dim<60>());
235		auto av3 = av2.as_array_view(dim<3>(), dim<4>(), dim<5>());
236		auto av4 = av3.as_array_view(dim<4>(), dim<>(3), dim<5>());
237		auto av5 = av4.as_array_view(dim<3>(), dim<4>(), dim<5>());
238		auto av6 = av5.as_array_view(dim<12>(), dim<>(5));
239
240		fill(av6.begin(), av6.end(), 1);
241
242		auto av7 = av6.as_bytes();
243
244		auto av8 = av7.as_array_view<int>();
245
246		CHECK(av8.size() == av6.size());
247		for (size_t i = 0; i < av8.size(); i++)
248		{
249			CHECK(av8[i] == 1);
250		}
251
252#ifdef CONFIRM_COMPILATION_ERRORS
253		struct Foo {char c[11];};
254		auto av9 = av7.as_array_view<Foo>();
255#endif
256	}
257
258
259	TEST (array_view_section_test)
260	{
261		int a[30][4][5];
262
263		auto av = as_array_view(a);
264		auto sub = av.section({15, 0, 0}, Guide::index<3>{2, 2, 2});
265		auto subsub = sub.section({1, 0, 0}, Guide::index<3>{1, 1, 1});
266	}
267
268
269	TEST(constructors)
270	{
271		array_view<int, dynamic_range> av(nullptr);
272		CHECK(av.length() == 0);
273
274		array_view<int, dynamic_range> av2;
275		CHECK(av2.length() == 0);
276
277		array_view<int, dynamic_range> av3(nullptr, 0);
278		CHECK(av3.length() == 0);
279
280		// Constructing from a nullptr + length is specifically disallowed
281		auto f = [&]() {array_view<int, dynamic_range> av4(nullptr, 2);};
282		CHECK_THROW(f(), fail_fast);
283
284		int arr1[2][3];
285		array_view<int, 2, dynamic_range> av5(arr1);
286
287		array<int, 15> arr2;
288		array_view<int, 15> av6(arr2);
289
290		vector<int> vec1(19);
291		array_view<int> av7(vec1);
292		CHECK(av7.length() == 19);
293
294
295		array_view<int> av8;
296		CHECK(av8.length() == 0);
297		array_view<int> av9(arr2);
298		CHECK(av9.length() == 15);
299
300
301#ifdef CONFIRM_COMPILATION_ERRORS
302		array_view<int, 4> av10;
303		DerivedClass *p = nullptr;
304		array_view<BaseClass> av11(p, 0);
305#endif
306
307
308	}
309
310	TEST(copyandassignment)
311	{
312		array_view<int, dynamic_range> av1;
313
314		int arr[] = {3, 4, 5};
315		av1 = arr;
316		array_view<array_view_options<const int, unsigned char>, dynamic_range> av2;
317		av2 = av1;
318	}
319
320	TEST(array_view_first)
321	{
322		int arr[5] = { 1, 2, 3, 4, 5 };
323
324		{
325			array_view<int, 5> av = arr;
326			CHECK((av.first<2>().bounds() == static_bounds<size_t, 2>()));
327			CHECK(av.first<2>().length() == 2);
328			CHECK(av.first(2).length() == 2);
329		}
330
331		{
332			array_view<int, 5> av = arr;
333			CHECK((av.first<0>().bounds() == static_bounds<size_t, 0>()));
334			CHECK(av.first<0>().length() == 0);
335			CHECK(av.first(0).length() == 0);
336		}
337
338		{
339			array_view<int, 5> av = arr;
340			CHECK((av.first<5>().bounds() == static_bounds<size_t, 5>()));
341			CHECK(av.first<5>().length() == 5);
342			CHECK(av.first(5).length() == 5);
343		}
344
345		{
346			array_view<int, 5> av = arr;
347#ifdef CONFIRM_COMPILATION_ERRORS
348			CHECK(av.first<6>().bounds() == static_bounds<size_t, 6>());
349			CHECK(av.first<6>().length() == 6);
350#endif
351			CHECK_THROW(av.first(6).length(), fail_fast);
352		}
353
354		{
355			array_view<int, dynamic_range> av;
356			CHECK((av.first<0>().bounds() == static_bounds<size_t, 0>()));
357			CHECK(av.first<0>().length() == 0);
358			CHECK(av.first(0).length() == 0);
359		}
360	}
361
362	TEST(array_view_last)
363	{
364		int arr[5] = { 1, 2, 3, 4, 5 };
365
366		{
367			array_view<int, 5> av = arr;
368			CHECK((av.last<2>().bounds() == static_bounds<size_t, 2>()));
369			CHECK(av.last<2>().length() == 2);
370			CHECK(av.last(2).length() == 2);
371		}
372
373		{
374			array_view<int, 5> av = arr;
375			CHECK((av.last<0>().bounds() == static_bounds<size_t, 0>()));
376			CHECK(av.last<0>().length() == 0);
377			CHECK(av.last(0).length() == 0);
378		}
379
380		{
381			array_view<int, 5> av = arr;
382			CHECK((av.last<5>().bounds() == static_bounds<size_t, 5>()));
383			CHECK(av.last<5>().length() == 5);
384			CHECK(av.last(5).length() == 5);
385		}
386
387
388		{
389			array_view<int, 5> av = arr;
390#ifdef CONFIRM_COMPILATION_ERRORS
391			CHECK((av.last<6>().bounds() == static_bounds<size_t, 6>()));
392			CHECK(av.last<6>().length() == 6);
393#endif
394			CHECK_THROW(av.last(6).length(), fail_fast);
395		}
396
397		{
398			array_view<int, dynamic_range> av;
399			CHECK((av.last<0>().bounds() == static_bounds<size_t, 0>()));
400			CHECK(av.last<0>().length() == 0);
401			CHECK(av.last(0).length() == 0);
402		}
403	}
404
405	TEST(custmized_array_view_size)
406	{
407		double (*arr)[3][4] = new double[100][3][4];
408		array_view<array_view_options<double, char>, dynamic_range, 3, 4> av1(arr, (char)10);
409
410		struct EffectiveStructure
411		{
412			double* v1;
413			char v2;
414		};
415		CHECK(sizeof(av1) == sizeof(EffectiveStructure));
416
417		CHECK_THROW(av1[10][3][4], fail_fast);
418
419		array_view<const double, dynamic_range, 6, 4> av2 = av1.as_array_view(dim<>(5), dim<6>(), dim<4>());
420
421	}
422
423	TEST(array_view_sub)
424	{
425		int arr[5] = { 1, 2, 3, 4, 5 };
426
427		{
428			array_view<int, 5> av = arr;
429			CHECK((av.sub<2,2>().bounds() == static_bounds<size_t, 2>()));
430			CHECK((av.sub<2,2>().length() == 2));
431			CHECK(av.sub(2,2).length() == 2);
432		}
433
434
435		{
436			array_view<int, 5> av = arr;
437			CHECK((av.sub<0,0>().bounds() == static_bounds<size_t, 0>()));
438			CHECK((av.sub<0,0>().length() == 0));
439			CHECK(av.sub(0,0).length() == 0);
440		}
441
442		{
443			array_view<int, 5> av = arr;
444			CHECK((av.sub<0,5>().bounds() == static_bounds<size_t, 5>()));
445			CHECK((av.sub<0,5>().length() == 5));
446			CHECK(av.sub(0,5).length() == 5);
447		}
448
449		{
450			array_view<int, 5> av = arr;
451#ifdef CONFIRM_COMPILATION_ERRORS
452			CHECK((av.sub<5,0>().bounds() == static_bounds<size_t, 0>()));
453			CHECK((av.sub<5,0>().length() == 0));
454#endif
455			CHECK_THROW(av.sub(5,0).length(), fail_fast);
456		}
457
458		{
459			array_view<int, dynamic_range> av;
460			CHECK((av.sub<0,0>().bounds() == static_bounds<size_t, 0>()));
461			CHECK((av.sub<0,0>().length() == 0));
462			CHECK(av.sub(0,0).length() == 0);
463		}
464	}
465
466	void AssertNullEmptyProperties(array_view<int, dynamic_range>& av)
467	{
468		CHECK(av.length() == 0);
469		CHECK(av.data() == nullptr);
470		CHECK(!av);
471	}
472
473	template <class T, class U>
474	void AssertContentsMatch(T a1, U a2)
475	{
476		CHECK(a1.length() == a2.length());
477		for (size_t i = 0; i < a1.length(); ++i)
478			CHECK(a1[i] == a2[i]);
479	}
480
481	TEST(TestNullConstruction)
482	{
483		array_view<int, dynamic_range> av;
484		AssertNullEmptyProperties(av);
485
486		array_view<int, dynamic_range> av2(nullptr);
487		AssertNullEmptyProperties(av2);
488	}
489
490	TEST(ArrayConstruction)
491	{
492		int a[] = { 1, 2, 3, 4 };
493
494		array_view<int, dynamic_range> av = { &a[1], 3 };
495		CHECK(av.length() == 3);
496
497		array_view<int, dynamic_range> av3 = { a, 2 };
498		CHECK(av3.length() == 2);
499
500		array_view<int, dynamic_range> av2 = a;
501		CHECK(av2.length() == 4);
502	}
503
504	TEST(NonConstConstConversions)
505	{
506		int a[] = { 1, 2, 3, 4 };
507
508#ifdef CONFIRM_COMPILATION_ERRORS
509		array_view<const int, dynamic_range> cav = a;
510		array_view<int, dynamic_range> av = cav;
511#else
512		array_view<int, dynamic_range> av = a;
513		array_view<const int, dynamic_range> cav = av;
514#endif
515		AssertContentsMatch(av, cav);
516	}
517
518	TEST(FixedSizeConversions)
519	{
520		int arr[] = { 1, 2, 3, 4 };
521
522		// converting to an array_view from an equal size array is ok
523		array_view<int, 4> av4 = arr;
524		CHECK(av4.length() == 4);
525
526		// converting to dynamic_range a_v is always ok
527		{
528			array_view<int, dynamic_range> av = av4;
529		}
530		{
531			array_view<int, dynamic_range> av = arr;
532		}
533
534		// initialization or assignment to static array_view that REDUCES size is NOT ok
535#ifdef CONFIRM_COMPILATION_ERRORS
536		{
537			array_view<int, 2> av2 = arr;
538		}
539		{
540			array_view<int, 2> av2 = av4;
541		}
542#endif
543
544		{
545			array_view<int, dynamic_range> av = arr;
546			array_view<int, 2> av2 = av;
547		}
548
549#ifdef CONFIRM_COMPILATION_ERRORS
550		{
551			array_view<int, dynamic_range> av = arr;
552			array_view<int, 2, 1> av2 = av.as_array_view(dim<2>(), dim<2>());
553		}
554#endif
555
556		{
557			array_view<int, dynamic_range> av = arr;
558			auto f = [&]() {array_view<int, 2, 1> av2 = av.as_array_view(dim<>(2), dim<>(2));};
559			CHECK_THROW(f(), fail_fast);
560		}
561
562		// but doing so explicitly is ok
563
564		// you can convert statically
565		{
566			array_view<int, 2> av2 = {arr, 2};
567		}
568		{
569			array_view<int, 1> av2 = av4.first<1>();
570		}
571
572		// ...or dynamically
573		{
574			// NB: implicit conversion to array_view<int,2> from array_view<int,dynamic_range>
575			array_view<int, 1> av2 = av4.first(1);
576		}
577
578		// initialization or assignment to static array_view that requires size INCREASE is not ok.
579		int arr2[2]  = { 1, 2 };
580
581#ifdef CONFIRM_COMPILATION_ERRORS
582		{
583			array_view<int, 4> av4 = arr2;
584		}
585		{
586			array_view<int, 2> av2 = arr2;
587			array_view<int, 4> av4 = av2;
588		}
589#endif
590		{
591			auto f = [&]() {array_view<int, 4> av4 = {arr2, 2};};
592			CHECK_THROW(f(), fail_fast);
593		}
594
595		// this should fail - we are trying to assign a small dynamic a_v to a fixed_size larger one
596		array_view<int, dynamic_range> av = arr2;
597		auto f = [&](){ array_view<int, 4> av2 = av; };
598		CHECK_THROW(f(), fail_fast);
599	}
600
601	TEST(AsWriteableBytes)
602	{
603		int a[] = { 1, 2, 3, 4 };
604
605		{
606#ifdef CONFIRM_COMPILATION_ERRORS
607			// you should not be able to get writeable bytes for const objects
608			array_view<const int, dynamic_range> av = a;
609			auto wav = av.as_writeable_bytes();
610#endif
611		}
612
613		{
614			array_view<int, dynamic_range> av;
615			auto wav = av.as_writeable_bytes();
616			CHECK(wav.length() == av.length());
617			CHECK(wav.length() == 0);
618			CHECK(wav.bytes() == 0);
619		}
620
621		{
622			array_view<int, dynamic_range> av = a;
623			auto wav = av.as_writeable_bytes();
624			CHECK(wav.data() == (byte*)&a[0]);
625			CHECK(wav.length() == sizeof(a));
626		}
627
628	}
629
630
631	TEST(ArrayViewComparison)
632	{
633		int arr[10][2];
634		auto av1 = as_array_view(arr);
635		array_view<const int, dynamic_range, 2> av2 = av1;
636
637		CHECK(av1 == av2);
638
639		array_view<array_view_options<int, char>, 20> av3 = av1.as_array_view(dim<>(20));
640		CHECK(av3 == av2 && av3 == av1);
641
642	}
643}
644
645int main(int, const char *[])
646{
647	return UnitTest::RunAllTests();
648}
649