The Pedigree Project 0.1
StaticString.h
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#ifndef STATICSTRING_H
21#define STATICSTRING_H
22#include "pedigree/kernel/compiler.h"
23#include "pedigree/kernel/processor/types.h"
24#include "pedigree/kernel/utilities/String.h"
25#include "pedigree/kernel/utilities/assert.h"
26#include "pedigree/kernel/utilities/utility.h"
27
28#include <config.h>
29
34#define STATICSTRING_ASSERTS 0
35
36#if STATICSTRING_ASSERTS
37#define STATICSTRING_ASSERT(...) assert(__VA_ARGS__)
38#else
39#define STATICSTRING_ASSERT(...)
40#endif
41
48template <unsigned int N>
49class EXPORTED_PUBLIC StaticString {
50 public:
54 StaticString() : m_Length(0), m_Hash(0), m_AllowHashes(false) {
55 m_pData[0] = '\0';
56
57 updateHash();
58 }
59
65 explicit StaticString(const char* pSrc) : m_Length(0), m_Hash(0), m_AllowHashes(false) {
66 assign(pSrc);
67 }
68
74 StaticString(const char* pSrc, size_t len) : m_Length(0), m_Hash(0), m_AllowHashes(false) {
75 assign(pSrc, len);
76 }
77
79 StaticString(const String& str) : m_Length(0), m_Hash(0), m_AllowHashes(false) {
80 assign(str.cstr(), str.length());
81 }
82
87 template <unsigned int N2>
88 explicit StaticString(const StaticString<N2>& src)
89 : StaticString(static_cast<const char*>(src), src.length()) {}
90
91 operator const char*() const {
92 return m_pData;
93 }
94
95 template <unsigned int N2>
96 StaticString& operator+=(const StaticString<N2>& str) {
97 if (length() == 0) {
98 assign(str);
99 return *this;
100 }
101
102 append(str);
103 return *this;
104 }
105
106 template <typename T>
107 StaticString& operator+=(const T& i) {
108 append(i);
109 return *this;
110 }
111
112 void clear() {
113 m_Length = 0;
114 m_pData[0] = '\0';
115
116 updateHash();
117 }
118
119 void assign(const char* str, size_t len = 0) {
120 if (!str) {
121 clear();
122 return;
123 }
124
125 if (!len) {
126 len = min(N - 1, StringLength(str));
127 } else {
128 len = min(len, N - 1);
129 }
130
131 MemoryCopy(m_pData, str, len);
132
133 m_Length = len;
134 m_pData[len] = 0;
135
136 check();
137 updateHash();
138 }
139
140 void assign(const String& str) {
141 assign(str.cstr(), str.length());
142 }
143
144 template <unsigned int N2>
145 void assign(const StaticString<N2>& other) {
146 assign(other, other.length());
147 }
148
149 StaticString& operator=(const char* str) {
150 assign(str);
151 return *this;
152 }
153
154 StaticString& operator=(const String& str) {
155 assign(str);
156 return *this;
157 }
158
159 bool operator==(const char* pStr) const {
160 if (StringLength(pStr) != length()) {
161 return false;
162 }
163
164 return StringCompareN(m_pData, pStr, length()) == 0;
165 }
166
167 template <unsigned int N2>
168 bool operator==(const StaticString<N2>& other) const {
169 if (other.length() != length()) {
170 return false;
171 } else if ((m_AllowHashes && other.m_AllowHashes) && (m_Hash != other.hash())) {
172 return false;
173 }
174
175 return StringCompareN(m_pData, other.m_pData, length()) == 0;
176 }
177
178 int last(const char search) const {
179 for (int i = length(); i >= 0; i--)
180 if (m_pData[i] == search)
181 return i;
182 return -1;
183 }
184
185 int first(const char search) const {
186 for (size_t i = 0; i < length(); i++)
187 if (m_pData[i] == search)
188 return i;
189 return -1;
190 }
191
192 void stripLast() {
193 if (m_Length) {
194 m_pData[--m_Length] = '\0';
195 updateHash();
196 }
197 }
198
199 bool contains(const char* other) const {
200 return contains(m_pData, other, length(), StringLength(other));
201 }
202
203 template <unsigned int N2>
204 bool contains(const StaticString<N2>& other) const {
205 return contains(m_pData, other.m_pData, length(), other.length());
206 }
207
208 int intValue(int nBase = 0) const {
209 char* pEnd;
210 int ret = StringToUnsignedLong(m_pData, &pEnd, nBase);
211 if (pEnd == m_pData)
212 return -1; // Failed to find anything.
213 else
214 return ret;
215 }
216
217 uintptr_t uintptrValue(int nBase = 0) const {
218 char* pEnd;
219 uintptr_t ret = StringToUnsignedLong(m_pData, &pEnd, nBase);
220 if (pEnd == m_pData)
221 return ~0UL; // Failed to find anything.
222 else
223 return ret;
224 }
225
226 void truncate(size_t len) {
227 if (len > m_Length)
228 return;
229 m_Length = len;
230 m_pData[len] = '\0';
231
232 updateHash();
233 }
234
235 StaticString left(int n) const {
236 return StaticString<N>(m_pData, n);
237 }
238
239 StaticString right(int n) const {
242 return StaticString<N>(m_pData + n + 1, length() - n - 1);
243 }
244
245 StaticString& stripFirst(size_t n = 1) {
246 if (n > length()) {
247 m_pData[0] = '\0';
248 m_Length = 0;
249 return *this;
250 }
251 int i;
252 for (i = n; m_pData[i] != '\0'; i++)
253 m_pData[i - n] = m_pData[i];
254 m_pData[i - n] = '\0';
255 m_Length -= n;
256
257 updateHash();
258
259 return *this;
260 }
261
262 template <typename T>
263 StaticString& operator<<(const T& t) {
264 append(t);
265 return *this;
266 }
267
268 void append(char Char, size_t nLen = 0, char c = '0') {
269 char Characters[] = {Char, '\0'};
270 append(Characters, nLen, c);
271 }
272
273 void append(short nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0') {
274 if (nInt < 0) {
275 append("-");
276 unsigned short magnitude = static_cast<unsigned short>(-(nInt + 1));
277 append(++magnitude, nRadix, nLen, c);
278 return;
279 }
280 append(static_cast<unsigned short>(nInt), nRadix, nLen, c);
281 }
282
283 void append(int nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0') {
284 if (nInt < 0) {
285 append("-");
286 unsigned int magnitude = static_cast<unsigned int>(-(nInt + 1));
287 append(++magnitude, nRadix, nLen, c);
288 return;
289 }
290 append(static_cast<unsigned int>(nInt), nRadix, nLen, c);
291 }
292
293 void append(long nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0') {
294 if (nInt < 0) {
295 append("-");
296 unsigned long magnitude = static_cast<unsigned long>(-(nInt + 1));
297 append(++magnitude, nRadix, nLen, c);
298 return;
299 }
300 append(static_cast<unsigned long>(nInt), nRadix, nLen, c);
301 }
302
303 void append(long long nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0') {
304 if (nInt < 0) {
305 append("-");
306 unsigned long long magnitude = static_cast<unsigned long long>(-(nInt + 1));
307 append(++magnitude, nRadix, nLen, c);
308 return;
309 }
310 append(static_cast<unsigned long long>(nInt), nRadix, nLen, c);
311 }
312
313 void append(unsigned char nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0') {
314 appendInteger<sizeof(char)>(nInt, nRadix, nLen, c);
315 }
316
317 void append(unsigned short nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0') {
318 appendInteger<sizeof(short)>(nInt, nRadix, nLen, c);
319 }
320
321 void append(unsigned int nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0') {
322 appendInteger<sizeof(int)>(nInt, nRadix, nLen, c);
323 }
324
325 void append(unsigned long nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0') {
326 appendInteger<sizeof(long)>(nInt, nRadix, nLen, c);
327 }
328
329 void append(unsigned long long nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0') {
330 appendInteger<sizeof(long long)>(nInt, nRadix, nLen, c);
331 }
332
333 template <unsigned int size, typename T>
334 void appendInteger(T nInt, size_t nRadix, size_t nLen, char c) {
335 if (!canAppend() || (nRadix < 2) || (nRadix > 36)) {
336 // cannot append any longer
337 return;
338 }
339
340 char pStr[size * 8 + 1];
341 size_t index = 0;
342 do {
343 size_t tmp = nInt % nRadix;
344 nInt /= nRadix;
345 if (tmp < 10)
346 pStr[index++] = '0' + tmp;
347 else
348 pStr[index++] = 'a' + (tmp - 10);
349 } while (nInt != 0);
350
351 for (size_t i = 0; i < (index / 2); i++) {
352 char tmp = pStr[i];
353 pStr[i] = pStr[index - i - 1];
354 pStr[index - i - 1] = tmp;
355 }
356
357 pStr[index] = '\0';
358
359 append(pStr, nLen, c);
360 }
361
362 void append(const char* str, size_t nLen = 0, char c = ' ') {
363 if (!str || !canAppend()) {
364 return;
365 }
366
367 const size_t available = (N - 1) - m_Length;
368 size_t stringLength = nLen ? BoundedStringLength(str, nLen) : StringLength(str);
369 size_t padding = nLen > stringLength ? nLen - stringLength : 0;
370 padding = min(padding, available);
371
372 if (padding) {
373 ByteSet(m_pData + m_Length, c, padding);
374 m_Length += padding;
375 }
376
377 const size_t remaining = (N - 1) - m_Length;
378 const size_t copyLength = min(stringLength, remaining);
379 MemoryCopy(m_pData + m_Length, str, copyLength);
380 m_Length += copyLength;
381 m_pData[m_Length] = 0;
382
383 check();
384
385 updateHash();
386 }
387
388 void append(const String& str) {
389 append(str.cstr(), str.length());
390 }
391
392 void appendBytes(const char* bytes, size_t numBytes) {
393 if (!canAppend()) {
394 // cannot append any longer
395 return;
396 }
397
398 for (size_t i = 0; i < numBytes; ++i) {
399 char c = bytes[i];
400 if ((c < -1) || (c >= 0x20 && c != 0x7f)) {
401 // normal append (lets utf-8 and others still work in logs)
402 append(c);
403 } else {
404 // render \xXX formatted character code instead of raw character
405 append("\\x");
406 append(static_cast<unsigned int>(static_cast<unsigned char>(c)), 16, 2);
407 }
408 }
409 }
410
411 template <unsigned int N2>
412 void append(const StaticString<N2>& str, size_t nLen = 0, char c = ' ') {
413 if (!canAppend()) {
414 // cannot append any longer
415 return;
416 }
417
418 const size_t available = (N - 1) - m_Length;
419 const size_t stringLength = nLen ? min(nLen, str.length()) : str.length();
420 size_t padding = nLen > stringLength ? nLen - stringLength : 0;
421 padding = min(padding, available);
422 if (padding) {
423 ByteSet(m_pData + m_Length, c, padding);
424 m_Length += padding;
425 }
426
427 const size_t remaining = (N - 1) - m_Length;
428 const size_t copyLength = min(stringLength, remaining);
429 MemoryCopy(m_pData + m_Length, static_cast<const char*>(str), copyLength);
430 m_Length += copyLength;
431 m_pData[m_Length] = 0;
432
433 check();
434
435 updateHash();
436 }
437
438 void pad(size_t nLen, char c = ' ') {
439 if (!canAppend()) {
440 // cannot append any longer
441 return;
442 }
443
444 // Pad, if needed
445 if (nLen > length()) {
446 const size_t newLength = min(nLen, static_cast<size_t>(N - 1));
447 ByteSet(m_pData + m_Length, c, newLength - m_Length);
448 m_Length = newLength;
449 m_pData[m_Length] = '\0';
450 }
451
452 updateHash();
453 }
454
455 size_t length() const {
456 return m_Length;
457 }
458
459 uint64_t hash() const {
460 return m_Hash;
461 }
462
470 void allowHashing(bool computeNow = false) {
471 m_AllowHashes = true;
472 if (computeNow) {
473 updateHash();
474 }
475 }
476
479 m_AllowHashes = false;
480 }
481
482 private:
483 static bool contains(const char* a, const char* b, size_t alen, size_t blen) {
484 return StringContainsN(a, alen, b, blen) == 1;
485 }
486
487 void updateHash() {
488 if (m_AllowHashes) {
489 // sanity check
490 STATICSTRING_ASSERT(StringLength(m_pData) == m_Length);
491
492 m_Hash = spookyHash(m_pData, m_Length);
493 }
494 }
495
496 void check() {
497 if (m_Length >= N) {
498 m_pData[N - 1] = '\0';
499 m_Length = N - 1;
500 }
501 }
502
503 bool canAppend() const {
504 return m_Length < (N - 1);
505 }
506
510 char m_pData[N];
511
512 size_t m_Length;
513 uint64_t m_Hash;
514
515 bool m_AllowHashes;
516};
517
518// Specializations for the typedefs below (in StaticString.cc)
519extern template class EXPORTED_PUBLIC StaticString<32>; // IWYU pragma: keep
520extern template class EXPORTED_PUBLIC StaticString<64>; // IWYU pragma: keep
521extern template class EXPORTED_PUBLIC StaticString<128>; // IWYU pragma: keep
522extern template class EXPORTED_PUBLIC StaticString<1024>; // IWYU pragma: keep
523
528
531#endif
StaticString(const String &str)
void disableHashing()
void allowHashing(bool computeNow=false)
StaticString(const StaticString< N2 > &src)
StaticString(const char *pSrc, size_t len)
StaticString(const char *pSrc)
StaticString right(int n) const
bool operator==(const Iterator< originalT, Struct, FunctionPrev, FunctionNext, T1 > &x1, const Iterator< originalT, Struct, FunctionPrev, FunctionNext, T2 > &x2)
Definition Iterator.h:256