FLANG
character-value-impl.h
1//===-- include/flang/Evaluate/character-value-impl.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_VALUE_IMPL_H_
10#define FORTRAN_EVALUATE_CHARACTER_VALUE_IMPL_H_
11
12#include "flang/Evaluate/common.h"
13#include "llvm/Support/ErrorHandling.h"
14#include <cstddef>
15#include <optional>
16#include <string>
17#include <utility>
18#include <variant>
19
20namespace Fortran::evaluate::value {
21
22class CharacterValueImpl {
23 using Storage =
24 std::variant<std::monostate, std::string, std::u16string, std::u32string>;
25
26public:
27 // rule-of-five
28 ~CharacterValueImpl() = default;
29 CharacterValueImpl(const CharacterValueImpl &) = default;
30 CharacterValueImpl(CharacterValueImpl &&) = default;
31 CharacterValueImpl &operator=(const CharacterValueImpl &) = default;
32 CharacterValueImpl &operator=(CharacterValueImpl &&) = default;
33
34 CharacterValueImpl() = default;
35 explicit CharacterValueImpl(int kind, std::string s) {
36 WithCharProto(kind, [&](auto c) {
37 using CharT = std::decay_t<decltype(c)>;
38 using StringT = std::basic_string<CharT>;
39 if (std::is_same_v<StringT, std::string>) {
40 storage_ = std::move(s);
41 } else {
42 StringT buf;
43 buf.resize(s.length());
44 for (auto [i, c] : llvm::enumerate(s)) {
45 // Platforms may defined char as either signed or unsigned.
46 // Cast to unsigned to avoid platform-dependent widening.
47 buf[i] = static_cast<unsigned char>(c);
48 }
49 storage_ = std::move(buf);
50 }
51 });
52
53 CHECK(this->kind() == kind);
54 }
55
56 explicit CharacterValueImpl(int kind, std::u16string s)
57 : storage_{std::move(s)} {
58 CHECK(kind == 2);
59 CHECK(this->kind() == kind);
60 }
61
62 explicit CharacterValueImpl(int kind, std::u32string s)
63 : storage_{std::move(s)} {
64 CHECK(kind == 4);
65 CHECK(this->kind() == kind);
66 }
67
69 CharacterValueImpl(int kind, std::size_t n, char32_t c);
70
71 static CharacterValueImpl Zero(int kind);
72
73 static CharacterValueImpl FromRawBytes(
74 int kind, const void *raw, size_t byteSize);
75
76 void print(llvm::raw_ostream &os) const;
77
78#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
79 LLVM_DUMP_METHOD void dump() const;
80#endif
81
82 std::optional<llvm::StringRef> AsStringRef() const;
83
85 std::optional<std::string> AsStdString() const;
86 std::optional<std::u16string> AsU16String() const;
87 std::optional<std::u32string> AsU32String() const;
88
89 std::string ToStdString() const;
90
91 bool IsNull() const { return storage_.index() == 0; }
92 int kind() const;
93
95 std::size_t charSize() const;
96
98 std::size_t size() const;
99
101 std::size_t length() const { return size(); }
102
104 bool empty() const { return size() == 0; }
105
107 void *data() { return charData(); }
108 const void *data() const { return charData(); }
109 void *charData();
110 const void *charData() const;
111
112 // Comparison operators
113 Ordering Compare(const CharacterValueImpl &y) const;
114 bool operator<(const CharacterValueImpl &y) const;
115 bool operator<=(const CharacterValueImpl &y) const { return !(y < *this); }
116 bool operator==(const CharacterValueImpl &y) const;
117 bool operator!=(const CharacterValueImpl &y) const { return !(*this == y); }
118 bool operator>=(const CharacterValueImpl &y) const { return !(*this < y); }
119 bool operator>(const CharacterValueImpl &y) const { return y < *this; }
120
122 void assign(int kind, std::size_t n, char32_t c);
123
125 void assign(const char *p, std::size_t n) { storage_ = std::string(p, n); }
126 void assign(const char16_t *p, std::size_t n) {
127 storage_ = std::u16string(p, n);
128 }
129 void assign(const char32_t *p, std::size_t n) {
130 storage_ = std::u32string(p, n);
131 }
132
134 void erase(std::size_t pos);
135
137 void append(std::size_t n, char32_t c);
138
140 CharacterValueImpl &replace(
141 std::size_t pos, std::size_t len, const CharacterValueImpl &other);
142
144 CharacterValueImpl substr(std::size_t pos) const;
145
147 CharacterValueImpl substr(std::size_t pos, std::size_t len) const;
148
149 CharacterValueImpl ToAscii(int kind) const;
150
152 void reserve(std::size_t n);
153
155 char32_t operator[](std::size_t i) const;
156
158 CharacterValueImpl operator+(const CharacterValueImpl &y) const;
159
161 CharacterValueImpl &operator+=(const CharacterValueImpl &y);
162
164 CharacterValueImpl &operator+=(char32_t c);
165
167 static constexpr std::size_t npos{std::string::npos};
168
169 // Find-family methods; return npos when not found.
170 std::size_t find(const CharacterValueImpl &pattern) const;
171 std::size_t rfind(const CharacterValueImpl &pattern) const;
172
173 std::size_t find_first_not_of(char c) const {
174 return find_first_not_of(static_cast<char32_t>(c));
175 }
176 std::size_t find_first_not_of(char16_t c) const {
177 return find_first_not_of(static_cast<char32_t>(c));
178 }
179 std::size_t find_first_not_of(char32_t c) const;
180 std::size_t find_last_not_of(char c) const {
181 return find_last_not_of(static_cast<char32_t>(c));
182 }
183 std::size_t find_last_not_of(char16_t c) const {
184 return find_last_not_of(static_cast<char32_t>(c));
185 }
186 std::size_t find_last_not_of(char32_t c) const;
187 std::size_t find_first_not_of(const CharacterValueImpl &set) const;
188 std::size_t find_last_not_of(const CharacterValueImpl &set) const;
189 std::size_t find_first_of(const CharacterValueImpl &set) const;
190 std::size_t find_last_of(const CharacterValueImpl &set) const;
191
192 void StoreRawBytes(
193 void *dst, std::size_t size, bool *changed = nullptr) const;
194
195 // Compile-time dispatchers to current/specified kind
196
197 template <typename CharT, typename = std::void_t<std::basic_string<CharT>>>
198 const std::basic_string<CharT> &GetBasicString() const;
199
200 template <typename F>
201 auto WithCharProto(F &&f) const
202 -> decltype(std::declval<F>()(std::declval<char>())) {
203 return WithCharProto(kind(), f);
204 }
205
206 template <typename F>
207 static auto WithCharProto(int kind, F &&f)
208 -> decltype(std::declval<F>()(std::declval<char>())) {
209 switch (kind) {
210 case 1:
211 return f(char{});
212 case 2:
213 return f(char16_t{});
214 case 4:
215 return f(char32_t{});
216 default:
217 DIE("unsupported character kind/null state");
218 }
219 }
220
221 template <typename F>
222 auto WithBasicString(F &&f) const
223 -> decltype(f(std::declval<const std::string &>())) {
224 return common::visit(
225 common::visitors{
226 [](std::monostate) -> decltype(f(
227 std::declval<const std::string &>())) {
228 DIE("operation on uninitialized CharacterValueImpl");
229 },
230 f,
231 },
232 storage_);
233 }
234
235private:
236 Storage storage_;
237};
238
239} // namespace Fortran::evaluate::value
240
241namespace llvm {
243inline raw_ostream &operator<<(
244 raw_ostream &os, const Fortran::evaluate::value::CharacterValueImpl &v) {
245 v.print(os);
246 return os;
247}
248} // namespace llvm
249
250#endif // FORTRAN_EVALUATE_CHARACTER_VALUE_IMPL_H_
Definition character-value-impl.h:22
void append(std::size_t n, char32_t c)
Append n copies of the given character.
Definition character-value-impl.cpp:216
void * data()
Raw byte pointer to the underlying character data.
Definition character-value-impl.h:107
std::size_t charSize() const
Byte size of one character unit (1, 2, or 4).
Definition character-value-impl.cpp:79
CharacterValueImpl & replace(std::size_t pos, std::size_t len, const CharacterValueImpl &other)
Replace the substring [pos, pos+len) with characters from other.
Definition character-value-impl.cpp:230
void reserve(std::size_t n)
Reserve storage for at least n characters.
Definition character-value-impl.cpp:368
static constexpr std::size_t npos
Sentinel value for "not found" positions (same as std::string::npos).
Definition character-value-impl.h:167
void erase(std::size_t pos)
Erase from position pos to end.
Definition character-value-impl.cpp:203
CharacterValueImpl & operator+=(const CharacterValueImpl &y)
Append another same-kind string.
Definition character-value-impl.cpp:414
void assign(int kind, std::size_t n, char32_t c)
Assign n copies of the given character.
Definition character-value-impl.cpp:196
bool empty() const
True when the string is empty.
Definition character-value-impl.h:104
std::size_t size() const
Number of characters in this string.
Definition character-value-impl.cpp:92
std::optional< std::string > AsStdString() const
Return the string as std::string if kind==1, or nullopt otherwise.
Definition character-value-impl.cpp:289
char32_t operator[](std::size_t i) const
Return the character at position i as char32_t (safe for all kinds).
Definition character-value-impl.cpp:379
void assign(const char *p, std::size_t n)
Assign from a raw character pointer and length.
Definition character-value-impl.h:125
std::size_t length() const
String length (synonym for size()).
Definition character-value-impl.h:101
CharacterValueImpl operator+(const CharacterValueImpl &y) const
Concatenate two same-kind strings.
Definition character-value-impl.cpp:396
CharacterValueImpl substr(std::size_t pos) const
Return a suffix starting at pos.
Definition character-value-impl.cpp:249