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 
23 #include "pedigree/kernel/compiler.h"
24 #include "pedigree/kernel/processor/types.h"
25 #include "pedigree/kernel/utilities/assert.h"
26 #include "pedigree/kernel/utilities/utility.h"
27 
32 #define STATICSTRING_ASSERTS 0
33 
34 #if STATICSTRING_ASSERTS
35 #define STATICSTRING_ASSERT(...) assert(__VA_ARGS__)
36 #else
37 #define STATICSTRING_ASSERT(...)
38 #endif
39 
46 template <unsigned int N>
48 {
49  public:
53  StaticString() : m_Length(0), m_Hash(0), m_AllowHashes(false)
54  {
55  m_pData[0] = '\0';
56 
57  updateHash();
58  }
59 
65  explicit StaticString(const char *pSrc) : m_Length(StringLength(pSrc)), m_Hash(0), m_AllowHashes(false)
66  {
67  assign(pSrc);
68  }
69 
75  StaticString(const char *pSrc, size_t len) : m_Length(0), m_Hash(0), m_AllowHashes(false)
76  {
77  assign(pSrc, len);
78  }
79 
84  template <unsigned int N2>
85  explicit StaticString(const StaticString<N2> &src) : StaticString(static_cast<const char *>(src), src.length()) {}
86 
87  operator const char *() const
88  {
89  return m_pData;
90  }
91 
92  template <unsigned int N2>
93  StaticString &operator+=(const StaticString<N2> &str)
94  {
95  if (length() == 0)
96  {
97  assign(str);
98  return *this;
99  }
100 
101  append(str);
102  return *this;
103  }
104 
105  template <typename T>
106  StaticString &operator+=(T i)
107  {
108  append(i);
109  return *this;
110  }
111 
112  void clear()
113  {
114  m_Length = 0;
115  m_pData[0] = '\0';
116 
117  updateHash();
118  }
119 
120  void assign(const char *str, size_t len=0)
121  {
122  if (!len)
123  {
124  len = min(N - 1, StringLength(str));
125  }
126  else
127  {
128  len = min(len, N - 1);
129  }
130 
132  ForwardMemoryCopy(m_pData, str, len);
133 
134  m_Length = len;
135  m_pData[len] = 0;
136 
137  check();
138  updateHash();
139  }
140 
141  template <unsigned int N2>
142  void assign(const StaticString<N2> &other)
143  {
144  assign(other, other.length());
145  }
146 
147  StaticString &operator=(const char *str)
148  {
149  assign(str);
150  return *this;
151  }
152 
153  bool operator==(const char *pStr) const
154  {
155  if (StringLength(pStr) != length())
156  {
157  return false;
158  }
159 
160  return StringCompareN(m_pData, pStr, length()) == 0;
161  }
162 
163  template <unsigned int N2>
164  bool operator==(const StaticString<N2> &other) const
165  {
166  if (other.length() != length())
167  {
168  return false;
169  }
170  else if ((m_AllowHashes && other.m_AllowHashes) && (m_Hash != other.hash()))
171  {
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  {
180  for (int i = length(); i >= 0; i--)
181  if (m_pData[i] == search)
182  return i;
183  return -1;
184  }
185 
186  int first(const char search) const
187  {
188  for (size_t i = 0; i < length(); i++)
189  if (m_pData[i] == search)
190  return i;
191  return -1;
192  }
193 
194  void stripLast()
195  {
196  if (m_Length)
197  {
198  m_pData[--m_Length] = '\0';
199  updateHash();
200  }
201  }
202 
203  bool contains(const char *other) const
204  {
205  return contains(m_pData, other, length(), StringLength(other));
206  }
207 
208  template <unsigned int N2>
209  bool contains(const StaticString<N2> &other) const
210  {
211  return contains(m_pData, other.m_pData, length(), other.length());
212  }
213 
214  int intValue(int nBase = 0) const
215  {
216  const char *pEnd;
217  int ret = StringToUnsignedLong(m_pData, &pEnd, nBase);
218  if (pEnd == m_pData)
219  return -1; // Failed to find anything.
220  else
221  return ret;
222  }
223 
224  uintptr_t uintptrValue(int nBase = 0) const
225  {
226  const char *pEnd;
227  uintptr_t ret = StringToUnsignedLong(m_pData, &pEnd, nBase);
228  if (pEnd == m_pData)
229  return ~0UL; // Failed to find anything.
230  else
231  return ret;
232  }
233 
234  void truncate(size_t len)
235  {
236  if (len > m_Length)
237  return;
238  m_Length = len;
239  m_pData[len] = '\0';
240 
241  updateHash();
242  }
243 
244  StaticString left(int n) const
245  {
246  return StaticString<N>(m_pData, n);
247  }
248 
249  StaticString right(int n) const
250  {
253  return StaticString<N>(m_pData + n + 1, length() - n - 1);
254  }
255 
256  StaticString &stripFirst(size_t n = 1)
257  {
258  if (n > length())
259  {
260  m_pData[0] = '\0';
261  m_Length = 0;
262  return *this;
263  }
264  int i;
265  for (i = n; m_pData[i] != '\0'; i++)
266  m_pData[i - n] = m_pData[i];
267  m_pData[i - n] = '\0';
268  m_Length -= n;
269 
270  updateHash();
271 
272  return *this;
273  }
274 
275  template <typename T>
276  StaticString &operator<<(T t)
277  {
278  append(t);
279  return *this;
280  }
281 
282  void append(char Char, size_t nLen = 0, char c = '0')
283  {
284  char Characters[] = {Char, '\0'};
285  append(Characters, nLen, c);
286  }
287 
288  void append(short nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0')
289  {
290  if (nInt < 0)
291  {
292  append("-");
293  nInt = -nInt;
294  }
295  append(static_cast<unsigned short>(nInt), nRadix, nLen, c);
296  }
297 
298  void append(int nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0')
299  {
300  if (nInt < 0)
301  {
302  append("-");
303  nInt = -nInt;
304  }
305  append(static_cast<unsigned int>(nInt), nRadix, nLen, c);
306  }
307 
308  void append(long nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0')
309  {
310  if (nInt < 0)
311  {
312  append("-");
313  nInt = -nInt;
314  }
315  append(static_cast<unsigned long>(nInt), nRadix, nLen, c);
316  }
317 
318  void
319  append(long long nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0')
320  {
321  if (nInt < 0)
322  {
323  append("-");
324  nInt = -nInt;
325  }
326  append(static_cast<unsigned long long>(nInt), nRadix, nLen, c);
327  }
328 
329  void append(
330  unsigned char nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0')
331  {
332  appendInteger<sizeof(char)>(nInt, nRadix, nLen, c);
333  }
334 
335  void append(
336  unsigned short nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0')
337  {
338  appendInteger<sizeof(short)>(nInt, nRadix, nLen, c);
339  }
340 
341  void
342  append(unsigned int nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0')
343  {
344  appendInteger<sizeof(int)>(nInt, nRadix, nLen, c);
345  }
346 
347  void append(
348  unsigned long nInt, size_t nRadix = 10, size_t nLen = 0, char c = '0')
349  {
350  appendInteger<sizeof(long)>(nInt, nRadix, nLen, c);
351  }
352 
353  void append(
354  unsigned long long nInt, size_t nRadix = 10, size_t nLen = 0,
355  char c = '0')
356  {
357  appendInteger<sizeof(long long)>(nInt, nRadix, nLen, c);
358  }
359 
360  template <unsigned int size, typename T>
361  void appendInteger(T nInt, size_t nRadix, size_t nLen, char c)
362  {
363  if (!canAppend())
364  {
365  // cannot append any longer
366  return;
367  }
368 
369  char pStr[size * 8 + 1];
370  size_t index = 0;
371  do
372  {
373  size_t tmp = nInt % nRadix;
374  nInt /= nRadix;
375  if (tmp < 10)
376  pStr[index++] = '0' + tmp;
377  else
378  pStr[index++] = 'a' + (tmp - 10);
379  } while (nInt != 0);
380 
381  for (size_t i = 0; i < (index / 2); i++)
382  {
383  char tmp = pStr[i];
384  pStr[i] = pStr[index - i - 1];
385  pStr[index - i - 1] = tmp;
386  }
387 
388  pStr[index] = '\0';
389 
390  append(pStr, nLen, c);
391  }
392 
393  void append(const char *str, size_t nLen = 0, char c = ' ')
394  {
395  if (!canAppend())
396  {
397  // cannot append any longer
398  return;
399  }
400 
401  if (nLen == 0 && length() == 0)
402  {
403  assign(str);
404  return;
405  }
406 
407  // Only need to add padding if nLen > 0, as if it's zero we are not
408  // trying to fill a particular width with the appended string.
409  if (nLen)
410  {
412  size_t length2 = min(nLen, StringLength(str));
413 
414  if (nLen > length2)
415  {
416  // need padding
417  size_t i;
418  for (i = 0; i < nLen - length2; i++)
419  {
420  m_pData[i + length()] = c;
421  }
422  m_pData[i + length()] = '\0';
423  m_Length += nLen - length2;
424 
425  nLen - length2;
426  }
427  }
428 
429  // Append.
430  size_t i = m_Length;
431  size_t appended = 0;
432  // NOTE: we split here so we aren't checking if(nLen) every iteration
433  if (nLen)
434  {
435  while ((i <= N) && (appended++ < nLen) && *str)
436  {
437  m_pData[i++] = *str++;
438  }
439 
440  m_Length = i;
441  m_pData[i] = 0;
442  }
443  else
444  {
445  size_t otherLen = StringLength(str);
446  size_t copyLen = min(N - length(), otherLen);
447 
448  // not allowing memmove here - append by definition won't overlap
449  ForwardMemoryCopy(m_pData + length(), str, copyLen);
450 
451  m_Length += copyLen;
452  m_pData[m_Length] = 0;
453  }
454 
455  check();
456 
457  updateHash();
458  }
459 
460  void appendBytes(const char *bytes, size_t numBytes)
461  {
462  if (!canAppend())
463  {
464  // cannot append any longer
465  return;
466  }
467 
468  for (size_t i = 0; i < numBytes; ++i)
469  {
470  char c = bytes[i];
471  if ((c < -1) || (c >= 0x20 && c != 0x7f))
472  {
473  // normal append (lets utf-8 and others still work in logs)
474  append(c);
475  }
476  else
477  {
478  // render \xXX formatted character code instead of raw character
479  append("\\x");
480  append(static_cast<unsigned int>(c), 16, 2);
481  }
482  }
483  }
484 
485  template <unsigned int N2>
486  void append(const StaticString<N2> &str, size_t nLen = 0, char c = ' ')
487  {
488  if (!canAppend())
489  {
490  // cannot append any longer
491  return;
492  }
493 
494  if (nLen == 0 && length() == 0)
495  {
496  assign(str);
497  return;
498  }
499 
500  // Pad, if needed
501  if (nLen > str.length())
502  {
503  size_t i;
504  for (i = 0; i < nLen - str.length(); i++)
505  {
506  m_pData[i + length()] = c;
507  }
508  m_pData[i + length()] = '\0';
509  m_Length += nLen - str.length();
510  }
511 
512  // Add the string
513  // note: not allowing memmove here - append by definition won't overlap
514  ForwardMemoryCopy(m_pData + length(), str, N - length());
515  m_Length += str.length();
516  m_pData[m_Length] = 0;
517 
518  check();
519 
520  updateHash();
521  }
522 
523  void pad(size_t nLen, char c = ' ')
524  {
525  if (!canAppend())
526  {
527  // cannot append any longer
528  return;
529  }
530 
531  // Pad, if needed
532  if (nLen > length())
533  {
534  size_t i;
535  for (i = 0; i < nLen - length(); i++)
536  {
537  m_pData[i + length()] = c;
538  }
539  m_pData[i + length()] = '\0';
540  m_Length += nLen - length();
541  }
542 
543  updateHash();
544  }
545 
546  size_t length() const
547  {
548  return m_Length;
549  }
550 
551  uint64_t hash() const
552  {
553  return m_Hash;
554  }
555 
563  void allowHashing(bool computeNow=false)
564  {
565  m_AllowHashes = true;
566  if (computeNow)
567  {
568  updateHash();
569  }
570  }
571 
574  {
575  m_AllowHashes = false;
576  }
577 
578  private:
579  static bool contains(const char *a, const char *b, size_t alen, size_t blen)
580  {
581  return StringContainsN(a, alen, b, blen) == 1;
582  }
583 
584  void updateHash()
585  {
586  if (m_AllowHashes)
587  {
588  // sanity check
589  STATICSTRING_ASSERT(StringLength(m_pData) == m_Length);
590 
591  m_Hash = spookyHash(m_pData, m_Length);
592  }
593  }
594 
595  void check()
596  {
597  if (m_Length >= N)
598  {
599  m_pData[N - 1] = '\0';
600  m_Length = N - 1;
601  }
602  }
603 
604  bool canAppend() const
605  {
606  return m_Length < (N - 1);
607  }
608 
612  char m_pData[N];
613 
614  size_t m_Length;
615  uint64_t m_Hash;
616 
617  bool m_AllowHashes;
618 };
619 
620 // Specializations for the typedefs below (in StaticString.cc)
621 extern template class EXPORTED_PUBLIC StaticString<32>; // IWYU pragma: keep
622 extern template class EXPORTED_PUBLIC StaticString<64>; // IWYU pragma: keep
623 extern template class EXPORTED_PUBLIC StaticString<128>; // IWYU pragma: keep
624 extern template class EXPORTED_PUBLIC StaticString<1024>; // IWYU pragma: keep
625 
626 typedef StaticString<32> TinyStaticString;
627 typedef StaticString<64> NormalStaticString;
628 typedef StaticString<128> LargeStaticString;
629 typedef StaticString<1024> HugeStaticString;
630 
633 #endif
void assign(const char *str, size_t len=0)
Definition: StaticString.h:120
StaticString right(int n) const
Definition: StaticString.h:249
void allowHashing(bool computeNow=false)
Definition: StaticString.h:563
StaticString(const char *pSrc, size_t len)
Definition: StaticString.h:75
StaticString(const char *pSrc)
Definition: StaticString.h:65
char m_pData[N]
Definition: StaticString.h:612
void disableHashing()
Definition: StaticString.h:573
bool operator==(const Iterator< originalT, Struct, FunctionPrev, FunctionNext, T1 > &x1, const Iterator< originalT, Struct, FunctionPrev, FunctionNext, T2 > &x2)
Definition: Iterator.h:326
StaticString(const StaticString< N2 > &src)
Definition: StaticString.h:85
void append(const char *str, size_t nLen=0, char c= ' ')
Definition: StaticString.h:393