1ffc67bb3SDavid Spickett //===-- flang/unittests/Runtime/ArrayConstructor.cpp-------------*- C++ -*-===// 2ffc67bb3SDavid Spickett // 3ffc67bb3SDavid Spickett // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ffc67bb3SDavid Spickett // See https://llvm.org/LICENSE.txt for license information. 5ffc67bb3SDavid Spickett // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ffc67bb3SDavid Spickett // 7ffc67bb3SDavid Spickett //===----------------------------------------------------------------------===// 8ffc67bb3SDavid Spickett 9ffc67bb3SDavid Spickett #include "gtest/gtest.h" 10ffc67bb3SDavid Spickett #include "tools.h" 11ffc67bb3SDavid Spickett #include "flang/Runtime/allocatable.h" 12ffc67bb3SDavid Spickett #include "flang/Runtime/array-constructor.h" 13ffc67bb3SDavid Spickett #include "flang/Runtime/cpp-type.h" 14ffc67bb3SDavid Spickett #include "flang/Runtime/descriptor.h" 15ffc67bb3SDavid Spickett #include "flang/Runtime/type-code.h" 16ffc67bb3SDavid Spickett 17ffc67bb3SDavid Spickett #include <memory> 18ffc67bb3SDavid Spickett 19ffc67bb3SDavid Spickett using namespace Fortran::runtime; 20ffc67bb3SDavid Spickett using Fortran::common::TypeCategory; 21ffc67bb3SDavid Spickett 22ffc67bb3SDavid Spickett TEST(ArrayConstructor, Basic) { 23ffc67bb3SDavid Spickett // X(4) = [1,2,3,4] 24ffc67bb3SDavid Spickett // Y(2:3,4:6) = RESHAPE([5,6,7,8,9,10], shape=[2,3]) 25ffc67bb3SDavid Spickett // 26ffc67bb3SDavid Spickett // Test creation of: [(i, X, Y, i=0,99,1)] 27ffc67bb3SDavid Spickett auto x{MakeArray<TypeCategory::Integer, 4>( 28ffc67bb3SDavid Spickett std::vector<int>{4}, std::vector<std::int32_t>{1, 2, 3, 4})}; 29ffc67bb3SDavid Spickett auto y{MakeArray<TypeCategory::Integer, 4>( 30ffc67bb3SDavid Spickett std::vector<int>{2, 3}, std::vector<std::int32_t>{5, 6, 7, 8, 9, 10})}; 31ffc67bb3SDavid Spickett y->GetDimension(0).SetBounds(2, 3); 32ffc67bb3SDavid Spickett y->GetDimension(1).SetBounds(4, 6); 33ffc67bb3SDavid Spickett 34ffc67bb3SDavid Spickett StaticDescriptor<1, false> statDesc; 35ffc67bb3SDavid Spickett Descriptor &result{statDesc.descriptor()}; 36ffc67bb3SDavid Spickett result.Establish(TypeCode{CFI_type_int32_t}, 4, /*p=*/nullptr, 37ffc67bb3SDavid Spickett /*rank=*/1, /*extents=*/nullptr, CFI_attribute_allocatable); 38ffc67bb3SDavid Spickett std::allocator<ArrayConstructorVector> cookieAllocator; 39ffc67bb3SDavid Spickett ArrayConstructorVector *acVector{cookieAllocator.allocate(1)}; 40ffc67bb3SDavid Spickett ASSERT_TRUE(acVector); 41ffc67bb3SDavid Spickett 42ffc67bb3SDavid Spickett // Case 1: result is a temp and extent is unknown before first call. 43ffc67bb3SDavid Spickett result.GetDimension(0).SetBounds(1, 0); 44ffc67bb3SDavid Spickett 45ffc67bb3SDavid Spickett RTNAME(InitArrayConstructorVector) 46c91ba043SMichael Kruse (*acVector, result, /*useValueLengthParameters=*/false); 47ffc67bb3SDavid Spickett for (std::int32_t i{0}; i <= 99; ++i) { 48ffc67bb3SDavid Spickett RTNAME(PushArrayConstructorSimpleScalar)(*acVector, &i); 49ffc67bb3SDavid Spickett RTNAME(PushArrayConstructorValue)(*acVector, *x); 50ffc67bb3SDavid Spickett RTNAME(PushArrayConstructorValue)(*acVector, *y); 51ffc67bb3SDavid Spickett } 52ffc67bb3SDavid Spickett 53ffc67bb3SDavid Spickett ASSERT_TRUE(result.IsAllocated()); 54ffc67bb3SDavid Spickett ASSERT_EQ(result.Elements(), static_cast<std::size_t>(100 * (1 + 4 + 2 * 3))); 55ffc67bb3SDavid Spickett SubscriptValue subscript[1]{1}; 56ffc67bb3SDavid Spickett for (std::int32_t i{0}; i <= 99; ++i) { 57ffc67bb3SDavid Spickett ASSERT_EQ(*result.Element<std::int32_t>(subscript), i); 58ffc67bb3SDavid Spickett ++subscript[0]; 59ffc67bb3SDavid Spickett for (std::int32_t j{1}; j <= 10; ++j) { 60ffc67bb3SDavid Spickett EXPECT_EQ(*result.Element<std::int32_t>(subscript), j); 61ffc67bb3SDavid Spickett ++subscript[0]; 62ffc67bb3SDavid Spickett } 63ffc67bb3SDavid Spickett } 64ffc67bb3SDavid Spickett EXPECT_LE(result.Elements(), 65ffc67bb3SDavid Spickett static_cast<std::size_t>(acVector->actualAllocationSize)); 66ffc67bb3SDavid Spickett result.Deallocate(); 67ffc67bb3SDavid Spickett ASSERT_TRUE(!result.IsAllocated()); 68ffc67bb3SDavid Spickett 69ffc67bb3SDavid Spickett // Case 2: result is an unallocated temp and extent is know before first call. 70ffc67bb3SDavid Spickett // and is allocated when the first value is pushed. 71ffc67bb3SDavid Spickett result.GetDimension(0).SetBounds(1, 1234); 72ffc67bb3SDavid Spickett RTNAME(InitArrayConstructorVector) 73c91ba043SMichael Kruse (*acVector, result, /*useValueLengthParameters=*/false); 74ffc67bb3SDavid Spickett EXPECT_EQ(0, acVector->actualAllocationSize); 75ffc67bb3SDavid Spickett std::int32_t i{42}; 76ffc67bb3SDavid Spickett RTNAME(PushArrayConstructorSimpleScalar)(*acVector, &i); 77ffc67bb3SDavid Spickett ASSERT_TRUE(result.IsAllocated()); 78ffc67bb3SDavid Spickett EXPECT_EQ(1234, acVector->actualAllocationSize); 79ffc67bb3SDavid Spickett result.Deallocate(); 80ffc67bb3SDavid Spickett 81ffc67bb3SDavid Spickett cookieAllocator.deallocate(acVector, 1); 82ffc67bb3SDavid Spickett } 83ffc67bb3SDavid Spickett 84ffc67bb3SDavid Spickett TEST(ArrayConstructor, Character) { 85ffc67bb3SDavid Spickett // CHARACTER(2) :: C = "12" 86ffc67bb3SDavid Spickett // X(4) = ["ab", "cd", "ef", "gh"] 87ffc67bb3SDavid Spickett // Y(2:3,4:6) = RESHAPE(["ij", "jl", "mn", "op", "qr","st"], shape=[2,3]) 88ffc67bb3SDavid Spickett auto x{MakeArray<TypeCategory::Character, 1>(std::vector<int>{4}, 89ffc67bb3SDavid Spickett std::vector<std::string>{"ab", "cd", "ef", "gh"}, 2)}; 90ffc67bb3SDavid Spickett auto y{MakeArray<TypeCategory::Character, 1>(std::vector<int>{2, 3}, 91ffc67bb3SDavid Spickett std::vector<std::string>{"ij", "kl", "mn", "op", "qr", "st"}, 2)}; 92ffc67bb3SDavid Spickett y->GetDimension(0).SetBounds(2, 3); 93ffc67bb3SDavid Spickett y->GetDimension(1).SetBounds(4, 6); 94ffc67bb3SDavid Spickett auto c{MakeArray<TypeCategory::Character, 1>( 95ffc67bb3SDavid Spickett std::vector<int>{}, std::vector<std::string>{"12"}, 2)}; 96ffc67bb3SDavid Spickett 97ffc67bb3SDavid Spickett StaticDescriptor<1, false> statDesc; 98ffc67bb3SDavid Spickett Descriptor &result{statDesc.descriptor()}; 99ffc67bb3SDavid Spickett result.Establish(TypeCode{CFI_type_char}, 0, /*p=*/nullptr, 100ffc67bb3SDavid Spickett /*rank=*/1, /*extents=*/nullptr, CFI_attribute_allocatable); 101ffc67bb3SDavid Spickett std::allocator<ArrayConstructorVector> cookieAllocator; 102ffc67bb3SDavid Spickett ArrayConstructorVector *acVector{cookieAllocator.allocate(1)}; 103ffc67bb3SDavid Spickett ASSERT_TRUE(acVector); 104ffc67bb3SDavid Spickett 105ffc67bb3SDavid Spickett // Case 1: result is a temp and extent and length are unknown before the first 106ffc67bb3SDavid Spickett // call. Test creation of: [(C, X, Y, i=1,10,1)] 107ffc67bb3SDavid Spickett static constexpr std::size_t expectedElements{10 * (1 + 4 + 2 * 3)}; 108ffc67bb3SDavid Spickett result.GetDimension(0).SetBounds(1, 0); 109ffc67bb3SDavid Spickett RTNAME(InitArrayConstructorVector) 110c91ba043SMichael Kruse (*acVector, result, /*useValueLengthParameters=*/true); 111ffc67bb3SDavid Spickett for (std::int32_t i{1}; i <= 10; ++i) { 112ffc67bb3SDavid Spickett RTNAME(PushArrayConstructorValue)(*acVector, *c); 113ffc67bb3SDavid Spickett RTNAME(PushArrayConstructorValue)(*acVector, *x); 114ffc67bb3SDavid Spickett RTNAME(PushArrayConstructorValue)(*acVector, *y); 115ffc67bb3SDavid Spickett } 116ffc67bb3SDavid Spickett ASSERT_TRUE(result.IsAllocated()); 117ffc67bb3SDavid Spickett ASSERT_EQ(result.Elements(), expectedElements); 118ffc67bb3SDavid Spickett ASSERT_EQ(result.ElementBytes(), 2u); 119ffc67bb3SDavid Spickett EXPECT_LE(result.Elements(), 120ffc67bb3SDavid Spickett static_cast<std::size_t>(acVector->actualAllocationSize)); 121ffc67bb3SDavid Spickett std::string CXY{"12abcdefghijklmnopqrst"}; 122ffc67bb3SDavid Spickett std::string expect; 123ffc67bb3SDavid Spickett for (int i{0}; i < 10; ++i) 124ffc67bb3SDavid Spickett expect.append(CXY); 125ffc67bb3SDavid Spickett EXPECT_EQ(std::memcmp( 126ffc67bb3SDavid Spickett result.OffsetElement<char>(0), expect.data(), expect.length()), 127ffc67bb3SDavid Spickett 0); 128ffc67bb3SDavid Spickett result.Deallocate(); 129ffc67bb3SDavid Spickett cookieAllocator.deallocate(acVector, 1); 130*c870632eSMatthias Springer x->Deallocate(); 131*c870632eSMatthias Springer y->Deallocate(); 132*c870632eSMatthias Springer c->Deallocate(); 133ffc67bb3SDavid Spickett } 134ffc67bb3SDavid Spickett 135ffc67bb3SDavid Spickett TEST(ArrayConstructor, CharacterRuntimeCheck) { 136ffc67bb3SDavid Spickett // CHARACTER(2) :: C2 137ffc67bb3SDavid Spickett // CHARACTER(3) :: C3 138ffc67bb3SDavid Spickett // Test the runtime catch bad [C2, C3] array constructors (Fortran 2018 7.8 139ffc67bb3SDavid Spickett // point 2.) 140ffc67bb3SDavid Spickett auto c2{MakeArray<TypeCategory::Character, 1>( 141ffc67bb3SDavid Spickett std::vector<int>{}, std::vector<std::string>{"ab"}, 2)}; 142ffc67bb3SDavid Spickett auto c3{MakeArray<TypeCategory::Character, 1>( 143ffc67bb3SDavid Spickett std::vector<int>{}, std::vector<std::string>{"abc"}, 3)}; 144ffc67bb3SDavid Spickett StaticDescriptor<1, false> statDesc; 145ffc67bb3SDavid Spickett Descriptor &result{statDesc.descriptor()}; 146ffc67bb3SDavid Spickett result.Establish(TypeCode{CFI_type_char}, 0, /*p=*/nullptr, 147ffc67bb3SDavid Spickett /*rank=*/1, /*extents=*/nullptr, CFI_attribute_allocatable); 148ffc67bb3SDavid Spickett std::allocator<ArrayConstructorVector> cookieAllocator; 149ffc67bb3SDavid Spickett ArrayConstructorVector *acVector{cookieAllocator.allocate(1)}; 150ffc67bb3SDavid Spickett ASSERT_TRUE(acVector); 151ffc67bb3SDavid Spickett 152ffc67bb3SDavid Spickett result.GetDimension(0).SetBounds(1, 0); 153ffc67bb3SDavid Spickett RTNAME(InitArrayConstructorVector) 154c91ba043SMichael Kruse (*acVector, result, /*useValueLengthParameters=*/true); 155ffc67bb3SDavid Spickett RTNAME(PushArrayConstructorValue)(*acVector, *c2); 156ffc67bb3SDavid Spickett ASSERT_DEATH(RTNAME(PushArrayConstructorValue)(*acVector, *c3), 157ffc67bb3SDavid Spickett "Array constructor: mismatched character lengths"); 158ffc67bb3SDavid Spickett } 159