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)
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:183
#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:199
Definition: Base64.h:25
Defines that class that is corresponding to std::unique_ptr.
#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:109
#define NLIB_CEXPR
Defines constexpr if it is available for use. If not, holds an empty string.
Definition: Config.h:111
TimeSpan operator*(int i, const TimeSpan &rhs) noexcept
Increases rhs by a factor of i.
Definition: DateTime.h:195
#define NLIB_FINAL
Defines final if it is available for use. If not, holds an empty string.
Definition: Config.h:250
int errno_t
Indicates with an int-type typedef that a POSIX error value is returned as the return value...
Definition: NMalloc.h:37