Sane C++ Libraries
C++ Platform Abstraction Libraries
StringIterator.h
1// Copyright (c) Stefano Cristiano
2// SPDX-License-Identifier: MIT
3#pragma once
4#include "../Foundation/Assert.h" //Assert::unreachable
5#include "../Foundation/Span.h"
6
7namespace SC
8{
11
14
17{
18 Ascii = 0,
19 Utf8 = 1,
20 Utf16 = 2,
21#if SC_PLATFORM_WINDOWS
22 Native = Utf16,
23 Wide = Utf16
24#else
25 Native = Utf8
26#endif
27};
28
34{
35 return (encoding1 == encoding2) or (encoding2 == StringEncoding::Ascii and encoding1 == StringEncoding::Utf8) or
36 (encoding2 == StringEncoding::Utf8 and encoding1 == StringEncoding::Ascii);
37}
38
43{
44 switch (encoding)
45 {
46 case StringEncoding::Utf16: return 2;
47 case StringEncoding::Ascii: return 1;
48 case StringEncoding::Utf8: return 1;
49 }
50 Assert::unreachable();
51}
52
61template <typename CharIterator>
63{
64 static constexpr StringEncoding getEncoding() { return CharIterator::getEncoding(); }
65
66 using CodeUnit = char;
67 using CodePoint = StringCodePoint;
68
70 constexpr void setToStart() { it = start; }
71
73 constexpr void setToEnd() { it = end; }
74
77 [[nodiscard]] constexpr bool isAtEnd() const { return it >= end; }
78
81 [[nodiscard]] constexpr bool isAtStart() const { return it <= start; }
82
86 [[nodiscard]] constexpr bool advanceUntilMatches(CodePoint c);
87
91 [[nodiscard]] bool reverseAdvanceUntilMatches(CodePoint c);
92
97 [[nodiscard]] bool advanceAfterFinding(StringIterator other);
98
103 [[nodiscard]] bool advanceBeforeFinding(StringIterator other);
104
108 [[nodiscard]] bool advanceByLengthOf(StringIterator other) { return advanceOfBytes(other.end - other.it); }
109
114 [[nodiscard]] bool advanceUntilMatchesAny(Span<const CodePoint> items, CodePoint& matched);
115
120 [[nodiscard]] bool reverseAdvanceUntilMatchesAny(Span<const CodePoint> items, CodePoint& matched);
121
126 [[nodiscard]] bool advanceUntilDifferentFrom(CodePoint c, CodePoint* optionalReadChar = nullptr);
127
131 [[nodiscard]] constexpr bool advanceIfMatches(CodePoint c);
132
136 [[nodiscard]] bool advanceBackwardIfMatches(CodePoint c);
137
142
147 [[nodiscard]] bool advanceIfMatchesRange(CodePoint first, CodePoint last);
148
153 [[nodiscard]] bool match(CodePoint c) { return it < end and CharIterator::decode(it) == c; }
154
158 [[nodiscard]] constexpr bool advanceRead(CodePoint& c);
159
163 [[nodiscard]] bool read(CodePoint& c);
164
168 [[nodiscard]] bool advanceBackwardRead(CodePoint& c);
169
172 [[nodiscard]] constexpr bool stepForward();
173
176 [[nodiscard]] constexpr bool stepBackward();
177
181 [[nodiscard]] constexpr bool advanceCodePoints(size_t numCodePoints);
182
186 [[nodiscard]] bool reverseAdvanceCodePoints(size_t numCodePoints);
187
191 [[nodiscard]] constexpr bool isFollowedBy(CodePoint c);
192
196 [[nodiscard]] constexpr bool isPrecededBy(CodePoint c);
197
201 [[nodiscard]] constexpr StringIterator sliceFromStartUntil(StringIterator otherPoint) const;
202
206 [[nodiscard]] constexpr ssize_t bytesDistanceFrom(StringIterator other) const;
207
211 [[nodiscard]] bool endsWithAnyOf(Span<const CodePoint> codePoints) const;
212
216 [[nodiscard]] bool startsWithAnyOf(Span<const CodePoint> codePoints) const;
217
221 template <typename IteratorType>
222 [[nodiscard]] bool endsWith(IteratorType other) const;
223
227 template <typename IteratorType>
228 [[nodiscard]] bool startsWith(IteratorType other) const;
229
230 protected:
231 [[nodiscard]] bool advanceOfBytes(ssize_t bytesLength);
232
233 friend struct StringView;
234 static constexpr const CodeUnit* getNextOf(const CodeUnit* src) { return CharIterator::getNextOf(src); }
235 static constexpr const CodeUnit* getPreviousOf(const CodeUnit* src) { return CharIterator::getPreviousOf(src); }
236 constexpr StringIterator(const CodeUnit* it, const CodeUnit* end) : it(it), start(it), end(end) {}
237 constexpr auto* getCurrentIt() const { return it; }
238 const CodeUnit* it;
239 const CodeUnit* start;
240 const CodeUnit* end;
241};
242
244struct SC_COMPILER_EXPORT StringIteratorASCII : public StringIterator<StringIteratorASCII>
245{
246 [[nodiscard]] constexpr bool advanceUntilMatches(CodePoint c);
247
248 private:
249 [[nodiscard]] bool advanceUntilMatchesNonConstexpr(CodePoint c);
250 using StringIterator::StringIterator;
252 friend Parent;
253 friend struct StringView;
254
255 [[nodiscard]] static constexpr StringEncoding getEncoding() { return StringEncoding::Ascii; }
256
257 [[nodiscard]] static constexpr const char* getNextOf(const char* src) { return src + 1; }
258 [[nodiscard]] static constexpr const char* getPreviousOf(const char* src) { return src - 1; }
259 [[nodiscard]] static constexpr CodePoint decode(const char* src) { return static_cast<CodePoint>(*src); }
260};
261
263struct SC_COMPILER_EXPORT StringIteratorUTF16 : public StringIterator<StringIteratorUTF16>
264{
265 private:
266 using StringIterator::StringIterator;
268 friend Parent;
269 friend struct StringView;
270
271 [[nodiscard]] static StringEncoding getEncoding() { return StringEncoding::Utf16; }
272
273 [[nodiscard]] static const char* getNextOf(const char* bytes);
274
275 [[nodiscard]] static const char* getPreviousOf(const char* bytes);
276
277 [[nodiscard]] static uint32_t decode(const char* bytes);
278};
279
281struct SC_COMPILER_EXPORT StringIteratorUTF8 : public StringIterator<StringIteratorUTF8>
282{
283 private:
285 friend Parent;
286 friend struct StringView;
287 using StringIterator::StringIterator;
288
289 [[nodiscard]] static StringEncoding getEncoding() { return StringEncoding::Utf8; }
290
291 [[nodiscard]] static const char* getNextOf(const char* src);
292
293 [[nodiscard]] static const char* getPreviousOf(const char* src);
294
295 [[nodiscard]] static uint32_t decode(const char* src);
296};
297
300{
301 bool matches[256] = {false};
303 {
304 for (auto c : chars)
305 {
306 matches[static_cast<int>(c)] = true;
307 }
308 }
309};
311
312//-----------------------------------------------------------------------------------------------------------------------
313// Implementations Details
314//-----------------------------------------------------------------------------------------------------------------------
315template <typename CharIterator>
317{
318 while (it < end)
319 {
320 if (CharIterator::decode(it) == c)
321 return true;
322 it = getNextOf(it);
323 }
324 return false;
325}
326
327template <typename CharIterator>
329{
330 if (it < end and CharIterator::decode(it) == c)
331 {
332 it = getNextOf(it);
333 return true;
334 }
335 return false;
336}
337
338template <typename CharIterator>
340{
341 if (it < end)
342 {
343 c = CharIterator::decode(it);
344 it = getNextOf(it);
345 return true;
346 }
347 return false;
348}
349
350template <typename CharIterator>
352{
353 if (it < end)
354 {
355 it = getNextOf(it);
356 return true;
357 }
358 return false;
359}
360
361template <typename CharIterator>
363{
364 if (it > start)
365 {
366 it = getPreviousOf(it);
367 return true;
368 }
369 return false;
370}
371
372template <typename CharIterator>
373constexpr bool StringIterator<CharIterator>::advanceCodePoints(size_t numCodePoints)
374{
375 while (numCodePoints > 0)
376 {
377 numCodePoints -= 1;
378 if (it >= end)
379 {
380 return false;
381 }
382 it = getNextOf(it);
383 }
384 return true;
385}
386
387template <typename CharIterator>
389{
390 return it < end ? CharIterator::decode(getNextOf(it)) == c : false;
391}
392
393template <typename CharIterator>
395{
396 return it > start ? CharIterator::decode(getPreviousOf(it)) == c : false;
397}
398
399template <typename CharIterator>
401 StringIterator otherPoint) const
402{
403 SC_ASSERT_RELEASE(it <= otherPoint.it);
404 return StringIterator(it, otherPoint.it);
405}
406
407template <typename CharIterator>
409{
410 return (it - other.it) * static_cast<ssize_t>(sizeof(CodeUnit));
411}
412
413// StringIteratorASCII
414[[nodiscard]] constexpr bool StringIteratorASCII::advanceUntilMatches(CodePoint c)
415{
416 return __builtin_is_constant_evaluated() ? StringIterator::advanceUntilMatches(c)
417 : advanceUntilMatchesNonConstexpr(c);
418}
419
420} // namespace SC
#define SC_COMPILER_EXPORT
Macro for symbol visibility in non-MSVC compilers.
Definition: Compiler.h:78
#define SC_ASSERT_RELEASE(e)
Assert expression e to be true.
Definition: Assert.h:66
unsigned char uint8_t
Platform independent (1) byte unsigned int.
Definition: PrimitiveTypes.h:36
unsigned int uint32_t
Platform independent (4) bytes unsigned int.
Definition: PrimitiveTypes.h:38
signed long ssize_t
Platform independent signed size type.
Definition: PrimitiveTypes.h:57
uint32_t StringCodePoint
UTF code point (32 bit)
Definition: StringIterator.h:13
constexpr bool StringEncodingAreBinaryCompatible(StringEncoding encoding1, StringEncoding encoding2)
Checks if two encodings have the same utf unit size.
Definition: StringIterator.h:33
StringEncoding
String Encoding (Ascii, Utf8, Utf16)
Definition: StringIterator.h:17
constexpr uint32_t StringEncodingGetSize(StringEncoding encoding)
Returns the number of bytes to represent an utf unit in the given encoding.
Definition: StringIterator.h:42
@ Ascii
Encoding is ASCII.
@ Utf8
Encoding is UTF8.
@ Native
Encoding is UTF8.
@ Utf16
Encoding is UTF16-LE.
View over a contiguous sequence of items (pointer + size in elements).
Definition: Span.h:24
A string iterator for ASCII strings.
Definition: StringIterator.h:245
A position inside a fixed range [start, end) of UTF code points.
Definition: StringIterator.h:63
constexpr void setToStart()
Rewind current position to start of iterator range.
Definition: StringIterator.h:70
constexpr ssize_t bytesDistanceFrom(StringIterator other) const
Get distance in bytes from current position to another StringIterator current position.
Definition: StringIterator.h:408
constexpr void setToEnd()
Set current position to end of iterator range.
Definition: StringIterator.h:73
bool advanceUntilMatchesAny(Span< const CodePoint > items, CodePoint &matched)
Advances position until any CodePoint in the given Span is found.
bool advanceBackwardIfMatches(CodePoint c)
Move position by one code point towards start if previous code point matches c
constexpr bool advanceIfMatches(CodePoint c)
Advance position only if next code point matches c.
Definition: StringIterator.h:328
constexpr bool isAtStart() const
Check if current position is at start of iterator range.
Definition: StringIterator.h:81
bool reverseAdvanceUntilMatches(CodePoint c)
Moves position towards start until CodePoint c is found or position == end
bool advanceBeforeFinding(StringIterator other)
Advances position towards end until a matching range of character equal to other[it,...
bool advanceUntilDifferentFrom(CodePoint c, CodePoint *optionalReadChar=nullptr)
Advances position until a code point different from c is found or end is reached.
bool advanceAfterFinding(StringIterator other)
Advances position towards end until a matching range of character equal to other[it,...
bool startsWith(IteratorType other) const
Check if this Iterator at its start matches entirely another Iterator's range.
bool reverseAdvanceCodePoints(size_t numCodePoints)
Move position backwards (towards start) by variable number of code pints.
constexpr bool stepBackward()
Move position to previous code point.
Definition: StringIterator.h:362
constexpr bool advanceCodePoints(size_t numCodePoints)
Move position forward (towards end) by variable number of code points.
Definition: StringIterator.h:373
bool reverseAdvanceUntilMatchesAny(Span< const CodePoint > items, CodePoint &matched)
Moves position towards start until any CodePoint in the given Span is found.
constexpr bool stepForward()
Move position to next code point.
Definition: StringIterator.h:351
bool endsWithAnyOf(Span< const CodePoint > codePoints) const
Check if this Iterator ends with any code point in the given span.
bool advanceIfMatchesAny(Span< const CodePoint > items)
Advance position only if any of the code points in given Span is matched.
constexpr bool isFollowedBy(CodePoint c)
Check if next code point is c
Definition: StringIterator.h:388
bool advanceBackwardRead(CodePoint &c)
Move to previous position and read code unit.
bool startsWithAnyOf(Span< const CodePoint > codePoints) const
Check if this Iterator starts with any code point in the given span.
constexpr StringIterator sliceFromStartUntil(StringIterator otherPoint) const
Returns another StringIterator range, starting from start to otherPoint position.
Definition: StringIterator.h:400
constexpr bool isPrecededBy(CodePoint c)
Check if previous code point is c
Definition: StringIterator.h:394
constexpr bool advanceUntilMatches(CodePoint c)
Advances position towards end until it matches CodePoint c or position == end
Definition: StringIterator.h:316
bool read(CodePoint &c)
Read code unit at current position.
constexpr bool advanceRead(CodePoint &c)
Decode code unit at current position and advance.
Definition: StringIterator.h:339
bool match(CodePoint c)
Check if code unit at current position matches CodePoint c
Definition: StringIterator.h:153
constexpr bool isAtEnd() const
Check if current position is at end of iterator range.
Definition: StringIterator.h:77
bool advanceIfMatchesRange(CodePoint first, CodePoint last)
Advance position if any code point in the range [first, last] is matched.
bool endsWith(IteratorType other) const
Check if this Iterator at its end matches entirely another Iterator's range.
bool advanceByLengthOf(StringIterator other)
Advances position by the same number of code points as other.
Definition: StringIterator.h:108
Builds a constexpr bool skip table of 256 entries used in some parsers.
Definition: StringIterator.h:300
A string iterator for UTF16 strings.
Definition: StringIterator.h:264
A string iterator for UTF8 strings.
Definition: StringIterator.h:282
Non-owning view over a range of characters with UTF Encoding.
Definition: StringView.h:47