1 //===-- lib/Evaluate/character.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_EVALUATE_CHARACTER_H_ 10 #define FORTRAN_EVALUATE_CHARACTER_H_ 11 12 #include "flang/Evaluate/type.h" 13 #include <string> 14 15 // Provides implementations of intrinsic functions operating on character 16 // scalars. 17 18 namespace Fortran::evaluate { 19 20 template <int KIND> class CharacterUtils { 21 using Character = Scalar<Type<TypeCategory::Character, KIND>>; 22 using CharT = typename Character::value_type; 23 24 public: 25 // CHAR also implements ACHAR under assumption that character encodings 26 // contain ASCII CHAR(std::uint64_t code)27 static Character CHAR(std::uint64_t code) { 28 return Character{{static_cast<CharT>(code)}}; 29 } 30 31 // ICHAR also implements IACHAR under assumption that character encodings 32 // contain ASCII ICHAR(const Character & c)33 static std::int64_t ICHAR(const Character &c) { 34 CHECK(c.length() == 1); 35 // Convert first to an unsigned integer type to avoid sign extension 36 return static_cast<common::HostUnsignedIntType<(8 * KIND)>>(c[0]); 37 } 38 NEW_LINE()39 static Character NEW_LINE() { return Character{{NewLine()}}; } 40 ADJUSTL(const Character & str)41 static Character ADJUSTL(const Character &str) { 42 auto pos{str.find_first_not_of(Space())}; 43 if (pos != Character::npos && pos != 0) { 44 return Character{str.substr(pos) + Character(pos, Space())}; 45 } 46 // else empty or only spaces, or no leading spaces 47 return str; 48 } 49 ADJUSTR(const Character & str)50 static Character ADJUSTR(const Character &str) { 51 auto pos{str.find_last_not_of(Space())}; 52 if (pos != Character::npos && pos != str.length() - 1) { 53 auto delta{str.length() - 1 - pos}; 54 return Character{Character(delta, Space()) + str.substr(0, pos + 1)}; 55 } 56 // else empty or only spaces, or no trailing spaces 57 return str; 58 } 59 60 static ConstantSubscript INDEX( 61 const Character &str, const Character &substr, bool back = false) { 62 auto pos{back ? str.rfind(substr) : str.find(substr)}; 63 return static_cast<ConstantSubscript>(pos == str.npos ? 0 : pos + 1); 64 } 65 66 static ConstantSubscript SCAN( 67 const Character &str, const Character &set, bool back = false) { 68 auto pos{back ? str.find_last_of(set) : str.find_first_of(set)}; 69 return static_cast<ConstantSubscript>(pos == str.npos ? 0 : pos + 1); 70 } 71 72 static ConstantSubscript VERIFY( 73 const Character &str, const Character &set, bool back = false) { 74 auto pos{back ? str.find_last_not_of(set) : str.find_first_not_of(set)}; 75 return static_cast<ConstantSubscript>(pos == str.npos ? 0 : pos + 1); 76 } 77 78 // Resize adds spaces on the right if the new size is bigger than the 79 // original, or by trimming the rightmost characters otherwise. Resize(const Character & str,std::size_t newLength)80 static Character Resize(const Character &str, std::size_t newLength) { 81 auto oldLength{str.length()}; 82 if (newLength > oldLength) { 83 return str + Character(newLength - oldLength, Space()); 84 } else { 85 return str.substr(0, newLength); 86 } 87 } 88 LEN_TRIM(const Character & str)89 static ConstantSubscript LEN_TRIM(const Character &str) { 90 auto j{str.length()}; 91 for (; j >= 1; --j) { 92 if (str[j - 1] != ' ') { 93 break; 94 } 95 } 96 return static_cast<ConstantSubscript>(j); 97 } 98 REPEAT(const Character & str,ConstantSubscript ncopies)99 static Character REPEAT(const Character &str, ConstantSubscript ncopies) { 100 Character result; 101 if (!str.empty() && ncopies > 0) { 102 result.reserve(ncopies * str.size()); 103 while (ncopies-- > 0) { 104 result += str; 105 } 106 } 107 return result; 108 } 109 TRIM(const Character & str)110 static Character TRIM(const Character &str) { 111 return str.substr(0, LEN_TRIM(str)); 112 } 113 114 private: 115 // Following helpers assume that character encodings contain ASCII Space()116 static constexpr CharT Space() { return 0x20; } NewLine()117 static constexpr CharT NewLine() { return 0x0a; } 118 }; 119 120 } // namespace Fortran::evaluate 121 122 #endif // FORTRAN_EVALUATE_CHARACTER_H_ 123