1651f58bfSDiana Picus //===-- runtime/character.cpp ---------------------------------------------===//
24d54bb7aSpeter klausler //
34d54bb7aSpeter klausler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44d54bb7aSpeter klausler // See https://llvm.org/LICENSE.txt for license information.
54d54bb7aSpeter klausler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64d54bb7aSpeter klausler //
74d54bb7aSpeter klausler //===----------------------------------------------------------------------===//
84d54bb7aSpeter klausler 
9830c0b90SPeter Klausler #include "flang/Runtime/character.h"
104d54bb7aSpeter klausler #include "terminator.h"
11e372e0f9Speter klausler #include "tools.h"
123d627d6fSpeter klausler #include "flang/Common/bit-population-count.h"
133d627d6fSpeter klausler #include "flang/Common/uint128.h"
14830c0b90SPeter Klausler #include "flang/Runtime/cpp-type.h"
15830c0b90SPeter Klausler #include "flang/Runtime/descriptor.h"
164d54bb7aSpeter klausler #include <algorithm>
174d54bb7aSpeter klausler #include <cstring>
184d54bb7aSpeter klausler 
194d54bb7aSpeter klausler namespace Fortran::runtime {
20fc026241Speter klausler 
213d627d6fSpeter klausler template <typename CHAR>
CompareToBlankPadding(const CHAR * x,std::size_t chars)223d627d6fSpeter klausler inline int CompareToBlankPadding(const CHAR *x, std::size_t chars) {
23fc026241Speter klausler   for (; chars-- > 0; ++x) {
24fc026241Speter klausler     if (*x < ' ') {
25fc026241Speter klausler       return -1;
26fc026241Speter klausler     }
27fc026241Speter klausler     if (*x > ' ') {
28fc026241Speter klausler       return 1;
29fc026241Speter klausler     }
30fc026241Speter klausler   }
31fc026241Speter klausler   return 0;
32fc026241Speter klausler }
33fc026241Speter klausler 
343d627d6fSpeter klausler template <typename CHAR>
CharacterScalarCompare(const CHAR * x,const CHAR * y,std::size_t xChars,std::size_t yChars)35e372e0f9Speter klausler int CharacterScalarCompare(
363d627d6fSpeter klausler     const CHAR *x, const CHAR *y, std::size_t xChars, std::size_t yChars) {
373d627d6fSpeter klausler   auto minChars{std::min(xChars, yChars)};
383d627d6fSpeter klausler   if constexpr (sizeof(CHAR) == 1) {
39fc026241Speter klausler     // don't use for kind=2 or =4, that would fail on little-endian machines
403d627d6fSpeter klausler     int cmp{std::memcmp(x, y, minChars)};
41fc026241Speter klausler     if (cmp < 0) {
42fc026241Speter klausler       return -1;
43fc026241Speter klausler     }
44fc026241Speter klausler     if (cmp > 0) {
45fc026241Speter klausler       return 1;
46fc026241Speter klausler     }
473d627d6fSpeter klausler     if (xChars == yChars) {
48fc026241Speter klausler       return 0;
49fc026241Speter klausler     }
503d627d6fSpeter klausler     x += minChars;
513d627d6fSpeter klausler     y += minChars;
52fc026241Speter klausler   } else {
533d627d6fSpeter klausler     for (std::size_t n{minChars}; n-- > 0; ++x, ++y) {
54fc026241Speter klausler       if (*x < *y) {
55fc026241Speter klausler         return -1;
56fc026241Speter klausler       }
57fc026241Speter klausler       if (*x > *y) {
58fc026241Speter klausler         return 1;
59fc026241Speter klausler       }
60fc026241Speter klausler     }
61fc026241Speter klausler   }
623d627d6fSpeter klausler   if (int cmp{CompareToBlankPadding(x, xChars - minChars)}) {
63fc026241Speter klausler     return cmp;
64fc026241Speter klausler   }
653d627d6fSpeter klausler   return -CompareToBlankPadding(y, yChars - minChars);
663d627d6fSpeter klausler }
673d627d6fSpeter klausler 
68e372e0f9Speter klausler template int CharacterScalarCompare<char>(
69e372e0f9Speter klausler     const char *x, const char *y, std::size_t xChars, std::size_t yChars);
70e372e0f9Speter klausler template int CharacterScalarCompare<char16_t>(const char16_t *x,
71e372e0f9Speter klausler     const char16_t *y, std::size_t xChars, std::size_t yChars);
72e372e0f9Speter klausler template int CharacterScalarCompare<char32_t>(const char32_t *x,
73e372e0f9Speter klausler     const char32_t *y, std::size_t xChars, std::size_t yChars);
74e372e0f9Speter klausler 
753d627d6fSpeter klausler // Shift count to use when converting between character lengths
763d627d6fSpeter klausler // and byte counts.
773d627d6fSpeter klausler template <typename CHAR>
783d627d6fSpeter klausler constexpr int shift{common::TrailingZeroBitCount(sizeof(CHAR))};
793d627d6fSpeter klausler 
803d627d6fSpeter klausler template <typename CHAR>
Compare(Descriptor & result,const Descriptor & x,const Descriptor & y,const Terminator & terminator)813d627d6fSpeter klausler static void Compare(Descriptor &result, const Descriptor &x,
823d627d6fSpeter klausler     const Descriptor &y, const Terminator &terminator) {
833d627d6fSpeter klausler   RUNTIME_CHECK(
843d627d6fSpeter klausler       terminator, x.rank() == y.rank() || x.rank() == 0 || y.rank() == 0);
853d627d6fSpeter klausler   int rank{std::max(x.rank(), y.rank())};
868ba9ee46Speter klausler   SubscriptValue ub[maxRank], xAt[maxRank], yAt[maxRank];
873d627d6fSpeter klausler   SubscriptValue elements{1};
883d627d6fSpeter klausler   for (int j{0}; j < rank; ++j) {
893d627d6fSpeter klausler     if (x.rank() > 0 && y.rank() > 0) {
903d627d6fSpeter klausler       SubscriptValue xUB{x.GetDimension(j).Extent()};
913d627d6fSpeter klausler       SubscriptValue yUB{y.GetDimension(j).Extent()};
923d627d6fSpeter klausler       if (xUB != yUB) {
933d627d6fSpeter klausler         terminator.Crash("Character array comparison: operands are not "
943d627d6fSpeter klausler                          "conforming on dimension %d (%jd != %jd)",
953d627d6fSpeter klausler             j + 1, static_cast<std::intmax_t>(xUB),
963d627d6fSpeter klausler             static_cast<std::intmax_t>(yUB));
973d627d6fSpeter klausler       }
983d627d6fSpeter klausler       ub[j] = xUB;
993d627d6fSpeter klausler     } else {
1003d627d6fSpeter klausler       ub[j] = (x.rank() ? x : y).GetDimension(j).Extent();
1013d627d6fSpeter klausler     }
1023d627d6fSpeter klausler     elements *= ub[j];
1033d627d6fSpeter klausler   }
1048ba9ee46Speter klausler   x.GetLowerBounds(xAt);
1058ba9ee46Speter klausler   y.GetLowerBounds(yAt);
1065a451a42Speter klausler   result.Establish(
1075a451a42Speter klausler       TypeCategory::Logical, 1, nullptr, rank, ub, CFI_attribute_allocatable);
1088ba9ee46Speter klausler   for (int j{0}; j < rank; ++j) {
1098ba9ee46Speter klausler     result.GetDimension(j).SetBounds(1, ub[j]);
1108ba9ee46Speter klausler   }
1118ba9ee46Speter klausler   if (result.Allocate() != CFI_SUCCESS) {
1123d627d6fSpeter klausler     terminator.Crash("Compare: could not allocate storage for result");
1133d627d6fSpeter klausler   }
1143d627d6fSpeter klausler   std::size_t xChars{x.ElementBytes() >> shift<CHAR>};
1153d627d6fSpeter klausler   std::size_t yChars{y.ElementBytes() >> shift<char>};
1163d627d6fSpeter klausler   for (SubscriptValue resultAt{0}; elements-- > 0;
1173d627d6fSpeter klausler        ++resultAt, x.IncrementSubscripts(xAt), y.IncrementSubscripts(yAt)) {
118e372e0f9Speter klausler     *result.OffsetElement<char>(resultAt) = CharacterScalarCompare<CHAR>(
119e372e0f9Speter klausler         x.Element<CHAR>(xAt), y.Element<CHAR>(yAt), xChars, yChars);
1203d627d6fSpeter klausler   }
1213d627d6fSpeter klausler }
1223d627d6fSpeter klausler 
1233d627d6fSpeter klausler template <typename CHAR, bool ADJUSTR>
Adjust(CHAR * to,const CHAR * from,std::size_t chars)1243d627d6fSpeter klausler static void Adjust(CHAR *to, const CHAR *from, std::size_t chars) {
1253d627d6fSpeter klausler   if constexpr (ADJUSTR) {
1263d627d6fSpeter klausler     std::size_t j{chars}, k{chars};
1273d627d6fSpeter klausler     for (; k > 0 && from[k - 1] == ' '; --k) {
1283d627d6fSpeter klausler     }
1293d627d6fSpeter klausler     while (k > 0) {
1303d627d6fSpeter klausler       to[--j] = from[--k];
1313d627d6fSpeter klausler     }
1323d627d6fSpeter klausler     while (j > 0) {
1333d627d6fSpeter klausler       to[--j] = ' ';
1343d627d6fSpeter klausler     }
1353d627d6fSpeter klausler   } else { // ADJUSTL
1363d627d6fSpeter klausler     std::size_t j{0}, k{0};
1373d627d6fSpeter klausler     for (; k < chars && from[k] == ' '; ++k) {
1383d627d6fSpeter klausler     }
1393d627d6fSpeter klausler     while (k < chars) {
1403d627d6fSpeter klausler       to[j++] = from[k++];
1413d627d6fSpeter klausler     }
1423d627d6fSpeter klausler     while (j < chars) {
1433d627d6fSpeter klausler       to[j++] = ' ';
1443d627d6fSpeter klausler     }
1453d627d6fSpeter klausler   }
1463d627d6fSpeter klausler }
1473d627d6fSpeter klausler 
1483d627d6fSpeter klausler template <typename CHAR, bool ADJUSTR>
AdjustLRHelper(Descriptor & result,const Descriptor & string,const Terminator & terminator)1493d627d6fSpeter klausler static void AdjustLRHelper(Descriptor &result, const Descriptor &string,
1503d627d6fSpeter klausler     const Terminator &terminator) {
1513d627d6fSpeter klausler   int rank{string.rank()};
1528ba9ee46Speter klausler   SubscriptValue ub[maxRank], stringAt[maxRank];
1533d627d6fSpeter klausler   SubscriptValue elements{1};
1543d627d6fSpeter klausler   for (int j{0}; j < rank; ++j) {
1553d627d6fSpeter klausler     ub[j] = string.GetDimension(j).Extent();
1563d627d6fSpeter klausler     elements *= ub[j];
1573d627d6fSpeter klausler     stringAt[j] = 1;
1583d627d6fSpeter klausler   }
1598ba9ee46Speter klausler   string.GetLowerBounds(stringAt);
1603d627d6fSpeter klausler   std::size_t elementBytes{string.ElementBytes()};
1615a451a42Speter klausler   result.Establish(string.type(), elementBytes, nullptr, rank, ub,
1625a451a42Speter klausler       CFI_attribute_allocatable);
1638ba9ee46Speter klausler   for (int j{0}; j < rank; ++j) {
1648ba9ee46Speter klausler     result.GetDimension(j).SetBounds(1, ub[j]);
1658ba9ee46Speter klausler   }
1668ba9ee46Speter klausler   if (result.Allocate() != CFI_SUCCESS) {
1673d627d6fSpeter klausler     terminator.Crash("ADJUSTL/R: could not allocate storage for result");
1683d627d6fSpeter klausler   }
1693d627d6fSpeter klausler   for (SubscriptValue resultAt{0}; elements-- > 0;
1703d627d6fSpeter klausler        resultAt += elementBytes, string.IncrementSubscripts(stringAt)) {
1713d627d6fSpeter klausler     Adjust<CHAR, ADJUSTR>(result.OffsetElement<CHAR>(resultAt),
1723d627d6fSpeter klausler         string.Element<const CHAR>(stringAt), elementBytes >> shift<CHAR>);
1733d627d6fSpeter klausler   }
1743d627d6fSpeter klausler }
1753d627d6fSpeter klausler 
1763d627d6fSpeter klausler template <bool ADJUSTR>
AdjustLR(Descriptor & result,const Descriptor & string,const char * sourceFile,int sourceLine)1773d627d6fSpeter klausler void AdjustLR(Descriptor &result, const Descriptor &string,
1783d627d6fSpeter klausler     const char *sourceFile, int sourceLine) {
1793d627d6fSpeter klausler   Terminator terminator{sourceFile, sourceLine};
1803d627d6fSpeter klausler   switch (string.raw().type) {
1813d627d6fSpeter klausler   case CFI_type_char:
1823d627d6fSpeter klausler     AdjustLRHelper<char, ADJUSTR>(result, string, terminator);
1833d627d6fSpeter klausler     break;
1843d627d6fSpeter klausler   case CFI_type_char16_t:
1853d627d6fSpeter klausler     AdjustLRHelper<char16_t, ADJUSTR>(result, string, terminator);
1863d627d6fSpeter klausler     break;
1873d627d6fSpeter klausler   case CFI_type_char32_t:
1883d627d6fSpeter klausler     AdjustLRHelper<char32_t, ADJUSTR>(result, string, terminator);
1893d627d6fSpeter klausler     break;
1903d627d6fSpeter klausler   default:
1913d627d6fSpeter klausler     terminator.Crash("ADJUSTL/R: bad string type code %d",
1923d627d6fSpeter klausler         static_cast<int>(string.raw().type));
1933d627d6fSpeter klausler   }
1943d627d6fSpeter klausler }
1953d627d6fSpeter klausler 
1963d627d6fSpeter klausler template <typename CHAR>
LenTrim(const CHAR * x,std::size_t chars)1973d627d6fSpeter klausler inline std::size_t LenTrim(const CHAR *x, std::size_t chars) {
1983d627d6fSpeter klausler   while (chars > 0 && x[chars - 1] == ' ') {
1993d627d6fSpeter klausler     --chars;
2003d627d6fSpeter klausler   }
2013d627d6fSpeter klausler   return chars;
2023d627d6fSpeter klausler }
2033d627d6fSpeter klausler 
2043d627d6fSpeter klausler template <typename INT, typename CHAR>
LenTrim(Descriptor & result,const Descriptor & string,const Terminator & terminator)2053d627d6fSpeter klausler static void LenTrim(Descriptor &result, const Descriptor &string,
2063d627d6fSpeter klausler     const Terminator &terminator) {
2073d627d6fSpeter klausler   int rank{string.rank()};
2088ba9ee46Speter klausler   SubscriptValue ub[maxRank], stringAt[maxRank];
2093d627d6fSpeter klausler   SubscriptValue elements{1};
2103d627d6fSpeter klausler   for (int j{0}; j < rank; ++j) {
2113d627d6fSpeter klausler     ub[j] = string.GetDimension(j).Extent();
2123d627d6fSpeter klausler     elements *= ub[j];
2133d627d6fSpeter klausler   }
2148ba9ee46Speter klausler   string.GetLowerBounds(stringAt);
2155a451a42Speter klausler   result.Establish(TypeCategory::Integer, sizeof(INT), nullptr, rank, ub,
2165a451a42Speter klausler       CFI_attribute_allocatable);
2178ba9ee46Speter klausler   for (int j{0}; j < rank; ++j) {
2188ba9ee46Speter klausler     result.GetDimension(j).SetBounds(1, ub[j]);
2198ba9ee46Speter klausler   }
2208ba9ee46Speter klausler   if (result.Allocate() != CFI_SUCCESS) {
2213d627d6fSpeter klausler     terminator.Crash("LEN_TRIM: could not allocate storage for result");
2223d627d6fSpeter klausler   }
2233d627d6fSpeter klausler   std::size_t stringElementChars{string.ElementBytes() >> shift<CHAR>};
2243d627d6fSpeter klausler   for (SubscriptValue resultAt{0}; elements-- > 0;
2253d627d6fSpeter klausler        resultAt += sizeof(INT), string.IncrementSubscripts(stringAt)) {
2263d627d6fSpeter klausler     *result.OffsetElement<INT>(resultAt) =
2273d627d6fSpeter klausler         LenTrim(string.Element<CHAR>(stringAt), stringElementChars);
2283d627d6fSpeter klausler   }
2293d627d6fSpeter klausler }
2303d627d6fSpeter klausler 
2313d627d6fSpeter klausler template <typename CHAR>
LenTrimKind(Descriptor & result,const Descriptor & string,int kind,const Terminator & terminator)2323d627d6fSpeter klausler static void LenTrimKind(Descriptor &result, const Descriptor &string, int kind,
2333d627d6fSpeter klausler     const Terminator &terminator) {
2343d627d6fSpeter klausler   switch (kind) {
2353d627d6fSpeter klausler   case 1:
236e372e0f9Speter klausler     LenTrim<CppTypeFor<TypeCategory::Integer, 1>, CHAR>(
237e372e0f9Speter klausler         result, string, terminator);
2383d627d6fSpeter klausler     break;
2393d627d6fSpeter klausler   case 2:
240e372e0f9Speter klausler     LenTrim<CppTypeFor<TypeCategory::Integer, 2>, CHAR>(
241e372e0f9Speter klausler         result, string, terminator);
2423d627d6fSpeter klausler     break;
2433d627d6fSpeter klausler   case 4:
244e372e0f9Speter klausler     LenTrim<CppTypeFor<TypeCategory::Integer, 4>, CHAR>(
245e372e0f9Speter klausler         result, string, terminator);
2463d627d6fSpeter klausler     break;
2473d627d6fSpeter klausler   case 8:
248e372e0f9Speter klausler     LenTrim<CppTypeFor<TypeCategory::Integer, 8>, CHAR>(
249e372e0f9Speter klausler         result, string, terminator);
2503d627d6fSpeter klausler     break;
2513d627d6fSpeter klausler   case 16:
252e372e0f9Speter klausler     LenTrim<CppTypeFor<TypeCategory::Integer, 16>, CHAR>(
253e372e0f9Speter klausler         result, string, terminator);
2543d627d6fSpeter klausler     break;
2553d627d6fSpeter klausler   default:
256d4609ae4SPeter Steinfeld     terminator.Crash("not yet implemented: LEN_TRIM: KIND=%d", kind);
2573d627d6fSpeter klausler   }
2583d627d6fSpeter klausler }
2593d627d6fSpeter klausler 
2606811b961Speter klausler // INDEX implementation
2616811b961Speter klausler template <typename CHAR>
Index(const CHAR * x,std::size_t xLen,const CHAR * want,std::size_t wantLen,bool back)2626811b961Speter klausler inline std::size_t Index(const CHAR *x, std::size_t xLen, const CHAR *want,
2636811b961Speter klausler     std::size_t wantLen, bool back) {
2646811b961Speter klausler   if (xLen < wantLen) {
2656811b961Speter klausler     return 0;
2666811b961Speter klausler   }
2676811b961Speter klausler   if (xLen == 0) {
2686811b961Speter klausler     return 1; // wantLen is also 0, so trivial match
2696811b961Speter klausler   }
2706811b961Speter klausler   if (back) {
2716811b961Speter klausler     // If wantLen==0, returns xLen + 1 per standard (and all other compilers)
2726811b961Speter klausler     std::size_t at{xLen - wantLen + 1};
2736811b961Speter klausler     for (; at > 0; --at) {
2746811b961Speter klausler       std::size_t j{1};
2756811b961Speter klausler       for (; j <= wantLen; ++j) {
2766811b961Speter klausler         if (x[at + j - 2] != want[j - 1]) {
2776811b961Speter klausler           break;
2786811b961Speter klausler         }
2796811b961Speter klausler       }
2806811b961Speter klausler       if (j > wantLen) {
2816811b961Speter klausler         return at;
2826811b961Speter klausler       }
2836811b961Speter klausler     }
2846811b961Speter klausler     return 0;
2856811b961Speter klausler   }
2866811b961Speter klausler   // Non-trivial forward substring search: use a simplified form of
2876811b961Speter klausler   // Boyer-Moore substring searching.
2886811b961Speter klausler   for (std::size_t at{1}; at + wantLen - 1 <= xLen;) {
2896811b961Speter klausler     // Compare x(at:at+wantLen-1) with want(1:wantLen).
2906811b961Speter klausler     // The comparison proceeds from the ends of the substrings forward
2916811b961Speter klausler     // so that we can skip ahead by multiple positions on a miss.
2926811b961Speter klausler     std::size_t j{wantLen};
2936811b961Speter klausler     CHAR ch;
2946811b961Speter klausler     for (; j > 0; --j) {
2956811b961Speter klausler       ch = x[at + j - 2];
2966811b961Speter klausler       if (ch != want[j - 1]) {
2976811b961Speter klausler         break;
2986811b961Speter klausler       }
2996811b961Speter klausler     }
3006811b961Speter klausler     if (j == 0) {
3016811b961Speter klausler       return at; // found a match
3026811b961Speter klausler     }
3036811b961Speter klausler     // Suppose we have at==2:
3046811b961Speter klausler     // "THAT FORTRAN THAT I RAN" <- the string (x) in which we search
3056811b961Speter klausler     //   "THAT I RAN"            <- the string (want) for which we search
3066811b961Speter klausler     //          ^------------------ j==7, ch=='T'
3076811b961Speter klausler     // We can shift ahead 3 positions to at==5 to align the 'T's:
3086811b961Speter klausler     // "THAT FORTRAN THAT I RAN"
3096811b961Speter klausler     //      "THAT I RAN"
3106811b961Speter klausler     std::size_t shift{1};
3116811b961Speter klausler     for (; shift < j; ++shift) {
3126811b961Speter klausler       if (want[j - shift - 1] == ch) {
3136811b961Speter klausler         break;
3146811b961Speter klausler       }
3156811b961Speter klausler     }
3166811b961Speter klausler     at += shift;
3176811b961Speter klausler   }
3186811b961Speter klausler   return 0;
3196811b961Speter klausler }
3206811b961Speter klausler 
3215a451a42Speter klausler // SCAN and VERIFY implementation help.  These intrinsic functions
3225a451a42Speter klausler // do pretty much the same thing, so they're templatized with a
3235a451a42Speter klausler // distinguishing flag.
3245a451a42Speter klausler 
3256811b961Speter klausler enum class CharFunc { Index, Scan, Verify };
3266811b961Speter klausler 
3276811b961Speter klausler template <typename CHAR, CharFunc FUNC>
ScanVerify(const CHAR * x,std::size_t xLen,const CHAR * set,std::size_t setLen,bool back)3285a451a42Speter klausler inline std::size_t ScanVerify(const CHAR *x, std::size_t xLen, const CHAR *set,
3295a451a42Speter klausler     std::size_t setLen, bool back) {
3305a451a42Speter klausler   std::size_t at{back ? xLen : 1};
3315a451a42Speter klausler   int increment{back ? -1 : 1};
3325a451a42Speter klausler   for (; xLen-- > 0; at += increment) {
3335a451a42Speter klausler     CHAR ch{x[at - 1]};
3345a451a42Speter klausler     bool inSet{false};
3355a451a42Speter klausler     // TODO: If set is sorted, could use binary search
3365a451a42Speter klausler     for (std::size_t j{0}; j < setLen; ++j) {
3375a451a42Speter klausler       if (set[j] == ch) {
3385a451a42Speter klausler         inSet = true;
3395a451a42Speter klausler         break;
3405a451a42Speter klausler       }
3415a451a42Speter klausler     }
3426811b961Speter klausler     if (inSet != (FUNC == CharFunc::Verify)) {
3435a451a42Speter klausler       return at;
3445a451a42Speter klausler     }
3455a451a42Speter klausler   }
3465a451a42Speter klausler   return 0;
3475a451a42Speter klausler }
3485a451a42Speter klausler 
3495a451a42Speter klausler // Specialization for one-byte characters
3505a451a42Speter klausler template <bool IS_VERIFY = false>
ScanVerify(const char * x,std::size_t xLen,const char * set,std::size_t setLen,bool back)3515a451a42Speter klausler inline std::size_t ScanVerify(const char *x, std::size_t xLen, const char *set,
3525a451a42Speter klausler     std::size_t setLen, bool back) {
3535a451a42Speter klausler   std::size_t at{back ? xLen : 1};
3545a451a42Speter klausler   int increment{back ? -1 : 1};
3555a451a42Speter klausler   if (xLen > 0) {
3565a451a42Speter klausler     std::uint64_t bitSet[256 / 64]{0};
3575a451a42Speter klausler     std::uint64_t one{1};
3585a451a42Speter klausler     for (std::size_t j{0}; j < setLen; ++j) {
3595a451a42Speter klausler       unsigned setCh{static_cast<unsigned char>(set[j])};
3605a451a42Speter klausler       bitSet[setCh / 64] |= one << (setCh % 64);
3615a451a42Speter klausler     }
3625a451a42Speter klausler     for (; xLen-- > 0; at += increment) {
3635a451a42Speter klausler       unsigned ch{static_cast<unsigned char>(x[at - 1])};
3645a451a42Speter klausler       bool inSet{((bitSet[ch / 64] >> (ch % 64)) & 1) != 0};
3655a451a42Speter klausler       if (inSet != IS_VERIFY) {
3665a451a42Speter klausler         return at;
3675a451a42Speter klausler       }
3685a451a42Speter klausler     }
3695a451a42Speter klausler   }
3705a451a42Speter klausler   return 0;
3715a451a42Speter klausler }
3725a451a42Speter klausler 
3736811b961Speter klausler template <typename INT, typename CHAR, CharFunc FUNC>
GeneralCharFunc(Descriptor & result,const Descriptor & string,const Descriptor & arg,const Descriptor * back,const Terminator & terminator)3746811b961Speter klausler static void GeneralCharFunc(Descriptor &result, const Descriptor &string,
3756811b961Speter klausler     const Descriptor &arg, const Descriptor *back,
3765a451a42Speter klausler     const Terminator &terminator) {
3775a451a42Speter klausler   int rank{string.rank() ? string.rank()
3786811b961Speter klausler           : arg.rank()   ? arg.rank()
3796811b961Speter klausler           : back         ? back->rank()
3806811b961Speter klausler                          : 0};
3818ba9ee46Speter klausler   SubscriptValue ub[maxRank], stringAt[maxRank], argAt[maxRank],
3825a451a42Speter klausler       backAt[maxRank];
3835a451a42Speter klausler   SubscriptValue elements{1};
3845a451a42Speter klausler   for (int j{0}; j < rank; ++j) {
3856811b961Speter klausler     ub[j] = string.rank() ? string.GetDimension(j).Extent()
3866811b961Speter klausler         : arg.rank()      ? arg.GetDimension(j).Extent()
3876811b961Speter klausler         : back            ? back->GetDimension(j).Extent()
3886811b961Speter klausler                           : 1;
3895a451a42Speter klausler     elements *= ub[j];
3908ba9ee46Speter klausler   }
3918ba9ee46Speter klausler   string.GetLowerBounds(stringAt);
3928ba9ee46Speter klausler   arg.GetLowerBounds(argAt);
3938ba9ee46Speter klausler   if (back) {
3948ba9ee46Speter klausler     back->GetLowerBounds(backAt);
3955a451a42Speter klausler   }
3965a451a42Speter klausler   result.Establish(TypeCategory::Integer, sizeof(INT), nullptr, rank, ub,
3975a451a42Speter klausler       CFI_attribute_allocatable);
3988ba9ee46Speter klausler   for (int j{0}; j < rank; ++j) {
3998ba9ee46Speter klausler     result.GetDimension(j).SetBounds(1, ub[j]);
4008ba9ee46Speter klausler   }
4018ba9ee46Speter klausler   if (result.Allocate() != CFI_SUCCESS) {
4025a451a42Speter klausler     terminator.Crash("SCAN/VERIFY: could not allocate storage for result");
4035a451a42Speter klausler   }
4045a451a42Speter klausler   std::size_t stringElementChars{string.ElementBytes() >> shift<CHAR>};
4056811b961Speter klausler   std::size_t argElementChars{arg.ElementBytes() >> shift<CHAR>};
4065a451a42Speter klausler   for (SubscriptValue resultAt{0}; elements-- > 0; resultAt += sizeof(INT),
4076811b961Speter klausler        string.IncrementSubscripts(stringAt), arg.IncrementSubscripts(argAt),
4085a451a42Speter klausler        back && back->IncrementSubscripts(backAt)) {
4096811b961Speter klausler     if constexpr (FUNC == CharFunc::Index) {
4105a451a42Speter klausler       *result.OffsetElement<INT>(resultAt) =
4116811b961Speter klausler           Index<CHAR>(string.Element<CHAR>(stringAt), stringElementChars,
4126811b961Speter klausler               arg.Element<CHAR>(argAt), argElementChars,
4135a451a42Speter klausler               back && IsLogicalElementTrue(*back, backAt));
4146811b961Speter klausler     } else if constexpr (FUNC == CharFunc::Scan) {
4156811b961Speter klausler       *result.OffsetElement<INT>(resultAt) =
4166811b961Speter klausler           ScanVerify<CHAR, CharFunc::Scan>(string.Element<CHAR>(stringAt),
4176811b961Speter klausler               stringElementChars, arg.Element<CHAR>(argAt), argElementChars,
4186811b961Speter klausler               back && IsLogicalElementTrue(*back, backAt));
4196811b961Speter klausler     } else if constexpr (FUNC == CharFunc::Verify) {
4206811b961Speter klausler       *result.OffsetElement<INT>(resultAt) =
4216811b961Speter klausler           ScanVerify<CHAR, CharFunc::Verify>(string.Element<CHAR>(stringAt),
4226811b961Speter klausler               stringElementChars, arg.Element<CHAR>(argAt), argElementChars,
4236811b961Speter klausler               back && IsLogicalElementTrue(*back, backAt));
4246811b961Speter klausler     } else {
4256811b961Speter klausler       static_assert(FUNC == CharFunc::Index || FUNC == CharFunc::Scan ||
4266811b961Speter klausler           FUNC == CharFunc::Verify);
4276811b961Speter klausler     }
4285a451a42Speter klausler   }
4295a451a42Speter klausler }
4305a451a42Speter klausler 
4316811b961Speter klausler template <typename CHAR, CharFunc FUNC>
GeneralCharFuncKind(Descriptor & result,const Descriptor & string,const Descriptor & arg,const Descriptor * back,int kind,const Terminator & terminator)4326811b961Speter klausler static void GeneralCharFuncKind(Descriptor &result, const Descriptor &string,
4336811b961Speter klausler     const Descriptor &arg, const Descriptor *back, int kind,
4345a451a42Speter klausler     const Terminator &terminator) {
4355a451a42Speter klausler   switch (kind) {
4365a451a42Speter klausler   case 1:
437e372e0f9Speter klausler     GeneralCharFunc<CppTypeFor<TypeCategory::Integer, 1>, CHAR, FUNC>(
4386811b961Speter klausler         result, string, arg, back, terminator);
4395a451a42Speter klausler     break;
4405a451a42Speter klausler   case 2:
441e372e0f9Speter klausler     GeneralCharFunc<CppTypeFor<TypeCategory::Integer, 2>, CHAR, FUNC>(
4426811b961Speter klausler         result, string, arg, back, terminator);
4435a451a42Speter klausler     break;
4445a451a42Speter klausler   case 4:
445e372e0f9Speter klausler     GeneralCharFunc<CppTypeFor<TypeCategory::Integer, 4>, CHAR, FUNC>(
4466811b961Speter klausler         result, string, arg, back, terminator);
4475a451a42Speter klausler     break;
4485a451a42Speter klausler   case 8:
449e372e0f9Speter klausler     GeneralCharFunc<CppTypeFor<TypeCategory::Integer, 8>, CHAR, FUNC>(
4506811b961Speter klausler         result, string, arg, back, terminator);
4515a451a42Speter klausler     break;
4525a451a42Speter klausler   case 16:
453e372e0f9Speter klausler     GeneralCharFunc<CppTypeFor<TypeCategory::Integer, 16>, CHAR, FUNC>(
4546811b961Speter klausler         result, string, arg, back, terminator);
4555a451a42Speter klausler     break;
4565a451a42Speter klausler   default:
457d4609ae4SPeter Steinfeld     terminator.Crash("not yet implemented: INDEX/SCAN/VERIFY: KIND=%d", kind);
4585a451a42Speter klausler   }
4595a451a42Speter klausler }
4605a451a42Speter klausler 
4613d627d6fSpeter klausler template <typename TO, typename FROM>
CopyAndPad(TO * to,const FROM * from,std::size_t toChars,std::size_t fromChars)4623d627d6fSpeter klausler static void CopyAndPad(
4633d627d6fSpeter klausler     TO *to, const FROM *from, std::size_t toChars, std::size_t fromChars) {
4643d627d6fSpeter klausler   if constexpr (sizeof(TO) != sizeof(FROM)) {
4653d627d6fSpeter klausler     std::size_t copyChars{std::min(toChars, fromChars)};
4663d627d6fSpeter klausler     for (std::size_t j{0}; j < copyChars; ++j) {
4673d627d6fSpeter klausler       to[j] = from[j];
4683d627d6fSpeter klausler     }
4693d627d6fSpeter klausler     for (std::size_t j{copyChars}; j < toChars; ++j) {
4703d627d6fSpeter klausler       to[j] = static_cast<TO>(' ');
4713d627d6fSpeter klausler     }
4723d627d6fSpeter klausler   } else if (toChars <= fromChars) {
4735112bd6bSDiana Picus     std::memcpy(to, from, toChars * sizeof(TO));
4743d627d6fSpeter klausler   } else {
4755112bd6bSDiana Picus     std::memcpy(to, from, fromChars * sizeof(TO));
4763d627d6fSpeter klausler     for (std::size_t j{fromChars}; j < toChars; ++j) {
4773d627d6fSpeter klausler       to[j] = static_cast<TO>(' ');
4783d627d6fSpeter klausler     }
4793d627d6fSpeter klausler   }
4803d627d6fSpeter klausler }
4813d627d6fSpeter klausler 
4823d627d6fSpeter klausler template <typename CHAR, bool ISMIN>
MaxMinHelper(Descriptor & accumulator,const Descriptor & x,const Terminator & terminator)4833d627d6fSpeter klausler static void MaxMinHelper(Descriptor &accumulator, const Descriptor &x,
4843d627d6fSpeter klausler     const Terminator &terminator) {
4853d627d6fSpeter klausler   RUNTIME_CHECK(terminator,
4863d627d6fSpeter klausler       accumulator.rank() == 0 || x.rank() == 0 ||
4873d627d6fSpeter klausler           accumulator.rank() == x.rank());
4888ba9ee46Speter klausler   SubscriptValue ub[maxRank], xAt[maxRank];
4893d627d6fSpeter klausler   SubscriptValue elements{1};
4903d627d6fSpeter klausler   std::size_t accumChars{accumulator.ElementBytes() >> shift<CHAR>};
4913d627d6fSpeter klausler   std::size_t xChars{x.ElementBytes() >> shift<CHAR>};
4923d627d6fSpeter klausler   std::size_t chars{std::max(accumChars, xChars)};
4933d627d6fSpeter klausler   bool reallocate{accumulator.raw().base_addr == nullptr ||
4942ea36e94SDiana Picus       accumChars != chars || (accumulator.rank() == 0 && x.rank() > 0)};
4953d627d6fSpeter klausler   int rank{std::max(accumulator.rank(), x.rank())};
4963d627d6fSpeter klausler   for (int j{0}; j < rank; ++j) {
4973d627d6fSpeter klausler     if (x.rank() > 0) {
4983d627d6fSpeter klausler       ub[j] = x.GetDimension(j).Extent();
4993d627d6fSpeter klausler       if (accumulator.rank() > 0) {
5003d627d6fSpeter klausler         SubscriptValue accumExt{accumulator.GetDimension(j).Extent()};
5013d627d6fSpeter klausler         if (accumExt != ub[j]) {
5023d627d6fSpeter klausler           terminator.Crash("Character MAX/MIN: operands are not "
5033d627d6fSpeter klausler                            "conforming on dimension %d (%jd != %jd)",
5043d627d6fSpeter klausler               j + 1, static_cast<std::intmax_t>(accumExt),
5053d627d6fSpeter klausler               static_cast<std::intmax_t>(ub[j]));
5063d627d6fSpeter klausler         }
5073d627d6fSpeter klausler       }
5083d627d6fSpeter klausler     } else {
5093d627d6fSpeter klausler       ub[j] = accumulator.GetDimension(j).Extent();
5103d627d6fSpeter klausler     }
5113d627d6fSpeter klausler     elements *= ub[j];
5123d627d6fSpeter klausler   }
5138ba9ee46Speter klausler   x.GetLowerBounds(xAt);
5143d627d6fSpeter klausler   void *old{nullptr};
5153d627d6fSpeter klausler   const CHAR *accumData{accumulator.OffsetElement<CHAR>()};
5163d627d6fSpeter klausler   if (reallocate) {
5173d627d6fSpeter klausler     old = accumulator.raw().base_addr;
5183d627d6fSpeter klausler     accumulator.set_base_addr(nullptr);
5193d627d6fSpeter klausler     accumulator.raw().elem_len = chars << shift<CHAR>;
5208ba9ee46Speter klausler     for (int j{0}; j < rank; ++j) {
5218ba9ee46Speter klausler       accumulator.GetDimension(j).SetBounds(1, ub[j]);
5228ba9ee46Speter klausler     }
5238ba9ee46Speter klausler     RUNTIME_CHECK(terminator, accumulator.Allocate() == CFI_SUCCESS);
5243d627d6fSpeter klausler   }
5253d627d6fSpeter klausler   for (CHAR *result{accumulator.OffsetElement<CHAR>()}; elements-- > 0;
5263d627d6fSpeter klausler        accumData += accumChars, result += chars, x.IncrementSubscripts(xAt)) {
5273d627d6fSpeter klausler     const CHAR *xData{x.Element<CHAR>(xAt)};
528e372e0f9Speter klausler     int cmp{CharacterScalarCompare(accumData, xData, accumChars, xChars)};
5293d627d6fSpeter klausler     if constexpr (ISMIN) {
5303d627d6fSpeter klausler       cmp = -cmp;
5313d627d6fSpeter klausler     }
5323d627d6fSpeter klausler     if (cmp < 0) {
5333d627d6fSpeter klausler       CopyAndPad(result, xData, chars, xChars);
5343d627d6fSpeter klausler     } else if (result != accumData) {
5353d627d6fSpeter klausler       CopyAndPad(result, accumData, chars, accumChars);
5363d627d6fSpeter klausler     }
5373d627d6fSpeter klausler   }
5383d627d6fSpeter klausler   FreeMemory(old);
5393d627d6fSpeter klausler }
5403d627d6fSpeter klausler 
5413d627d6fSpeter klausler template <bool ISMIN>
MaxMin(Descriptor & accumulator,const Descriptor & x,const char * sourceFile,int sourceLine)5423d627d6fSpeter klausler static void MaxMin(Descriptor &accumulator, const Descriptor &x,
5433d627d6fSpeter klausler     const char *sourceFile, int sourceLine) {
5443d627d6fSpeter klausler   Terminator terminator{sourceFile, sourceLine};
5453d627d6fSpeter klausler   RUNTIME_CHECK(terminator, accumulator.raw().type == x.raw().type);
5463d627d6fSpeter klausler   switch (accumulator.raw().type) {
5473d627d6fSpeter klausler   case CFI_type_char:
5483d627d6fSpeter klausler     MaxMinHelper<char, ISMIN>(accumulator, x, terminator);
5493d627d6fSpeter klausler     break;
5503d627d6fSpeter klausler   case CFI_type_char16_t:
5513d627d6fSpeter klausler     MaxMinHelper<char16_t, ISMIN>(accumulator, x, terminator);
5523d627d6fSpeter klausler     break;
5533d627d6fSpeter klausler   case CFI_type_char32_t:
5543d627d6fSpeter klausler     MaxMinHelper<char32_t, ISMIN>(accumulator, x, terminator);
5553d627d6fSpeter klausler     break;
5563d627d6fSpeter klausler   default:
5573d627d6fSpeter klausler     terminator.Crash(
5583d627d6fSpeter klausler         "Character MAX/MIN: result does not have a character type");
5593d627d6fSpeter klausler   }
560fc026241Speter klausler }
561fc026241Speter klausler 
5624d54bb7aSpeter klausler extern "C" {
5634d54bb7aSpeter klausler 
RTNAME(CharacterConcatenate)5643d627d6fSpeter klausler void RTNAME(CharacterConcatenate)(Descriptor &accumulator,
5653d627d6fSpeter klausler     const Descriptor &from, const char *sourceFile, int sourceLine) {
5663d627d6fSpeter klausler   Terminator terminator{sourceFile, sourceLine};
5673d627d6fSpeter klausler   RUNTIME_CHECK(terminator,
5683d627d6fSpeter klausler       accumulator.rank() == 0 || from.rank() == 0 ||
5693d627d6fSpeter klausler           accumulator.rank() == from.rank());
5703d627d6fSpeter klausler   int rank{std::max(accumulator.rank(), from.rank())};
5718ba9ee46Speter klausler   SubscriptValue ub[maxRank], fromAt[maxRank];
5723d627d6fSpeter klausler   SubscriptValue elements{1};
5733d627d6fSpeter klausler   for (int j{0}; j < rank; ++j) {
5743d627d6fSpeter klausler     if (accumulator.rank() > 0 && from.rank() > 0) {
5753d627d6fSpeter klausler       ub[j] = accumulator.GetDimension(j).Extent();
5763d627d6fSpeter klausler       SubscriptValue fromUB{from.GetDimension(j).Extent()};
5773d627d6fSpeter klausler       if (ub[j] != fromUB) {
5783d627d6fSpeter klausler         terminator.Crash("Character array concatenation: operands are not "
5793d627d6fSpeter klausler                          "conforming on dimension %d (%jd != %jd)",
5803d627d6fSpeter klausler             j + 1, static_cast<std::intmax_t>(ub[j]),
5813d627d6fSpeter klausler             static_cast<std::intmax_t>(fromUB));
5823d627d6fSpeter klausler       }
5833d627d6fSpeter klausler     } else {
5843d627d6fSpeter klausler       ub[j] =
5853d627d6fSpeter klausler           (accumulator.rank() ? accumulator : from).GetDimension(j).Extent();
5863d627d6fSpeter klausler     }
5873d627d6fSpeter klausler     elements *= ub[j];
5883d627d6fSpeter klausler   }
5893d627d6fSpeter klausler   std::size_t oldBytes{accumulator.ElementBytes()};
5903d627d6fSpeter klausler   void *old{accumulator.raw().base_addr};
5913d627d6fSpeter klausler   accumulator.set_base_addr(nullptr);
5923d627d6fSpeter klausler   std::size_t fromBytes{from.ElementBytes()};
5933d627d6fSpeter klausler   accumulator.raw().elem_len += fromBytes;
5943d627d6fSpeter klausler   std::size_t newBytes{accumulator.ElementBytes()};
5958ba9ee46Speter klausler   for (int j{0}; j < rank; ++j) {
5968ba9ee46Speter klausler     accumulator.GetDimension(j).SetBounds(1, ub[j]);
5978ba9ee46Speter klausler   }
5988ba9ee46Speter klausler   if (accumulator.Allocate() != CFI_SUCCESS) {
5993d627d6fSpeter klausler     terminator.Crash(
6003d627d6fSpeter klausler         "CharacterConcatenate: could not allocate storage for result");
6013d627d6fSpeter klausler   }
6023d627d6fSpeter klausler   const char *p{static_cast<const char *>(old)};
6033d627d6fSpeter klausler   char *to{static_cast<char *>(accumulator.raw().base_addr)};
6048ba9ee46Speter klausler   from.GetLowerBounds(fromAt);
6053d627d6fSpeter klausler   for (; elements-- > 0;
6063d627d6fSpeter klausler        to += newBytes, p += oldBytes, from.IncrementSubscripts(fromAt)) {
6073d627d6fSpeter klausler     std::memcpy(to, p, oldBytes);
6083d627d6fSpeter klausler     std::memcpy(to + oldBytes, from.Element<char>(fromAt), fromBytes);
6093d627d6fSpeter klausler   }
6103d627d6fSpeter klausler   FreeMemory(old);
6114d54bb7aSpeter klausler }
6124d54bb7aSpeter klausler 
RTNAME(CharacterConcatenateScalar1)6133d627d6fSpeter klausler void RTNAME(CharacterConcatenateScalar1)(
6143d627d6fSpeter klausler     Descriptor &accumulator, const char *from, std::size_t chars) {
6153d627d6fSpeter klausler   Terminator terminator{__FILE__, __LINE__};
6163d627d6fSpeter klausler   RUNTIME_CHECK(terminator, accumulator.rank() == 0);
6173d627d6fSpeter klausler   void *old{accumulator.raw().base_addr};
6183d627d6fSpeter klausler   accumulator.set_base_addr(nullptr);
6193d627d6fSpeter klausler   std::size_t oldLen{accumulator.ElementBytes()};
6203d627d6fSpeter klausler   accumulator.raw().elem_len += chars;
6218ba9ee46Speter klausler   RUNTIME_CHECK(terminator, accumulator.Allocate() == CFI_SUCCESS);
6223d627d6fSpeter klausler   std::memcpy(accumulator.OffsetElement<char>(oldLen), from, chars);
6233d627d6fSpeter klausler   FreeMemory(old);
6244d54bb7aSpeter klausler }
6254d54bb7aSpeter klausler 
RTNAME(CharacterAssign)6263d627d6fSpeter klausler void RTNAME(CharacterAssign)(Descriptor &lhs, const Descriptor &rhs,
6273d627d6fSpeter klausler     const char *sourceFile, int sourceLine) {
6283d627d6fSpeter klausler   Terminator terminator{sourceFile, sourceLine};
6293d627d6fSpeter klausler   int rank{lhs.rank()};
6303d627d6fSpeter klausler   RUNTIME_CHECK(terminator, rhs.rank() == 0 || rhs.rank() == rank);
6313d627d6fSpeter klausler   SubscriptValue ub[maxRank], lhsAt[maxRank], rhsAt[maxRank];
6323d627d6fSpeter klausler   SubscriptValue elements{1};
6333d627d6fSpeter klausler   std::size_t lhsBytes{lhs.ElementBytes()};
6343d627d6fSpeter klausler   std::size_t rhsBytes{rhs.ElementBytes()};
6353d627d6fSpeter klausler   bool reallocate{lhs.IsAllocatable() &&
6363d627d6fSpeter klausler       (lhs.raw().base_addr == nullptr || lhsBytes != rhsBytes)};
6373d627d6fSpeter klausler   for (int j{0}; j < rank; ++j) {
6383d627d6fSpeter klausler     lhsAt[j] = lhs.GetDimension(j).LowerBound();
6393d627d6fSpeter klausler     if (rhs.rank() > 0) {
6403d627d6fSpeter klausler       SubscriptValue lhsExt{lhs.GetDimension(j).Extent()};
6413d627d6fSpeter klausler       SubscriptValue rhsExt{rhs.GetDimension(j).Extent()};
6423d627d6fSpeter klausler       ub[j] = lhsAt[j] + rhsExt - 1;
6433d627d6fSpeter klausler       if (lhsExt != rhsExt) {
6443d627d6fSpeter klausler         if (lhs.IsAllocatable()) {
6453d627d6fSpeter klausler           reallocate = true;
6463d627d6fSpeter klausler         } else {
6473d627d6fSpeter klausler           terminator.Crash("Character array assignment: operands are not "
6483d627d6fSpeter klausler                            "conforming on dimension %d (%jd != %jd)",
6493d627d6fSpeter klausler               j + 1, static_cast<std::intmax_t>(lhsExt),
6503d627d6fSpeter klausler               static_cast<std::intmax_t>(rhsExt));
6513d627d6fSpeter klausler         }
6523d627d6fSpeter klausler       }
6533d627d6fSpeter klausler       rhsAt[j] = rhs.GetDimension(j).LowerBound();
6543d627d6fSpeter klausler     } else {
6553d627d6fSpeter klausler       ub[j] = lhs.GetDimension(j).UpperBound();
6563d627d6fSpeter klausler     }
6573d627d6fSpeter klausler     elements *= ub[j] - lhsAt[j] + 1;
6583d627d6fSpeter klausler   }
6593d627d6fSpeter klausler   void *old{nullptr};
6603d627d6fSpeter klausler   if (reallocate) {
6613d627d6fSpeter klausler     old = lhs.raw().base_addr;
6623d627d6fSpeter klausler     lhs.set_base_addr(nullptr);
6633d627d6fSpeter klausler     lhs.raw().elem_len = lhsBytes = rhsBytes;
6643d627d6fSpeter klausler     if (rhs.rank() > 0) {
6653d627d6fSpeter klausler       // When the RHS is not scalar, the LHS acquires its bounds.
6663d627d6fSpeter klausler       for (int j{0}; j < rank; ++j) {
6673d627d6fSpeter klausler         lhsAt[j] = rhsAt[j];
6683d627d6fSpeter klausler         ub[j] = rhs.GetDimension(j).UpperBound();
6698ba9ee46Speter klausler         lhs.GetDimension(j).SetBounds(lhsAt[j], ub[j]);
6703d627d6fSpeter klausler       }
6713d627d6fSpeter klausler     }
6728ba9ee46Speter klausler     RUNTIME_CHECK(terminator, lhs.Allocate() == CFI_SUCCESS);
6733d627d6fSpeter klausler   }
6743d627d6fSpeter klausler   switch (lhs.raw().type) {
6753d627d6fSpeter klausler   case CFI_type_char:
6763d627d6fSpeter klausler     switch (rhs.raw().type) {
6773d627d6fSpeter klausler     case CFI_type_char:
6783d627d6fSpeter klausler       for (; elements-- > 0;
6793d627d6fSpeter klausler            lhs.IncrementSubscripts(lhsAt), rhs.IncrementSubscripts(rhsAt)) {
6803d627d6fSpeter klausler         CopyAndPad(lhs.Element<char>(lhsAt), rhs.Element<char>(rhsAt), lhsBytes,
6813d627d6fSpeter klausler             rhsBytes);
6823d627d6fSpeter klausler       }
6833d627d6fSpeter klausler       break;
6843d627d6fSpeter klausler     case CFI_type_char16_t:
6853d627d6fSpeter klausler       for (; elements-- > 0;
6863d627d6fSpeter klausler            lhs.IncrementSubscripts(lhsAt), rhs.IncrementSubscripts(rhsAt)) {
6873d627d6fSpeter klausler         CopyAndPad(lhs.Element<char>(lhsAt), rhs.Element<char16_t>(rhsAt),
6883d627d6fSpeter klausler             lhsBytes, rhsBytes >> 1);
6893d627d6fSpeter klausler       }
6903d627d6fSpeter klausler       break;
6913d627d6fSpeter klausler     case CFI_type_char32_t:
6923d627d6fSpeter klausler       for (; elements-- > 0;
6933d627d6fSpeter klausler            lhs.IncrementSubscripts(lhsAt), rhs.IncrementSubscripts(rhsAt)) {
6943d627d6fSpeter klausler         CopyAndPad(lhs.Element<char>(lhsAt), rhs.Element<char32_t>(rhsAt),
6953d627d6fSpeter klausler             lhsBytes, rhsBytes >> 2);
6963d627d6fSpeter klausler       }
6973d627d6fSpeter klausler       break;
6983d627d6fSpeter klausler     default:
6993d627d6fSpeter klausler       terminator.Crash(
7003d627d6fSpeter klausler           "RHS of character assignment does not have a character type");
7013d627d6fSpeter klausler     }
7023d627d6fSpeter klausler     break;
7033d627d6fSpeter klausler   case CFI_type_char16_t:
7043d627d6fSpeter klausler     switch (rhs.raw().type) {
7053d627d6fSpeter klausler     case CFI_type_char:
7063d627d6fSpeter klausler       for (; elements-- > 0;
7073d627d6fSpeter klausler            lhs.IncrementSubscripts(lhsAt), rhs.IncrementSubscripts(rhsAt)) {
7083d627d6fSpeter klausler         CopyAndPad(lhs.Element<char16_t>(lhsAt), rhs.Element<char>(rhsAt),
7093d627d6fSpeter klausler             lhsBytes >> 1, rhsBytes);
7103d627d6fSpeter klausler       }
7113d627d6fSpeter klausler       break;
7123d627d6fSpeter klausler     case CFI_type_char16_t:
7133d627d6fSpeter klausler       for (; elements-- > 0;
7143d627d6fSpeter klausler            lhs.IncrementSubscripts(lhsAt), rhs.IncrementSubscripts(rhsAt)) {
7153d627d6fSpeter klausler         CopyAndPad(lhs.Element<char16_t>(lhsAt), rhs.Element<char16_t>(rhsAt),
7163d627d6fSpeter klausler             lhsBytes >> 1, rhsBytes >> 1);
7173d627d6fSpeter klausler       }
7183d627d6fSpeter klausler       break;
7193d627d6fSpeter klausler     case CFI_type_char32_t:
7203d627d6fSpeter klausler       for (; elements-- > 0;
7213d627d6fSpeter klausler            lhs.IncrementSubscripts(lhsAt), rhs.IncrementSubscripts(rhsAt)) {
7223d627d6fSpeter klausler         CopyAndPad(lhs.Element<char16_t>(lhsAt), rhs.Element<char32_t>(rhsAt),
7233d627d6fSpeter klausler             lhsBytes >> 1, rhsBytes >> 2);
7243d627d6fSpeter klausler       }
7253d627d6fSpeter klausler       break;
7263d627d6fSpeter klausler     default:
7273d627d6fSpeter klausler       terminator.Crash(
7283d627d6fSpeter klausler           "RHS of character assignment does not have a character type");
7293d627d6fSpeter klausler     }
7303d627d6fSpeter klausler     break;
7313d627d6fSpeter klausler   case CFI_type_char32_t:
7323d627d6fSpeter klausler     switch (rhs.raw().type) {
7333d627d6fSpeter klausler     case CFI_type_char:
7343d627d6fSpeter klausler       for (; elements-- > 0;
7353d627d6fSpeter klausler            lhs.IncrementSubscripts(lhsAt), rhs.IncrementSubscripts(rhsAt)) {
7363d627d6fSpeter klausler         CopyAndPad(lhs.Element<char32_t>(lhsAt), rhs.Element<char>(rhsAt),
7373d627d6fSpeter klausler             lhsBytes >> 2, rhsBytes);
7383d627d6fSpeter klausler       }
7393d627d6fSpeter klausler       break;
7403d627d6fSpeter klausler     case CFI_type_char16_t:
7413d627d6fSpeter klausler       for (; elements-- > 0;
7423d627d6fSpeter klausler            lhs.IncrementSubscripts(lhsAt), rhs.IncrementSubscripts(rhsAt)) {
7433d627d6fSpeter klausler         CopyAndPad(lhs.Element<char32_t>(lhsAt), rhs.Element<char16_t>(rhsAt),
7443d627d6fSpeter klausler             lhsBytes >> 2, rhsBytes >> 1);
7453d627d6fSpeter klausler       }
7463d627d6fSpeter klausler       break;
7473d627d6fSpeter klausler     case CFI_type_char32_t:
7483d627d6fSpeter klausler       for (; elements-- > 0;
7493d627d6fSpeter klausler            lhs.IncrementSubscripts(lhsAt), rhs.IncrementSubscripts(rhsAt)) {
7503d627d6fSpeter klausler         CopyAndPad(lhs.Element<char32_t>(lhsAt), rhs.Element<char32_t>(rhsAt),
7513d627d6fSpeter klausler             lhsBytes >> 2, rhsBytes >> 2);
7523d627d6fSpeter klausler       }
7533d627d6fSpeter klausler       break;
7543d627d6fSpeter klausler     default:
7553d627d6fSpeter klausler       terminator.Crash(
7563d627d6fSpeter klausler           "RHS of character assignment does not have a character type");
7573d627d6fSpeter klausler     }
7583d627d6fSpeter klausler     break;
7593d627d6fSpeter klausler   default:
7603d627d6fSpeter klausler     terminator.Crash(
7613d627d6fSpeter klausler         "LHS of character assignment does not have a character type");
7623d627d6fSpeter klausler   }
7633d627d6fSpeter klausler   if (reallocate) {
7643d627d6fSpeter klausler     FreeMemory(old);
7653d627d6fSpeter klausler   }
7664d54bb7aSpeter klausler }
7674d54bb7aSpeter klausler 
RTNAME(CharacterCompareScalar)7683d627d6fSpeter klausler int RTNAME(CharacterCompareScalar)(const Descriptor &x, const Descriptor &y) {
7693d627d6fSpeter klausler   Terminator terminator{__FILE__, __LINE__};
7703d627d6fSpeter klausler   RUNTIME_CHECK(terminator, x.rank() == 0);
7713d627d6fSpeter klausler   RUNTIME_CHECK(terminator, y.rank() == 0);
7723d627d6fSpeter klausler   RUNTIME_CHECK(terminator, x.raw().type == y.raw().type);
7733d627d6fSpeter klausler   switch (x.raw().type) {
7743d627d6fSpeter klausler   case CFI_type_char:
775e372e0f9Speter klausler     return CharacterScalarCompare<char>(x.OffsetElement<char>(),
776e372e0f9Speter klausler         y.OffsetElement<char>(), x.ElementBytes(), y.ElementBytes());
7773d627d6fSpeter klausler   case CFI_type_char16_t:
778e372e0f9Speter klausler     return CharacterScalarCompare<char16_t>(x.OffsetElement<char16_t>(),
779e372e0f9Speter klausler         y.OffsetElement<char16_t>(), x.ElementBytes() >> 1,
780e372e0f9Speter klausler         y.ElementBytes() >> 1);
7813d627d6fSpeter klausler   case CFI_type_char32_t:
782e372e0f9Speter klausler     return CharacterScalarCompare<char32_t>(x.OffsetElement<char32_t>(),
783e372e0f9Speter klausler         y.OffsetElement<char32_t>(), x.ElementBytes() >> 2,
784e372e0f9Speter klausler         y.ElementBytes() >> 2);
7853d627d6fSpeter klausler   default:
7863d627d6fSpeter klausler     terminator.Crash("CharacterCompareScalar: bad string type code %d",
7873d627d6fSpeter klausler         static_cast<int>(x.raw().type));
7883d627d6fSpeter klausler   }
789fc026241Speter klausler   return 0;
790fc026241Speter klausler }
791fc026241Speter klausler 
RTNAME(CharacterCompareScalar1)792fc026241Speter klausler int RTNAME(CharacterCompareScalar1)(
7933d627d6fSpeter klausler     const char *x, const char *y, std::size_t xChars, std::size_t yChars) {
794e372e0f9Speter klausler   return CharacterScalarCompare(x, y, xChars, yChars);
795fc026241Speter klausler }
796fc026241Speter klausler 
RTNAME(CharacterCompareScalar2)797fc026241Speter klausler int RTNAME(CharacterCompareScalar2)(const char16_t *x, const char16_t *y,
7983d627d6fSpeter klausler     std::size_t xChars, std::size_t yChars) {
799e372e0f9Speter klausler   return CharacterScalarCompare(x, y, xChars, yChars);
800fc026241Speter klausler }
801fc026241Speter klausler 
RTNAME(CharacterCompareScalar4)802fc026241Speter klausler int RTNAME(CharacterCompareScalar4)(const char32_t *x, const char32_t *y,
8033d627d6fSpeter klausler     std::size_t xChars, std::size_t yChars) {
804e372e0f9Speter klausler   return CharacterScalarCompare(x, y, xChars, yChars);
805fc026241Speter klausler }
806fc026241Speter klausler 
RTNAME(CharacterCompare)807fc026241Speter klausler void RTNAME(CharacterCompare)(
8083d627d6fSpeter klausler     Descriptor &result, const Descriptor &x, const Descriptor &y) {
8093d627d6fSpeter klausler   Terminator terminator{__FILE__, __LINE__};
8103d627d6fSpeter klausler   RUNTIME_CHECK(terminator, x.raw().type == y.raw().type);
8113d627d6fSpeter klausler   switch (x.raw().type) {
8123d627d6fSpeter klausler   case CFI_type_char:
8133d627d6fSpeter klausler     Compare<char>(result, x, y, terminator);
8143d627d6fSpeter klausler     break;
8153d627d6fSpeter klausler   case CFI_type_char16_t:
8163d627d6fSpeter klausler     Compare<char16_t>(result, x, y, terminator);
8173d627d6fSpeter klausler     break;
8183d627d6fSpeter klausler   case CFI_type_char32_t:
8193d627d6fSpeter klausler     Compare<char32_t>(result, x, y, terminator);
8203d627d6fSpeter klausler     break;
8213d627d6fSpeter klausler   default:
8223d627d6fSpeter klausler     terminator.Crash("CharacterCompareScalar: bad string type code %d",
8233d627d6fSpeter klausler         static_cast<int>(x.raw().type));
8243d627d6fSpeter klausler   }
825fc026241Speter klausler }
826fc026241Speter klausler 
RTNAME(CharacterAppend1)827fc026241Speter klausler std::size_t RTNAME(CharacterAppend1)(char *lhs, std::size_t lhsBytes,
828fc026241Speter klausler     std::size_t offset, const char *rhs, std::size_t rhsBytes) {
829fc026241Speter klausler   if (auto n{std::min(lhsBytes - offset, rhsBytes)}) {
8304d54bb7aSpeter klausler     std::memcpy(lhs + offset, rhs, n);
8314d54bb7aSpeter klausler     offset += n;
8324d54bb7aSpeter klausler   }
8334d54bb7aSpeter klausler   return offset;
8344d54bb7aSpeter klausler }
8354d54bb7aSpeter klausler 
RTNAME(CharacterPad1)836fc026241Speter klausler void RTNAME(CharacterPad1)(char *lhs, std::size_t bytes, std::size_t offset) {
837fc026241Speter klausler   if (bytes > offset) {
838fc026241Speter klausler     std::memset(lhs + offset, ' ', bytes - offset);
8394d54bb7aSpeter klausler   }
8404d54bb7aSpeter klausler }
8413d627d6fSpeter klausler 
8425a451a42Speter klausler // Intrinsic function entry points
8433d627d6fSpeter klausler 
RTNAME(Adjustl)844263a89c9SDiana Picus void RTNAME(Adjustl)(Descriptor &result, const Descriptor &string,
8453d627d6fSpeter klausler     const char *sourceFile, int sourceLine) {
8463d627d6fSpeter klausler   AdjustLR<false>(result, string, sourceFile, sourceLine);
8473d627d6fSpeter klausler }
8483d627d6fSpeter klausler 
RTNAME(Adjustr)849263a89c9SDiana Picus void RTNAME(Adjustr)(Descriptor &result, const Descriptor &string,
8503d627d6fSpeter klausler     const char *sourceFile, int sourceLine) {
8513d627d6fSpeter klausler   AdjustLR<true>(result, string, sourceFile, sourceLine);
8523d627d6fSpeter klausler }
8533d627d6fSpeter klausler 
RTNAME(Index1)8546811b961Speter klausler std::size_t RTNAME(Index1)(const char *x, std::size_t xLen, const char *set,
8556811b961Speter klausler     std::size_t setLen, bool back) {
8566811b961Speter klausler   return Index<char>(x, xLen, set, setLen, back);
8576811b961Speter klausler }
RTNAME(Index2)8586811b961Speter klausler std::size_t RTNAME(Index2)(const char16_t *x, std::size_t xLen,
8596811b961Speter klausler     const char16_t *set, std::size_t setLen, bool back) {
8606811b961Speter klausler   return Index<char16_t>(x, xLen, set, setLen, back);
8616811b961Speter klausler }
RTNAME(Index4)8626811b961Speter klausler std::size_t RTNAME(Index4)(const char32_t *x, std::size_t xLen,
8636811b961Speter klausler     const char32_t *set, std::size_t setLen, bool back) {
8646811b961Speter klausler   return Index<char32_t>(x, xLen, set, setLen, back);
8656811b961Speter klausler }
8666811b961Speter klausler 
RTNAME(Index)8676811b961Speter klausler void RTNAME(Index)(Descriptor &result, const Descriptor &string,
8686811b961Speter klausler     const Descriptor &substring, const Descriptor *back, int kind,
8696811b961Speter klausler     const char *sourceFile, int sourceLine) {
8706811b961Speter klausler   Terminator terminator{sourceFile, sourceLine};
8716811b961Speter klausler   switch (string.raw().type) {
8726811b961Speter klausler   case CFI_type_char:
8736811b961Speter klausler     GeneralCharFuncKind<char, CharFunc::Index>(
8746811b961Speter klausler         result, string, substring, back, kind, terminator);
8756811b961Speter klausler     break;
8766811b961Speter klausler   case CFI_type_char16_t:
8776811b961Speter klausler     GeneralCharFuncKind<char16_t, CharFunc::Index>(
8786811b961Speter klausler         result, string, substring, back, kind, terminator);
8796811b961Speter klausler     break;
8806811b961Speter klausler   case CFI_type_char32_t:
8816811b961Speter klausler     GeneralCharFuncKind<char32_t, CharFunc::Index>(
8826811b961Speter klausler         result, string, substring, back, kind, terminator);
8836811b961Speter klausler     break;
8846811b961Speter klausler   default:
8856811b961Speter klausler     terminator.Crash(
8866811b961Speter klausler         "INDEX: bad string type code %d", static_cast<int>(string.raw().type));
8876811b961Speter klausler   }
8886811b961Speter klausler }
8896811b961Speter klausler 
RTNAME(LenTrim1)8903d627d6fSpeter klausler std::size_t RTNAME(LenTrim1)(const char *x, std::size_t chars) {
8913d627d6fSpeter klausler   return LenTrim(x, chars);
8923d627d6fSpeter klausler }
RTNAME(LenTrim2)8933d627d6fSpeter klausler std::size_t RTNAME(LenTrim2)(const char16_t *x, std::size_t chars) {
8943d627d6fSpeter klausler   return LenTrim(x, chars);
8953d627d6fSpeter klausler }
RTNAME(LenTrim4)8963d627d6fSpeter klausler std::size_t RTNAME(LenTrim4)(const char32_t *x, std::size_t chars) {
8973d627d6fSpeter klausler   return LenTrim(x, chars);
8983d627d6fSpeter klausler }
8993d627d6fSpeter klausler 
RTNAME(LenTrim)9003d627d6fSpeter klausler void RTNAME(LenTrim)(Descriptor &result, const Descriptor &string, int kind,
9013d627d6fSpeter klausler     const char *sourceFile, int sourceLine) {
9023d627d6fSpeter klausler   Terminator terminator{sourceFile, sourceLine};
9033d627d6fSpeter klausler   switch (string.raw().type) {
9043d627d6fSpeter klausler   case CFI_type_char:
9053d627d6fSpeter klausler     LenTrimKind<char>(result, string, kind, terminator);
9063d627d6fSpeter klausler     break;
9073d627d6fSpeter klausler   case CFI_type_char16_t:
9083d627d6fSpeter klausler     LenTrimKind<char16_t>(result, string, kind, terminator);
9093d627d6fSpeter klausler     break;
9103d627d6fSpeter klausler   case CFI_type_char32_t:
9113d627d6fSpeter klausler     LenTrimKind<char32_t>(result, string, kind, terminator);
9123d627d6fSpeter klausler     break;
9133d627d6fSpeter klausler   default:
9143d627d6fSpeter klausler     terminator.Crash("LEN_TRIM: bad string type code %d",
9153d627d6fSpeter klausler         static_cast<int>(string.raw().type));
9163d627d6fSpeter klausler   }
9173d627d6fSpeter klausler }
9183d627d6fSpeter klausler 
RTNAME(Scan1)9195a451a42Speter klausler std::size_t RTNAME(Scan1)(const char *x, std::size_t xLen, const char *set,
9205a451a42Speter klausler     std::size_t setLen, bool back) {
9216811b961Speter klausler   return ScanVerify<char, CharFunc::Scan>(x, xLen, set, setLen, back);
9225a451a42Speter klausler }
RTNAME(Scan2)9235a451a42Speter klausler std::size_t RTNAME(Scan2)(const char16_t *x, std::size_t xLen,
9245a451a42Speter klausler     const char16_t *set, std::size_t setLen, bool back) {
9256811b961Speter klausler   return ScanVerify<char16_t, CharFunc::Scan>(x, xLen, set, setLen, back);
9265a451a42Speter klausler }
RTNAME(Scan4)9275a451a42Speter klausler std::size_t RTNAME(Scan4)(const char32_t *x, std::size_t xLen,
9285a451a42Speter klausler     const char32_t *set, std::size_t setLen, bool back) {
9296811b961Speter klausler   return ScanVerify<char32_t, CharFunc::Scan>(x, xLen, set, setLen, back);
9305a451a42Speter klausler }
9315a451a42Speter klausler 
RTNAME(Scan)9325a451a42Speter klausler void RTNAME(Scan)(Descriptor &result, const Descriptor &string,
9335a451a42Speter klausler     const Descriptor &set, const Descriptor *back, int kind,
9345a451a42Speter klausler     const char *sourceFile, int sourceLine) {
9355a451a42Speter klausler   Terminator terminator{sourceFile, sourceLine};
9365a451a42Speter klausler   switch (string.raw().type) {
9375a451a42Speter klausler   case CFI_type_char:
9386811b961Speter klausler     GeneralCharFuncKind<char, CharFunc::Scan>(
9396811b961Speter klausler         result, string, set, back, kind, terminator);
9405a451a42Speter klausler     break;
9415a451a42Speter klausler   case CFI_type_char16_t:
9426811b961Speter klausler     GeneralCharFuncKind<char16_t, CharFunc::Scan>(
9435a451a42Speter klausler         result, string, set, back, kind, terminator);
9445a451a42Speter klausler     break;
9455a451a42Speter klausler   case CFI_type_char32_t:
9466811b961Speter klausler     GeneralCharFuncKind<char32_t, CharFunc::Scan>(
9475a451a42Speter klausler         result, string, set, back, kind, terminator);
9485a451a42Speter klausler     break;
9495a451a42Speter klausler   default:
9505a451a42Speter klausler     terminator.Crash(
9515a451a42Speter klausler         "SCAN: bad string type code %d", static_cast<int>(string.raw().type));
9525a451a42Speter klausler   }
9535a451a42Speter klausler }
9545a451a42Speter klausler 
RTNAME(Repeat)9553d627d6fSpeter klausler void RTNAME(Repeat)(Descriptor &result, const Descriptor &string,
956*db6c3ecdSPeter Klausler     std::int64_t ncopies, const char *sourceFile, int sourceLine) {
9573d627d6fSpeter klausler   Terminator terminator{sourceFile, sourceLine};
958*db6c3ecdSPeter Klausler   if (ncopies < 0) {
959*db6c3ecdSPeter Klausler     terminator.Crash(
960*db6c3ecdSPeter Klausler         "REPEAT has negative NCOPIES=%jd", static_cast<std::intmax_t>(ncopies));
961*db6c3ecdSPeter Klausler   }
9623d627d6fSpeter klausler   std::size_t origBytes{string.ElementBytes()};
9635a451a42Speter klausler   result.Establish(string.type(), origBytes * ncopies, nullptr, 0, nullptr,
9645a451a42Speter klausler       CFI_attribute_allocatable);
9658ba9ee46Speter klausler   if (result.Allocate() != CFI_SUCCESS) {
9663d627d6fSpeter klausler     terminator.Crash("REPEAT could not allocate storage for result");
9673d627d6fSpeter klausler   }
9683d627d6fSpeter klausler   const char *from{string.OffsetElement()};
9693d627d6fSpeter klausler   for (char *to{result.OffsetElement()}; ncopies-- > 0; to += origBytes) {
9703d627d6fSpeter klausler     std::memcpy(to, from, origBytes);
9713d627d6fSpeter klausler   }
9723d627d6fSpeter klausler }
9733d627d6fSpeter klausler 
RTNAME(Trim)9743d627d6fSpeter klausler void RTNAME(Trim)(Descriptor &result, const Descriptor &string,
9753d627d6fSpeter klausler     const char *sourceFile, int sourceLine) {
9763d627d6fSpeter klausler   Terminator terminator{sourceFile, sourceLine};
9773d627d6fSpeter klausler   std::size_t resultBytes{0};
9783d627d6fSpeter klausler   switch (string.raw().type) {
9793d627d6fSpeter klausler   case CFI_type_char:
9803d627d6fSpeter klausler     resultBytes =
9813d627d6fSpeter klausler         LenTrim(string.OffsetElement<const char>(), string.ElementBytes());
9823d627d6fSpeter klausler     break;
9833d627d6fSpeter klausler   case CFI_type_char16_t:
9843d627d6fSpeter klausler     resultBytes = LenTrim(string.OffsetElement<const char16_t>(),
9853d627d6fSpeter klausler                       string.ElementBytes() >> 1)
9863d627d6fSpeter klausler         << 1;
9873d627d6fSpeter klausler     break;
9883d627d6fSpeter klausler   case CFI_type_char32_t:
9893d627d6fSpeter klausler     resultBytes = LenTrim(string.OffsetElement<const char32_t>(),
9903d627d6fSpeter klausler                       string.ElementBytes() >> 2)
9913d627d6fSpeter klausler         << 2;
9923d627d6fSpeter klausler     break;
9933d627d6fSpeter klausler   default:
9943d627d6fSpeter klausler     terminator.Crash(
9953d627d6fSpeter klausler         "TRIM: bad string type code %d", static_cast<int>(string.raw().type));
9963d627d6fSpeter klausler   }
997b146dfe5SJean Perier   result.Establish(string.type(), resultBytes, nullptr, 0, nullptr,
998b146dfe5SJean Perier       CFI_attribute_allocatable);
9998ba9ee46Speter klausler   RUNTIME_CHECK(terminator, result.Allocate() == CFI_SUCCESS);
10003aee64a9Speter klausler   std::memcpy(result.OffsetElement(), string.OffsetElement(), resultBytes);
10013d627d6fSpeter klausler }
10023d627d6fSpeter klausler 
RTNAME(Verify1)10035a451a42Speter klausler std::size_t RTNAME(Verify1)(const char *x, std::size_t xLen, const char *set,
10045a451a42Speter klausler     std::size_t setLen, bool back) {
10056811b961Speter klausler   return ScanVerify<char, CharFunc::Verify>(x, xLen, set, setLen, back);
10065a451a42Speter klausler }
RTNAME(Verify2)10075a451a42Speter klausler std::size_t RTNAME(Verify2)(const char16_t *x, std::size_t xLen,
10085a451a42Speter klausler     const char16_t *set, std::size_t setLen, bool back) {
10096811b961Speter klausler   return ScanVerify<char16_t, CharFunc::Verify>(x, xLen, set, setLen, back);
10105a451a42Speter klausler }
RTNAME(Verify4)10115a451a42Speter klausler std::size_t RTNAME(Verify4)(const char32_t *x, std::size_t xLen,
10125a451a42Speter klausler     const char32_t *set, std::size_t setLen, bool back) {
10136811b961Speter klausler   return ScanVerify<char32_t, CharFunc::Verify>(x, xLen, set, setLen, back);
10145a451a42Speter klausler }
10155a451a42Speter klausler 
RTNAME(Verify)10165a451a42Speter klausler void RTNAME(Verify)(Descriptor &result, const Descriptor &string,
10175a451a42Speter klausler     const Descriptor &set, const Descriptor *back, int kind,
10185a451a42Speter klausler     const char *sourceFile, int sourceLine) {
10195a451a42Speter klausler   Terminator terminator{sourceFile, sourceLine};
10205a451a42Speter klausler   switch (string.raw().type) {
10215a451a42Speter klausler   case CFI_type_char:
10226811b961Speter klausler     GeneralCharFuncKind<char, CharFunc::Verify>(
10236811b961Speter klausler         result, string, set, back, kind, terminator);
10245a451a42Speter klausler     break;
10255a451a42Speter klausler   case CFI_type_char16_t:
10266811b961Speter klausler     GeneralCharFuncKind<char16_t, CharFunc::Verify>(
10276811b961Speter klausler         result, string, set, back, kind, terminator);
10285a451a42Speter klausler     break;
10295a451a42Speter klausler   case CFI_type_char32_t:
10306811b961Speter klausler     GeneralCharFuncKind<char32_t, CharFunc::Verify>(
10316811b961Speter klausler         result, string, set, back, kind, terminator);
10325a451a42Speter klausler     break;
10335a451a42Speter klausler   default:
10345a451a42Speter klausler     terminator.Crash(
10355a451a42Speter klausler         "VERIFY: bad string type code %d", static_cast<int>(string.raw().type));
10365a451a42Speter klausler   }
10375a451a42Speter klausler }
10385a451a42Speter klausler 
RTNAME(CharacterMax)10393d627d6fSpeter klausler void RTNAME(CharacterMax)(Descriptor &accumulator, const Descriptor &x,
10403d627d6fSpeter klausler     const char *sourceFile, int sourceLine) {
10413d627d6fSpeter klausler   MaxMin<false>(accumulator, x, sourceFile, sourceLine);
10423d627d6fSpeter klausler }
10433d627d6fSpeter klausler 
RTNAME(CharacterMin)10443d627d6fSpeter klausler void RTNAME(CharacterMin)(Descriptor &accumulator, const Descriptor &x,
10453d627d6fSpeter klausler     const char *sourceFile, int sourceLine) {
10463d627d6fSpeter klausler   MaxMin<true>(accumulator, x, sourceFile, sourceLine);
10473d627d6fSpeter klausler }
10484d54bb7aSpeter klausler }
10494d54bb7aSpeter klausler } // namespace Fortran::runtime
1050