#include "flang/Runtime/array-constructor.h"
#include "derived.h"
#include "terminator.h"
#include "tools.h"
#include "type-info.h"
#include "flang/Runtime/allocatable.h"
#include "flang/Runtime/assign.h"
#include "flang/Runtime/descriptor.h"
namespace Fortran::runtime {
static RT_API_ATTRS SubscriptValue initialAllocationSize(
SubscriptValue initialNumberOfElements, SubscriptValue elementBytes) {
static constexpr SubscriptValue minNumberOfBytes{128};
static constexpr SubscriptValue minNumberOfElements{4};
SubscriptValue numberOfElements{initialNumberOfElements > minNumberOfElements
? initialNumberOfElements
: minNumberOfElements};
SubscriptValue elementsForMinBytes{minNumberOfBytes / elementBytes};
return std::max(numberOfElements, elementsForMinBytes);
}
static RT_API_ATTRS void AllocateOrReallocateVectorIfNeeded(
ArrayConstructorVector &vector, Terminator &terminator,
SubscriptValue previousToElements, SubscriptValue fromElements) {
Descriptor &to{vector.to};
if (to.IsAllocatable() && !to.IsAllocated()) {
if (previousToElements == 0) {
SubscriptValue allocationSize{
initialAllocationSize(fromElements, to.ElementBytes())};
to.GetDimension(0).SetBounds(1, allocationSize);
RTNAME(AllocatableAllocate)
(to, false, nullptr, vector.sourceFile,
vector.sourceLine);
to.GetDimension(0).SetBounds(1, fromElements);
vector.actualAllocationSize = allocationSize;
} else {
RUNTIME_CHECK(terminator, previousToElements >= fromElements);
RTNAME(AllocatableAllocate)
(to, false, nullptr, vector.sourceFile,
vector.sourceLine);
vector.actualAllocationSize = previousToElements;
}
} else {
SubscriptValue newToElements{vector.nextValuePosition + fromElements};
if (to.IsAllocatable() && vector.actualAllocationSize < newToElements) {
SubscriptValue requestedAllocationSize{
std::max(newToElements, vector.actualAllocationSize * 2)};
std::size_t newByteSize{requestedAllocationSize * to.ElementBytes()};
if (newByteSize > 0) {
void *p{ReallocateMemoryOrCrash(
terminator, to.raw().base_addr, newByteSize)};
to.set_base_addr(p);
}
vector.actualAllocationSize = requestedAllocationSize;
to.GetDimension(0).SetBounds(1, newToElements);
} else if (previousToElements < newToElements) {
to.GetDimension(0).SetBounds(1, newToElements);
}
}
}
extern "C" {
RT_EXT_API_GROUP_BEGIN
void RTDEF(InitArrayConstructorVector)(ArrayConstructorVector &vector,
Descriptor &to, bool useValueLengthParameters, int vectorClassSize,
const char *sourceFile, int sourceLine) {
Terminator terminator{vector.sourceFile, vector.sourceLine};
RUNTIME_CHECK(terminator,
to.rank() == 1 &&
sizeof(ArrayConstructorVector) <=
static_cast<std::size_t>(vectorClassSize));
SubscriptValue actualAllocationSize{
to.IsAllocated() ? static_cast<SubscriptValue>(to.Elements()) : 0};
(void)new (&vector) ArrayConstructorVector{to, 0,
actualAllocationSize, sourceFile, sourceLine, useValueLengthParameters};
}
void RTDEF(PushArrayConstructorValue)(
ArrayConstructorVector &vector, const Descriptor &from) {
Terminator terminator{vector.sourceFile, vector.sourceLine};
Descriptor &to{vector.to};
SubscriptValue fromElements{static_cast<SubscriptValue>(from.Elements())};
SubscriptValue previousToElements{static_cast<SubscriptValue>(to.Elements())};
if (vector.useValueLengthParameters()) {
if (to.IsAllocatable() && !to.IsAllocated()) {
if (to.type().IsCharacter()) {
to.raw().elem_len = from.ElementBytes();
} else if (auto *toAddendum{to.Addendum()}) {
if (const auto *fromAddendum{from.Addendum()}) {
if (const auto *toDerived{toAddendum->derivedType()}) {
std::size_t lenParms{toDerived->LenParameters()};
for (std::size_t j{0}; j < lenParms; ++j) {
toAddendum->SetLenParameterValue(
j, fromAddendum->LenParameterValue(j));
}
}
}
}
} else if (to.type().IsCharacter()) {
if (to.ElementBytes() != from.ElementBytes()) {
terminator.Crash("Array constructor: mismatched character lengths (%d "
"!= %d) between "
"values of an array constructor without type-spec",
to.ElementBytes() / to.type().GetCategoryAndKind()->second,
from.ElementBytes() / from.type().GetCategoryAndKind()->second);
}
}
}
AllocateOrReallocateVectorIfNeeded(
vector, terminator, previousToElements, fromElements);
SubscriptValue lower[1]{
to.GetDimension(0).LowerBound() + vector.nextValuePosition};
SubscriptValue upper[1]{lower[0] + fromElements - 1};
SubscriptValue stride[1]{from.rank() == 0 ? 0 : 1};
StaticDescriptor<maxRank, true, 1> staticDesc;
Descriptor &toCurrentElement{staticDesc.descriptor()};
toCurrentElement.EstablishPointerSection(to, lower, upper, stride);
RTNAME(AssignTemporary)
(toCurrentElement, from, vector.sourceFile, vector.sourceLine);
vector.nextValuePosition += fromElements;
}
void RTDEF(PushArrayConstructorSimpleScalar)(
ArrayConstructorVector &vector, void *from) {
Terminator terminator{vector.sourceFile, vector.sourceLine};
Descriptor &to{vector.to};
AllocateOrReallocateVectorIfNeeded(vector, terminator, to.Elements(), 1);
SubscriptValue subscript[1]{
to.GetDimension(0).LowerBound() + vector.nextValuePosition};
std::memcpy(to.Element<char>(subscript), from, to.ElementBytes());
++vector.nextValuePosition;
}
RT_EXT_API_GROUP_END
}
}