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
コンパイラに関数をインライン展開するように強く示します。
Definition: Platform_unix.h:97
#define NLIB_DISALLOW_COPY_AND_ASSIGN(TypeName)
TypeName で指定されたクラスのコピーコンストラクタと代入演算子を禁止します。
Definition: Config.h:179
Definition: Base64.h:25
#define NLIB_UNLIKELY(x)
条件xが偽になる傾向が高いことをコンパイラに示します。
#define NLIB_CEXPR14
C++14のconstexprが利用可能であればconstexprが定義されます。そうでない場合は空文字列です。 ...
Definition: Config.h:108
#define NLIB_DEPRECATED
関数等がdeprecatedになったことを示します。
Definition: Config.h:109
void * nlib_malloc(size_t size)
C標準関数のmalloc()を呼び出すweak関数です。nlibはこの関数を経由してmalloc()を呼び出します。 ...
空の構造体で、関数の引数をムーブすべきことを示すために利用されます。
Definition: Config.h:265
static errno_t nlib_memcpy(void *s1, size_t s1max, const void *s2, size_t n)
N1078のmemcpy_sに相当する実装です。
Definition: Platform.h:2437
#define NLIB_NOEXCEPT
環境に合わせてnoexcept 又は同等の定義がされます。
Definition: Config.h:105
開発環境別の設定が書かれるファイルです。
size_t nlib_strlen(const char *s)
内部でstrlen()を呼び出します。独自の実装が動作する場合もあります。
#define NLIB_FINAL
利用可能であればfinalが定義されます。そうでない場合は空文字列です。
Definition: Config.h:245
#define NLIB_STATIC_ASSERT(exp)
静的アサートが定義されます。利用可能であればstatic_assertを利用します。
Definition: Config.h:170
void nlib_free(void *ptr)
C標準関数のfree()を呼び出すweak関数です。nlibはこの関数を経由してfree()を呼び出します。 ...
errno_t nlib_swapendian_64(uint64_t *p, size_t count)
エンディアンを変換します。
unsigned char nlib_byte_t
C++17以降でstd::byteにtypedefされる型です。
Definition: Platform.h:319
int errno_t
intのtypedefで、戻り値としてPOSIXのエラー値を返すことを示します。
Definition: NMalloc.h:37