1 // smartptr.h - originally written and placed in the public domain by Wei Dai
2 
3 /// \file smartptr.h
4 /// \brief Classes for automatic resource management
5 
6 #ifndef CRYPTOPP_SMARTPTR_H
7 #define CRYPTOPP_SMARTPTR_H
8 
9 #include "config.h"
10 #include "stdcpp.h"
11 
NAMESPACE_BEGIN(CryptoPP)12 NAMESPACE_BEGIN(CryptoPP)
13 
14 /// \brief Manages resources for a single object
15 /// \tparam T class or type
16 /// \details \p simple_ptr is used frequently in the library to manage resources and
17 ///   ensure cleanup under the RAII pattern (Resource Acquisition Is Initialization).
18 template <class T> class simple_ptr
19 {
20 public:
21 	simple_ptr(T *p = NULLPTR) : m_p(p) {}
22 	~simple_ptr()
23 	{
24 		delete m_p;
25 		m_p = NULLPTR;
26 	}
27 
28 	T *m_p;
29 };
30 
31 /// \brief Pointer that overloads operator ->
32 /// \tparam T class or type
33 /// \details member_ptr is used frequently in the library to avoid the issues related to
34 ///  std::auto_ptr in C++11 (deprecated) and std::unique_ptr in C++03 (non-existent).
35 /// \bug <a href="http://github.com/weidai11/cryptopp/issues/48">Issue 48: "Use of auto_ptr
36 ///  causes dirty compile under C++11"</a>
37 template <class T> class member_ptr
38 {
39 public:
m_p(p)40 	explicit member_ptr(T *p = NULLPTR) : m_p(p) {}
41 
42 	~member_ptr();
43 
44 	const T& operator*() const { return *m_p; }
45 	T& operator*() { return *m_p; }
46 
47 	const T* operator->() const { return m_p; }
48 	T* operator->() { return m_p; }
49 
get()50 	const T* get() const { return m_p; }
get()51 	T* get() { return m_p; }
52 
release()53 	T* release()
54 	{
55 		T *old_p = m_p;
56 		m_p = NULLPTR;
57 		return old_p;
58 	}
59 
60 	void reset(T *p = NULLPTR);
61 
62 protected:
63 	member_ptr(const member_ptr<T>& rhs);		// copy not allowed
64 	void operator=(const member_ptr<T>& rhs);	// assignment not allowed
65 
66 	T *m_p;
67 };
68 
~member_ptr()69 template <class T> member_ptr<T>::~member_ptr() {delete m_p;}
reset(T * p)70 template <class T> void member_ptr<T>::reset(T *p) {delete m_p; m_p = p;}
71 
72 // ********************************************************
73 
74 /// \brief Value pointer
75 /// \tparam T class or type
76 template<class T> class value_ptr : public member_ptr<T>
77 {
78 public:
value_ptr(const T & obj)79 	value_ptr(const T &obj) : member_ptr<T>(new T(obj)) {}
80 	value_ptr(T *p = NULLPTR) : member_ptr<T>(p) {}
value_ptr(const value_ptr<T> & rhs)81 	value_ptr(const value_ptr<T>& rhs)
82 		: member_ptr<T>(rhs.m_p ? new T(*rhs.m_p) : NULLPTR) {}
83 
84 	value_ptr<T>& operator=(const value_ptr<T>& rhs);
85 	bool operator==(const value_ptr<T>& rhs)
86 	{
87 		return (!this->m_p && !rhs.m_p) || (this->m_p && rhs.m_p && *this->m_p == *rhs.m_p);
88 	}
89 };
90 
91 template <class T> value_ptr<T>& value_ptr<T>::operator=(const value_ptr<T>& rhs)
92 {
93 	T *old_p = this->m_p;
94 	this->m_p = rhs.m_p ? new T(*rhs.m_p) : NULLPTR;
95 	delete old_p;
96 	return *this;
97 }
98 
99 // ********************************************************
100 
101 /// \brief A pointer which can be copied and cloned
102 /// \tparam T class or type
103 /// \details \p T should adhere to the \p Clonable interface
104 template<class T> class clonable_ptr : public member_ptr<T>
105 {
106 public:
clonable_ptr(const T & obj)107 	clonable_ptr(const T &obj) : member_ptr<T>(obj.Clone()) {}
108 	clonable_ptr(T *p = NULLPTR) : member_ptr<T>(p) {}
clonable_ptr(const clonable_ptr<T> & rhs)109 	clonable_ptr(const clonable_ptr<T>& rhs)
110 		: member_ptr<T>(rhs.m_p ? rhs.m_p->Clone() : NULLPTR) {}
111 
112 	clonable_ptr<T>& operator=(const clonable_ptr<T>& rhs);
113 };
114 
115 template <class T> clonable_ptr<T>& clonable_ptr<T>::operator=(const clonable_ptr<T>& rhs)
116 {
117 	T *old_p = this->m_p;
118 	this->m_p = rhs.m_p ? rhs.m_p->Clone() : NULLPTR;
119 	delete old_p;
120 	return *this;
121 }
122 
123 // ********************************************************
124 
125 /// \brief Reference counted pointer
126 /// \tparam T class or type
127 /// \details users should declare \p m_referenceCount as <tt>std::atomic<unsigned></tt>
128 ///   (or similar) under C++ 11
129 template<class T> class counted_ptr
130 {
131 public:
132 	explicit counted_ptr(T *p = NULLPTR);
counted_ptr(const T & r)133 	counted_ptr(const T &r) : m_p(0) {attach(r);}
134 	counted_ptr(const counted_ptr<T>& rhs);
135 
136 	~counted_ptr();
137 
138 	const T& operator*() const { return *m_p; }
139 	T& operator*() { return *m_p; }
140 
141 	const T* operator->() const { return m_p; }
142 	T* operator->() { return get(); }
143 
get()144 	const T* get() const { return m_p; }
145 	T* get();
146 
147 	void attach(const T &p);
148 
149 	counted_ptr<T> & operator=(const counted_ptr<T>& rhs);
150 
151 private:
152 	T *m_p;
153 };
154 
counted_ptr(T * p)155 template <class T> counted_ptr<T>::counted_ptr(T *p)
156 	: m_p(p)
157 {
158 	if (m_p)
159 		m_p->m_referenceCount = 1;
160 }
161 
counted_ptr(const counted_ptr<T> & rhs)162 template <class T> counted_ptr<T>::counted_ptr(const counted_ptr<T>& rhs)
163 	: m_p(rhs.m_p)
164 {
165 	if (m_p)
166 		m_p->m_referenceCount++;
167 }
168 
~counted_ptr()169 template <class T> counted_ptr<T>::~counted_ptr()
170 {
171 	if (m_p && --m_p->m_referenceCount == 0)
172 		delete m_p;
173 }
174 
attach(const T & r)175 template <class T> void counted_ptr<T>::attach(const T &r)
176 {
177 	if (m_p && --m_p->m_referenceCount == 0)
178 		delete m_p;
179 	if (r.m_referenceCount == 0)
180 	{
181 		m_p = r.clone();
182 		m_p->m_referenceCount = 1;
183 	}
184 	else
185 	{
186 		m_p = const_cast<T *>(&r);
187 		m_p->m_referenceCount++;
188 	}
189 }
190 
get()191 template <class T> T* counted_ptr<T>::get()
192 {
193 	if (m_p && m_p->m_referenceCount > 1)
194 	{
195 		T *temp = m_p->clone();
196 		m_p->m_referenceCount--;
197 		m_p = temp;
198 		m_p->m_referenceCount = 1;
199 	}
200 	return m_p;
201 }
202 
203 template <class T> counted_ptr<T> & counted_ptr<T>::operator=(const counted_ptr<T>& rhs)
204 {
205 	if (m_p != rhs.m_p)
206 	{
207 		if (m_p && --m_p->m_referenceCount == 0)
208 			delete m_p;
209 		m_p = rhs.m_p;
210 		if (m_p)
211 			m_p->m_referenceCount++;
212 	}
213 	return *this;
214 }
215 
216 // ********************************************************
217 
218 /// \brief Manages resources for an array of objects
219 /// \tparam T class or type
220 template <class T> class vector_member_ptrs
221 {
222 public:
223 	/// Construct an arry of \p T
224 	/// \param size the size of the array, in elements
225 	/// \details If \p T is a Plain Old Dataype (POD), then the array is uninitialized.
226 	vector_member_ptrs(size_t size=0)
m_size(size)227 		: m_size(size), m_ptr(new member_ptr<T>[size]) {}
~vector_member_ptrs()228 	~vector_member_ptrs()
229 		{delete [] this->m_ptr;}
230 
231 	member_ptr<T>& operator[](size_t index)
232 		{CRYPTOPP_ASSERT(index<this->m_size); return this->m_ptr[index];}
233 	const member_ptr<T>& operator[](size_t index) const
234 		{CRYPTOPP_ASSERT(index<this->m_size); return this->m_ptr[index];}
235 
size()236 	size_t size() const {return this->m_size;}
resize(size_t newSize)237 	void resize(size_t newSize)
238 	{
239 		member_ptr<T> *newPtr = new member_ptr<T>[newSize];
240 		for (size_t i=0; i<this->m_size && i<newSize; i++)
241 			newPtr[i].reset(this->m_ptr[i].release());
242 		delete [] this->m_ptr;
243 		this->m_size = newSize;
244 		this->m_ptr = newPtr;
245 	}
246 
247 private:
248 	vector_member_ptrs(const vector_member_ptrs<T> &c);	// copy not allowed
249 	void operator=(const vector_member_ptrs<T> &x);		// assignment not allowed
250 
251 	size_t m_size;
252 	member_ptr<T> *m_ptr;
253 };
254 
255 NAMESPACE_END
256 
257 #endif
258