brintos

brintos / llvm-project-archived public Read only

0
0
Text · 23.5 KiB · e61f5a6 Raw
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