nlib
LimitedSharedPtr.h
1 
2 #pragma once
3 #ifndef INCLUDE_NN_NLIB_THREADING_LIMITEDSHAREDPTR_H_
4 #define INCLUDE_NN_NLIB_THREADING_LIMITEDSHAREDPTR_H_
5 
6 #include <new>
7 
8 #include "nn/nlib/Swap.h"
9 #include "nn/nlib/UniquePtr.h"
10 
11 NLIB_NAMESPACE_BEGIN
12 namespace threading {
13 
14 namespace internal {
15 
16 class LspStatus {
17  public:
18  NLIB_CEXPR LspStatus() NLIB_NOEXCEPT : value_(NULL) {}
19  ~LspStatus() NLIB_NOEXCEPT {}
20  NLIB_MOVE_MEMBER_HELPER_1(LspStatus, value_)
21  errno_t ToShare(LspStatus* ptr) NLIB_NOEXCEPT {
22  if (!value_) {
23  value_ = new (std::nothrow) int32_t(2);
24  if (!value_) return ENOMEM;
25  } else {
27  }
28  NLIB_ASSERT(!ptr->value_);
29  ptr->value_ = value_;
30  return 0;
31  }
32  bool ToUnshare() NLIB_NOEXCEPT {
33  if (!value_) return false;
34  if (nlib_atomic_sub_fetch32(value_, 1, NLIB_ATOMIC_ACQUIRE) == 0) {
35  delete value_;
36  value_ = NULL;
37  return false;
38  }
39  value_ = NULL;
40  return true;
41  }
42  bool IsUnique() NLIB_NOEXCEPT {
43  if (!value_) return true;
44  return nlib_atomic_load32(value_, NLIB_ATOMIC_ACQUIRE) == 1;
45  }
46  void swap(LspStatus& rhs) NLIB_NOEXCEPT { // NOLINT
47  using std::swap;
48  swap(value_, rhs.value_);
49  }
50 
51  private:
52  int32_t* value_;
54 };
55 
56 } // namespace internal
57 
58 // Use of shared_ptr is discouraged because of unexpected overhead,
59 // and You have to share the pointer by calling MakeSharedFrom() method.
60 template <class T, class DEL = DefaultDelete<T> >
61 class LimitedSharedPtr {
62  public:
63  LimitedSharedPtr() NLIB_NOEXCEPT : ptr_(NULL) {}
64  ~LimitedSharedPtr() NLIB_NOEXCEPT { release(); }
65  explicit LimitedSharedPtr(nullptr_t) NLIB_NOEXCEPT : ptr_(NULL) {}
66  explicit LimitedSharedPtr(T* p) NLIB_NOEXCEPT : ptr_(p) {
67  // Do not count up LspStatus because there is the risk of alloc failure.
68  }
69  NLIB_MOVE_MEMBER_HELPER_2(LimitedSharedPtr, ptr_, status_)
70  void reset(T* p = 0) NLIB_NOEXCEPT { LimitedSharedPtr<T>(p).swap(*this); }
71  T& operator*() const {
72  NLIB_ASSERT(ptr_ != NULL);
73  return *ptr_;
74  }
75  T* operator->() const NLIB_NOEXCEPT {
76  NLIB_ASSERT(ptr_ != NULL);
77  return ptr_;
78  }
79  T* get() const NLIB_NOEXCEPT { return ptr_; }
80  errno_t MakeSharedFrom(const LimitedSharedPtr& p) NLIB_NOEXCEPT; // NOLINT
81  bool IsUnique() const NLIB_NOEXCEPT { return status_.IsUnique(); }
82  bool MakeUniquePtr(UniquePtr<T>& p) NLIB_NOEXCEPT; // NOLINT
83  void swap(LimitedSharedPtr& rhs) NLIB_NOEXCEPT { // NOLINT
84  using std::swap;
85  swap(ptr_, rhs.ptr_);
86  status_.swap(rhs.status_);
87  }
88  LimitedSharedPtr& operator=(nullptr_t) NLIB_NOEXCEPT {
89  release();
90  return *this;
91  }
92  NLIB_SAFE_BOOL(LimitedSharedPtr, ptr_ != NULL);
93 
94  private:
95  void release() NLIB_NOEXCEPT {
96  if (!status_.ToUnshare()) DEL()(ptr_);
97  ptr_ = NULL;
98  }
99 
100  private:
101  T* ptr_;
102  mutable internal::LspStatus status_;
103  // NLIB_DISALLOW_COPY_AND_ASSIGN(LimitedSharedPtr);
104 };
105 
106 template <class T, class DEL>
107 errno_t LimitedSharedPtr<T, DEL>::MakeSharedFrom(const LimitedSharedPtr& p)
108  NLIB_NOEXCEPT { // NOLINT
109  LimitedSharedPtr tmp;
110  if (p) {
111  errno_t e = p.status_.ToShare(&tmp.status_);
112  if (e != 0) return e;
113  tmp.ptr_ = p.ptr_;
114  }
115  tmp.swap(*this);
116  return 0;
117 }
118 
119 template <class T, class DEL>
120 bool LimitedSharedPtr<T, DEL>::MakeUniquePtr(UniquePtr<T>& p) NLIB_NOEXCEPT { // NOLINT
121  if (IsUnique()) {
122  p.reset(ptr_);
123  ptr_ = NULL;
124  release();
125  return true;
126  } else {
127  return false;
128  }
129 }
130 
131 template <class T, class DEL>
132 class LimitedSharedPtr<T[], DEL> {
133  private:
134  NLIB_DISALLOW_COPY_AND_ASSIGN(LimitedSharedPtr);
135 }; // not allowed for now
136 
137 } // namespace threading
138 NLIB_NAMESPACE_END
139 
140 #ifndef NLIB_STD_SWAP_WORKAROUND
141 NLIB_NAMESPACE_BEGIN
142 #endif
143 
144 NLIB_DEFINE_STD_SWAP_T_BEGIN1(threading) // NOLINT
145 NLIB_DEFINE_STD_SWAP_T2(T, DEL, NLIB_NS::threading::LimitedSharedPtr) // NOLINT
146 NLIB_DEFINE_STD_SWAP_T_END1(threading) // NOLINT
147 
148 #ifndef NLIB_STD_SWAP_WORKAROUND
149 NLIB_NAMESPACE_END
150 #endif
151 
152 #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:145
#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:160
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:86
#define NLIB_CEXPR
Defines constexpr if it is available for use. If not, holds an empty string.
Definition: Config.h:80
TimeSpan operator*(int i, const TimeSpan &rhs) noexcept
Increases rhs by a factor of i.
Definition: DateTime.h:212
int errno_t
Indicates with an int-type typedef that a POSIX error value is returned as the return value...
Definition: NMalloc.h:24