1 //===-- runtime/tools.cpp -------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
10 #include "terminator.h"
16 namespace Fortran::runtime
{
18 std::size_t TrimTrailingSpaces(const char *s
, std::size_t n
) {
19 while (n
> 0 && s
[n
- 1] == ' ') {
25 OwningPtr
<char> SaveDefaultCharacter(
26 const char *s
, std::size_t length
, const Terminator
&terminator
) {
28 auto *p
{static_cast<char *>(AllocateMemoryOrCrash(terminator
, length
+ 1))};
29 std::memcpy(p
, s
, length
);
31 return OwningPtr
<char>{p
};
33 return OwningPtr
<char>{};
37 static bool CaseInsensitiveMatch(
38 const char *value
, std::size_t length
, const char *possibility
) {
39 for (; length
-- > 0; ++possibility
) {
41 if (ch
>= 'a' && ch
<= 'z') {
44 if (*possibility
!= ch
) {
45 if (*possibility
!= '\0' || ch
!= ' ') {
48 // Ignore trailing blanks (12.5.6.2 p1)
49 while (length
-- > 0) {
50 if (*value
++ != ' ') {
57 return *possibility
== '\0';
61 const char *value
, std::size_t length
, const char *possibilities
[]) {
63 for (int j
{0}; possibilities
[j
]; ++j
) {
64 if (CaseInsensitiveMatch(value
, length
, possibilities
[j
])) {
72 void ToFortranDefaultCharacter(
73 char *to
, std::size_t toLength
, const char *from
) {
74 std::size_t len
{std::strlen(from
)};
76 std::memcpy(to
, from
, len
);
77 std::memset(to
+ len
, ' ', toLength
- len
);
79 std::memcpy(to
, from
, toLength
);
83 void CheckConformability(const Descriptor
&to
, const Descriptor
&x
,
84 Terminator
&terminator
, const char *funcName
, const char *toName
,
87 return; // scalar conforms with anything
90 if (x
.rank() != rank
) {
92 "Incompatible array arguments to %s: %s has rank %d but %s has rank %d",
93 funcName
, toName
, rank
, xName
, x
.rank());
95 for (int j
{0}; j
< rank
; ++j
) {
96 auto toExtent
{static_cast<std::int64_t>(to
.GetDimension(j
).Extent())};
97 auto xExtent
{static_cast<std::int64_t>(x
.GetDimension(j
).Extent())};
98 if (xExtent
!= toExtent
) {
99 terminator
.Crash("Incompatible array arguments to %s: dimension %d of "
100 "%s has extent %" PRId64
" but %s has extent %" PRId64
,
101 funcName
, j
+ 1, toName
, toExtent
, xName
, xExtent
);
107 void CheckIntegerKind(Terminator
&terminator
, int kind
, const char *intrinsic
) {
108 if (kind
< 1 || kind
> 16 || (kind
& (kind
- 1)) != 0) {
110 "not yet implemented: %s: KIND=%d argument", intrinsic
, kind
);
114 void ShallowCopyDiscontiguousToDiscontiguous(
115 const Descriptor
&to
, const Descriptor
&from
) {
116 SubscriptValue toAt
[maxRank
], fromAt
[maxRank
];
117 to
.GetLowerBounds(toAt
);
118 from
.GetLowerBounds(fromAt
);
119 std::size_t elementBytes
{to
.ElementBytes()};
120 for (std::size_t n
{to
.Elements()}; n
-- > 0;
121 to
.IncrementSubscripts(toAt
), from
.IncrementSubscripts(fromAt
)) {
123 to
.Element
<char>(toAt
), from
.Element
<char>(fromAt
), elementBytes
);
127 void ShallowCopyDiscontiguousToContiguous(
128 const Descriptor
&to
, const Descriptor
&from
) {
129 char *toAt
{to
.OffsetElement()};
130 SubscriptValue fromAt
[maxRank
];
131 from
.GetLowerBounds(fromAt
);
132 std::size_t elementBytes
{to
.ElementBytes()};
133 for (std::size_t n
{to
.Elements()}; n
-- > 0;
134 toAt
+= elementBytes
, from
.IncrementSubscripts(fromAt
)) {
135 std::memcpy(toAt
, from
.Element
<char>(fromAt
), elementBytes
);
139 void ShallowCopyContiguousToDiscontiguous(
140 const Descriptor
&to
, const Descriptor
&from
) {
141 SubscriptValue toAt
[maxRank
];
142 to
.GetLowerBounds(toAt
);
143 char *fromAt
{from
.OffsetElement()};
144 std::size_t elementBytes
{to
.ElementBytes()};
145 for (std::size_t n
{to
.Elements()}; n
-- > 0;
146 to
.IncrementSubscripts(toAt
), fromAt
+= elementBytes
) {
147 std::memcpy(to
.Element
<char>(toAt
), fromAt
, elementBytes
);
151 void ShallowCopy(const Descriptor
&to
, const Descriptor
&from
,
152 bool toIsContiguous
, bool fromIsContiguous
) {
153 if (toIsContiguous
) {
154 if (fromIsContiguous
) {
155 std::memcpy(to
.OffsetElement(), from
.OffsetElement(),
156 to
.Elements() * to
.ElementBytes());
158 ShallowCopyDiscontiguousToContiguous(to
, from
);
161 if (fromIsContiguous
) {
162 ShallowCopyContiguousToDiscontiguous(to
, from
);
164 ShallowCopyDiscontiguousToDiscontiguous(to
, from
);
169 void ShallowCopy(const Descriptor
&to
, const Descriptor
&from
) {
170 ShallowCopy(to
, from
, to
.IsContiguous(), from
.IsContiguous());
172 } // namespace Fortran::runtime