source: filezilla/trunk/fuentes/src/include/refcount.h @ 130

Last change on this file since 130 was 130, checked in by jrpelegrina, 3 years ago

First release to xenial

File size: 4.9 KB
Line 
1#ifndef __REFCOUNT_H__
2#define __REFCOUNT_H__
3
4#include <memory>
5#include <type_traits>
6
7// Template class to refcount objects with COW semantics.
8// This class is thread-safe under the following assumptions:
9// - The object stored in it must be thread-safe for reading
10// - Any instance Get() is called on must never be used in
11//   different threads.
12template<class T> class CRefcountObject final
13{
14public:
15        CRefcountObject();
16        CRefcountObject(CRefcountObject<T> const& v) = default;
17        CRefcountObject(CRefcountObject<T> && v) noexcept = default;
18        explicit CRefcountObject(const T& v);
19
20        void clear();
21
22        T& Get();
23
24        const T& operator*() const;
25        const T* operator->() const;
26
27        // Comparison operators are deep. If two intances point to
28        // different objects, those objects are compared
29        bool operator==(CRefcountObject<T> const& cmp) const;
30        bool operator==(T const& cmp) const;
31        bool operator<(CRefcountObject<T> const& cmp) const;
32        bool operator<(T const& cmp) const;
33
34        inline bool operator!=(const CRefcountObject<T>& cmp) const { return !(*this == cmp); }
35
36        CRefcountObject<T>& operator=(CRefcountObject<T> const& v) = default;
37        CRefcountObject<T>& operator=(CRefcountObject<T> && v) noexcept = default;
38protected:
39        std::shared_ptr<T> data_;
40};
41
42template<class T> class CRefcountObject_Uninitialized final
43{
44        /* Almost same as CRefcountObject but does not allocate
45           an object initially.
46           You need to ensure to assign some data prior to calling
47           operator* or ->, otherwise you'll dereference the null-pointer.
48         */
49public:
50        CRefcountObject_Uninitialized() = default;
51        CRefcountObject_Uninitialized(CRefcountObject_Uninitialized<T> const& v) = default;
52        CRefcountObject_Uninitialized(CRefcountObject_Uninitialized<T> && v) noexcept = default;
53        explicit CRefcountObject_Uninitialized(T const& v);
54
55        void clear();
56
57        T& Get();
58
59        const T& operator*() const;
60        const T* operator->() const;
61
62        bool operator==(const CRefcountObject_Uninitialized<T>& cmp) const;
63        inline bool operator!=(const CRefcountObject_Uninitialized<T>& cmp) const { return !(*this == cmp); }
64        bool operator<(const CRefcountObject_Uninitialized<T>& cmp) const;
65
66        CRefcountObject_Uninitialized<T>& operator=(CRefcountObject_Uninitialized<T> const& v) = default;
67        CRefcountObject_Uninitialized<T>& operator=(CRefcountObject_Uninitialized<T> && v) noexcept = default;
68
69        bool operator!() const { return !data_; }
70        explicit operator bool() const { return data_; }
71
72        bool empty() const { return data_.get(); }
73protected:
74        std::shared_ptr<T> data_;
75};
76
77template<class T> bool CRefcountObject<T>::operator==(CRefcountObject<T> const& cmp) const
78{
79        if (data_ == cmp.data_)
80                return true;
81
82        return *data_ == *cmp.data_;
83}
84
85template<class T> bool CRefcountObject<T>::operator==(T const& cmp) const
86{
87        return *data_ == cmp;
88}
89
90template<class T> CRefcountObject<T>::CRefcountObject()
91        : data_(std::make_shared<T>())
92{
93}
94
95template<class T> CRefcountObject<T>::CRefcountObject(const T& v)
96        : data_(std::make_shared<T>(v))
97{
98}
99
100template<class T> T& CRefcountObject<T>::Get()
101{
102        if (!data_.unique()) {
103                data_ = std::make_shared<T>(*data_);
104        }
105
106        return *data_.get();
107}
108
109template<class T> bool CRefcountObject<T>::operator<(CRefcountObject<T> const& cmp) const
110{
111        if (data_ == cmp.data_)
112                return false;
113
114        return *data_.get() < *cmp.data_.get();
115}
116
117template<class T> bool CRefcountObject<T>::operator<(T const& cmp) const
118{
119        if (!data_) {
120                return true;
121        }
122        return *data_.get() < cmp;
123}
124
125template<class T> void CRefcountObject<T>::clear()
126{
127        if (data_.unique()) {
128                *data_.get() = T();
129        }
130        else {
131                data_ = std::make_shared<T>();
132        }
133}
134
135template<class T> const T& CRefcountObject<T>::operator*() const
136{
137        return *data_;
138}
139
140template<class T> const T* CRefcountObject<T>::operator->() const
141{
142        return data_.get();
143}
144
145// The same for the uninitialized version
146template<class T> bool CRefcountObject_Uninitialized<T>::operator==(const CRefcountObject_Uninitialized<T>& cmp) const
147{
148        if (data_ == cmp.data_)
149                return true;
150
151        if (!data_) {
152                return !cmp.data_;
153        }
154        else if (!cmp.data_) {
155                return false;
156        }
157        return *data_.get() == *cmp.data_.get();
158}
159
160template<class T> CRefcountObject_Uninitialized<T>::CRefcountObject_Uninitialized(T const& v)
161        : data_(std::make_shared<T>(v))
162{
163}
164
165template<class T> T& CRefcountObject_Uninitialized<T>::Get()
166{
167        if (!data_) {
168                data_ = std::make_shared<T>();
169        }
170        else if (!data_.unique()) {
171                data_ = std::make_shared<T>(*data_);
172        }
173
174        return *data_.get();
175}
176
177template<class T> bool CRefcountObject_Uninitialized<T>::operator<(const CRefcountObject_Uninitialized<T>& cmp) const
178{
179        if (data_ == cmp.data_) {
180                return false;
181        }
182        else if (!data_) {
183                return cmp.data_;
184        }
185        else if (!cmp.data_) {
186                return false;
187        }
188
189        return *data_.get() < *cmp.data_.get();
190
191}
192
193template<class T> void CRefcountObject_Uninitialized<T>::clear()
194{
195        data_.reset();
196}
197
198template<class T> const T& CRefcountObject_Uninitialized<T>::operator*() const
199{
200        return *data_.get();
201}
202
203template<class T> const T* CRefcountObject_Uninitialized<T>::operator->() const
204{
205        return data_.get();
206}
207
208#endif //__REFCOUNT_H__
Note: See TracBrowser for help on using the repository browser.