Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
AsciiSet.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Misc/Char.h"
6
7/**
8 * ASCII character bitset useful for fast and readable parsing
9 *
10 * Entirely constexpr. Works with both wide and narrow strings.
11 *
12 * Example use cases:
13 *
14 * constexpr FAsciiSet WhitespaceCharacters(" \v\f\t\r\n");
15 * bool bIsWhitespace = WhitespaceCharacters.Test(MyChar);
16 * const char* HelloWorld = FAsciiSet::Skip(" \t\tHello world!", WhitespaceCharacters);
17 *
18 * constexpr FAsciiSet XmlEscapeChars("&<>\"'");
19 * check(FAsciiSet::HasNone(EscapedXmlString, XmlEscapeChars));
20 *
21 * constexpr FAsciiSet Delimiters(".:;");
22 * const TCHAR* DelimiterOrEnd = FAsciiSet::FindFirstOrEnd(PrefixedName, Delimiters);
23 * FString Prefix(PrefixedName, DelimiterOrEnd - PrefixedName);
24 *
25 * constexpr FAsciiSet Slashes("/\\");
26 * const TCHAR* SlashOrEnd = FAsciiSet::FindLastOrEnd(PathName, Slashes);
27 * const TCHAR* FileName = *SlashOrEnd ? SlashOrEnd + 1 : PathName;
28 */
29class FAsciiSet
30{
31public:
32 template<typename CharType, int N>
33 constexpr FAsciiSet(const CharType(&Chars)[N])
34 : FAsciiSet(StringToBitset(Chars))
35 {}
36
37 /** Returns true if a character is part of the set */
38 template<typename CharType>
39 constexpr FORCEINLINE bool Contains(CharType Char) const
40 {
41 return !!TestImpl(TChar<CharType>::ToUnsigned(Char));
42 }
43
44 /** Returns non-zero if a character is part of the set. Prefer Contains() to avoid VS2019 conversion warnings. */
45 template<typename CharType>
46 constexpr FORCEINLINE uint64 Test(CharType Char) const
47 {
48 return TestImpl(TChar<CharType>::ToUnsigned(Char));
49 }
50
51 /** Create new set with specified character in it */
52 constexpr FORCEINLINE FAsciiSet operator+(char Char) const
53 {
54 InitData Bitset = { LoMask, HiMask };
55 SetImpl(Bitset, TChar<char>::ToUnsigned(Char));
56 return FAsciiSet(Bitset);
57 }
58
59 /** Create new set containing inverse set of characters - likely including null-terminator */
60 constexpr FORCEINLINE FAsciiSet operator~() const
61 {
62 return FAsciiSet(~LoMask, ~HiMask);
63 }
64
65 ////////// Algorithms for C strings //////////
66
67 /** Find first character of string inside set or end pointer. Never returns null. */
68 template<class CharType>
69 static constexpr const CharType* FindFirstOrEnd(const CharType* Str, FAsciiSet Set)
70 {
71 for (FAsciiSet SetOrNil(Set.LoMask | NilMask, Set.HiMask); !SetOrNil.Test(*Str); ++Str);
72
73 return Str;
74 }
75
76 /** Find last character of string inside set or end pointer. Never returns null. */
77 template<class CharType>
78 static constexpr const CharType* FindLastOrEnd(const CharType* Str, FAsciiSet Set)
79 {
80 const CharType* Last = FindFirstOrEnd(Str, Set);
81
82 for (const CharType* It = Last; *It; It = FindFirstOrEnd(It + 1, Set))
83 {
84 Last = It;
85 }
86
87 return Last;
88 }
89
90 /** Find first character of string outside of set. Never returns null. */
91 template<typename CharType>
92 static constexpr const CharType* Skip(const CharType* Str, FAsciiSet Set)
93 {
94 while (Set.Contains(*Str))
95 {
96 ++Str;
97 }
98
99 return Str;
100 }
101
102 /** Test if string contains any character in set */
103 template<typename CharType>
104 static constexpr bool HasAny(const CharType* Str, FAsciiSet Set)
105 {
106 return *FindFirstOrEnd(Str, Set) != '\0';
107 }
108
109 /** Test if string contains no character in set */
110 template<typename CharType>
111 static constexpr bool HasNone(const CharType* Str, FAsciiSet Set)
112 {
113 return *FindFirstOrEnd(Str, Set) == '\0';
114 }
115
116 /** Test if string contains any character outside of set */
117 template<typename CharType>
118 static constexpr bool HasOnly(const CharType* Str, FAsciiSet Set)
119 {
120 return *Skip(Str, Set) == '\0';
121 }
122
123 ////////// Algorithms for string types like FStringView and FString //////////
124
125 /** Get initial substring with all characters in set */
126 template<class StringType>
127 static constexpr StringType FindPrefixWith(const StringType& Str, FAsciiSet Set)
128 {
129 return Scan<EDir::Forward, EInclude::Members, EKeep::Head>(Str, Set);
130 }
131
132 /** Get initial substring with no characters in set */
133 template<class StringType>
134 static constexpr StringType FindPrefixWithout(const StringType& Str, FAsciiSet Set)
135 {
136 return Scan<EDir::Forward, EInclude::NonMembers, EKeep::Head>(Str, Set);
137 }
138
139 /** Trim initial characters in set */
140 template<class StringType>
141 static constexpr StringType TrimPrefixWith(const StringType& Str, FAsciiSet Set)
142 {
143 return Scan<EDir::Forward, EInclude::Members, EKeep::Tail>(Str, Set);
144 }
145
146 /** Trim initial characters not in set */
147 template<class StringType>
148 static constexpr StringType TrimPrefixWithout(const StringType& Str, FAsciiSet Set)
149 {
150 return Scan<EDir::Forward, EInclude::NonMembers, EKeep::Tail>(Str, Set);
151 }
152
153 /** Get trailing substring with all characters in set */
154 template<class StringType>
155 static constexpr StringType FindSuffixWith(const StringType& Str, FAsciiSet Set)
156 {
157 return Scan<EDir::Reverse, EInclude::Members, EKeep::Tail>(Str, Set);
158 }
159
160 /** Get trailing substring with no characters in set */
161 template<class StringType>
162 static constexpr StringType FindSuffixWithout(const StringType& Str, FAsciiSet Set)
163 {
164 return Scan<EDir::Reverse, EInclude::NonMembers, EKeep::Tail>(Str, Set);
165 }
166
167 /** Trim trailing characters in set */
168 template<class StringType>
169 static constexpr StringType TrimSuffixWith(const StringType& Str, FAsciiSet Set)
170 {
171 return Scan<EDir::Reverse, EInclude::Members, EKeep::Head>(Str, Set);
172 }
173
174 /** Trim trailing characters not in set */
175 template<class StringType>
176 static constexpr StringType TrimSuffixWithout(const StringType& Str, FAsciiSet Set)
177 {
178 return Scan<EDir::Reverse, EInclude::NonMembers, EKeep::Head>(Str, Set);
179 }
180
181 /** Test if string contains any character in set */
182 template<class StringType>
183 static constexpr bool HasAny(const StringType& Str, FAsciiSet Set)
184 {
185 return !HasNone(Str, Set);
186 }
187
188 /** Test if string contains no character in set */
189 template<class StringType>
190 static constexpr bool HasNone(const StringType& Str, FAsciiSet Set)
191 {
192 uint64 Match = 0;
193 for (auto Char : Str)
194 {
195 Match |= Set.Test(Char);
196 }
197 return Match == 0;
198 }
199
200 /** Test if string contains any character outside of set */
201 template<class StringType>
202 static constexpr bool HasOnly(const StringType& Str, FAsciiSet Set)
203 {
204 auto End = GetData(Str) + GetNum(Str);
205 return FindFirst<EInclude::Members>(Set, GetData(Str), End) == End;
206 }
207
208private:
209 enum class EDir {Forward, Reverse};
210 enum class EInclude {Members, NonMembers};
211 enum class EKeep {Head, Tail};
212
213 template<EInclude Include, typename CharType>
214 static constexpr const CharType* FindFirst(FAsciiSet Set, const CharType* It, const CharType* End)
215 {
216 for (; It != End && (Include == EInclude::Members) == !!Set.Test(*It); ++It);
217 return It;
218 }
219
220 template<EInclude Include, typename CharType>
221 static constexpr const CharType* FindLast(FAsciiSet Set, const CharType* It, const CharType* End)
222 {
223 for (; It != End && (Include == EInclude::Members) == !!Set.Test(*It); --It);
224 return It;
225 }
226
227 template<EDir Dir, EInclude Include, EKeep Keep, class StringType>
228 static constexpr StringType Scan(const StringType& Str, FAsciiSet Set)
229 {
230 auto Begin = GetData(Str);
231 auto End = Begin + GetNum(Str);
232 auto It = Dir == EDir::Forward ? FindFirst<Include>(Set, Begin, End)
233 : FindLast<Include>(Set, End - 1, Begin - 1) + 1;
234
235 return Keep == EKeep::Head ? StringType(Begin, static_cast<int32>(It - Begin))
236 : StringType(It, static_cast<int32>(End - It));
237 }
238
239 // Work-around for constexpr limitations
240 struct InitData { uint64 Lo, Hi; };
241 static constexpr uint64 NilMask = uint64(1) << '\0';
242
243 static constexpr FORCEINLINE void SetImpl(InitData& Bitset, uint32 Char)
244 {
245 uint64 IsLo = uint64(0) - (Char >> 6 == 0);
246 uint64 IsHi = uint64(0) - (Char >> 6 == 1);
247 uint64 Bit = uint64(1) << uint8(Char & 0x3f);
248
249 Bitset.Lo |= Bit & IsLo;
250 Bitset.Hi |= Bit & IsHi;
251 }
252
253 constexpr FORCEINLINE uint64 TestImpl(uint32 Char) const
254 {
255 uint64 IsLo = uint64(0) - (Char >> 6 == 0);
256 uint64 IsHi = uint64(0) - (Char >> 6 == 1);
257 uint64 Bit = uint64(1) << (Char & 0x3f);
258
259 return (Bit & IsLo & LoMask) | (Bit & IsHi & HiMask);
260 }
261
262 template<typename CharType, int N>
263 static constexpr InitData StringToBitset(const CharType(&Chars)[N])
264 {
265 InitData Bitset = { 0, 0 };
266 for (int I = 0; I < N - 1; ++I)
267 {
268 SetImpl(Bitset, TChar<CharType>::ToUnsigned(Chars[I]));
269 }
270
271 return Bitset;
272 }
273
274 constexpr FAsciiSet(InitData Bitset)
275 : LoMask(Bitset.Lo), HiMask(Bitset.Hi)
276 {}
277
278 constexpr FAsciiSet(uint64 Lo, uint64 Hi)
279 : LoMask(Lo), HiMask(Hi)
280 {}
281
282 uint64 LoMask, HiMask;
283};
#define FORCEINLINE
Definition Platform.h:644