617 lines · cpp
1//===-- unittests/Runtime/Transformational.cpp ------------------*- C++ -*-===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "flang/Runtime/transformational.h"10#include "tools.h"11#include "gtest/gtest.h"12#include "flang-rt/runtime/type-code.h"13#include "flang/Common/float128.h"14#include <vector>15 16using namespace Fortran::runtime;17using Fortran::common::TypeCategory;18 19template <int KIND>20using 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 24template <int KIND>25using BesselX0FuncType =26 std::function<void(Descriptor &, int32_t, int32_t, const char *, int)>;27 28template <int KIND>29constexpr CppTypeFor<TypeCategory::Real, KIND>30 besselEpsilon = CppTypeFor<TypeCategory::Real, KIND>(1e-4);31 32template <int KIND>33static 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 60template <int KIND>61static 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 90template <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 100template <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 108static void testBesselJn() {109 testBesselJn<4>(RTNAME(BesselJn_4));110 testBesselJn<8>(RTNAME(BesselJn_8));111#if HAS_FLOAT80112 testBesselJn<10>(RTNAME(BesselJn_10));113#endif114#if HAS_LDBL128 || HAS_FLOAT128115 testBesselJn<16>(RTNAME(BesselJn_16));116#endif117 118 testBesselJnX0<4>(RTNAME(BesselJnX0_4));119 testBesselJnX0<8>(RTNAME(BesselJnX0_8));120#if HAS_FLOAT80121 testBesselJnX0<10>(RTNAME(BesselJnX0_10));122#endif123#if HAS_LDBL128 || HAS_FLOAT128124 testBesselJnX0<16>(RTNAME(BesselJnX0_16));125#endif126}127 128TEST(Transformational, BesselJn) { testBesselJn(); }129 130template <int KIND>131static 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 158template <int KIND>159static 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 184template <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 193template <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 201static void testBesselYn() {202 testBesselYn<4>(RTNAME(BesselYn_4));203 testBesselYn<8>(RTNAME(BesselYn_8));204#if HAS_FLOAT80205 testBesselYn<10>(RTNAME(BesselYn_10));206#endif207#if HAS_LDBL128 || HAS_FLOAT128208 testBesselYn<16>(RTNAME(BesselYn_16));209#endif210 211 testBesselYnX0<4>(RTNAME(BesselYnX0_4));212 testBesselYnX0<8>(RTNAME(BesselYnX0_8));213#if HAS_FLOAT80214 testBesselYnX0<10>(RTNAME(BesselYnX0_10));215#endif216#if HAS_LDBL128 || HAS_FLOAT128217 testBesselYnX0<16>(RTNAME(BesselYnX0_16));218#endif219}220 221TEST(Transformational, BesselYn) { testBesselYn(); }222 223TEST(Transformational, Shifts) {224 // ARRAY 1 3 5225 // 2 4 6226 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 matter229 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 matter253 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 6269 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 matter323 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 EOSHIFT339 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 bounds359 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 375TEST(Transformational, Pack) {376 // ARRAY 1 3 5377 // 2 4 6378 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 matter381 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 matter385 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 416TEST(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 matter420 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 460TEST(Transformational, Transpose) {461 // ARRAY 1 3 5462 // 2 4 6463 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 matter466 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 483TEST(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 matter487 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 matter490 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 matter494 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" argument510 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_FLOAT80527// Make sure the destination descriptor is created by the runtime528// with proper element size, when REAL*10 maps to 'long double'.529#define Real10CppType long double530TEST(Transformational, TransposeReal10) {531 // ARRAY 1 3 5532 // 2 4 6533 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#endif553 554TEST(Transformational, ShallowCopy) {555 auto charArray{MakeArray<TypeCategory::Character, 1>(std::vector<int>{2, 3},556 std::vector<std::string>{"ab", "cd", "ef", "gh", "ij", "kl"}, 2)};557 charArray->GetDimension(0).SetBounds(-1, 0);558 charArray->GetDimension(1).SetBounds(3, 5);559 StaticDescriptor<2> staticCharResult;560 Descriptor &charResult{staticCharResult.descriptor()};561 562 // Test allocating ShallowCopy.563 RTNAME(ShallowCopy)(charResult, *charArray);564 ASSERT_TRUE(charResult.IsAllocated());565 ASSERT_TRUE(charResult.IsContiguous());566 ASSERT_EQ(charResult.type(), charArray->type());567 ASSERT_EQ(charResult.ElementBytes(), 2u);568 EXPECT_EQ(charResult.GetDimension(0).LowerBound(), 1);569 EXPECT_EQ(charResult.GetDimension(0).Extent(), 2);570 EXPECT_EQ(charResult.GetDimension(1).LowerBound(), 1);571 EXPECT_EQ(charResult.GetDimension(1).Extent(), 3);572 std::string expectedCharResult{"abcdefghijkl"};573 EXPECT_EQ(std::memcmp(charResult.OffsetElement<char>(0),574 expectedCharResult.data(), expectedCharResult.length()),575 0);576 577 // Test ShallowCopyDirect with pre-allocated result.578 char *allocatedPtr = charResult.OffsetElement<char>(0);579 std::memset(580 charResult.OffsetElement<char>(0), 'x', expectedCharResult.length());581 // Set new lower bounds for charResult.582 charResult.GetDimension(0).SetBounds(-2, -1);583 charResult.GetDimension(1).SetBounds(2, 4);584 RTNAME(ShallowCopyDirect)(charResult, *charArray);585 ASSERT_TRUE(charResult.IsAllocated());586 ASSERT_TRUE(charResult.IsContiguous());587 ASSERT_EQ(charResult.type(), charArray->type());588 ASSERT_EQ(charResult.ElementBytes(), 2u);589 EXPECT_EQ(charResult.GetDimension(0).LowerBound(), -2);590 EXPECT_EQ(charResult.GetDimension(0).Extent(), 2);591 EXPECT_EQ(charResult.GetDimension(1).LowerBound(), 2);592 EXPECT_EQ(charResult.GetDimension(1).Extent(), 3);593 // Test that the result was not re-allocated.594 EXPECT_EQ(allocatedPtr, charResult.OffsetElement<char>(0));595 EXPECT_EQ(std::memcmp(charResult.OffsetElement<char>(0),596 expectedCharResult.data(), expectedCharResult.length()),597 0);598 charResult.Destroy();599 600 auto intScalar{MakeArray<TypeCategory::Integer, 4>(601 std::vector<int>{}, std::vector<std::int32_t>{-1})};602 StaticDescriptor<0> staticIntResult;603 Descriptor &intResult{staticIntResult.descriptor()};604 RTNAME(ShallowCopy)(intResult, *intScalar);605 ASSERT_TRUE(intResult.IsAllocated());606 ASSERT_EQ(intResult.rank(), 0);607 ASSERT_EQ(*intResult.ZeroBasedIndexedElement<std::int32_t>(0), -1);608 *intResult.ZeroBasedIndexedElement<std::int32_t>(0) = 0;609 allocatedPtr = intResult.OffsetElement<char>(0);610 RTNAME(ShallowCopyDirect)(intResult, *intScalar);611 ASSERT_TRUE(intResult.IsAllocated());612 ASSERT_EQ(intResult.rank(), 0);613 ASSERT_EQ(*intResult.ZeroBasedIndexedElement<std::int32_t>(0), -1);614 EXPECT_EQ(allocatedPtr, intResult.OffsetElement<char>(0));615 intResult.Destroy();616}617