nlib
StringHolder.h
1 
2 /*--------------------------------------------------------------------------------*
3  Project: CrossRoad
4  Copyright (C)Nintendo All rights reserved.
5 
6  These coded instructions, statements, and computer programs contain proprietary
7  information of Nintendo and/or its licensed developers and are protected by
8  national and international copyright laws. They may not be disclosed to third
9  parties or copied or duplicated in any form, in whole or in part, without the
10  prior written consent of Nintendo.
11 
12  The content herein is highly confidential and should be handled accordingly.
13  *--------------------------------------------------------------------------------*/
14 
15 #pragma once
16 #ifndef INCLUDE_NN_NLIB_STRINGHOLDER_H_
17 #define INCLUDE_NN_NLIB_STRINGHOLDER_H_
18 
19 #include "nn/nlib/Config.h"
20 #include "nn/nlib/Swap.h"
21 
22 NLIB_NAMESPACE_BEGIN
23 
24 template<size_t N, class Ch = char>
25 class StringHolder NLIB_FINAL {
26  public:
27  NLIB_CEXPR14 StringHolder() NLIB_NOEXCEPT {
28  NLIB_STATIC_ASSERT(sizeof(Ch) == 1);
29  NLIB_STATIC_ASSERT(sizeof(Ch*) <= 8);
30  NLIB_STATIC_ASSERT(N >= 24);
31  NLIB_STATIC_ASSERT(N % 8 == 0);
32  str_.ptr = nullptr;
33  str_.sso[N - 1] = static_cast<Ch>(-1);
34  }
35  ~StringHolder() NLIB_NOEXCEPT {
36  if (str_.sso[N - 1] && str_.ptr) nlib_free(str_.ptr);
37  }
38 #ifdef __cpp_rvalue_references
39  StringHolder(StringHolder&& rhs) NLIB_NOEXCEPT : str_(rhs.str_) {
40  rhs.str_.ptr = nullptr;
41  rhs.str_.sso[N - 1] = static_cast<Ch>(-1);
42  }
43  StringHolder& operator=(StringHolder&& rhs) NLIB_NOEXCEPT {
44  nlib_memcpy(&str_.sso[0], N, &rhs.str_.sso[0], N);
45  rhs.str_.ptr = nullptr;
46  rhs.str_.sso[N - 1] = static_cast<Ch>(-1);
47  return *this;
48  }
49 #endif
50  StringHolder(StringHolder& rhs, move_tag) NLIB_NOEXCEPT : str_(rhs.str_) {
51  rhs.str_.ptr = nullptr;
52  rhs.str_.sso[N - 1] = static_cast<Ch>(-1);
53  }
54  StringHolder& assign(StringHolder& rhs, move_tag) NLIB_NOEXCEPT { // NOLINT
55  nlib_memcpy(static_cast<void*>(&str_.sso[0]), N,
56  static_cast<const void*>(&rhs.str_.sso[0]), N);
57  rhs.str_.ptr = nullptr;
58  rhs.str_.sso[N - 1] = static_cast<Ch>(-1);
59  return *this;
60  }
61  NLIB_DEPRECATED void swap(StringHolder& rhs) NLIB_NOEXCEPT { // NOLINT
62  Ch sso[N];
63  // cast for CTR
64  nlib_memcpy(static_cast<void*>(&sso[0]), sizeof(sso),
65  static_cast<const void*>(&str_), sizeof(str_));
66  nlib_memcpy(static_cast<void*>(&str_), sizeof(str_),
67  static_cast<const void*>(&rhs.str_), sizeof(rhs.str_));
68  nlib_memcpy(static_cast<void*>(&rhs.str_), sizeof(rhs.str_),
69  static_cast<const void*>(&sso[0]), sizeof(sso));
70  }
71  // NOTE: add move ctor/assign
72  errno_t Init(const Ch* first, const Ch* last) NLIB_NOEXCEPT;
73  errno_t Init(const Ch* str) NLIB_NOEXCEPT {
74  NLIB_ASSERT(str);
75  return Init(str, str + nlib_strlen(str));
76  }
77  size_t length() const NLIB_NOEXCEPT {
78  if (str_.sso[N - 1]) {
79  return str_.ptr ? static_cast<size_t>(str_.len.val) : 0U;
80  } else {
81  return nlib_strlen(&str_.sso[0]);
82  }
83  }
84  const Ch* c_str() const NLIB_NOEXCEPT {
85  return str_.sso[N - 1] ? str_.ptr : &str_.sso[0];
86  }
87  const Ch* get() const NLIB_NOEXCEPT {
88  // for unique_ptr<char[]> compatible
89  return c_str();
90  }
91  operator const Ch*() const NLIB_NOEXCEPT { return c_str(); }
92  void reset() NLIB_NOEXCEPT {
93  // for unique_ptr<char[]> compatible
94  if (str_.sso[N - 1]) {
95  if (str_.ptr) nlib_free(str_.ptr);
96  } else {
97  str_.sso[N - 1] = static_cast<Ch>(-1);
98  }
99  str_.ptr = nullptr;
100  }
101 
102  private:
103  union {
104  Ch sso[N];
105  Ch* ptr;
106  struct lentype {
107  uint64_t _;
108  uint64_t val;
109  } len;
110  } str_;
111  NLIB_DISALLOW_COPY_AND_ASSIGN(StringHolder);
112 };
113 
114 template<size_t N, class Ch>
115 errno_t StringHolder<N, Ch>::Init(const Ch* first, const Ch* last) NLIB_NOEXCEPT {
116  NLIB_ASSERT(first);
117  size_t n = std::distance(first, last);
118  Ch* p;
119  if (n + 1 > N) {
120  p = static_cast<Ch*>(nlib_malloc(n + 1));
121  if (!p) return ENOMEM;
122  if (str_.sso[N - 1]) {
123  if (str_.ptr) nlib_free(str_.ptr);
124  } else {
125  str_.sso[N - 1] = static_cast<Ch>(-1);
126  }
127  str_.ptr = p;
128  str_.len.val = n;
129  // cast for CTR
130  nlib_memcpy(static_cast<void*>(p), n + 1,
131  static_cast<const void*>(first), n);
132  p[n] = static_cast<Ch>('\0');
133  } else {
134  p = &str_.sso[0];
135  if (str_.sso[N - 1]) {
136  if (str_.ptr) nlib_free(str_.ptr);
137  str_.sso[N - 1] = static_cast<Ch>('\0');
138  }
139  // cast for CTR
140  nlib_memcpy(static_cast<void*>(p), N - 1,
141  static_cast<const void*>(first), n);
142  if (n != N - 1) {
143  p[n] = static_cast<Ch>('\0');
144  }
145  }
146  return 0;
147 }
148 
149 template<class Ch>
150 class StringHolder<16, Ch> NLIB_FINAL {
151  public:
152  NLIB_CEXPR14 StringHolder() NLIB_NOEXCEPT {
153  NLIB_STATIC_ASSERT(sizeof(Ch) == 1);
154  NLIB_STATIC_ASSERT(sizeof(Ch*) <= 8);
155  str_.ptr = nullptr;
156  str_.sso[15] = static_cast<Ch>(-1);
157  }
158  ~StringHolder() NLIB_NOEXCEPT {
159  if (str_.sso[15] && str_.ptr) nlib_free(str_.ptr);
160  }
161 #ifdef __cpp_rvalue_references
162  StringHolder(StringHolder&& rhs) NLIB_NOEXCEPT : str_(rhs.str_) {
163  rhs.str_.ptr = nullptr;
164  rhs.str_.sso[15] = static_cast<Ch>(-1);
165  }
166  StringHolder& operator=(StringHolder&& rhs) NLIB_NOEXCEPT {
167  nlib_memcpy(&str_.sso[0], 16, &rhs.str_.sso[0], 16);
168  rhs.str_.ptr = nullptr;
169  rhs.str_.sso[15] = static_cast<Ch>(-1);
170  return *this;
171  }
172 #endif
173  StringHolder(StringHolder& rhs, move_tag) NLIB_NOEXCEPT : str_(rhs.str_) {
174  rhs.str_.ptr = nullptr;
175  rhs.str_.sso[15] = static_cast<Ch>(-1);
176  }
177  StringHolder& assign(StringHolder& rhs, move_tag) NLIB_NOEXCEPT { // NOLINT
178  nlib_memcpy(static_cast<void*>(&str_.sso[0]), 16,
179  static_cast<const void*>(&rhs.str_.sso[0]), 16);
180  rhs.str_.ptr = nullptr;
181  rhs.str_.sso[15] = static_cast<Ch>(-1);
182  return *this;
183  }
184  NLIB_DEPRECATED void swap(StringHolder& rhs) NLIB_NOEXCEPT {
185  Ch sso[16];
186  // cast for CTR
187  nlib_memcpy(static_cast<void*>(&sso[0]), sizeof(sso),
188  static_cast<const void*>(&str_), sizeof(str_));
189  nlib_memcpy(static_cast<void*>(&str_), sizeof(str_),
190  static_cast<const void*>(&rhs.str_), sizeof(rhs.str_));
191  nlib_memcpy(static_cast<void*>(&rhs.str_), sizeof(rhs.str_),
192  static_cast<const void*>(&sso[0]), sizeof(sso));
193  }
194  // NOTE: add move ctor/assign
195  errno_t Init(const Ch* first, const Ch* last) NLIB_NOEXCEPT;
196  errno_t Init(const Ch* str) NLIB_NOEXCEPT {
197  NLIB_ASSERT(str);
198  return Init(str, str + nlib_strlen(str));
199  }
200  size_t length() const NLIB_NOEXCEPT {
201  if (str_.sso[15]) {
202  if (!str_.ptr) return 0U;
203  int64_t len = str_.len.minus;
204 #ifndef NLIB_LITTLE_ENDIAN
205  nlib_swapendian_64(reinterpret_cast<uint64_t*>(&len), 1);
206 #endif
207  return static_cast<size_t>(-len);
208  } else {
209  return nlib_strlen(&str_.sso[0]);
210  }
211  }
212  const Ch* c_str() const NLIB_NOEXCEPT {
213  return str_.sso[15] ? str_.ptr : &str_.sso[0];
214  }
215  const Ch* get() const NLIB_NOEXCEPT {
216  // for unique_ptr<char[]> compatible
217  return c_str();
218  }
219  operator const Ch*() const NLIB_NOEXCEPT { return c_str(); }
220  void reset() NLIB_NOEXCEPT {
221  // for unique_ptr<char[]> compatible
222  if (str_.sso[15]) {
223  if (str_.ptr) nlib_free(str_.ptr);
224  } else {
225  str_.sso[15] = static_cast<Ch>(-1);
226  }
227  str_.ptr = nullptr;
228  }
229 
230  private:
231  union {
232  Ch sso[16];
233  Ch* ptr;
234  struct lentype {
235  uint64_t _;
236  int64_t minus;
237  } len;
238  } str_;
239  NLIB_DISALLOW_COPY_AND_ASSIGN(StringHolder);
240 };
241 
242 template<class Ch>
243 errno_t StringHolder<16, Ch>::Init(const Ch* first, const Ch* last) NLIB_NOEXCEPT {
244  NLIB_ASSERT(first);
245  ptrdiff_t n = std::distance(first, last);
246  Ch* p;
247  if (n > 15) {
248  p = static_cast<Ch*>(nlib_malloc(n + 1));
249  if (!p) return ENOMEM;
250  if (str_.sso[15]) {
251  if (str_.ptr) nlib_free(str_.ptr);
252  }
253  str_.ptr = p;
254  str_.len.minus = -n;
255 #ifndef NLIB_LITTLE_ENDIAN
256  nlib_swapendian_64(reinterpret_cast<uint64_t*>(&str_.len.minus), 1);
257 #endif
258  // cast for CTR
259  nlib_memcpy(static_cast<void*>(p), n + 1,
260  static_cast<const void*>(first), n);
261  p[n] = static_cast<Ch>('\0');
262  } else {
263  p = &str_.sso[0];
264  if (str_.sso[15]) {
265  if (str_.ptr) nlib_free(str_.ptr);
266  str_.sso[15] = static_cast<Ch>('\0');
267  }
268  // cast for CTR
269  nlib_memcpy(static_cast<void*>(p), 15,
270  static_cast<const void*>(first), n);
271  if (n != 15) {
272  p[n] = static_cast<Ch>('\0');
273  }
274  }
275  return 0;
276 }
277 
278 template<class BYTE = nlib_byte_t, size_t N = 232>
279 class BytePool {
280  public:
281  BytePool() NLIB_NOEXCEPT {
282  NLIB_STATIC_ASSERT(sizeof(BYTE) == sizeof(nlib_byte_t));
283  cur_ = &init_buf_[0];
284  end_ = &init_buf_[0] + N;
285  chunk_stack_ = nullptr;
286  }
287  ~BytePool() NLIB_NOEXCEPT { Reset(); }
288  void Reset() NLIB_NOEXCEPT;
289  BYTE* Alloc(size_t n) NLIB_NOEXCEPT;
290 
291  private:
292  struct Chunk {
293  Chunk* next;
294  BYTE buf[1]; // hacked
295  };
296  BYTE* cur_;
297  BYTE* end_;
298  Chunk* chunk_stack_;
299  BYTE init_buf_[N];
301 };
302 
303 template<class BYTE, size_t N>
304 void BytePool<BYTE, N>::Reset() NLIB_NOEXCEPT {
305  Chunk* p = chunk_stack_;
306  while (p) {
307  Chunk* tmp = p->next;
308  nlib_free(p);
309  p = tmp;
310  }
311  cur_ = &init_buf_[0];
312  end_ = &init_buf_[0] + N;
313  chunk_stack_ = nullptr;
314 }
315 
316 template<class BYTE, size_t N>
317 BYTE* BytePool<BYTE, N>::Alloc(size_t n) NLIB_NOEXCEPT {
318  if (NLIB_UNLIKELY(n > static_cast<size_t>(end_ - cur_))) {
319  size_t real_n = (n + sizeof(Chunk*) + 4095) & ~4095;
320  Chunk* chk = static_cast<Chunk*>(nlib_malloc(real_n));
321  if (NLIB_UNLIKELY(!chk)) return nullptr;
322  chk->next = chunk_stack_;
323  chunk_stack_ = chk;
324  cur_ = &chk->buf[0];
325  end_ = reinterpret_cast<BYTE*>(chk) + real_n;
326  }
327  BYTE* p;
328  p = cur_;
329  cur_ += n;
330  return p;
331 }
332 
333 NLIB_NAMESPACE_END
334 
335 NLIB_DEFINE_STD_SWAP_T_BEGIN2(nn, nlib) // NOLINT
336 #ifndef __cpp_rvalue_references
337 template<size_t N, class Ch> NLIB_ALWAYS_INLINE
338 void swap(nlib_ns::StringHolder<N, Ch>& lhs, nlib_ns::StringHolder<N, Ch>& rhs) /* NOLINT */ {
339  nlib_ns::StringHolder<N, Ch> x(lhs, nlib_ns::move_tag());
340  lhs.assign(rhs, nlib_ns::move_tag());
341  rhs.assign(x, nlib_ns::move_tag());
342 }
343 #endif
344 NLIB_DEFINE_STD_SWAP_T_END2(nn, nlib) // NOLINT
345 
346 #endif // INCLUDE_NN_NLIB_STRINGHOLDER_H_
#define NLIB_ALWAYS_INLINE
Indicates that the compiler is forced to perform inline expansion of functions.
Definition: Platform_unix.h:97
#define NLIB_DISALLOW_COPY_AND_ASSIGN(TypeName)
Prohibits use of the copy constructor and assignment operator for the class specified by TypeName...
Definition: Config.h:179
Definition: Base64.h:25
#define NLIB_UNLIKELY(x)
Indicates to the compiler that condition x is likely to be false.
#define NLIB_CEXPR14
constexpr is defined if C++14 constexpr is available for use. If not, holds an empty string...
Definition: Config.h:108
#define NLIB_DEPRECATED
Indicates that a function or something has been deprecated.
Definition: Config.h:109
void * nlib_malloc(size_t size)
A weak function that calls the C standard function malloc. nlib calls malloc via this function...
An empty structure indicating that an argument to a function needs to be moved.
Definition: Config.h:265
static errno_t nlib_memcpy(void *s1, size_t s1max, const void *s2, size_t n)
An implementation corresponding to N1078 memcpy_s.
Definition: Platform.h:2437
#define NLIB_NOEXCEPT
Defines noexcept geared to the environment, or the equivalent.
Definition: Config.h:105
A file that contains the configuration information for each development environment.
size_t nlib_strlen(const char *s)
Internally calls strlen(). In some cases, it may operate as an independent implementation.
#define NLIB_FINAL
Defines final if it is available for use. If not, holds an empty string.
Definition: Config.h:245
#define NLIB_STATIC_ASSERT(exp)
Defines a static assertion. Uses static_assert if it is available for use.
Definition: Config.h:170
void nlib_free(void *ptr)
A weak function that calls the C standard function free. nlib calls free via this function...
errno_t nlib_swapendian_64(uint64_t *p, size_t count)
Swaps the endianness.
unsigned char nlib_byte_t
This type will be defined as std::byte in a typedef of C++17 or later.
Definition: Platform.h:319
int errno_t
Indicates with an int-type typedef that a POSIX error value is returned as the return value...
Definition: NMalloc.h:37