Line data Source code
1 : #ifdef __PLUMED_HAS_ASMJIT
2 : // This file is part of AsmJit project <https://asmjit.com>
3 : //
4 : // See asmjit.h or LICENSE.md for license and copyright information
5 : // SPDX-License-Identifier: Zlib
6 :
7 : #ifndef ASMJIT_CORE_STRING_H_INCLUDED
8 : #define ASMJIT_CORE_STRING_H_INCLUDED
9 :
10 : #include "support.h"
11 : #include "zone.h"
12 :
13 : ASMJIT_BEGIN_NAMESPACE
14 :
15 : //! \addtogroup asmjit_utilities
16 : //! \{
17 :
18 : //! Format flags used by \ref String API.
19 : enum class StringFormatFlags : uint32_t {
20 : //! No flags.
21 : kNone = 0x00000000u,
22 : //! Show sign.
23 : kShowSign = 0x00000001u,
24 : //! Show space.
25 : kShowSpace = 0x00000002u,
26 : //! Alternate form (use 0x when formatting HEX number).
27 : kAlternate = 0x00000004u,
28 : //! The input is signed.
29 : kSigned = 0x80000000u
30 : };
31 0 : ASMJIT_DEFINE_ENUM_FLAGS(StringFormatFlags)
32 :
33 : //! Fixed string - only useful for strings that would never exceed `N - 1` characters; always null-terminated.
34 : template<size_t N>
35 : union FixedString {
36 : //! \name Constants
37 : //! \{
38 :
39 : // This cannot be constexpr as GCC 4.8 refuses constexpr members of unions.
40 : enum : uint32_t {
41 : kNumUInt32Words = uint32_t((N + sizeof(uint32_t) - 1) / sizeof(uint32_t))
42 : };
43 :
44 : //! \}
45 :
46 : //! \name Members
47 : //! \{
48 :
49 : char str[kNumUInt32Words * sizeof(uint32_t)];
50 : uint32_t u32[kNumUInt32Words];
51 :
52 : //! \}
53 :
54 : //! \name Utilities
55 : //! \{
56 :
57 : inline bool eq(const char* other) const noexcept {
58 355 : return strcmp(str, other) == 0;
59 : }
60 :
61 : //! \}
62 : };
63 :
64 : //! A simple non-reference counted string that uses small string optimization (SSO).
65 : //!
66 : //! This string has 3 allocation possibilities:
67 : //!
68 : //! 1. Small - embedded buffer is used for up to `kSSOCapacity` characters. This should handle most small
69 : //! strings and thus avoid dynamic memory allocation for most use-cases.
70 : //!
71 : //! 2. Large - string that doesn't fit into an embedded buffer (or string that was truncated from a larger
72 : //! buffer) and is owned by AsmJit. When you destroy the string AsmJit would automatically
73 : //! release the large buffer.
74 : //!
75 : //! 3. External - like Large (2), however, the large buffer is not owned by AsmJit and won't be released when
76 : //! the string is destroyed or reallocated. This is mostly useful for working with larger temporary
77 : //! strings allocated on stack or with immutable strings.
78 : class String {
79 : public:
80 : ASMJIT_NONCOPYABLE(String)
81 :
82 : //! String operation.
83 : enum class ModifyOp : uint32_t {
84 : //! Assignment - a new content replaces the current one.
85 : kAssign = 0,
86 : //! Append - a new content is appended to the string.
87 : kAppend = 1
88 : };
89 :
90 : //! \cond INTERNAL
91 : enum : uint32_t {
92 : kLayoutSize = 32,
93 : kSSOCapacity = kLayoutSize - 2
94 : };
95 :
96 : //! String type.
97 : enum Type : uint8_t {
98 : //! Large string (owned by String).
99 : kTypeLarge = 0x1Fu,
100 : //! External string (zone allocated or not owned by String).
101 : kTypeExternal = 0x20u
102 : };
103 :
104 : union Raw {
105 : uint8_t u8[kLayoutSize];
106 : uint64_t u64[kLayoutSize / sizeof(uint64_t)];
107 : uintptr_t uptr[kLayoutSize / sizeof(uintptr_t)];
108 : };
109 :
110 : struct Small {
111 : uint8_t type;
112 : char data[kSSOCapacity + 1u];
113 : };
114 :
115 : struct Large {
116 : uint8_t type;
117 : uint8_t reserved[sizeof(uintptr_t) - 1];
118 : size_t size;
119 : size_t capacity;
120 : char* data;
121 : };
122 :
123 : union {
124 : uint8_t _type;
125 : Raw _raw;
126 : Small _small;
127 : Large _large;
128 : };
129 : //! \endcond
130 :
131 : //! \name Construction & Destruction
132 : //! \{
133 :
134 : //! Creates a default-initialized string if zero length.
135 : inline String() noexcept
136 137460 : : _small {} {}
137 :
138 : //! Creates a string that takes ownership of the content of the `other` string.
139 : inline String(String&& other) noexcept {
140 : _raw = other._raw;
141 : other._resetInternal();
142 : }
143 :
144 : inline ~String() noexcept {
145 109968 : reset();
146 0 : }
147 :
148 : //! Reset the string into a construction state.
149 : ASMJIT_API Error reset() noexcept;
150 :
151 : //! \}
152 :
153 : //! \name Overloaded Operators
154 : //! \{
155 :
156 : inline String& operator=(String&& other) noexcept {
157 : swap(other);
158 : other.reset();
159 : return *this;
160 : }
161 :
162 : inline bool operator==(const char* other) const noexcept { return eq(other); }
163 : inline bool operator!=(const char* other) const noexcept { return !eq(other); }
164 :
165 : inline bool operator==(const String& other) const noexcept { return eq(other); }
166 : inline bool operator!=(const String& other) const noexcept { return !eq(other); }
167 :
168 : //! \}
169 :
170 : //! \name Accessors
171 : //! \{
172 :
173 : inline bool isExternal() const noexcept { return _type == kTypeExternal; }
174 0 : inline bool isLargeOrExternal() const noexcept { return _type >= kTypeLarge; }
175 :
176 : //! Tests whether the string is empty.
177 : inline bool empty() const noexcept { return size() == 0; }
178 : //! Returns the size of the string.
179 0 : inline size_t size() const noexcept { return isLargeOrExternal() ? size_t(_large.size) : size_t(_type); }
180 : //! Returns the capacity of the string.
181 0 : inline size_t capacity() const noexcept { return isLargeOrExternal() ? _large.capacity : size_t(kSSOCapacity); }
182 :
183 : //! Returns the data of the string.
184 0 : inline char* data() noexcept { return isLargeOrExternal() ? _large.data : _small.data; }
185 : //! \overload
186 0 : inline const char* data() const noexcept { return isLargeOrExternal() ? _large.data : _small.data; }
187 :
188 : inline char* start() noexcept { return data(); }
189 : inline const char* start() const noexcept { return data(); }
190 :
191 : inline char* end() noexcept { return data() + size(); }
192 : inline const char* end() const noexcept { return data() + size(); }
193 :
194 : //! \}
195 :
196 : //! \name String Operations
197 : //! \{
198 :
199 : //! Swaps the content of this string with `other`.
200 : inline void swap(String& other) noexcept {
201 : std::swap(_raw, other._raw);
202 : }
203 :
204 : //! Clears the content of the string.
205 : ASMJIT_API Error clear() noexcept;
206 :
207 : ASMJIT_API char* prepare(ModifyOp op, size_t size) noexcept;
208 :
209 : ASMJIT_API Error _opString(ModifyOp op, const char* str, size_t size = SIZE_MAX) noexcept;
210 : ASMJIT_API Error _opChar(ModifyOp op, char c) noexcept;
211 : ASMJIT_API Error _opChars(ModifyOp op, char c, size_t n) noexcept;
212 : ASMJIT_API Error _opNumber(ModifyOp op, uint64_t i, uint32_t base = 0, size_t width = 0, StringFormatFlags flags = StringFormatFlags::kNone) noexcept;
213 : ASMJIT_API Error _opHex(ModifyOp op, const void* data, size_t size, char separator = '\0') noexcept;
214 : ASMJIT_API Error _opFormat(ModifyOp op, const char* fmt, ...) noexcept;
215 : ASMJIT_API Error _opVFormat(ModifyOp op, const char* fmt, va_list ap) noexcept;
216 :
217 : //! Replaces the current of the string with `data` of the given `size`.
218 : //!
219 : //! Null terminated strings can set `size` to `SIZE_MAX`.
220 : ASMJIT_API Error assign(const char* data, size_t size = SIZE_MAX) noexcept;
221 :
222 : //! Replaces the current of the string with `other` string.
223 : inline Error assign(const String& other) noexcept {
224 : return assign(other.data(), other.size());
225 : }
226 :
227 : //! Replaces the current of the string by a single `c` character.
228 : inline Error assign(char c) noexcept {
229 : return _opChar(ModifyOp::kAssign, c);
230 : }
231 :
232 : //! Replaces the current of the string by a `c` character, repeated `n` times.
233 : inline Error assignChars(char c, size_t n) noexcept {
234 : return _opChars(ModifyOp::kAssign, c, n);
235 : }
236 :
237 : //! Replaces the current of the string by a formatted integer `i` (signed).
238 : inline Error assignInt(int64_t i, uint32_t base = 0, size_t width = 0, StringFormatFlags flags = StringFormatFlags::kNone) noexcept {
239 : return _opNumber(ModifyOp::kAssign, uint64_t(i), base, width, flags | StringFormatFlags::kSigned);
240 : }
241 :
242 : //! Replaces the current of the string by a formatted integer `i` (unsigned).
243 : inline Error assignUInt(uint64_t i, uint32_t base = 0, size_t width = 0, StringFormatFlags flags = StringFormatFlags::kNone) noexcept {
244 : return _opNumber(ModifyOp::kAssign, i, base, width, flags);
245 : }
246 :
247 : //! Replaces the current of the string by the given `data` converted to a HEX string.
248 : inline Error assignHex(const void* data, size_t size, char separator = '\0') noexcept {
249 : return _opHex(ModifyOp::kAssign, data, size, separator);
250 : }
251 :
252 : //! Replaces the current of the string by a formatted string `fmt`.
253 : template<typename... Args>
254 : inline Error assignFormat(const char* fmt, Args&&... args) noexcept {
255 0 : return _opFormat(ModifyOp::kAssign, fmt, std::forward<Args>(args)...);
256 : }
257 :
258 : //! Replaces the current of the string by a formatted string `fmt` (va_list version).
259 : inline Error assignVFormat(const char* fmt, va_list ap) noexcept {
260 : return _opVFormat(ModifyOp::kAssign, fmt, ap);
261 : }
262 :
263 : //! Appends `str` having the given size `size` to the string.
264 : //!
265 : //! Null terminated strings can set `size` to `SIZE_MAX`.
266 0 : inline Error append(const char* str, size_t size = SIZE_MAX) noexcept {
267 0 : return _opString(ModifyOp::kAppend, str, size);
268 : }
269 :
270 : //! Appends `other` string to this string.
271 : inline Error append(const String& other) noexcept {
272 : return append(other.data(), other.size());
273 : }
274 :
275 : //! Appends a single `c` character.
276 0 : inline Error append(char c) noexcept {
277 0 : return _opChar(ModifyOp::kAppend, c);
278 : }
279 :
280 : //! Appends `c` character repeated `n` times.
281 : inline Error appendChars(char c, size_t n) noexcept {
282 0 : return _opChars(ModifyOp::kAppend, c, n);
283 : }
284 :
285 : //! Appends a formatted integer `i` (signed).
286 0 : inline Error appendInt(int64_t i, uint32_t base = 0, size_t width = 0, StringFormatFlags flags = StringFormatFlags::kNone) noexcept {
287 0 : return _opNumber(ModifyOp::kAppend, uint64_t(i), base, width, flags | StringFormatFlags::kSigned);
288 : }
289 :
290 : //! Appends a formatted integer `i` (unsigned).
291 0 : inline Error appendUInt(uint64_t i, uint32_t base = 0, size_t width = 0, StringFormatFlags flags = StringFormatFlags::kNone) noexcept {
292 0 : return _opNumber(ModifyOp::kAppend, i, base, width, flags);
293 : }
294 :
295 : //! Appends the given `data` converted to a HEX string.
296 : inline Error appendHex(const void* data, size_t size, char separator = '\0') noexcept {
297 0 : return _opHex(ModifyOp::kAppend, data, size, separator);
298 : }
299 :
300 : //! Appends a formatted string `fmt` with `args`.
301 : template<typename... Args>
302 0 : inline Error appendFormat(const char* fmt, Args&&... args) noexcept {
303 0 : return _opFormat(ModifyOp::kAppend, fmt, std::forward<Args>(args)...);
304 : }
305 :
306 : //! Appends a formatted string `fmt` (va_list version).
307 : inline Error appendVFormat(const char* fmt, va_list ap) noexcept {
308 0 : return _opVFormat(ModifyOp::kAppend, fmt, ap);
309 : }
310 :
311 : ASMJIT_API Error padEnd(size_t n, char c = ' ') noexcept;
312 :
313 : //! Truncate the string length into `newSize`.
314 : ASMJIT_API Error truncate(size_t newSize) noexcept;
315 :
316 : ASMJIT_API bool eq(const char* other, size_t size = SIZE_MAX) const noexcept;
317 : inline bool eq(const String& other) const noexcept { return eq(other.data(), other.size()); }
318 :
319 : //! \}
320 :
321 : //! \name Internal Functions
322 : //! \{
323 :
324 : //! Resets string to embedded and makes it empty (zero length, zero first char)
325 : //!
326 : //! \note This is always called internally after an external buffer was released as it zeroes all bytes
327 : //! used by String's embedded storage.
328 : inline void _resetInternal() noexcept {
329 824760 : for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_raw.uptr); i++)
330 659808 : _raw.uptr[i] = 0;
331 : }
332 :
333 : inline void _setSize(size_t newSize) noexcept {
334 0 : if (isLargeOrExternal())
335 0 : _large.size = newSize;
336 : else
337 0 : _small.type = uint8_t(newSize);
338 : }
339 :
340 : //! \}
341 : };
342 :
343 : //! Temporary string builder, has statically allocated `N` bytes.
344 : template<size_t N>
345 82476 : class StringTmp : public String {
346 : public:
347 : ASMJIT_NONCOPYABLE(StringTmp)
348 :
349 : //! Embedded data.
350 : char _embeddedData[Support::alignUp(N + 1, sizeof(size_t))];
351 :
352 : //! \name Construction & Destruction
353 : //! \{
354 :
355 137460 : inline StringTmp() noexcept {
356 : _resetToTemporary();
357 0 : }
358 :
359 : inline void _resetToTemporary() noexcept {
360 137460 : _large.type = kTypeExternal;
361 137460 : _large.capacity = ASMJIT_ARRAY_SIZE(_embeddedData) - 1;
362 137460 : _large.data = _embeddedData;
363 109968 : _embeddedData[0] = '\0';
364 : }
365 :
366 : //! \}
367 : };
368 :
369 : //! \}
370 :
371 : ASMJIT_END_NAMESPACE
372 :
373 : #endif // ASMJIT_CORE_STRING_H_INCLUDED
374 :
375 : #endif // __PLUMED_HAS_ASMJIT
|