xref: /llvm-project/flang/lib/Evaluate/character.h (revision c6dfb62d4df969fc50f42cf2889b10bb82f51b1f)
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