1 /*
2  *  IceWM - Simple smart pointer
3  *  Copyright (C) 2002, 2017, 2019 The Authors of IceWM
4  *
5  *  Release under terms of the GNU Library General Public License
6  *
7  *  2001/08/02: Mathias Hasselmann <mathias.hasselmann@gmx.net>
8  *  - initial version
9  *  2017/06/10: Bert Gijsbers - complete redesign (no virtual, no refcount).
10  *  2019/12/30: Bert Gijsbers - rewrite to use derived class in super class.
11  */
12 
13 #ifndef YPOINTER_H
14 #define YPOINTER_H
15 
16 #include <utility>
17 
18 /**************************************************************************
19  * Smart pointers behave like pointers but delete the object they own when
20  * they go out of scope. The following smart pointers are distinguished:
21  *
22  *   0. ysmart is a common super class.
23  *   1. osmart for `new` objects, deallocated by delete.
24  *   2. asmart for `new[]` arrays, deallocated by delete[].
25  *   3. csmart for `new[]` character strings, deallocated by delete[].
26  *   5. fsmart for `malloc` data, deallocated by free.
27  *   6. xsmart for `Xmalloc` data, deallocated by XFree.
28  *
29  *************************************************************************/
30 
31 #if !defined(RAND_MAX) || !defined(EXIT_SUCCESS)
32 #include <stdlib.h>     // require free()
33 #endif
34 
35 // common smart base type
36 template<class DataType, class Derived>
37 class ysmart {
38 protected:
39     DataType* fData;
40     ysmart(const ysmart<DataType, Derived>&) = delete;
41 public:
fData(data)42     explicit ysmart(DataType* data = nullptr) : fData(data) { }
ysmart(ysmart && src)43     ysmart(ysmart&& src) : fData(src.fData) { src.fData = nullptr; }
44 
~ysmart()45     ~ysmart() { unref(); }
46 
unref()47     void unref() {
48         if (fData) {
49             Derived::dispose(fData);
50             fData = nullptr;
51         }
52     }
53 
release()54     DataType* release() {
55         DataType* p = fData;
56         fData = nullptr;
57         return p;
58     }
59 
data()60     DataType* data() const { return fData; }
61 
62     void operator=(DataType* data) {
63         if (data == fData) return;
64         unref();
65         fData = data;
66     }
67 
68     operator DataType *() const { return fData; }
69     DataType& operator*() const { return *fData; }
70     DataType* operator->() const { return fData; }
71 
72 protected:
73     void operator=(const ysmart<DataType, Derived>&);
74     DataType** operator&() { return &fData; }
75 };
76 
77 // For pointers to objects which were allocated with 'new'.
78 template <class DataType>
79 class osmart : public ysmart<DataType, osmart<DataType> > {
80     typedef ysmart<DataType, osmart<DataType> > super;
81     osmart(const osmart<DataType>&);
82 public:
dispose(DataType * p)83     static inline void dispose(DataType* p) { delete p; }
84 
super(data)85     explicit osmart(DataType* data = nullptr) : super(data) { }
86 
87     using super::operator=;
88 };
89 
90 // For arrays which were allocated with 'new[]'.
91 template <class DataType>
92 class asmart : public ysmart<DataType, asmart<DataType> > {
93 protected:
94     typedef ysmart<DataType, asmart<DataType> > super;
95     asmart(const asmart<DataType>&);
96 public:
dispose(DataType * p)97     static inline void dispose(DataType* p) { delete[] p; }
98 
super(data)99     explicit asmart(DataType* data = nullptr) : super(data) { }
asmart(asmart && src)100     explicit asmart(asmart&& src) : super(src) { }
101 
102     asmart<DataType>& operator=(DataType* data) {
103         super::operator=(data);
104         return *this;
105     }
106 
107     using super::operator&;
108 };
109 
110 // for new[] character strings
111 typedef asmart<char> csmart;
112 
113 // for malloc data
114 template <class DataType>
115 class fsmart : public ysmart<DataType, fsmart<DataType> > {
116     typedef ysmart<DataType, fsmart<DataType> > super;
117 public:
dispose(DataType * p)118     static inline void dispose(DataType* p) { ::free(p); }
119 
super(data)120     explicit fsmart(DataType* data = nullptr) : super(data) { }
121 
fsmart(fsmart<DataType> && src)122     fsmart(fsmart<DataType>&& src) : super(std::move(src)) { }
123 
124     using super::operator=;
125 
126     fsmart& operator=(fsmart<DataType>&& other) {
127         auto p = other.release();
128         *this = p;
129         return *this;
130     }
131 
create(size_t amount)132     static inline fsmart create(size_t amount) {
133         return fsmart((DataType*) malloc(amount));
134     }
135 
resize(size_t amount)136     fsmart& resize(size_t amount) {
137         *super::operator&() = (DataType*) realloc(super::data(), amount);
138         return *this;
139     }
140 };
141 
142 typedef fsmart<char> fcsmart;
143 
144 extern "C" {
145     extern int XFree(void*);
146 }
147 
148 // for XFree-able data
149 template <class DataType>
150 class xsmart : public ysmart<DataType, xsmart<DataType> > {
151     typedef ysmart<DataType, xsmart<DataType> > super;
152     xsmart(const xsmart<DataType>&);
153 public:
dispose(DataType * p)154     static inline void dispose(DataType* p) { ::XFree(p); }
155 
super(data)156     explicit xsmart(DataType* data = nullptr) : super(data) { }
157 
158     using super::operator=;
159 
160     using super::operator&;
161 
162     template <typename T>
convert()163     T* convert() const {
164         return reinterpret_cast<T *>(super::data());
165     }
166     template <typename T>
extract()167     T& extract() const {
168         return *convert<T>();
169     }
170 };
171 
172 #endif
173 
174 // vim: set sw=4 ts=4 et:
175