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