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 |
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 |
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 | |
39 | static Character NEW_LINE() { return Character{{NewLine()}}; } |
40 | |
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 | |
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. |
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 | |
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 | |
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 | |
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 |
116 | static constexpr CharT Space() { return 0x20; } |
117 | static constexpr CharT NewLine() { return 0x0a; } |
118 | }; |
119 | |
120 | } // namespace Fortran::evaluate |
121 | |
122 | #endif // FORTRAN_EVALUATE_CHARACTER_H_ |
123 | |