blob: ff05e76c8bb7b2c1e0ec5c237f14bbba09b84115 [file] [log] [blame]
peter klauslerfae12a02020-01-24 00:10:001//===-- runtime/tools.h -----------------------------------------*- 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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef FORTRAN_RUNTIME_TOOLS_H_
10#define FORTRAN_RUNTIME_TOOLS_H_
peter klauslerf7be2512020-01-24 00:59:2711
Slava Zakharin32120512023-05-22 21:05:1812#include "freestanding-tools.h"
peter klauslere372e0f2021-03-31 16:14:0813#include "terminator.h"
Peter Klausler830c0b92021-09-01 23:00:5314#include "flang/Runtime/cpp-type.h"
15#include "flang/Runtime/descriptor.h"
16#include "flang/Runtime/memory.h"
Peter Klausler52a0b022023-04-12 19:32:3717#include <cstring>
peter klauslerf7be2512020-01-24 00:59:2718#include <functional>
19#include <map>
20#include <type_traits>
21
peter klauslerfae12a02020-01-24 00:10:0022namespace Fortran::runtime {
23
24class Terminator;
25
Slava Zakharin8b953fd2023-10-04 15:21:4626RT_API_ATTRS std::size_t TrimTrailingSpaces(const char *, std::size_t);
peter klausler675ad1b2020-08-03 18:35:2927
Slava Zakharin8b953fd2023-10-04 15:21:4628RT_API_ATTRS OwningPtr<char> SaveDefaultCharacter(
peter klausler95696d52020-02-05 00:55:4529 const char *, std::size_t, const Terminator &);
peter klauslerfae12a02020-01-24 00:10:0030
31// For validating and recognizing default CHARACTER values in a
32// case-insensitive manner. Returns the zero-based index into the
33// null-terminated array of upper-case possibilities when the value is valid,
34// or -1 when it has no match.
Slava Zakharin8b953fd2023-10-04 15:21:4635RT_API_ATTRS int IdentifyValue(
peter klauslerfae12a02020-01-24 00:10:0036 const char *value, std::size_t length, const char *possibilities[]);
peter klauslerf7be2512020-01-24 00:59:2737
peter klausler3b635712020-02-13 22:41:5638// Truncates or pads as necessary
Slava Zakharin8b953fd2023-10-04 15:21:4639RT_API_ATTRS void ToFortranDefaultCharacter(
peter klausler3b635712020-02-13 22:41:5640 char *to, std::size_t toLength, const char *from);
peter klauslere372e0f2021-03-31 16:14:0841
42// Utility for dealing with elemental LOGICAL arguments
Slava Zakharin32120512023-05-22 21:05:1843inline RT_API_ATTRS bool IsLogicalElementTrue(
peter klauslere372e0f2021-03-31 16:14:0844 const Descriptor &logical, const SubscriptValue at[]) {
45 // A LOGICAL value is false if and only if all of its bytes are zero.
46 const char *p{logical.Element<char>(at)};
47 for (std::size_t j{logical.ElementBytes()}; j-- > 0; ++p) {
48 if (*p) {
49 return true;
50 }
51 }
52 return false;
53}
54
55// Check array conformability; a scalar 'x' conforms. Crashes on error.
Slava Zakharin32120512023-05-22 21:05:1856RT_API_ATTRS void CheckConformability(const Descriptor &to, const Descriptor &x,
peter klauslere372e0f2021-03-31 16:14:0857 Terminator &, const char *funcName, const char *toName,
58 const char *fromName);
59
Peter Steinfeld6cd417b2022-02-09 19:17:1860// Helper to store integer value in result[at].
61template <int KIND> struct StoreIntegerAt {
Slava Zakharin8b953fd2023-10-04 15:21:4662 RT_API_ATTRS void operator()(const Fortran::runtime::Descriptor &result,
63 std::size_t at, std::int64_t value) const {
Peter Steinfeld6cd417b2022-02-09 19:17:1864 *result.ZeroBasedIndexedElement<Fortran::runtime::CppTypeFor<
65 Fortran::common::TypeCategory::Integer, KIND>>(at) = value;
66 }
67};
68
peter klauslere372e0f2021-03-31 16:14:0869// Validate a KIND= argument
Slava Zakharin32120512023-05-22 21:05:1870RT_API_ATTRS void CheckIntegerKind(
71 Terminator &, int kind, const char *intrinsic);
peter klauslere372e0f2021-03-31 16:14:0872
73template <typename TO, typename FROM>
Slava Zakharin8b953fd2023-10-04 15:21:4674inline RT_API_ATTRS void PutContiguousConverted(
75 TO *to, FROM *from, std::size_t count) {
peter klauslere372e0f2021-03-31 16:14:0876 while (count-- > 0) {
77 *to++ = *from++;
78 }
79}
80
Slava Zakharin32120512023-05-22 21:05:1881static inline RT_API_ATTRS std::int64_t GetInt64(
peter klauslerc1db35f2021-05-20 17:37:0382 const char *p, std::size_t bytes, Terminator &terminator) {
peter klauslere372e0f2021-03-31 16:14:0883 switch (bytes) {
84 case 1:
85 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 1> *>(p);
86 case 2:
87 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 2> *>(p);
88 case 4:
89 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 4> *>(p);
90 case 8:
91 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 8> *>(p);
92 default:
peter klauslerc1db35f2021-05-20 17:37:0393 terminator.Crash("GetInt64: no case for %zd bytes", bytes);
peter klauslere372e0f2021-03-31 16:14:0894 }
95}
96
Peter Klausler8fc045e2023-12-26 23:12:3997static inline RT_API_ATTRS std::optional<std::int64_t> GetInt64Safe(
98 const char *p, std::size_t bytes, Terminator &terminator) {
99 switch (bytes) {
100 case 1:
101 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 1> *>(p);
102 case 2:
103 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 2> *>(p);
104 case 4:
105 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 4> *>(p);
106 case 8:
107 return *reinterpret_cast<const CppTypeFor<TypeCategory::Integer, 8> *>(p);
108 case 16: {
109 using Int128 = CppTypeFor<TypeCategory::Integer, 16>;
110 auto n{*reinterpret_cast<const Int128 *>(p)};
111 std::int64_t result = n;
112 if (result == n) {
113 return result;
114 }
115 return std::nullopt;
116 }
117 default:
118 terminator.Crash("GetInt64Safe: no case for %zd bytes", bytes);
119 }
120}
121
peter klauslere372e0f2021-03-31 16:14:08122template <typename INT>
Slava Zakharin8b953fd2023-10-04 15:21:46123inline RT_API_ATTRS bool SetInteger(INT &x, int kind, std::int64_t value) {
peter klauslere372e0f2021-03-31 16:14:08124 switch (kind) {
125 case 1:
126 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 1> &>(x) = value;
Peter Klausler73b193a2022-02-16 21:26:44127 return value == reinterpret_cast<CppTypeFor<TypeCategory::Integer, 1> &>(x);
peter klauslere372e0f2021-03-31 16:14:08128 case 2:
129 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 2> &>(x) = value;
Peter Klausler73b193a2022-02-16 21:26:44130 return value == reinterpret_cast<CppTypeFor<TypeCategory::Integer, 2> &>(x);
peter klauslere372e0f2021-03-31 16:14:08131 case 4:
132 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 4> &>(x) = value;
Peter Klausler73b193a2022-02-16 21:26:44133 return value == reinterpret_cast<CppTypeFor<TypeCategory::Integer, 4> &>(x);
peter klauslere372e0f2021-03-31 16:14:08134 case 8:
135 reinterpret_cast<CppTypeFor<TypeCategory::Integer, 8> &>(x) = value;
Peter Klausler73b193a2022-02-16 21:26:44136 return value == reinterpret_cast<CppTypeFor<TypeCategory::Integer, 8> &>(x);
peter klauslere372e0f2021-03-31 16:14:08137 default:
138 return false;
139 }
140}
141
peter klausler50e0b292021-05-12 19:07:51142// Maps intrinsic runtime type category and kind values to the appropriate
143// instantiation of a function object template and calls it with the supplied
144// arguments.
145template <template <TypeCategory, int> class FUNC, typename RESULT,
146 typename... A>
Slava Zakharin32120512023-05-22 21:05:18147inline RT_API_ATTRS RESULT ApplyType(
peter klausler50e0b292021-05-12 19:07:51148 TypeCategory cat, int kind, Terminator &terminator, A &&...x) {
149 switch (cat) {
150 case TypeCategory::Integer:
151 switch (kind) {
152 case 1:
153 return FUNC<TypeCategory::Integer, 1>{}(std::forward<A>(x)...);
154 case 2:
155 return FUNC<TypeCategory::Integer, 2>{}(std::forward<A>(x)...);
156 case 4:
157 return FUNC<TypeCategory::Integer, 4>{}(std::forward<A>(x)...);
158 case 8:
159 return FUNC<TypeCategory::Integer, 8>{}(std::forward<A>(x)...);
Peter Klausler1c35c1a2023-07-06 22:03:05160#if defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T
peter klausler50e0b292021-05-12 19:07:51161 case 16:
162 return FUNC<TypeCategory::Integer, 16>{}(std::forward<A>(x)...);
163#endif
164 default:
Peter Steinfeldebe24a22022-05-05 21:54:57165 terminator.Crash("not yet implemented: INTEGER(KIND=%d)", kind);
peter klausler50e0b292021-05-12 19:07:51166 }
167 case TypeCategory::Real:
168 switch (kind) {
169#if 0 // TODO: REAL(2 & 3)
170 case 2:
171 return FUNC<TypeCategory::Real, 2>{}(std::forward<A>(x)...);
172 case 3:
173 return FUNC<TypeCategory::Real, 3>{}(std::forward<A>(x)...);
174#endif
175 case 4:
176 return FUNC<TypeCategory::Real, 4>{}(std::forward<A>(x)...);
177 case 8:
178 return FUNC<TypeCategory::Real, 8>{}(std::forward<A>(x)...);
peter klausler50e0b292021-05-12 19:07:51179 case 10:
Peter Klausler4daa33f2022-05-31 21:06:11180 if constexpr (HasCppTypeFor<TypeCategory::Real, 10>) {
181 return FUNC<TypeCategory::Real, 10>{}(std::forward<A>(x)...);
182 }
183 break;
peter klausler50e0b292021-05-12 19:07:51184 case 16:
Peter Klausler4daa33f2022-05-31 21:06:11185 if constexpr (HasCppTypeFor<TypeCategory::Real, 16>) {
186 return FUNC<TypeCategory::Real, 16>{}(std::forward<A>(x)...);
187 }
188 break;
peter klausler50e0b292021-05-12 19:07:51189 }
Peter Klausler4daa33f2022-05-31 21:06:11190 terminator.Crash("not yet implemented: REAL(KIND=%d)", kind);
peter klausler50e0b292021-05-12 19:07:51191 case TypeCategory::Complex:
192 switch (kind) {
193#if 0 // TODO: COMPLEX(2 & 3)
194 case 2:
195 return FUNC<TypeCategory::Complex, 2>{}(std::forward<A>(x)...);
196 case 3:
197 return FUNC<TypeCategory::Complex, 3>{}(std::forward<A>(x)...);
198#endif
199 case 4:
200 return FUNC<TypeCategory::Complex, 4>{}(std::forward<A>(x)...);
201 case 8:
202 return FUNC<TypeCategory::Complex, 8>{}(std::forward<A>(x)...);
peter klausler50e0b292021-05-12 19:07:51203 case 10:
Peter Klausler4daa33f2022-05-31 21:06:11204 if constexpr (HasCppTypeFor<TypeCategory::Real, 10>) {
205 return FUNC<TypeCategory::Complex, 10>{}(std::forward<A>(x)...);
206 }
207 break;
peter klausler50e0b292021-05-12 19:07:51208 case 16:
Peter Klausler4daa33f2022-05-31 21:06:11209 if constexpr (HasCppTypeFor<TypeCategory::Real, 16>) {
210 return FUNC<TypeCategory::Complex, 16>{}(std::forward<A>(x)...);
211 }
212 break;
peter klausler50e0b292021-05-12 19:07:51213 }
Peter Klausler4daa33f2022-05-31 21:06:11214 terminator.Crash("not yet implemented: COMPLEX(KIND=%d)", kind);
peter klausler50e0b292021-05-12 19:07:51215 case TypeCategory::Character:
216 switch (kind) {
217 case 1:
218 return FUNC<TypeCategory::Character, 1>{}(std::forward<A>(x)...);
219 case 2:
220 return FUNC<TypeCategory::Character, 2>{}(std::forward<A>(x)...);
221 case 4:
222 return FUNC<TypeCategory::Character, 4>{}(std::forward<A>(x)...);
223 default:
Peter Steinfeldebe24a22022-05-05 21:54:57224 terminator.Crash("not yet implemented: CHARACTER(KIND=%d)", kind);
peter klausler50e0b292021-05-12 19:07:51225 }
226 case TypeCategory::Logical:
227 switch (kind) {
228 case 1:
229 return FUNC<TypeCategory::Logical, 1>{}(std::forward<A>(x)...);
230 case 2:
231 return FUNC<TypeCategory::Logical, 2>{}(std::forward<A>(x)...);
232 case 4:
233 return FUNC<TypeCategory::Logical, 4>{}(std::forward<A>(x)...);
234 case 8:
235 return FUNC<TypeCategory::Logical, 8>{}(std::forward<A>(x)...);
236 default:
Peter Steinfeldebe24a22022-05-05 21:54:57237 terminator.Crash("not yet implemented: LOGICAL(KIND=%d)", kind);
peter klausler50e0b292021-05-12 19:07:51238 }
239 default:
Peter Steinfeldebe24a22022-05-05 21:54:57240 terminator.Crash(
241 "not yet implemented: type category(%d)", static_cast<int>(cat));
peter klausler50e0b292021-05-12 19:07:51242 }
243}
244
peter klausler8d672c0b2021-04-20 16:19:21245// Maps a runtime INTEGER kind value to the appropriate instantiation of
246// a function object template and calls it with the supplied arguments.
247template <template <int KIND> class FUNC, typename RESULT, typename... A>
Slava Zakharin32120512023-05-22 21:05:18248inline RT_API_ATTRS RESULT ApplyIntegerKind(
249 int kind, Terminator &terminator, A &&...x) {
peter klausler8d672c0b2021-04-20 16:19:21250 switch (kind) {
251 case 1:
252 return FUNC<1>{}(std::forward<A>(x)...);
253 case 2:
254 return FUNC<2>{}(std::forward<A>(x)...);
255 case 4:
256 return FUNC<4>{}(std::forward<A>(x)...);
257 case 8:
258 return FUNC<8>{}(std::forward<A>(x)...);
Peter Klausler1c35c1a2023-07-06 22:03:05259#if defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T
peter klausler8d672c0b2021-04-20 16:19:21260 case 16:
261 return FUNC<16>{}(std::forward<A>(x)...);
262#endif
263 default:
Peter Steinfeldebe24a22022-05-05 21:54:57264 terminator.Crash("not yet implemented: INTEGER(KIND=%d)", kind);
peter klausler8d672c0b2021-04-20 16:19:21265 }
266}
267
268template <template <int KIND> class FUNC, typename RESULT, typename... A>
Slava Zakharin32120512023-05-22 21:05:18269inline RT_API_ATTRS RESULT ApplyFloatingPointKind(
peter klausler8d672c0b2021-04-20 16:19:21270 int kind, Terminator &terminator, A &&...x) {
271 switch (kind) {
272#if 0 // TODO: REAL/COMPLEX (2 & 3)
273 case 2:
274 return FUNC<2>{}(std::forward<A>(x)...);
275 case 3:
276 return FUNC<3>{}(std::forward<A>(x)...);
277#endif
278 case 4:
279 return FUNC<4>{}(std::forward<A>(x)...);
280 case 8:
281 return FUNC<8>{}(std::forward<A>(x)...);
peter klausler8d672c0b2021-04-20 16:19:21282 case 10:
Peter Klausler4daa33f2022-05-31 21:06:11283 if constexpr (HasCppTypeFor<TypeCategory::Real, 10>) {
284 return FUNC<10>{}(std::forward<A>(x)...);
285 }
286 break;
peter klausler8d672c0b2021-04-20 16:19:21287 case 16:
Peter Klausler4daa33f2022-05-31 21:06:11288 if constexpr (HasCppTypeFor<TypeCategory::Real, 16>) {
289 return FUNC<16>{}(std::forward<A>(x)...);
290 }
291 break;
peter klausler8d672c0b2021-04-20 16:19:21292 }
Peter Klausler4daa33f2022-05-31 21:06:11293 terminator.Crash("not yet implemented: REAL/COMPLEX(KIND=%d)", kind);
peter klausler8d672c0b2021-04-20 16:19:21294}
295
296template <template <int KIND> class FUNC, typename RESULT, typename... A>
Slava Zakharin32120512023-05-22 21:05:18297inline RT_API_ATTRS RESULT ApplyCharacterKind(
298 int kind, Terminator &terminator, A &&...x) {
peter klausler8d672c0b2021-04-20 16:19:21299 switch (kind) {
300 case 1:
301 return FUNC<1>{}(std::forward<A>(x)...);
302 case 2:
303 return FUNC<2>{}(std::forward<A>(x)...);
304 case 4:
305 return FUNC<4>{}(std::forward<A>(x)...);
306 default:
Peter Steinfeldebe24a22022-05-05 21:54:57307 terminator.Crash("not yet implemented: CHARACTER(KIND=%d)", kind);
peter klausler8d672c0b2021-04-20 16:19:21308 }
309}
310
311template <template <int KIND> class FUNC, typename RESULT, typename... A>
Slava Zakharin32120512023-05-22 21:05:18312inline RT_API_ATTRS RESULT ApplyLogicalKind(
313 int kind, Terminator &terminator, A &&...x) {
peter klausler8d672c0b2021-04-20 16:19:21314 switch (kind) {
315 case 1:
316 return FUNC<1>{}(std::forward<A>(x)...);
317 case 2:
318 return FUNC<2>{}(std::forward<A>(x)...);
319 case 4:
320 return FUNC<4>{}(std::forward<A>(x)...);
321 case 8:
322 return FUNC<8>{}(std::forward<A>(x)...);
323 default:
Peter Steinfeldebe24a22022-05-05 21:54:57324 terminator.Crash("not yet implemented: LOGICAL(KIND=%d)", kind);
peter klausler8d672c0b2021-04-20 16:19:21325 }
326}
327
peter klausler50e0b292021-05-12 19:07:51328// Calculate result type of (X op Y) for *, //, DOT_PRODUCT, &c.
Slava Zakharin8b953fd2023-10-04 15:21:46329std::optional<std::pair<TypeCategory, int>> inline constexpr RT_API_ATTRS
330GetResultType(TypeCategory xCat, int xKind, TypeCategory yCat, int yKind) {
peter klausler50e0b292021-05-12 19:07:51331 int maxKind{std::max(xKind, yKind)};
332 switch (xCat) {
333 case TypeCategory::Integer:
334 switch (yCat) {
335 case TypeCategory::Integer:
336 return std::make_pair(TypeCategory::Integer, maxKind);
337 case TypeCategory::Real:
338 case TypeCategory::Complex:
Peter Klausler1c35c1a2023-07-06 22:03:05339#if !(defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T)
340 if (xKind == 16) {
341 break;
342 }
343#endif
peter klausler50e0b292021-05-12 19:07:51344 return std::make_pair(yCat, yKind);
345 default:
346 break;
347 }
348 break;
349 case TypeCategory::Real:
350 switch (yCat) {
351 case TypeCategory::Integer:
Peter Klausler1c35c1a2023-07-06 22:03:05352#if !(defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T)
353 if (yKind == 16) {
354 break;
355 }
356#endif
peter klausler50e0b292021-05-12 19:07:51357 return std::make_pair(TypeCategory::Real, xKind);
358 case TypeCategory::Real:
359 case TypeCategory::Complex:
360 return std::make_pair(yCat, maxKind);
361 default:
362 break;
363 }
364 break;
365 case TypeCategory::Complex:
366 switch (yCat) {
367 case TypeCategory::Integer:
Peter Klausler1c35c1a2023-07-06 22:03:05368#if !(defined __SIZEOF_INT128__ && !AVOID_NATIVE_UINT128_T)
369 if (yKind == 16) {
370 break;
371 }
372#endif
peter klausler50e0b292021-05-12 19:07:51373 return std::make_pair(TypeCategory::Complex, xKind);
374 case TypeCategory::Real:
375 case TypeCategory::Complex:
376 return std::make_pair(TypeCategory::Complex, maxKind);
377 default:
378 break;
379 }
380 break;
381 case TypeCategory::Character:
382 if (yCat == TypeCategory::Character) {
383 return std::make_pair(TypeCategory::Character, maxKind);
384 } else {
385 return std::nullopt;
386 }
387 case TypeCategory::Logical:
388 if (yCat == TypeCategory::Logical) {
389 return std::make_pair(TypeCategory::Logical, maxKind);
390 } else {
391 return std::nullopt;
392 }
393 default:
394 break;
395 }
396 return std::nullopt;
397}
peter klausler79caf692021-06-17 20:13:19398
Peter Klauslera5a493e2021-10-19 18:30:45399// Accumulate floating-point results in (at least) double precision
400template <TypeCategory CAT, int KIND>
401using AccumulationType = CppTypeFor<CAT,
402 CAT == TypeCategory::Real || CAT == TypeCategory::Complex
403 ? std::max(KIND, static_cast<int>(sizeof(double)))
404 : KIND>;
405
Peter Klausler52a0b022023-04-12 19:32:37406// memchr() for any character type
407template <typename CHAR>
Slava Zakharin8b953fd2023-10-04 15:21:46408static inline RT_API_ATTRS const CHAR *FindCharacter(
Peter Klausler52a0b022023-04-12 19:32:37409 const CHAR *data, CHAR ch, std::size_t chars) {
410 const CHAR *end{data + chars};
411 for (const CHAR *p{data}; p < end; ++p) {
412 if (*p == ch) {
413 return p;
414 }
415 }
416 return nullptr;
417}
418
419template <>
Slava Zakharin8b953fd2023-10-04 15:21:46420inline RT_API_ATTRS const char *FindCharacter(
421 const char *data, char ch, std::size_t chars) {
Peter Klausler52a0b022023-04-12 19:32:37422 return reinterpret_cast<const char *>(
423 std::memchr(data, static_cast<int>(ch), chars));
424}
425
Peter Klauslerb21c24c2023-07-29 15:34:14426// Copy payload data from one allocated descriptor to another.
427// Assumes element counts and element sizes match, and that both
428// descriptors are allocated.
Slava Zakharin8b953fd2023-10-04 15:21:46429RT_API_ATTRS void ShallowCopyDiscontiguousToDiscontiguous(
Peter Klauslerb21c24c2023-07-29 15:34:14430 const Descriptor &to, const Descriptor &from);
Slava Zakharin8b953fd2023-10-04 15:21:46431RT_API_ATTRS void ShallowCopyDiscontiguousToContiguous(
Peter Klauslerb21c24c2023-07-29 15:34:14432 const Descriptor &to, const Descriptor &from);
Slava Zakharin8b953fd2023-10-04 15:21:46433RT_API_ATTRS void ShallowCopyContiguousToDiscontiguous(
Peter Klauslerb21c24c2023-07-29 15:34:14434 const Descriptor &to, const Descriptor &from);
Slava Zakharin8b953fd2023-10-04 15:21:46435RT_API_ATTRS void ShallowCopy(const Descriptor &to, const Descriptor &from,
Peter Klauslerb21c24c2023-07-29 15:34:14436 bool toIsContiguous, bool fromIsContiguous);
Slava Zakharin8b953fd2023-10-04 15:21:46437RT_API_ATTRS void ShallowCopy(const Descriptor &to, const Descriptor &from);
Peter Klauslerb21c24c2023-07-29 15:34:14438
Yi Wu18af0322023-12-21 10:35:28439// Defines a utility function for copying and padding characters
440template <typename TO, typename FROM>
441RT_API_ATTRS void CopyAndPad(
442 TO *to, const FROM *from, std::size_t toChars, std::size_t fromChars) {
443 if constexpr (sizeof(TO) != sizeof(FROM)) {
444 std::size_t copyChars{std::min(toChars, fromChars)};
445 for (std::size_t j{0}; j < copyChars; ++j) {
446 to[j] = from[j];
447 }
448 for (std::size_t j{copyChars}; j < toChars; ++j) {
449 to[j] = static_cast<TO>(' ');
450 }
451 } else if (toChars <= fromChars) {
452 std::memcpy(to, from, toChars * sizeof(TO));
453 } else {
454 std::memcpy(to, from, std::min(toChars, fromChars) * sizeof(TO));
455 for (std::size_t j{fromChars}; j < toChars; ++j) {
456 to[j] = static_cast<TO>(' ');
457 }
458 }
459}
460
Tim Keith1f879002020-03-29 04:00:16461} // namespace Fortran::runtime
462#endif // FORTRAN_RUNTIME_TOOLS_H_