nlib
LimitedSharedPtr.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_THREADING_LIMITEDSHAREDPTR_H_
17 #define INCLUDE_NN_NLIB_THREADING_LIMITEDSHAREDPTR_H_
18 
19 #include <new>
20 #include <utility>
21 
22 #include "nn/nlib/Swap.h"
23 #include "nn/nlib/UniquePtr.h"
24 
25 NLIB_NAMESPACE_BEGIN
26 namespace threading {
27 
28 namespace internal {
29 
30 class LspStatus NLIB_FINAL {
31  public:
32  NLIB_CEXPR LspStatus() NLIB_NOEXCEPT : prv_(nullptr) {}
33  ~LspStatus() NLIB_NOEXCEPT {}
34  NLIB_DEFMOVE_PIMPL(LspStatus);
35  errno_t ToShare(LspStatus* ptr) NLIB_NOEXCEPT {
36  if (!prv_) {
37  prv_ = new (std::nothrow) int32_t(2);
38  if (!prv_) return ENOMEM;
39  } else {
41  }
42  NLIB_ASSERT(!ptr->prv_);
43  ptr->prv_ = prv_;
44  return 0;
45  }
46  bool ToUnshare() NLIB_NOEXCEPT {
47  if (!prv_) return false;
48  if (nlib_atomic_sub_fetch32(prv_, 1, NLIB_ATOMIC_ACQUIRE) == 0) {
49  delete prv_;
50  prv_ = nullptr;
51  return false;
52  }
53  prv_ = nullptr;
54  return true;
55  }
56  bool IsUnique() NLIB_NOEXCEPT {
57  if (!prv_) return true;
58  return nlib_atomic_load32(prv_, NLIB_ATOMIC_ACQUIRE) == 1;
59  }
60  void Reset() NLIB_NOEXCEPT { ToUnshare(); }
61 
62  private:
63  int32_t* prv_;
65 };
66 
67 } // namespace internal
68 
69 // Use of shared_ptr is discouraged because of unexpected overhead,
70 // and You have to share the pointer by calling MakeSharedFrom() method.
71 template<class T, class DEL = DefaultDelete<T> >
72 class LimitedSharedPtr {
73  public:
74  NLIB_CEXPR LimitedSharedPtr() NLIB_NOEXCEPT : ptr_(nullptr) {}
75  ~LimitedSharedPtr() NLIB_NOEXCEPT { release(); }
76  explicit LimitedSharedPtr(nullptr_t) NLIB_NOEXCEPT : ptr_(nullptr) {}
77  explicit LimitedSharedPtr(T* p) NLIB_NOEXCEPT : ptr_(p) {
78  // Do not count up LspStatus because there is the risk of alloc failure.
79  }
80 #ifdef __cpp_rvalue_references
81  LimitedSharedPtr(LimitedSharedPtr&& rhs) NLIB_NOEXCEPT : ptr_(rhs.ptr_),
82  status_(std::move(rhs.status_)) {
83  rhs.ptr_ = nullptr;
84  }
85  LimitedSharedPtr& operator=(LimitedSharedPtr&& rhs) NLIB_NOEXCEPT {
86  if (!status_.ToUnshare()) DEL()(ptr_);
87  ptr_ = rhs.ptr_;
88  rhs.ptr_ = nullptr;
89  status_ = std::move(rhs.status_);
90  return *this;
91  }
92 #endif
93  LimitedSharedPtr(LimitedSharedPtr& rhs, move_tag) NLIB_NOEXCEPT
94  : ptr_(rhs.ptr_),
95  status_(rhs.status_, move_tag()) {
96  rhs.ptr_ = nullptr;
97  }
98  LimitedSharedPtr& assign(LimitedSharedPtr& rhs, move_tag) NLIB_NOEXCEPT {
99  if (!status_.ToUnshare()) DEL()(ptr_);
100  ptr_ = rhs.ptr_;
101  rhs.ptr_ = nullptr;
102  status_.assign(rhs.status_, move_tag());
103  return *this;
104  }
105  void reset(T* p = 0) NLIB_NOEXCEPT {
106  if (!status_.ToUnshare()) DEL()(ptr_);
107  ptr_ = p;
108  }
109  T& operator*() const {
110  NLIB_ASSERT(ptr_ != nullptr);
111  return *ptr_;
112  }
113  T* operator->() const NLIB_NOEXCEPT {
114  NLIB_ASSERT(ptr_ != nullptr);
115  return ptr_;
116  }
117  T* get() const NLIB_NOEXCEPT { return ptr_; }
118  errno_t MakeSharedFrom(const LimitedSharedPtr& p) NLIB_NOEXCEPT;
119  bool IsUnique() const NLIB_NOEXCEPT { return status_.IsUnique(); }
120  bool MakeUniquePtr(UniquePtr<T>& p) NLIB_NOEXCEPT;
121  LimitedSharedPtr& operator=(nullptr_t) NLIB_NOEXCEPT {
122  release();
123  return *this;
124  }
125  NLIB_SAFE_BOOL(LimitedSharedPtr, ptr_ != nullptr);
126 
127  private:
128  void release() NLIB_NOEXCEPT {
129  if (!status_.ToUnshare()) DEL()(ptr_);
130  ptr_ = nullptr;
131  }
132 
133  private:
134  T* ptr_;
135  mutable internal::LspStatus status_;
136  NLIB_DISALLOW_COPY_AND_ASSIGN(LimitedSharedPtr);
137 };
138 
139 template<class T, class DEL>
140 errno_t LimitedSharedPtr<T, DEL>::MakeSharedFrom(const LimitedSharedPtr& p) NLIB_NOEXCEPT {
141  LimitedSharedPtr tmp;
142  if (p) {
143  errno_t e = p.status_.ToShare(&tmp.status_);
144  if (e != 0) return e;
145  tmp.ptr_ = p.ptr_;
146  }
147  this->assign(tmp, move_tag());
148  return 0;
149 }
150 
151 template<class T, class DEL>
152 bool LimitedSharedPtr<T, DEL>::MakeUniquePtr(UniquePtr<T>& p) NLIB_NOEXCEPT {
153  if (IsUnique()) {
154  p.reset(ptr_);
155  ptr_ = nullptr;
156  release();
157  return true;
158  } else {
159  return false;
160  }
161 }
162 
163 template<class T, class DEL>
164 class LimitedSharedPtr<T[], DEL> {
165  private:
166  NLIB_DISALLOW_COPY_AND_ASSIGN(LimitedSharedPtr);
167 }; // not allowed for now
168 
169 } // namespace threading
170 NLIB_NAMESPACE_END
171 
172 NLIB_DEFINE_STD_SWAP_T_BEGIN3(nn, nlib, threading)
173 NLIB_DEFINE_STD_SWAP_T2(T, DEL, NLIB_NS::threading::LimitedSharedPtr)
174 NLIB_DEFINE_STD_SWAP_T_END3(nn, nlib, threading)
175 
176 #endif // INCLUDE_NN_NLIB_THREADING_LIMITEDSHAREDPTR_H_
int32_t nlib_atomic_load32(const int32_t *ptr, int memorder)
アトミックに値をロードします。動作はgccの__atomic_load_n()に準じます。
#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
std::unique_ptrに相当するクラスが定義されています。
#define NLIB_ATOMIC_ACQUIRE
gccの__ATOMIC_ACQUIREやC++11のstd::memory_order_acquireに準じます。
int32_t nlib_atomic_sub_fetch32(int32_t *ptr, int32_t val, int memorder)
アトミックな値の減算を行います。動作はgccの__atomic_sub_fetch()に準じます。
int32_t nlib_atomic_add_fetch32(int32_t *ptr, int32_t val, int memorder)
アトミックな値の加算を行います。動作はgccの__atomic_add_fetch()に準じます。
#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
int errno_t
intのtypedefで、戻り値としてPOSIXのエラー値を返すことを示します。
Definition: NMalloc.h:37