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 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 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 HAS_FLOAT80 112 testBesselJn<10>(RTNAME(BesselJn_10)); 113 #endif 114 #if HAS_LDBL128 || 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 HAS_FLOAT80 121 testBesselJnX0<10>(RTNAME(BesselJnX0_10)); 122 #endif 123 #if HAS_LDBL128 || 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 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<2> 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 HAS_FLOAT80 205 testBesselYn<10>(RTNAME(BesselYn_10)); 206 #endif 207 #if HAS_LDBL128 || 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 HAS_FLOAT80 214 testBesselYnX0<10>(RTNAME(BesselYnX0_10)); 215 #endif 216 #if HAS_LDBL128 || 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<maxRank, 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 HAS_FLOAT80 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