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  NLIB_DEPRECATED void swap(LspStatus& rhs) NLIB_NOEXCEPT { // NOLINT
36  using std::swap;
37  swap(prv_, rhs.prv_);
38  }
39  errno_t ToShare(LspStatus* ptr) NLIB_NOEXCEPT {
40  if (!prv_) {
41  prv_ = new (std::nothrow) int32_t(2);
42  if (!prv_) return ENOMEM;
43  } else {
45  }
46  NLIB_ASSERT(!ptr->prv_);
47  ptr->prv_ = prv_;
48  return 0;
49  }
50  bool ToUnshare() NLIB_NOEXCEPT {
51  if (!prv_) return false;
52  if (nlib_atomic_sub_fetch32(prv_, 1, NLIB_ATOMIC_ACQUIRE) == 0) {
53  delete prv_;
54  prv_ = nullptr;
55  return false;
56  }
57  prv_ = nullptr;
58  return true;
59  }
60  bool IsUnique() NLIB_NOEXCEPT {
61  if (!prv_) return true;
62  return nlib_atomic_load32(prv_, NLIB_ATOMIC_ACQUIRE) == 1;
63  }
64  void Reset() NLIB_NOEXCEPT { ToUnshare(); }
65 
66  private:
67  int32_t* prv_;
69 };
70 
71 } // namespace internal
72 
73 // Use of shared_ptr is discouraged because of unexpected overhead,
74 // and You have to share the pointer by calling MakeSharedFrom() method.
75 template <class T, class DEL = DefaultDelete<T> >
76 class LimitedSharedPtr {
77  public:
78  NLIB_CEXPR LimitedSharedPtr() NLIB_NOEXCEPT : ptr_(nullptr) {}
79  ~LimitedSharedPtr() NLIB_NOEXCEPT { release(); }
80  explicit LimitedSharedPtr(nullptr_t) NLIB_NOEXCEPT : ptr_(nullptr) {}
81  explicit LimitedSharedPtr(T* p) NLIB_NOEXCEPT : ptr_(p) {
82  // Do not count up LspStatus because there is the risk of alloc failure.
83  }
84 #ifdef __cpp_rvalue_references
85  LimitedSharedPtr(LimitedSharedPtr&& rhs) NLIB_NOEXCEPT
86  : ptr_(rhs.ptr_), status_(std::move(rhs.status_)) {
87  rhs.ptr_ = nullptr;
88  }
89  LimitedSharedPtr& operator=(LimitedSharedPtr&& rhs) NLIB_NOEXCEPT {
90  if (!status_.ToUnshare()) DEL()(ptr_);
91  ptr_ = rhs.ptr_;
92  rhs.ptr_ = nullptr;
93  status_ = std::move(rhs.status_);
94  return *this;
95  }
96 #endif
97  LimitedSharedPtr(LimitedSharedPtr& rhs, move_tag) NLIB_NOEXCEPT // NOLINT
98  : ptr_(rhs.ptr_), status_(rhs.status_, move_tag()) {
99  rhs.ptr_ = nullptr;
100  }
101  LimitedSharedPtr& assign(LimitedSharedPtr& rhs, move_tag) NLIB_NOEXCEPT { // NOLINT
102  if (!status_.ToUnshare()) DEL()(ptr_);
103  ptr_ = rhs.ptr_;
104  rhs.ptr_ = nullptr;
105  status_.assign(rhs.status_, move_tag());
106  return *this;
107  }
108  NLIB_DEPRECATED void swap(LimitedSharedPtr& rhs) NLIB_NOEXCEPT { // NOLINT
109  using std::swap;
110  swap(ptr_, rhs.ptr_);
111  swap(status_, rhs.status_);
112  }
113  void reset(T* p = 0) NLIB_NOEXCEPT {
114  if (!status_.ToUnshare()) DEL()(ptr_);
115  ptr_ = p;
116  }
117  T& operator*() const {
118  NLIB_ASSERT(ptr_ != nullptr);
119  return *ptr_;
120  }
121  T* operator->() const NLIB_NOEXCEPT {
122  NLIB_ASSERT(ptr_ != nullptr);
123  return ptr_;
124  }
125  T* get() const NLIB_NOEXCEPT { return ptr_; }
126  errno_t MakeSharedFrom(const LimitedSharedPtr& p) NLIB_NOEXCEPT; // NOLINT
127  bool IsUnique() const NLIB_NOEXCEPT { return status_.IsUnique(); }
128  bool MakeUniquePtr(UniquePtr<T>& p) NLIB_NOEXCEPT; // NOLINT
129  LimitedSharedPtr& operator=(nullptr_t) NLIB_NOEXCEPT {
130  release();
131  return *this;
132  }
133  NLIB_SAFE_BOOL(LimitedSharedPtr, ptr_ != nullptr);
134 
135  private:
136  void release() NLIB_NOEXCEPT {
137  if (!status_.ToUnshare()) DEL()(ptr_);
138  ptr_ = nullptr;
139  }
140 
141  private:
142  T* ptr_;
143  mutable internal::LspStatus status_;
144  NLIB_DISALLOW_COPY_AND_ASSIGN(LimitedSharedPtr);
145 };
146 
147 template <class T, class DEL>
148 errno_t LimitedSharedPtr<T, DEL>::MakeSharedFrom(const LimitedSharedPtr& p)
149  NLIB_NOEXCEPT { // NOLINT
150  LimitedSharedPtr tmp;
151  if (p) {
152  errno_t e = p.status_.ToShare(&tmp.status_);
153  if (e != 0) return e;
154  tmp.ptr_ = p.ptr_;
155  }
156  this->assign(tmp, move_tag());
157  return 0;
158 }
159 
160 template <class T, class DEL>
161 bool LimitedSharedPtr<T, DEL>::MakeUniquePtr(UniquePtr<T>& p) NLIB_NOEXCEPT { // NOLINT
162  if (IsUnique()) {
163  p.reset(ptr_);
164  ptr_ = nullptr;
165  release();
166  return true;
167  } else {
168  return false;
169  }
170 }
171 
172 template <class T, class DEL>
173 class LimitedSharedPtr<T[], DEL> {
174  private:
175  NLIB_DISALLOW_COPY_AND_ASSIGN(LimitedSharedPtr);
176 }; // not allowed for now
177 
178 } // namespace threading
179 NLIB_NAMESPACE_END
180 
181 NLIB_DEFINE_STD_SWAP_T_BEGIN3(nn, nlib, threading) // NOLINT
182 NLIB_DEFINE_STD_SWAP_T2(T, DEL, NLIB_NS::threading::LimitedSharedPtr) // NOLINT
183 NLIB_DEFINE_STD_SWAP_T_END3(nn, nlib, threading) // NOLINT
184 
185 #endif // INCLUDE_NN_NLIB_THREADING_LIMITEDSHAREDPTR_H_
int32_t nlib_atomic_load32(const int32_t *ptr, int memorder)
Loads a value in an atomic operation. Its behavior is similar to the one for __atomic_load_n() of gcc...
#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:179
#define NLIB_SAFE_BOOL(class_name, exp)
Defines a safe operator bool function in the class. Uses the C++11 explicit bool if it is available f...
Definition: Config.h:194
Definition: Base64.h:25
Defines that class that is corresponding to std::unique_ptr.
#define NLIB_DEPRECATED
Indicates that a function or something has been deprecated.
Definition: Config.h:109
#define NLIB_ATOMIC_ACQUIRE
Similar to __ATOMIC_ACQUIRE of gcc or std::memory_order_acquire of C++11.
int32_t nlib_atomic_sub_fetch32(int32_t *ptr, int32_t val, int memorder)
Subtracts atomic values. Its behavior is similar to the one for __atomic_sub_fetch() of gcc...
int32_t nlib_atomic_add_fetch32(int32_t *ptr, int32_t val, int memorder)
Adds atomic values. Its behavior is similar to the one for __atomic_add_fetch() of gcc...
#define NLIB_NOEXCEPT
Defines noexcept geared to the environment, or the equivalent.
Definition: Config.h:105
#define NLIB_CEXPR
Defines constexpr if it is available for use. If not, holds an empty string.
Definition: Config.h:107
TimeSpan operator*(int i, const TimeSpan &rhs) noexcept
Increases rhs by a factor of i.
Definition: DateTime.h:210
#define NLIB_FINAL
Defines final if it is available for use. If not, holds an empty string.
Definition: Config.h:245
int errno_t
Indicates with an int-type typedef that a POSIX error value is returned as the return value...
Definition: NMalloc.h:37