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 <iterator>
20 #include "nn/nlib/Config.h"
21 #include "nn/nlib/Swap.h"
22 
23 NLIB_NAMESPACE_BEGIN
24 
25 template<size_t N, class Ch = char>
26 class StringHolder NLIB_FINAL {
27  public:
28  NLIB_CEXPR14 StringHolder() NLIB_NOEXCEPT {
29  NLIB_STATIC_ASSERT(sizeof(Ch) == 1);
30  NLIB_STATIC_ASSERT(sizeof(Ch*) <= 8);
31  NLIB_STATIC_ASSERT(N >= 24);
32  NLIB_STATIC_ASSERT(N % 8 == 0);
33  str_.ptr = nullptr;
34  str_.sso[N - 1] = static_cast<Ch>(-1);
35  }
36  ~StringHolder() NLIB_NOEXCEPT {
37  if (str_.sso[N - 1] && str_.ptr) nlib_free(str_.ptr);
38  }
39 #ifdef __cpp_rvalue_references
40  StringHolder(StringHolder&& rhs) NLIB_NOEXCEPT : str_(rhs.str_) {
41  rhs.str_.ptr = nullptr;
42  rhs.str_.sso[N - 1] = static_cast<Ch>(-1);
43  }
44  StringHolder& operator=(StringHolder&& rhs) NLIB_NOEXCEPT {
45  nlib_memcpy(&str_.sso[0], N, &rhs.str_.sso[0], N);
46  rhs.str_.ptr = nullptr;
47  rhs.str_.sso[N - 1] = static_cast<Ch>(-1);
48  return *this;
49  }
50 #endif
51  StringHolder(StringHolder& rhs, move_tag) NLIB_NOEXCEPT : str_(rhs.str_) {
52  rhs.str_.ptr = nullptr;
53  rhs.str_.sso[N - 1] = static_cast<Ch>(-1);
54  }
55  StringHolder& assign(StringHolder& rhs, move_tag) NLIB_NOEXCEPT {
56  nlib_memcpy(static_cast<void*>(&str_.sso[0]), N, static_cast<const void*>(&rhs.str_.sso[0]),
57  N);
58  rhs.str_.ptr = nullptr;
59  rhs.str_.sso[N - 1] = static_cast<Ch>(-1);
60  return *this;
61  }
62  // NOTE: add move ctor/assign
63  errno_t Init(const Ch* first, const Ch* last) NLIB_NOEXCEPT;
64  errno_t Init(const Ch* str) NLIB_NOEXCEPT {
65  NLIB_ASSERT(str);
66  return Init(str, str + nlib_strlen(str));
67  }
68  size_t length() const NLIB_NOEXCEPT {
69  if (str_.sso[N - 1]) {
70  return str_.ptr ? static_cast<size_t>(str_.len.val) : 0U;
71  } else {
72  return nlib_strlen(&str_.sso[0]);
73  }
74  }
75  const Ch* c_str() const NLIB_NOEXCEPT { return str_.sso[N - 1] ? str_.ptr : &str_.sso[0]; }
76  const Ch* get() const NLIB_NOEXCEPT {
77  // for unique_ptr<char[]> compatible
78  return c_str();
79  }
80  operator const Ch*() const NLIB_NOEXCEPT { return c_str(); }
81  void reset() NLIB_NOEXCEPT {
82  // for unique_ptr<char[]> compatible
83  if (str_.sso[N - 1]) {
84  if (str_.ptr) nlib_free(str_.ptr);
85  } else {
86  str_.sso[N - 1] = static_cast<Ch>(-1);
87  }
88  str_.ptr = nullptr;
89  }
90 
91  private:
92  union {
93  Ch sso[N];
94  Ch* ptr;
95  struct lentype {
96  uint64_t _;
97  uint64_t val;
98  } len;
99  } str_;
100  NLIB_DISALLOW_COPY_AND_ASSIGN(StringHolder);
101 };
102 
103 template<size_t N, class Ch>
104 inline errno_t StringHolder<N, Ch>::Init(const Ch* first, const Ch* last) NLIB_NOEXCEPT {
105  NLIB_ASSERT(first);
106  size_t n = std::distance(first, last);
107  Ch* p;
108  if (n + 1 > N) {
109  p = static_cast<Ch*>(nlib_malloc(n + 1));
110  if (!p) return ENOMEM;
111  if (str_.sso[N - 1]) {
112  if (str_.ptr) nlib_free(str_.ptr);
113  } else {
114  str_.sso[N - 1] = static_cast<Ch>(-1);
115  }
116  str_.ptr = p;
117  str_.len.val = n;
118  // cast for CTR
119  nlib_memcpy(static_cast<void*>(p), n + 1, static_cast<const void*>(first), n);
120  p[n] = static_cast<Ch>('\0');
121  } else {
122  p = &str_.sso[0];
123  if (str_.sso[N - 1]) {
124  if (str_.ptr) nlib_free(str_.ptr);
125  str_.sso[N - 1] = static_cast<Ch>('\0');
126  }
127  // cast for CTR
128  nlib_memcpy(static_cast<void*>(p), N - 1, static_cast<const void*>(first), n);
129  if (n != N - 1) {
130  p[n] = static_cast<Ch>('\0');
131  }
132  }
133  return 0;
134 }
135 
136 template<class Ch>
137 class StringHolder<16, Ch> NLIB_FINAL {
138  public:
139  NLIB_CEXPR14 StringHolder() NLIB_NOEXCEPT {
140  NLIB_STATIC_ASSERT(sizeof(Ch) == 1);
141  NLIB_STATIC_ASSERT(sizeof(Ch*) <= 8);
142  str_.ptr = nullptr;
143  str_.sso[15] = static_cast<Ch>(-1);
144  }
145  ~StringHolder() NLIB_NOEXCEPT {
146  if (str_.sso[15] && str_.ptr) nlib_free(str_.ptr);
147  }
148 #ifdef __cpp_rvalue_references
149  StringHolder(StringHolder&& rhs) NLIB_NOEXCEPT : str_(rhs.str_) {
150  rhs.str_.ptr = nullptr;
151  rhs.str_.sso[15] = static_cast<Ch>(-1);
152  }
153  StringHolder& operator=(StringHolder&& rhs) NLIB_NOEXCEPT {
154  nlib_memcpy(&str_.sso[0], 16, &rhs.str_.sso[0], 16);
155  rhs.str_.ptr = nullptr;
156  rhs.str_.sso[15] = static_cast<Ch>(-1);
157  return *this;
158  }
159 #endif
160  StringHolder(StringHolder& rhs, move_tag) NLIB_NOEXCEPT : str_(rhs.str_) {
161  rhs.str_.ptr = nullptr;
162  rhs.str_.sso[15] = static_cast<Ch>(-1);
163  }
164  StringHolder& assign(StringHolder& rhs, move_tag) NLIB_NOEXCEPT {
165  nlib_memcpy(static_cast<void*>(&str_.sso[0]), 16,
166  static_cast<const void*>(&rhs.str_.sso[0]), 16);
167  rhs.str_.ptr = nullptr;
168  rhs.str_.sso[15] = static_cast<Ch>(-1);
169  return *this;
170  }
171  // NOTE: add move ctor/assign
172  errno_t Init(const Ch* first, const Ch* last) NLIB_NOEXCEPT;
173  errno_t Init(const Ch* str) NLIB_NOEXCEPT {
174  NLIB_ASSERT(str);
175  return Init(str, str + nlib_strlen(str));
176  }
177  size_t length() const NLIB_NOEXCEPT {
178  if (str_.sso[15]) {
179  if (!str_.ptr) return 0U;
180  int64_t len = str_.len.minus;
181 #ifndef NLIB_LITTLE_ENDIAN
182  nlib_swapendian_64(reinterpret_cast<uint64_t*>(&len), 1);
183 #endif
184  return static_cast<size_t>(-len);
185  } else {
186  return nlib_strlen(&str_.sso[0]);
187  }
188  }
189  const Ch* c_str() const NLIB_NOEXCEPT { return str_.sso[15] ? str_.ptr : &str_.sso[0]; }
190  const Ch* get() const NLIB_NOEXCEPT {
191  // for unique_ptr<char[]> compatible
192  return c_str();
193  }
194  operator const Ch*() const NLIB_NOEXCEPT { return c_str(); }
195  void reset() NLIB_NOEXCEPT {
196  // for unique_ptr<char[]> compatible
197  if (str_.sso[15]) {
198  if (str_.ptr) nlib_free(str_.ptr);
199  } else {
200  str_.sso[15] = static_cast<Ch>(-1);
201  }
202  str_.ptr = nullptr;
203  }
204 
205  private:
206  union {
207  Ch sso[16];
208  Ch* ptr;
209  struct lentype {
210  uint64_t _;
211  int64_t minus;
212  } len;
213  } str_;
214  NLIB_DISALLOW_COPY_AND_ASSIGN(StringHolder);
215 };
216 
217 template<class Ch>
218 inline errno_t StringHolder<16, Ch>::Init(const Ch* first, const Ch* last) NLIB_NOEXCEPT {
219  NLIB_ASSERT(first);
220  ptrdiff_t n = std::distance(first, last);
221  Ch* p;
222  if (n > 15) {
223  p = static_cast<Ch*>(nlib_malloc(n + 1));
224  if (!p) return ENOMEM;
225  if (str_.sso[15]) {
226  if (str_.ptr) nlib_free(str_.ptr);
227  }
228  str_.ptr = p;
229  str_.len.minus = -n;
230 #ifndef NLIB_LITTLE_ENDIAN
231  nlib_swapendian_64(reinterpret_cast<uint64_t*>(&str_.len.minus), 1);
232 #endif
233  // cast for CTR
234  nlib_memcpy(static_cast<void*>(p), n + 1, static_cast<const void*>(first), n);
235  p[n] = static_cast<Ch>('\0');
236  } else {
237  p = &str_.sso[0];
238  if (str_.sso[15]) {
239  if (str_.ptr) nlib_free(str_.ptr);
240  str_.sso[15] = static_cast<Ch>('\0');
241  }
242  // cast for CTR
243  nlib_memcpy(static_cast<void*>(p), 15, static_cast<const void*>(first), n);
244  if (n != 15) {
245  p[n] = static_cast<Ch>('\0');
246  }
247  }
248  return 0;
249 }
250 
251 template<class BYTE = nlib_byte_t, size_t N = 232>
252 class BytePool {
253  public:
254  BytePool() NLIB_NOEXCEPT {
255  NLIB_STATIC_ASSERT(sizeof(BYTE) == sizeof(nlib_byte_t));
256  cur_ = &init_buf_[0];
257  end_ = &init_buf_[0] + N;
258  chunk_stack_ = nullptr;
259  }
260  ~BytePool() NLIB_NOEXCEPT { Reset(); }
261  void Reset() NLIB_NOEXCEPT;
262  BYTE* Alloc(size_t n) NLIB_NOEXCEPT;
263 
264  private:
265  struct Chunk {
266  Chunk* next;
267  BYTE buf[1]; // hacked
268  };
269  BYTE* cur_;
270  BYTE* end_;
271  Chunk* chunk_stack_;
272  BYTE init_buf_[N];
274 };
275 
276 template<class BYTE, size_t N>
277 inline void BytePool<BYTE, N>::Reset() NLIB_NOEXCEPT {
278  Chunk* p = chunk_stack_;
279  while (p) {
280  Chunk* tmp = p->next;
281  nlib_free(p);
282  p = tmp;
283  }
284  cur_ = &init_buf_[0];
285  end_ = &init_buf_[0] + N;
286  chunk_stack_ = nullptr;
287 }
288 
289 template<class BYTE, size_t N>
290 inline BYTE* BytePool<BYTE, N>::Alloc(size_t n) NLIB_NOEXCEPT {
291  if (NLIB_UNLIKELY(n > static_cast<size_t>(end_ - cur_))) {
292  size_t real_n = (n + sizeof(Chunk*) + 4095) & ~4095;
293  Chunk* chk = static_cast<Chunk*>(nlib_malloc(real_n));
294  if (NLIB_UNLIKELY(!chk)) return nullptr;
295  chk->next = chunk_stack_;
296  chunk_stack_ = chk;
297  cur_ = &chk->buf[0];
298  end_ = reinterpret_cast<BYTE*>(chk) + real_n;
299  }
300  BYTE* p;
301  p = cur_;
302  cur_ += n;
303  return p;
304 }
305 
306 NLIB_NAMESPACE_END
307 
308 NLIB_DEFINE_STD_SWAP_T_BEGIN2(nn, nlib)
309 #ifndef __cpp_rvalue_references
310 template<size_t N, class Ch>
311 NLIB_ALWAYS_INLINE void swap(nlib_ns::StringHolder<N, Ch>& lhs, nlib_ns::StringHolder<N, Ch>& rhs) {
312  nlib_ns::StringHolder<N, Ch> x(lhs, nlib_ns::move_tag());
313  lhs.assign(rhs, nlib_ns::move_tag());
314  rhs.assign(x, nlib_ns::move_tag());
315 }
316 #endif
317 NLIB_DEFINE_STD_SWAP_T_END2(nn, nlib)
318 
319 #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:95
#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:183
Definition: Base64.h:25
#define NLIB_UNLIKELY(x)
Indicates to the compiler that condition x is likely to be false.
Definition: Platform_unix.h:98
#define NLIB_CEXPR14
constexpr is defined if C++14 constexpr is available for use. If not, holds an empty string...
Definition: Config.h:112
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:270
#define NLIB_NOEXCEPT
Defines noexcept geared to the environment, or the equivalent.
Definition: Config.h:109
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:250
#define NLIB_STATIC_ASSERT(exp)
Defines a static assertion. Uses static_assert if it is available for use.
Definition: Config.h:174
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:314
int errno_t
Indicates with an int-type typedef that a POSIX error value is returned as the return value...
Definition: NMalloc.h:37