1 | //===-- flang/unittests/Runtime/Transformational.cpp ----------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "flang/Runtime/transformational.h" |
10 | #include "gtest/gtest.h" |
11 | #include "tools.h" |
12 | #include "flang/Common/float128.h" |
13 | #include "flang/Runtime/type-code.h" |
14 | #include <vector> |
15 | |
16 | using namespace Fortran::runtime; |
17 | using Fortran::common::TypeCategory; |
18 | |
19 | template <int KIND> |
20 | using BesselFuncType = std::function<void(Descriptor &, int32_t, int32_t, |
21 | CppTypeFor<TypeCategory::Real, KIND>, CppTypeFor<TypeCategory::Real, KIND>, |
22 | CppTypeFor<TypeCategory::Real, KIND>, const char *, int)>; |
23 | |
24 | template <int KIND> |
25 | using BesselX0FuncType = |
26 | std::function<void(Descriptor &, int32_t, int32_t, const char *, int)>; |
27 | |
28 | template <int KIND> |
29 | constexpr CppTypeFor<TypeCategory::Real, KIND> |
30 | besselEpsilon = CppTypeFor<TypeCategory::Real, KIND>(1e-4); |
31 | |
32 | template <int KIND> |
33 | static void testBesselJn(BesselFuncType<KIND> rtFunc, int32_t n1, int32_t n2, |
34 | CppTypeFor<TypeCategory::Real, KIND> x, |
35 | const std::vector<CppTypeFor<TypeCategory::Real, KIND>> &expected) { |
36 | StaticDescriptor<1> desc; |
37 | Descriptor &result{desc.descriptor()}; |
38 | unsigned len = expected.size(); |
39 | |
40 | CppTypeFor<TypeCategory::Real, KIND> anc0 = len > 0 ? expected[len - 1] : 0.0; |
41 | CppTypeFor<TypeCategory::Real, KIND> anc1 = len > 1 ? expected[len - 2] : 0.0; |
42 | |
43 | rtFunc(result, n1, n2, x, anc0, anc1, __FILE__, __LINE__); |
44 | |
45 | EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Real, KIND})); |
46 | EXPECT_EQ(result.rank(), 1); |
47 | EXPECT_EQ( |
48 | result.ElementBytes(), sizeof(CppTypeFor<TypeCategory::Real, KIND>)); |
49 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
50 | EXPECT_EQ(result.GetDimension(0).Extent(), len); |
51 | |
52 | for (size_t j{0}; j < len; ++j) { |
53 | EXPECT_NEAR( |
54 | (*result.ZeroBasedIndexedElement<CppTypeFor<TypeCategory::Real, KIND>>( |
55 | j)), |
56 | expected[j], besselEpsilon<KIND>); |
57 | } |
58 | } |
59 | |
60 | template <int KIND> |
61 | static void testBesselJnX0( |
62 | BesselX0FuncType<KIND> rtFunc, int32_t n1, int32_t n2) { |
63 | StaticDescriptor<1> desc; |
64 | Descriptor &result{desc.descriptor()}; |
65 | |
66 | rtFunc(result, n1, n2, __FILE__, __LINE__); |
67 | |
68 | EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Real, KIND})); |
69 | EXPECT_EQ(result.rank(), 1); |
70 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
71 | EXPECT_EQ(result.GetDimension(0).Extent(), n2 >= n1 ? n2 - n1 + 1 : 0); |
72 | |
73 | if (n2 < n1) { |
74 | return; |
75 | } |
76 | |
77 | EXPECT_NEAR( |
78 | (*result.ZeroBasedIndexedElement<CppTypeFor<TypeCategory::Real, KIND>>( |
79 | 0)), |
80 | (n1 == 0) ? 1.0 : 0.0, 1e-5); |
81 | |
82 | for (int j{1}; j < (n2 - n1 + 1); ++j) { |
83 | EXPECT_NEAR( |
84 | (*result.ZeroBasedIndexedElement<CppTypeFor<TypeCategory::Real, KIND>>( |
85 | j)), |
86 | 0.0, besselEpsilon<KIND>); |
87 | } |
88 | } |
89 | |
90 | template <int KIND> static void testBesselJn(BesselFuncType<KIND> rtFunc) { |
91 | testBesselJn<KIND>(rtFunc, 1, 0, 1.0, {}); |
92 | testBesselJn<KIND>(rtFunc, 0, 0, 1.0, {0.765197694}); |
93 | testBesselJn<KIND>(rtFunc, 0, 1, 1.0, {0.765197694, 0.440050572}); |
94 | testBesselJn<KIND>( |
95 | rtFunc, 0, 2, 1.0, {0.765197694, 0.440050572, 0.114903487}); |
96 | testBesselJn<KIND>(rtFunc, 1, 5, 5.0, |
97 | {-0.327579111, 0.046565145, 0.364831239, 0.391232371, 0.261140555}); |
98 | } |
99 | |
100 | template <int KIND> static void testBesselJnX0(BesselX0FuncType<KIND> rtFunc) { |
101 | testBesselJnX0<KIND>(rtFunc, 1, 0); |
102 | testBesselJnX0<KIND>(rtFunc, 0, 0); |
103 | testBesselJnX0<KIND>(rtFunc, 1, 1); |
104 | testBesselJnX0<KIND>(rtFunc, 0, 3); |
105 | testBesselJnX0<KIND>(rtFunc, 1, 4); |
106 | } |
107 | |
108 | static void testBesselJn() { |
109 | testBesselJn<4>(RTNAME(BesselJn_4)); |
110 | testBesselJn<8>(RTNAME(BesselJn_8)); |
111 | #if LDBL_MANT_DIG == 64 |
112 | testBesselJn<10>(RTNAME(BesselJn_10)); |
113 | #endif |
114 | #if LDBL_MANT_DIG == 113 || HAS_FLOAT128 |
115 | testBesselJn<16>(RTNAME(BesselJn_16)); |
116 | #endif |
117 | |
118 | testBesselJnX0<4>(RTNAME(BesselJnX0_4)); |
119 | testBesselJnX0<8>(RTNAME(BesselJnX0_8)); |
120 | #if LDBL_MANT_DIG == 64 |
121 | testBesselJnX0<10>(RTNAME(BesselJnX0_10)); |
122 | #endif |
123 | #if LDBL_MANT_DIG == 113 || HAS_FLOAT128 |
124 | testBesselJnX0<16>(RTNAME(BesselJnX0_16)); |
125 | #endif |
126 | } |
127 | |
128 | TEST(Transformational, BesselJn) { testBesselJn(); } |
129 | |
130 | template <int KIND> |
131 | static void testBesselYn(BesselFuncType<KIND> rtFunc, int32_t n1, int32_t n2, |
132 | CppTypeFor<TypeCategory::Real, KIND> x, |
133 | const std::vector<CppTypeFor<TypeCategory::Real, KIND>> &expected) { |
134 | StaticDescriptor<1> desc; |
135 | Descriptor &result{desc.descriptor()}; |
136 | unsigned len = expected.size(); |
137 | |
138 | CppTypeFor<TypeCategory::Real, KIND> anc0 = len > 0 ? expected[0] : 0.0; |
139 | CppTypeFor<TypeCategory::Real, KIND> anc1 = len > 1 ? expected[1] : 0.0; |
140 | |
141 | rtFunc(result, n1, n2, x, anc0, anc1, __FILE__, __LINE__); |
142 | |
143 | EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Real, KIND})); |
144 | EXPECT_EQ(result.rank(), 1); |
145 | EXPECT_EQ( |
146 | result.ElementBytes(), sizeof(CppTypeFor<TypeCategory::Real, KIND>)); |
147 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
148 | EXPECT_EQ(result.GetDimension(0).Extent(), len); |
149 | |
150 | for (size_t j{0}; j < len; ++j) { |
151 | EXPECT_NEAR( |
152 | (*result.ZeroBasedIndexedElement<CppTypeFor<TypeCategory::Real, KIND>>( |
153 | j)), |
154 | expected[j], besselEpsilon<KIND>); |
155 | } |
156 | } |
157 | |
158 | template <int KIND> |
159 | static void testBesselYnX0( |
160 | BesselX0FuncType<KIND> rtFunc, int32_t n1, int32_t n2) { |
161 | StaticDescriptor<1> desc; |
162 | Descriptor &result{desc.descriptor()}; |
163 | |
164 | rtFunc(result, n1, n2, __FILE__, __LINE__); |
165 | |
166 | EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Real, KIND})); |
167 | EXPECT_EQ(result.rank(), 1); |
168 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
169 | EXPECT_EQ(result.GetDimension(0).Extent(), n2 >= n1 ? n2 - n1 + 1 : 0); |
170 | |
171 | if (n2 < n1) { |
172 | return; |
173 | } |
174 | |
175 | for (int j{0}; j < (n2 - n1 + 1); ++j) { |
176 | EXPECT_EQ( |
177 | (*result.ZeroBasedIndexedElement<CppTypeFor<TypeCategory::Real, KIND>>( |
178 | j)), |
179 | (-std::numeric_limits< |
180 | CppTypeFor<TypeCategory::Real, KIND>>::infinity())); |
181 | } |
182 | } |
183 | |
184 | template <int KIND> static void testBesselYn(BesselFuncType<KIND> rtFunc) { |
185 | testBesselYn<KIND>(rtFunc, 1, 0, 1.0, {}); |
186 | testBesselYn<KIND>(rtFunc, 0, 0, 1.0, {0.08825695}); |
187 | testBesselYn<KIND>(rtFunc, 0, 1, 1.0, {0.08825695, -0.7812128}); |
188 | testBesselYn<KIND>(rtFunc, 0, 2, 1.0, {0.0882569555, -0.7812128, -1.6506826}); |
189 | testBesselYn<KIND>(rtFunc, 1, 5, 1.0, |
190 | {-0.7812128, -1.6506826, -5.8215175, -33.278423, -260.40588}); |
191 | } |
192 | |
193 | template <int KIND> static void testBesselYnX0(BesselX0FuncType<KIND> rtFunc) { |
194 | testBesselYnX0<KIND>(rtFunc, 1, 0); |
195 | testBesselYnX0<KIND>(rtFunc, 0, 0); |
196 | testBesselYnX0<KIND>(rtFunc, 1, 1); |
197 | testBesselYnX0<KIND>(rtFunc, 0, 3); |
198 | testBesselYnX0<KIND>(rtFunc, 1, 4); |
199 | } |
200 | |
201 | static void testBesselYn() { |
202 | testBesselYn<4>(RTNAME(BesselYn_4)); |
203 | testBesselYn<8>(RTNAME(BesselYn_8)); |
204 | #if LDBL_MANT_DIG == 64 |
205 | testBesselYn<10>(RTNAME(BesselYn_10)); |
206 | #endif |
207 | #if LDBL_MANT_DIG == 113 || HAS_FLOAT128 |
208 | testBesselYn<16>(RTNAME(BesselYn_16)); |
209 | #endif |
210 | |
211 | testBesselYnX0<4>(RTNAME(BesselYnX0_4)); |
212 | testBesselYnX0<8>(RTNAME(BesselYnX0_8)); |
213 | #if LDBL_MANT_DIG == 64 |
214 | testBesselYnX0<10>(RTNAME(BesselYnX0_10)); |
215 | #endif |
216 | #if LDBL_MANT_DIG == 113 || HAS_FLOAT128 |
217 | testBesselYnX0<16>(RTNAME(BesselYnX0_16)); |
218 | #endif |
219 | } |
220 | |
221 | TEST(Transformational, BesselYn) { testBesselYn(); } |
222 | |
223 | TEST(Transformational, Shifts) { |
224 | // ARRAY 1 3 5 |
225 | // 2 4 6 |
226 | auto array{MakeArray<TypeCategory::Integer, 4>( |
227 | std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})}; |
228 | array->GetDimension(0).SetLowerBound(0); // shouldn't matter |
229 | array->GetDimension(1).SetLowerBound(-1); |
230 | StaticDescriptor<2, true> statDesc; |
231 | Descriptor &result{statDesc.descriptor()}; |
232 | |
233 | auto shift3{MakeArray<TypeCategory::Integer, 8>( |
234 | std::vector<int>{3}, std::vector<std::int64_t>{1, -1, 2})}; |
235 | RTNAME(Cshift)(result, *array, *shift3, 1, __FILE__, __LINE__); |
236 | EXPECT_EQ(result.type(), array->type()); |
237 | EXPECT_EQ(result.rank(), 2); |
238 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
239 | EXPECT_EQ(result.GetDimension(0).Extent(), 2); |
240 | EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); |
241 | EXPECT_EQ(result.GetDimension(1).Extent(), 3); |
242 | EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Integer, 4})); |
243 | static std::int32_t cshiftExpect1[6]{2, 1, 4, 3, 5, 6}; |
244 | for (int j{0}; j < 6; ++j) { |
245 | EXPECT_EQ( |
246 | *result.ZeroBasedIndexedElement<std::int32_t>(j), cshiftExpect1[j]); |
247 | } |
248 | result.Destroy(); |
249 | |
250 | auto shift2{MakeArray<TypeCategory::Integer, 1>( |
251 | std::vector<int>{2}, std::vector<std::int8_t>{1, -1})}; |
252 | shift2->GetDimension(0).SetLowerBound(-1); // shouldn't matter |
253 | RTNAME(Cshift)(result, *array, *shift2, 2, __FILE__, __LINE__); |
254 | EXPECT_EQ(result.type(), array->type()); |
255 | EXPECT_EQ(result.rank(), 2); |
256 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
257 | EXPECT_EQ(result.GetDimension(0).Extent(), 2); |
258 | EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); |
259 | EXPECT_EQ(result.GetDimension(1).Extent(), 3); |
260 | EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Integer, 4})); |
261 | static std::int32_t cshiftExpect2[6]{3, 6, 5, 2, 1, 4}; |
262 | for (int j{0}; j < 6; ++j) { |
263 | EXPECT_EQ( |
264 | *result.ZeroBasedIndexedElement<std::int32_t>(j), cshiftExpect2[j]); |
265 | } |
266 | result.Destroy(); |
267 | |
268 | // VECTOR 1 3 5 2 4 6 |
269 | auto vector{MakeArray<TypeCategory::Integer, 4>( |
270 | std::vector<int>{6}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})}; |
271 | vector->GetDimension(0).SetLowerBound(0); |
272 | StaticDescriptor<1, true> vectorDesc; |
273 | Descriptor &vectorResult{vectorDesc.descriptor()}; |
274 | |
275 | RTNAME(CshiftVector)(vectorResult, *vector, 2, __FILE__, __LINE__); |
276 | EXPECT_EQ(vectorResult.type(), array->type()); |
277 | EXPECT_EQ(vectorResult.rank(), 1); |
278 | EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1); |
279 | EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6); |
280 | EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4})); |
281 | static std::int32_t cshiftExpect3[6]{3, 4, 5, 6, 1, 2}; |
282 | for (int j{0}; j < 6; ++j) { |
283 | EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j), |
284 | cshiftExpect3[j]); |
285 | } |
286 | vectorResult.Destroy(); |
287 | |
288 | RTNAME(CshiftVector)(vectorResult, *vector, -2, __FILE__, __LINE__); |
289 | EXPECT_EQ(vectorResult.type(), array->type()); |
290 | EXPECT_EQ(vectorResult.rank(), 1); |
291 | EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1); |
292 | EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6); |
293 | EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4})); |
294 | static std::int32_t cshiftExpect4[6]{5, 6, 1, 2, 3, 4}; |
295 | for (int j{0}; j < 6; ++j) { |
296 | EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j), |
297 | cshiftExpect4[j]); |
298 | } |
299 | vectorResult.Destroy(); |
300 | |
301 | // VECTOR 1 3 5 2 4 6 WITH non zero lower bound in a negative cshift. |
302 | auto vectorWithLowerBounds{MakeArray<TypeCategory::Integer, 4>( |
303 | std::vector<int>{6}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})}; |
304 | vectorWithLowerBounds->GetDimension(0).SetLowerBound(2); |
305 | |
306 | RTNAME(CshiftVector) |
307 | (vectorResult, *vectorWithLowerBounds, -2, __FILE__, __LINE__); |
308 | EXPECT_EQ(vectorResult.type(), array->type()); |
309 | EXPECT_EQ(vectorResult.rank(), 1); |
310 | EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1); |
311 | EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6); |
312 | EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4})); |
313 | static std::int32_t cshiftExpect5[6]{5, 6, 1, 2, 3, 4}; |
314 | for (int j{0}; j < 6; ++j) { |
315 | EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j), |
316 | cshiftExpect5[j]); |
317 | } |
318 | vectorResult.Destroy(); |
319 | |
320 | auto boundary{MakeArray<TypeCategory::Integer, 4>( |
321 | std::vector<int>{3}, std::vector<std::int32_t>{-1, -2, -3})}; |
322 | boundary->GetDimension(0).SetLowerBound(9); // shouldn't matter |
323 | RTNAME(Eoshift)(result, *array, *shift3, &*boundary, 1, __FILE__, __LINE__); |
324 | EXPECT_EQ(result.type(), array->type()); |
325 | EXPECT_EQ(result.rank(), 2); |
326 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
327 | EXPECT_EQ(result.GetDimension(0).Extent(), 2); |
328 | EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); |
329 | EXPECT_EQ(result.GetDimension(1).Extent(), 3); |
330 | EXPECT_EQ(result.type(), (TypeCode{TypeCategory::Integer, 4})); |
331 | static std::int32_t eoshiftExpect1[6]{2, -1, -2, 3, -3, -3}; |
332 | for (int j{0}; j < 6; ++j) { |
333 | EXPECT_EQ( |
334 | *result.ZeroBasedIndexedElement<std::int32_t>(j), eoshiftExpect1[j]); |
335 | } |
336 | result.Destroy(); |
337 | |
338 | // VECTOR EOSHIFT |
339 | StaticDescriptor<0> boundaryDescriptor; |
340 | Descriptor vectorBoundary{boundaryDescriptor.descriptor()}; |
341 | std::int32_t boundaryValue{343}; |
342 | vectorBoundary.Establish(TypeCategory::Integer, 4, |
343 | const_cast<void *>(reinterpret_cast<const void *>(&boundaryValue)), 0); |
344 | RTNAME(EoshiftVector) |
345 | (vectorResult, *vector, 2, &vectorBoundary, __FILE__, __LINE__); |
346 | EXPECT_EQ(vectorResult.type(), array->type()); |
347 | EXPECT_EQ(vectorResult.rank(), 1); |
348 | EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1); |
349 | EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6); |
350 | EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4})); |
351 | static std::int32_t eoshiftVectorExpect[6]{3, 4, 5, 6, 343, 343}; |
352 | for (int j{0}; j < 6; ++j) { |
353 | EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j), |
354 | eoshiftVectorExpect[j]); |
355 | } |
356 | vectorResult.Destroy(); |
357 | |
358 | // VECTOR EOSHIFT on input with non zero lower bounds |
359 | RTNAME(EoshiftVector) |
360 | (vectorResult, *vectorWithLowerBounds, -2, &vectorBoundary, __FILE__, |
361 | __LINE__); |
362 | EXPECT_EQ(vectorResult.type(), array->type()); |
363 | EXPECT_EQ(vectorResult.rank(), 1); |
364 | EXPECT_EQ(vectorResult.GetDimension(0).LowerBound(), 1); |
365 | EXPECT_EQ(vectorResult.GetDimension(0).Extent(), 6); |
366 | EXPECT_EQ(vectorResult.type(), (TypeCode{TypeCategory::Integer, 4})); |
367 | static std::int32_t eoshiftVectorExpect2[6]{343, 343, 1, 2, 3, 4}; |
368 | for (int j{0}; j < 6; ++j) { |
369 | EXPECT_EQ(*vectorResult.ZeroBasedIndexedElement<std::int32_t>(j), |
370 | eoshiftVectorExpect2[j]); |
371 | } |
372 | vectorResult.Destroy(); |
373 | } |
374 | |
375 | TEST(Transformational, Pack) { |
376 | // ARRAY 1 3 5 |
377 | // 2 4 6 |
378 | auto array{MakeArray<TypeCategory::Integer, 4>( |
379 | std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})}; |
380 | array->GetDimension(0).SetLowerBound(2); // shouldn't matter |
381 | array->GetDimension(1).SetLowerBound(-1); |
382 | auto mask{MakeArray<TypeCategory::Logical, 1>(std::vector<int>{2, 3}, |
383 | std::vector<std::uint8_t>{false, true, true, false, false, true})}; |
384 | mask->GetDimension(0).SetLowerBound(0); // shouldn't matter |
385 | mask->GetDimension(1).SetLowerBound(2); |
386 | StaticDescriptor<1, true> statDesc; |
387 | Descriptor &result{statDesc.descriptor()}; |
388 | |
389 | RTNAME(Pack)(result, *array, *mask, nullptr, __FILE__, __LINE__); |
390 | EXPECT_EQ(result.type(), array->type()); |
391 | EXPECT_EQ(result.rank(), 1); |
392 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
393 | EXPECT_EQ(result.GetDimension(0).Extent(), 3); |
394 | static std::int32_t packExpect1[3]{2, 3, 6}; |
395 | for (int j{0}; j < 3; ++j) { |
396 | EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), packExpect1[j]) |
397 | << " at " << j; |
398 | } |
399 | result.Destroy(); |
400 | |
401 | auto vector{MakeArray<TypeCategory::Integer, 4>( |
402 | std::vector<int>{5}, std::vector<std::int32_t>{-1, -2, -3, -4, -5})}; |
403 | RTNAME(Pack)(result, *array, *mask, &*vector, __FILE__, __LINE__); |
404 | EXPECT_EQ(result.type(), array->type()); |
405 | EXPECT_EQ(result.rank(), 1); |
406 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
407 | EXPECT_EQ(result.GetDimension(0).Extent(), 5); |
408 | static std::int32_t packExpect2[5]{2, 3, 6, -4, -5}; |
409 | for (int j{0}; j < 5; ++j) { |
410 | EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), packExpect2[j]) |
411 | << " at " << j; |
412 | } |
413 | result.Destroy(); |
414 | } |
415 | |
416 | TEST(Transformational, Spread) { |
417 | auto array{MakeArray<TypeCategory::Integer, 4>( |
418 | std::vector<int>{3}, std::vector<std::int32_t>{1, 2, 3})}; |
419 | array->GetDimension(0).SetLowerBound(2); // shouldn't matter |
420 | StaticDescriptor<2, true> statDesc; |
421 | Descriptor &result{statDesc.descriptor()}; |
422 | |
423 | RTNAME(Spread)(result, *array, 1, 2, __FILE__, __LINE__); |
424 | EXPECT_EQ(result.type(), array->type()); |
425 | EXPECT_EQ(result.rank(), 2); |
426 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
427 | EXPECT_EQ(result.GetDimension(0).Extent(), 2); |
428 | EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); |
429 | EXPECT_EQ(result.GetDimension(1).Extent(), 3); |
430 | for (int j{0}; j < 6; ++j) { |
431 | EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), 1 + j / 2); |
432 | } |
433 | result.Destroy(); |
434 | |
435 | RTNAME(Spread)(result, *array, 2, 2, __FILE__, __LINE__); |
436 | EXPECT_EQ(result.type(), array->type()); |
437 | EXPECT_EQ(result.rank(), 2); |
438 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
439 | EXPECT_EQ(result.GetDimension(0).Extent(), 3); |
440 | EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); |
441 | EXPECT_EQ(result.GetDimension(1).Extent(), 2); |
442 | for (int j{0}; j < 6; ++j) { |
443 | EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), 1 + j % 3); |
444 | } |
445 | result.Destroy(); |
446 | |
447 | auto scalar{MakeArray<TypeCategory::Integer, 4>( |
448 | std::vector<int>{}, std::vector<std::int32_t>{1})}; |
449 | RTNAME(Spread)(result, *scalar, 1, 2, __FILE__, __LINE__); |
450 | EXPECT_EQ(result.type(), array->type()); |
451 | EXPECT_EQ(result.rank(), 1); |
452 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
453 | EXPECT_EQ(result.GetDimension(0).Extent(), 2); |
454 | for (int j{0}; j < 2; ++j) { |
455 | EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), 1); |
456 | } |
457 | result.Destroy(); |
458 | } |
459 | |
460 | TEST(Transformational, Transpose) { |
461 | // ARRAY 1 3 5 |
462 | // 2 4 6 |
463 | auto array{MakeArray<TypeCategory::Integer, 4>( |
464 | std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})}; |
465 | array->GetDimension(0).SetLowerBound(2); // shouldn't matter |
466 | array->GetDimension(1).SetLowerBound(-6); |
467 | StaticDescriptor<2, true> statDesc; |
468 | Descriptor &result{statDesc.descriptor()}; |
469 | RTNAME(Transpose)(result, *array, __FILE__, __LINE__); |
470 | EXPECT_EQ(result.type(), array->type()); |
471 | EXPECT_EQ(result.rank(), 2); |
472 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
473 | EXPECT_EQ(result.GetDimension(0).Extent(), 3); |
474 | EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); |
475 | EXPECT_EQ(result.GetDimension(1).Extent(), 2); |
476 | static std::int32_t expect[6]{1, 3, 5, 2, 4, 6}; |
477 | for (int j{0}; j < 6; ++j) { |
478 | EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), expect[j]); |
479 | } |
480 | result.Destroy(); |
481 | } |
482 | |
483 | TEST(Transformational, Unpack) { |
484 | auto vector{MakeArray<TypeCategory::Integer, 4>( |
485 | std::vector<int>{4}, std::vector<std::int32_t>{1, 2, 3, 4})}; |
486 | vector->GetDimension(0).SetLowerBound(2); // shouldn't matter |
487 | auto mask{MakeArray<TypeCategory::Logical, 1>(std::vector<int>{2, 3}, |
488 | std::vector<std::uint8_t>{false, true, true, false, false, true})}; |
489 | mask->GetDimension(0).SetLowerBound(0); // shouldn't matter |
490 | mask->GetDimension(1).SetLowerBound(2); |
491 | auto field{MakeArray<TypeCategory::Integer, 4>(std::vector<int>{2, 3}, |
492 | std::vector<std::int32_t>{-1, -2, -3, -4, -5, -6})}; |
493 | field->GetDimension(0).SetLowerBound(-1); // shouldn't matter |
494 | StaticDescriptor<2, true> statDesc; |
495 | Descriptor &result{statDesc.descriptor()}; |
496 | RTNAME(Unpack)(result, *vector, *mask, *field, __FILE__, __LINE__); |
497 | EXPECT_EQ(result.type(), vector->type()); |
498 | EXPECT_EQ(result.rank(), 2); |
499 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
500 | EXPECT_EQ(result.GetDimension(0).Extent(), 2); |
501 | EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); |
502 | EXPECT_EQ(result.GetDimension(1).Extent(), 3); |
503 | static std::int32_t expect[6]{-1, 1, 2, -4, -5, 3}; |
504 | for (int j{0}; j < 6; ++j) { |
505 | EXPECT_EQ(*result.ZeroBasedIndexedElement<std::int32_t>(j), expect[j]); |
506 | } |
507 | result.Destroy(); |
508 | |
509 | // Test for scalar value of the "field" argument |
510 | auto scalarField{MakeArray<TypeCategory::Integer, 4>( |
511 | std::vector<int>{}, std::vector<std::int32_t>{343})}; |
512 | RTNAME(Unpack)(result, *vector, *mask, *scalarField, __FILE__, __LINE__); |
513 | EXPECT_EQ(result.rank(), 2); |
514 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
515 | EXPECT_EQ(result.GetDimension(0).Extent(), 2); |
516 | EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); |
517 | EXPECT_EQ(result.GetDimension(1).Extent(), 3); |
518 | static std::int32_t scalarExpect[6]{343, 1, 2, 343, 343, 3}; |
519 | for (int j{0}; j < 6; ++j) { |
520 | EXPECT_EQ( |
521 | *result.ZeroBasedIndexedElement<std::int32_t>(j), scalarExpect[j]); |
522 | } |
523 | result.Destroy(); |
524 | } |
525 | |
526 | #if LDBL_MANT_DIG == 64 |
527 | // Make sure the destination descriptor is created by the runtime |
528 | // with proper element size, when REAL*10 maps to 'long double'. |
529 | #define Real10CppType long double |
530 | TEST(Transformational, TransposeReal10) { |
531 | // ARRAY 1 3 5 |
532 | // 2 4 6 |
533 | auto array{MakeArray<TypeCategory::Real, 10>(std::vector<int>{2, 3}, |
534 | std::vector<Real10CppType>{1.0, 2.0, 3.0, 4.0, 5.0, 6.0}, |
535 | sizeof(Real10CppType))}; |
536 | StaticDescriptor<2, true> statDesc; |
537 | Descriptor &result{statDesc.descriptor()}; |
538 | RTNAME(Transpose)(result, *array, __FILE__, __LINE__); |
539 | EXPECT_EQ(result.ElementBytes(), sizeof(Real10CppType)); |
540 | EXPECT_EQ(result.type(), array->type()); |
541 | EXPECT_EQ(result.rank(), 2); |
542 | EXPECT_EQ(result.GetDimension(0).LowerBound(), 1); |
543 | EXPECT_EQ(result.GetDimension(0).Extent(), 3); |
544 | EXPECT_EQ(result.GetDimension(1).LowerBound(), 1); |
545 | EXPECT_EQ(result.GetDimension(1).Extent(), 2); |
546 | static Real10CppType expect[6]{1.0, 3.0, 5.0, 2.0, 4.0, 6.0}; |
547 | for (int j{0}; j < 6; ++j) { |
548 | EXPECT_EQ(*result.ZeroBasedIndexedElement<Real10CppType>(j), expect[j]); |
549 | } |
550 | result.Destroy(); |
551 | } |
552 | #endif |
553 | |