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> // NOLINT
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); // NOLINT
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 { // NOLINT
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 { // NOLINT
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
101  : public IntegralConstant<bool, (sizeof(S) != 0 || sizeof(S) == 0)> {};
102 
103 template<>
104 struct IsCompleteType<void> : public TrueType {};
105 
106 } // namespace detail
107 
108 template <class T, class DEL = DefaultDelete<T> >
109 class UniquePtr NLIB_FINAL : public detail::UniquePtrBase<T, DEL, IsEmpty<DEL>::value> {
110  typedef detail::UniquePtrBase<T, DEL, IsEmpty<DEL>::value> BaseType;
111 
112  public:
113  typedef T* pointer_type; // simpler definition than std::unique_ptr
114  typedef DEL deleter_type; // note that DEL cannot have data members
115  typedef T element_type;
116 
118  NLIB_CEXPR explicit UniquePtr(nullptr_t) NLIB_NOEXCEPT : BaseType() {}
119  explicit UniquePtr(T* p) NLIB_NOEXCEPT : BaseType(p) {}
120  UniquePtr(T* p, const DEL& del) : BaseType(p, del) {}
121  UniquePtr(UniquePtr& rhs, move_tag) NLIB_NOEXCEPT : BaseType() { swap(rhs); }
123  UniquePtr tmp(release());
124  swap(rhs);
125  return *this;
126  }
127  void swap(UniquePtr& rhs) NLIB_NOEXCEPT { // NOLINT
128  this->Swap(rhs);
129  }
131  NLIB_STATIC_ASSERT(detail::IsCompleteType<T>::value);
132  // typedef char is_complete_type[sizeof(T) ? 1 : -1];
133  // (void) sizeof(is_complete_type);
134  if (this->ptr_) get_deleter()(this->ptr_);
135  }
136  void reset(T* p = 0) NLIB_NOEXCEPT {
137  // NOTE:
138  // this->ptr_ is for CTR
139  if (p != this->ptr_) {
140  T* old = this->ptr_;
141  this->ptr_ = p;
142  if (old) get_deleter()(old);
143  }
144  }
145  typename AddRef<T>::type operator*() const {
146  NLIB_ASSERT(this->ptr_ != NULL);
147  return *this->ptr_;
148  }
150  NLIB_ASSERT(this->ptr_ != NULL);
151  return this->ptr_;
152  }
153  T* get() const NLIB_NOEXCEPT { return this->ptr_; }
155  T* p = this->ptr_;
156  this->ptr_ = NULL;
157  return p;
158  }
160  this->reset();
161  return *this;
162  }
163  size_t GetHash() const { return Hash<T*>()(this->get()); }
164  DEL& get_deleter() { return BaseType::get_deleter(); }
165  const DEL& get_deleter() const { return BaseType::get_deleter(); }
166 
167  NLIB_SAFE_BOOL(UniquePtr, this->ptr_ != NULL);
168 
169  private:
170  template <class S, class D>
171  bool operator==(const UniquePtr<S, D>& p) const;
172  template <class S, class D>
173  bool operator!=(const UniquePtr<S, D>& p) const;
175 };
176 
177 template <class T, class DEL>
178 class UniquePtr<T[], DEL> : public detail::UniquePtrBase<T, DEL, IsEmpty<DEL>::value> {
179  typedef detail::UniquePtrBase<T, DEL, IsEmpty<DEL>::value> BaseType;
180 
181  public:
182  typedef T* pointer_type; // simpler definition than std::unique_ptr
183  typedef DEL deleter_type;
184  typedef T element_type;
185 
186  NLIB_CEXPR UniquePtr() NLIB_NOEXCEPT : BaseType() {}
187  NLIB_CEXPR explicit UniquePtr(nullptr_t) NLIB_NOEXCEPT : BaseType() {}
188  explicit UniquePtr(T* p) NLIB_NOEXCEPT : BaseType(p) {}
189  UniquePtr(T* p, const DEL& del) : BaseType(p, del) {}
190  UniquePtr(UniquePtr& rhs, move_tag) NLIB_NOEXCEPT : BaseType() { swap(rhs); }
191  UniquePtr& assign(UniquePtr& rhs, move_tag) NLIB_NOEXCEPT {
192  UniquePtr tmp(release());
193  swap(rhs);
194  return *this;
195  }
196  void swap(UniquePtr& rhs) NLIB_NOEXCEPT { // NOLINT
197  this->Swap(rhs);
198  }
200  NLIB_STATIC_ASSERT(sizeof(T));
201  get_deleter()(this->ptr_);
202  }
203  void reset(T* p = 0) NLIB_NOEXCEPT {
204  // NOTE:
205  // this->ptr_ is for CTR
206  if (p != this->ptr_) {
207  T* old = this->ptr_;
208  this->ptr_ = p;
209  if (old) get_deleter()(old);
210  }
211  }
212  T& operator*() const {
213  NLIB_ASSERT(this->ptr_ != NULL);
214  return *this->ptr_;
215  }
216  T* operator->() const NLIB_NOEXCEPT {
217  NLIB_ASSERT(this->ptr_ != NULL);
218  return this->ptr_;
219  }
220  T* get() const NLIB_NOEXCEPT { return this->ptr_; }
221  T* release() NLIB_NOEXCEPT {
222  T* p = this->ptr_;
223  this->ptr_ = NULL;
224  return p;
225  }
226  T& operator[](size_t n) { return get()[n]; }
227  const T& operator[](size_t n) const { return get()[n]; }
228  size_t GetHash() const { return Hash<T*>()(this->get()); }
229  DEL& get_deleter() { return BaseType::get_deleter(); }
230  const DEL& get_deleter() const { return BaseType::get_deleter(); }
231 
232  NLIB_SAFE_BOOL(UniquePtr, this->ptr_ != NULL);
233 
234  private:
235  template <class S, class D>
236  bool operator==(const UniquePtr<S, D>& p) const;
237  template <class S, class D>
238  bool operator!=(const UniquePtr<S, D>& p) const;
240 };
241 
242 template <class T1, class D1, class T2, class D2>
244  return rhs.get() == lhs.get();
245 }
246 
247 template <class T1, class D1>
248 bool operator==(const UniquePtr<T1, D1>& lhs, nullptr_t) NLIB_NOEXCEPT {
249  return !lhs;
250 }
251 
252 template <class T1, class D1>
253 bool operator==(nullptr_t, const UniquePtr<T1, D1>& rhs) NLIB_NOEXCEPT {
254  return !rhs;
255 }
256 
257 template <class T1, class D1, class T2, class D2>
259  return rhs.get() != lhs.get();
260 }
261 
262 template <class T1, class D1>
263 bool operator!=(const UniquePtr<T1, D1>& lhs, nullptr_t) NLIB_NOEXCEPT {
264  return static_cast<bool>(lhs);
265 }
266 
267 template <class T1, class D1>
268 bool operator!=(nullptr_t, const UniquePtr<T1, D1>& rhs) NLIB_NOEXCEPT {
269  return static_cast<bool>(rhs);
270 }
271 
272 NLIB_NAMESPACE_END
273 
274 NLIB_DEFINE_STD_SWAP_T_BEGIN2(nn, nlib)
275 NLIB_DEFINE_STD_SWAP_T2(T, DEL, NLIB_NS::UniquePtr) // NOLINT
276 NLIB_DEFINE_STD_SWAP_T_END2(nn, nlib)
277 
278 NLIB_DEFINE_STD_HASH_BEGIN2(nn, nlib)
279 NLIB_DEFINE_STD_HASH_T2(T, DEL, NLIB_NS::UniquePtr) // NOLINT
280 NLIB_DEFINE_STD_HASH_END2(nn, nlib)
281 
282 #endif
283 
284 NLIB_NAMESPACE_BEGIN
285 
286 /*
287 template<class T, void FreeFunc(void*) = free>
288 struct FreeDeleterT {
289  void operator()(T* p) const NLIB_NOEXCEPT {
290  NLIB_STATIC_ASSERT(sizeof(T));
291  NLIB_STATIC_ASSERT(IsPod<T>::value);
292  if (p) FreeFunc(p);
293  }
294 };
295 */
296 
297 namespace detail {
298 
299 template <class T, class ALLOC, bool DEL_EMPTY>
300 class DefaultDeleteExBase {
301  public:
302  DefaultDeleteExBase() : al() {}
303  explicit DefaultDeleteExBase(const ALLOC& al_) : al(al_) {}
304 
305  protected:
306  ALLOC& get_allocator() { return al; }
307  ALLOC al;
308 
309  private:
310  NLIB_DISALLOW_COPY_AND_ASSIGN(DefaultDeleteExBase);
311 };
312 
313 template <class T, class ALLOC>
314 class DefaultDeleteExBase<T, ALLOC, true> : public ALLOC {
315  public:
316  DefaultDeleteExBase() {}
317  explicit DefaultDeleteExBase(const ALLOC& al_) { NLIB_UNUSED(al_); }
318 
319  protected:
320  ALLOC& get_allocator() { return *this; }
321 };
322 
323 } // namespace detail
324 
325 template <class T, class ALLOC = std::allocator<T> >
326 struct DefaultDeleteEx : public detail::DefaultDeleteExBase<T, ALLOC, IsEmpty<ALLOC>::value> {
327  void operator()(T* p)NLIB_NOEXCEPT {
328  NLIB_STATIC_ASSERT(sizeof(T));
329  NLIB_STATIC_ASSERT(!IsArray<T>::value);
330  typedef detail::DefaultDeleteExBase<T, ALLOC, IsEmpty<ALLOC>::value> BaseType;
331  if (p) {
332  ALLOC& al = BaseType::get_allocator();
333  al.destroy(p);
334  al.deallocate(p, 1);
335  }
336  }
337 };
338 
339 template <class T, class ALLOC>
340 struct DefaultDeleteEx<T[], ALLOC>
341  : public detail::DefaultDeleteExBase<T, ALLOC, IsEmpty<ALLOC>::value> {
342  // mainly for using malloc variant like nmalloc
343  // ex.
344  // UniquePtr<
345  // unsigned char[],
346  // DefaultDeleteEx<unsigned char[], NMallocStlAllocator<unsigned char> >
347  // >
348  void operator()(T* p)NLIB_NOEXCEPT {
349  typedef detail::DefaultDeleteExBase<T, ALLOC, IsEmpty<ALLOC>::value> BaseType;
350  NLIB_STATIC_ASSERT(sizeof(T));
351  NLIB_STATIC_ASSERT(IsPod<T>::value);
352  if (p) {
353  ALLOC& al = BaseType::get_allocator();
354  // The length is unknown
355  al.deallocate(p, 1);
356  }
357  }
358 };
359 
360 NLIB_NAMESPACE_END
361 
362 #ifdef NLIB_CXX11_DEFAULTED_AND_DELETED_FUNCTIONS
363 template<class T, class DEL>
364 bool nlib_is_error(NLIB_NS::UniquePtr<T, DEL>&) = delete;
365 #else
366 template<class T, class DEL>
367 bool nlib_is_error(NLIB_NS::UniquePtr<T, DEL>&);
368 #endif
369 
370 #endif // INCLUDE_NN_NLIB_UNIQUEPTR_H_
~UniquePtr() noexcept
デストラクタです。ポインタがNULLでなければデリータを実行して削除します。
Definition: UniquePtr.h:130
UniquePtr(T *p) noexcept
ポインタを設定します。
Definition: UniquePtr.h:119
C++11の標準ヘッダとなるtype_traitsの代用定義です。 コンパイラや標準ライブラリによってサポートされてい...
constexpr UniquePtr(nullptr_t) noexcept
引数にnullptrを与えた場合に呼び出されます。
Definition: UniquePtr.h:118
#define NLIB_DISALLOW_COPY_AND_ASSIGN(TypeName)
TypeName で指定されたクラスのコピーコンストラクタと代入演算子を禁止します。
Definition: Config.h:179
#define NLIB_SAFE_BOOL(class_name, exp)
クラス内に安全なoperator bool()を定義します。 可能であればC++11のexplicit boolを利用します。 ...
Definition: Config.h:194
Definition: Base64.h:25
T element_type
Tがtypedefされています。
Definition: UniquePtr.h:115
UniquePtrはポインタの所有権を保持し、UniquePtrがスコープから出るときにデストラクタでポインタをDELで指...
Definition: UniquePtr.h:109
bool operator==(const HeapHash &rhs, const HeapHash &lhs)
2つのサマリを比較して等価ならば、trueを返します。
Definition: NMalloc.h:149
bool operator!=(const HeapHash &rhs, const HeapHash &lhs)
2つのサマリを比較して等価でなければ、trueを返します。
Definition: NMalloc.h:154
void reset(T *p=0) noexcept
ポインタを置き換えます。置き換えられたポインタは削除されます。
Definition: UniquePtr.h:136
constexpr UniquePtr() noexcept
デフォルトコンストラクタです。
Definition: UniquePtr.h:117
size_t GetHash() const
ポインタに対してハッシュ値の計算を行い、計算結果を返します。
Definition: UniquePtr.h:163
UniquePtr & operator=(nullptr_t) noexcept
nullptrを代入します。
Definition: UniquePtr.h:159
AddRef< T >::type operator*() const
ポインタの参照外しを行います。
Definition: UniquePtr.h:145
空の構造体で、関数の引数をムーブすべきことを示すために利用されます。
Definition: Config.h:265
void swap(UniquePtr &rhs) noexcept
格納されているポインタをスワップします。
Definition: UniquePtr.h:127
T * operator->() const noexcept
ポインタを返します。
Definition: UniquePtr.h:149
DefaultDelete< FutureTuple< R1, R2 > > deleter_type
DELがtypedefされています。
Definition: UniquePtr.h:114
#define NLIB_NOEXCEPT
環境に合わせてnoexcept 又は同等の定義がされます。
Definition: Config.h:105
#define NLIB_CEXPR
利用可能であればconstexprが定義されます。そうでない場合は空文字列です。
Definition: Config.h:107
開発環境別の設定が書かれるファイルです。
TimeSpan operator*(int i, const TimeSpan &rhs) noexcept
rhs を i 倍します。
Definition: DateTime.h:210
UniquePtr & assign(UniquePtr &rhs, move_tag) noexcept
ムーブにより代入します。
Definition: UniquePtr.h:122
UniquePtr(UniquePtr &rhs, move_tag) noexcept
ムーブによりオブジェクトを構築します。
Definition: UniquePtr.h:121
UniquePtr(T *p, const DEL &del)
ポインタとデリータを設定します。
Definition: UniquePtr.h:120
#define NLIB_FINAL
利用可能であればfinalが定義されます。そうでない場合は空文字列です。
Definition: Config.h:245
#define NLIB_STATIC_ASSERT(exp)
静的アサートが定義されます。利用可能であればstatic_assertを利用します。
Definition: Config.h:170
T * pointer_type
T*がtypedefされています。
Definition: UniquePtr.h:113
bool nlib_is_error(const T &obj) noexcept
処理の結果やオブジェクトの状態がエラーである場合にtrueを返します。
Definition: Config.h:682
T * release() noexcept
ポインタの所有権を手放し、ポインタを返します。
Definition: UniquePtr.h:154