nlib
UniquePtr.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_UNIQUEPTR_H_
17 #define INCLUDE_NN_NLIB_UNIQUEPTR_H_
18 
19 #include <stdlib.h>
20 #include <memory>
21 
22 #include "nn/nlib/Config.h"
23 #include "nn/nlib/Swap.h"
24 #include "nn/nlib/Hash.h"
25 #include "nn/nlib/TypeTraits.h"
26 
27 #if defined(NLIB_CXX11_UNIQUEPTR) && defined(__cpp_alias_templates)
28 NLIB_NAMESPACE_BEGIN
29 
30 template<class T, class DEL = std::default_delete<T> >
31 using UniquePtr = std::unique_ptr<T, DEL>;
32 template<class T>
33 using DefaultDelete = std::default_delete<T>;
34 
35 NLIB_NAMESPACE_END
36 #else
37 #include <algorithm>
38 
39 NLIB_NAMESPACE_BEGIN
40 
41 template<class T>
42 struct DefaultDelete {
43  void operator()(T* p) const NLIB_NOEXCEPT {
44  NLIB_STATIC_ASSERT(sizeof(T));
45  if (p) delete p;
46  }
47 };
48 
49 template<class T>
50 struct DefaultDelete<T[]> {
51  void operator()(T* p) const NLIB_NOEXCEPT {
52  NLIB_STATIC_ASSERT(sizeof(T));
53  if (p) delete[] p;
54  }
55 };
56 
57 NLIB_STATIC_ASSERT(IsEmpty<DefaultDelete<int> >::value&& IsEmpty<DefaultDelete<int[]> >::value);
58 
59 namespace detail {
60 
61 template<class T, class DEL, bool DEL_EMPTY>
62 class UniquePtrBase {
63  public:
64  UniquePtrBase() : ptr_(NULL), deleter_() {}
65  explicit UniquePtrBase(T* ptr) : ptr_(ptr), deleter_() {}
66  UniquePtrBase(T* ptr, const DEL& del) : ptr_(ptr), deleter_(del) {}
67 
68  protected:
69  DEL& get_deleter() { return deleter_; }
70  const DEL& get_deleter() const { return deleter_; }
71  T* ptr_;
72  DEL deleter_;
73  void Swap(UniquePtrBase& rhs) NLIB_NOEXCEPT {
74  using std::swap;
75  swap(this->ptr_, rhs.ptr_);
76  swap(this->deleter_, rhs.deleter_);
77  }
78  NLIB_DISALLOW_COPY_AND_ASSIGN(UniquePtrBase);
79 };
80 
81 template<class T, class DEL>
82 class UniquePtrBase<T, DEL, true> : public DEL {
83  public:
84  UniquePtrBase() : ptr_(NULL) {}
85  explicit UniquePtrBase(T* ptr) : ptr_(ptr) {}
86  UniquePtrBase(T* ptr, const DEL& del) : DEL(del), ptr_(ptr) {}
87 
88  protected:
89  DEL& get_deleter() { return *this; }
90  const DEL& get_deleter() const { return *this; }
91  T* ptr_;
92  void Swap(UniquePtrBase& rhs) NLIB_NOEXCEPT {
93  using std::swap;
94  swap(this->ptr_, rhs.ptr_);
95  }
96  NLIB_DISALLOW_COPY_AND_ASSIGN(UniquePtrBase);
97 };
98 
99 template<class S>
100 struct IsCompleteType : public IntegralConstant<bool, (sizeof(S) != 0 || sizeof(S) == 0)> {};
101 
102 template<>
103 struct IsCompleteType<void> : public TrueType {};
104 
105 } // namespace detail
106 
107 template<class T, class DEL = DefaultDelete<T> >
108 class UniquePtr NLIB_FINAL : public detail::UniquePtrBase<T, DEL, IsEmpty<DEL>::value> {
109  typedef detail::UniquePtrBase<T, DEL, IsEmpty<DEL>::value> BaseType;
110 
111  public:
112  typedef T* pointer_type; // simpler definition than std::unique_ptr
113  typedef DEL deleter_type; // note that DEL cannot have data members
114  typedef T element_type;
115 
116  NLIB_CEXPR UniquePtr() NLIB_NOEXCEPT : BaseType() {}
117  NLIB_CEXPR explicit UniquePtr(nullptr_t) NLIB_NOEXCEPT : BaseType() {}
118  explicit UniquePtr(T* p) NLIB_NOEXCEPT : BaseType(p) {}
119  UniquePtr(T* p, const DEL& del) : BaseType(p, del) {}
120  UniquePtr(UniquePtr& rhs, move_tag) NLIB_NOEXCEPT : BaseType() { swap(rhs); }
121  UniquePtr& assign(UniquePtr& rhs, move_tag) NLIB_NOEXCEPT {
122  UniquePtr tmp(release());
123  swap(rhs);
124  return *this;
125  }
126  void swap(UniquePtr& rhs) NLIB_NOEXCEPT { this->Swap(rhs); }
128  NLIB_STATIC_ASSERT(detail::IsCompleteType<T>::value);
129  // typedef char is_complete_type[sizeof(T) ? 1 : -1];
130  // (void) sizeof(is_complete_type);
131  if (this->ptr_) get_deleter()(this->ptr_);
132  }
133  void reset(T* p = 0) NLIB_NOEXCEPT {
134  // NOTE:
135  // this->ptr_ is for CTR
136  if (p != this->ptr_) {
137  T* old = this->ptr_;
138  this->ptr_ = p;
139  if (old) get_deleter()(old);
140  }
141  }
142  typename AddRef<T>::type operator*() const {
143  NLIB_ASSERT(this->ptr_ != NULL);
144  return *this->ptr_;
145  }
146  T* operator->() const NLIB_NOEXCEPT {
147  NLIB_ASSERT(this->ptr_ != NULL);
148  return this->ptr_;
149  }
150  T* get() const NLIB_NOEXCEPT { return this->ptr_; }
151  T* release() NLIB_NOEXCEPT {
152  T* p = this->ptr_;
153  this->ptr_ = NULL;
154  return p;
155  }
156  UniquePtr& operator=(nullptr_t) NLIB_NOEXCEPT {
157  this->reset();
158  return *this;
159  }
160  size_t GetHash() const { return Hash<T*>()(this->get()); }
161  DEL& get_deleter() { return BaseType::get_deleter(); }
162  const DEL& get_deleter() const { return BaseType::get_deleter(); }
163 
164  NLIB_SAFE_BOOL(UniquePtr, this->ptr_ != NULL);
165 
166  private:
167  template<class S, class D>
168  bool operator==(const UniquePtr<S, D>& p) const;
169  template<class S, class D>
170  bool operator!=(const UniquePtr<S, D>& p) const;
172 };
173 
174 template<class T, class DEL>
175 class UniquePtr<T[], DEL> : public detail::UniquePtrBase<T, DEL, IsEmpty<DEL>::value> {
176  typedef detail::UniquePtrBase<T, DEL, IsEmpty<DEL>::value> BaseType;
177 
178  public:
179  typedef T* pointer_type; // simpler definition than std::unique_ptr
180  typedef DEL deleter_type;
181  typedef T element_type;
182 
183  NLIB_CEXPR UniquePtr() NLIB_NOEXCEPT : BaseType() {}
184  NLIB_CEXPR explicit UniquePtr(nullptr_t) NLIB_NOEXCEPT : BaseType() {}
185  explicit UniquePtr(T* p) NLIB_NOEXCEPT : BaseType(p) {}
186  UniquePtr(T* p, const DEL& del) : BaseType(p, del) {}
187  UniquePtr(UniquePtr& rhs, move_tag) NLIB_NOEXCEPT : BaseType() { swap(rhs); }
188  UniquePtr& assign(UniquePtr& rhs, move_tag) NLIB_NOEXCEPT {
189  UniquePtr tmp(release());
190  swap(rhs);
191  return *this;
192  }
193  void swap(UniquePtr& rhs) NLIB_NOEXCEPT { this->Swap(rhs); }
194  ~UniquePtr() NLIB_NOEXCEPT {
195  NLIB_STATIC_ASSERT(sizeof(T));
196  get_deleter()(this->ptr_);
197  }
198  void reset(T* p = 0) NLIB_NOEXCEPT {
199  // NOTE:
200  // this->ptr_ is for CTR
201  if (p != this->ptr_) {
202  T* old = this->ptr_;
203  this->ptr_ = p;
204  if (old) get_deleter()(old);
205  }
206  }
207  T& operator*() const {
208  NLIB_ASSERT(this->ptr_ != NULL);
209  return *this->ptr_;
210  }
211  T* operator->() const NLIB_NOEXCEPT {
212  NLIB_ASSERT(this->ptr_ != NULL);
213  return this->ptr_;
214  }
215  T* get() const NLIB_NOEXCEPT { return this->ptr_; }
216  T* release() NLIB_NOEXCEPT {
217  T* p = this->ptr_;
218  this->ptr_ = NULL;
219  return p;
220  }
221  T& operator[](size_t n) { return get()[n]; }
222  const T& operator[](size_t n) const { return get()[n]; }
223  size_t GetHash() const { return Hash<T*>()(this->get()); }
224  DEL& get_deleter() { return BaseType::get_deleter(); }
225  const DEL& get_deleter() const { return BaseType::get_deleter(); }
226 
227  NLIB_SAFE_BOOL(UniquePtr, this->ptr_ != NULL);
228 
229  private:
230  template<class S, class D>
231  bool operator==(const UniquePtr<S, D>& p) const;
232  template<class S, class D>
233  bool operator!=(const UniquePtr<S, D>& p) const;
235 };
236 
237 template<class T1, class D1, class T2, class D2>
238 bool operator==(const UniquePtr<T1, D1>& rhs, const UniquePtr<T2, D2>& lhs) NLIB_NOEXCEPT {
239  return rhs.get() == lhs.get();
240 }
241 
242 template<class T1, class D1>
243 bool operator==(const UniquePtr<T1, D1>& lhs, nullptr_t) NLIB_NOEXCEPT {
244  return !lhs;
245 }
246 
247 template<class T1, class D1>
248 bool operator==(nullptr_t, const UniquePtr<T1, D1>& rhs) NLIB_NOEXCEPT {
249  return !rhs;
250 }
251 
252 template<class T1, class D1, class T2, class D2>
253 bool operator!=(const UniquePtr<T1, D1>& rhs, const UniquePtr<T2, D2>& lhs) NLIB_NOEXCEPT {
254  return rhs.get() != lhs.get();
255 }
256 
257 template<class T1, class D1>
258 bool operator!=(const UniquePtr<T1, D1>& lhs, nullptr_t) NLIB_NOEXCEPT {
259  return static_cast<bool>(lhs);
260 }
261 
262 template<class T1, class D1>
263 bool operator!=(nullptr_t, const UniquePtr<T1, D1>& rhs) NLIB_NOEXCEPT {
264  return static_cast<bool>(rhs);
265 }
266 
267 NLIB_NAMESPACE_END
268 
269 NLIB_DEFINE_STD_SWAP_T_BEGIN2(nn, nlib)
270 NLIB_DEFINE_STD_SWAP_T2(T, DEL, NLIB_NS::UniquePtr)
271 NLIB_DEFINE_STD_SWAP_T_END2(nn, nlib)
272 
273 NLIB_DEFINE_STD_HASH_BEGIN2(nn, nlib)
274 NLIB_DEFINE_STD_HASH_T2(T, DEL, NLIB_NS::UniquePtr)
275 NLIB_DEFINE_STD_HASH_END2(nn, nlib)
276 
277 #endif
278 
279 NLIB_NAMESPACE_BEGIN
280 
281 /*
282 template<class T, void FreeFunc(void*) = free>
283 struct FreeDeleterT {
284  void operator()(T* p) const NLIB_NOEXCEPT {
285  NLIB_STATIC_ASSERT(sizeof(T));
286  NLIB_STATIC_ASSERT(IsPod<T>::value);
287  if (p) FreeFunc(p);
288  }
289 };
290 */
291 
292 namespace detail {
293 
294 template<class T, class ALLOC, bool DEL_EMPTY>
295 class DefaultDeleteExBase {
296  public:
297  DefaultDeleteExBase() : al() {}
298  explicit DefaultDeleteExBase(const ALLOC& al_) : al(al_) {}
299 
300  protected:
301  ALLOC& get_allocator() { return al; }
302  ALLOC al;
303 
304  private:
305  NLIB_DISALLOW_COPY_AND_ASSIGN(DefaultDeleteExBase);
306 };
307 
308 template<class T, class ALLOC>
309 class DefaultDeleteExBase<T, ALLOC, true> : public ALLOC {
310  public:
311  DefaultDeleteExBase() {}
312  explicit DefaultDeleteExBase(const ALLOC& al_) { NLIB_UNUSED(al_); }
313 
314  protected:
315  ALLOC& get_allocator() { return *this; }
316 };
317 
318 } // namespace detail
319 
320 template<class T, class ALLOC = std::allocator<T> >
321 struct DefaultDeleteEx : public detail::DefaultDeleteExBase<T, ALLOC, IsEmpty<ALLOC>::value> {
322  void operator()(T* p) NLIB_NOEXCEPT {
323  NLIB_STATIC_ASSERT(sizeof(T));
324  NLIB_STATIC_ASSERT(!IsArray<T>::value);
325  typedef detail::DefaultDeleteExBase<T, ALLOC, IsEmpty<ALLOC>::value> BaseType;
326  if (p) {
327  ALLOC& al = BaseType::get_allocator();
328  al.destroy(p);
329  al.deallocate(p, 1);
330  }
331  }
332 };
333 
334 template<class T, class ALLOC>
335 struct DefaultDeleteEx<T[], ALLOC>
336  : public detail::DefaultDeleteExBase<T, ALLOC, IsEmpty<ALLOC>::value> {
337  // mainly for using malloc variant like nmalloc
338  // ex.
339  // UniquePtr<
340  // unsigned char[],
341  // DefaultDeleteEx<unsigned char[], NMallocStlAllocator<unsigned char> >
342  // >
343  void operator()(T* p) NLIB_NOEXCEPT {
344  typedef detail::DefaultDeleteExBase<T, ALLOC, IsEmpty<ALLOC>::value> BaseType;
345  NLIB_STATIC_ASSERT(sizeof(T));
346  NLIB_STATIC_ASSERT(IsPod<T>::value);
347  if (p) {
348  ALLOC& al = BaseType::get_allocator();
349  // The length is unknown
350  al.deallocate(p, 1);
351  }
352  }
353 };
354 
355 NLIB_NAMESPACE_END
356 
357 #ifdef NLIB_CXX11_DEFAULTED_AND_DELETED_FUNCTIONS
358 template<class T, class DEL>
359 bool nlib_is_error(NLIB_NS::UniquePtr<T, DEL>&) = delete;
360 #else
361 template<class T, class DEL>
362 bool nlib_is_error(NLIB_NS::UniquePtr<T, DEL>&);
363 #endif
364 
365 #endif // INCLUDE_NN_NLIB_UNIQUEPTR_H_
C++11の標準ヘッダとなるtype_traitsの代用定義です。 コンパイラや標準ライブラリによってサポートされてい...
#define NLIB_DISALLOW_COPY_AND_ASSIGN(TypeName)
TypeName で指定されたクラスのコピーコンストラクタと代入演算子を禁止します。
Definition: Config.h:183
#define NLIB_SAFE_BOOL(class_name, exp)
クラス内に安全なoperator bool()を定義します。 可能であればC++11のexplicit boolを利用します。 ...
Definition: Config.h:199
Definition: Base64.h:25
C++11環境(エイリアステンプレートが可能な環境)においてはstd::unique_ptrにエイリアステンプレートされま...
Definition: UniquePtr.h:108
bool operator==(const HeapHash &rhs, const HeapHash &lhs)
2つのサマリを比較して等価ならば、trueを返します。
Definition: NMalloc.h:130
bool operator!=(const HeapHash &rhs, const HeapHash &lhs)
2つのサマリを比較して等価でなければ、trueを返します。
Definition: NMalloc.h:135
空の構造体で、関数の引数をムーブすべきことを示すために利用されます。
Definition: Config.h:270
#define NLIB_NOEXCEPT
環境に合わせてnoexcept 又は同等の定義がされます。
Definition: Config.h:109
#define NLIB_CEXPR
利用可能であればconstexprが定義されます。そうでない場合は空文字列です。
Definition: Config.h:111
開発環境別の設定が書かれるファイルです。
TimeSpan operator*(int i, const TimeSpan &rhs) noexcept
rhs を i 倍します。
Definition: DateTime.h:195
#define NLIB_FINAL
利用可能であればfinalが定義されます。そうでない場合は空文字列です。
Definition: Config.h:250
#define NLIB_STATIC_ASSERT(exp)
静的アサートが定義されます。利用可能であればstatic_assertを利用します。
Definition: Config.h:174
bool nlib_is_error(const T &obj) noexcept
処理の結果やオブジェクトの状態がエラーである場合にtrueを返します。
Definition: Config.h:658