1 //===-- runtime/ragged.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/ragged.h"
10 #include <cstdlib>
11 
12 namespace Fortran::runtime {
13 
isIndirection(const RaggedArrayHeader * const header)14 inline bool isIndirection(const RaggedArrayHeader *const header) {
15   return header->flags & 1;
16 }
17 
rank(const RaggedArrayHeader * const header)18 inline std::size_t rank(const RaggedArrayHeader *const header) {
19   return header->flags >> 1;
20 }
21 
RaggedArrayAllocate(RaggedArrayHeader * header,bool isHeader,std::int64_t rank,std::int64_t elementSize,std::int64_t * extentVector)22 RaggedArrayHeader *RaggedArrayAllocate(RaggedArrayHeader *header, bool isHeader,
23     std::int64_t rank, std::int64_t elementSize, std::int64_t *extentVector) {
24   if (header && rank) {
25     std::int64_t size{1};
26     for (std::int64_t counter{0}; counter < rank; ++counter) {
27       size *= extentVector[counter];
28       if (size <= 0) {
29         return nullptr;
30       }
31     }
32     header->flags = (rank << 1) | isHeader;
33     header->extentPointer = extentVector;
34     if (isHeader) {
35       header->bufferPointer = std::calloc(sizeof(RaggedArrayHeader), size);
36     } else {
37       header->bufferPointer =
38           static_cast<void *>(std::calloc(elementSize, size));
39     }
40     return header;
41   } else {
42     return nullptr;
43   }
44 }
45 
46 // Deallocate a ragged array from the heap.
RaggedArrayDeallocate(RaggedArrayHeader * raggedArrayHeader)47 void RaggedArrayDeallocate(RaggedArrayHeader *raggedArrayHeader) {
48   if (raggedArrayHeader) {
49     if (std::size_t end{rank(raggedArrayHeader)}) {
50       if (isIndirection(raggedArrayHeader)) {
51         std::size_t linearExtent{1u};
52         for (std::size_t counter{0u}; counter < end && linearExtent > 0;
53              ++counter) {
54           linearExtent *= raggedArrayHeader->extentPointer[counter];
55         }
56         for (std::size_t counter{0u}; counter < linearExtent; ++counter) {
57           RaggedArrayDeallocate(&static_cast<RaggedArrayHeader *>(
58               raggedArrayHeader->bufferPointer)[counter]);
59         }
60       }
61       std::free(raggedArrayHeader->bufferPointer);
62       std::free(raggedArrayHeader->extentPointer);
63       raggedArrayHeader->flags = 0u;
64     }
65   }
66 }
67 
68 extern "C" {
RTNAME(RaggedArrayAllocate)69 void *RTNAME(RaggedArrayAllocate)(void *header, bool isHeader,
70     std::int64_t rank, std::int64_t elementSize, std::int64_t *extentVector) {
71   auto *result = RaggedArrayAllocate(static_cast<RaggedArrayHeader *>(header),
72       isHeader, rank, elementSize, extentVector);
73   return static_cast<void *>(result);
74 }
75 
RTNAME(RaggedArrayDeallocate)76 void RTNAME(RaggedArrayDeallocate)(void *raggedArrayHeader) {
77   RaggedArrayDeallocate(static_cast<RaggedArrayHeader *>(raggedArrayHeader));
78 }
79 } // extern "C"
80 } // namespace Fortran::runtime
81