casacore
Loading...
Searching...
No Matches
Storage.h
Go to the documentation of this file.
1#ifndef CASACORE_STORAGE_2_H
2#define CASACORE_STORAGE_2_H
3
4#include <cstring>
5#include <memory>
6
7namespace casacore {
8
9namespace arrays_internal {
10
11// This class emplements a static (but run-time) sized array. It is used in the
12// Array class, and is necessary because std::vector specializes for bool.
13// It holds the same functionality as a normal array, and enables allocation
14// through different allocators similar to std::vector.
15template<typename T, typename Alloc>
16class Storage : public Alloc
17{
18public:
19 // Construct an empty Storage
20 Storage(const Alloc& allocator) :
21 Alloc(allocator),
22 _data(nullptr),
23 _end(nullptr),
24 _isShared(false)
25 { }
26
27 // Construct Storage with a given size.
28 // The elements will be default constructed
29 Storage(std::size_t n, const Alloc& allocator) :
30 Alloc(allocator),
31 _data(construct(n)),
32 _end(_data + n),
33 _isShared(false)
34 { }
35
36 // Construct Storage with a given size.
37 // The elements will be copy constructed from the given value
38 Storage(std::size_t n, const T& val, const Alloc& allocator) :
39 Alloc(allocator),
40 _data(construct(n, val)),
41 _end(_data + n),
42 _isShared(false)
43 { }
44
45 // Construct Storage from a range.
46 // The elements will be copy constructed from the given values.
47 // Note that this constructor can be chosen over
48 // of Storage(std::size_t, const T&, const Alloc) when T=size_t. Therefore,
49 // this constructor forwards to the appropriate constructor based on
50 // whether T is an integral.
51 template<typename InputIterator>
52 Storage(InputIterator startIter, InputIterator endIter, const Alloc& allocator) :
53 Storage(startIter, endIter, allocator,
55 std::is_integral<InputIterator>,
57 std::is_same<InputIterator, const char*>,
58 std::is_base_of<std::string, T>
59 >
60 >())
61 { }
62
63 // Construct Storage from a range by moving.
64 // The elements will be move constructed from the given values.
65 static std::unique_ptr<Storage<T, Alloc>> MakeFromMove(T* startIter, T* endIter, const Alloc& allocator)
66 {
67 return std::unique_ptr<Storage<T, Alloc>>(new Storage(startIter, endIter, allocator, std::false_type(), std::true_type()));
68 }
69
70 // Construct a Storage from existing data.
71 // The given pointer will not be owned by this class.
72 static std::unique_ptr<Storage<T, Alloc>> MakeFromSharedData(T* existingData, size_t n, const Alloc& allocator)
73 {
74 std::unique_ptr<Storage<T, Alloc>> newStorage = std::unique_ptr<Storage>(new Storage<T, Alloc>(allocator));
75 newStorage->_data = existingData;
76 newStorage->_end = existingData + n;
77 newStorage->_isShared = true;
78 return newStorage;
79 }
80
81 // Construct a Storage with uninitialized data.
82 // This will skip the constructor of the elements. This is only allowed for
83 // trivial types.
84 static std::unique_ptr<Storage<T, Alloc>> MakeUninitialized(size_t n, const Alloc& allocator)
85 {
86 static_assert(std::is_trivial<T>::value, "Only trivial types can be constructed uninitialized");
87 std::unique_ptr<Storage<T, Alloc>> newStorage = std::unique_ptr<Storage>(new Storage<T, Alloc>(allocator));
88 if(n == 0)
89 newStorage->_data = nullptr;
90 else
91 newStorage->_data = static_cast<Alloc&>(*newStorage).allocate(n);
92 newStorage->_end = newStorage->_data + n;
93 return newStorage;
94 }
95
96 // Destructs the elements and deallocates the data
97 ~Storage() noexcept
98 {
99 if(size() && !_isShared)
100 {
101 for(size_t i=0; i!=size(); ++i)
102 _data[size()-i-1].~T();
103 Alloc::deallocate(_data, size());
104 }
105 }
106
107 // Return a pointer to the storage data.
108 // @{
109 T* data() { return _data; }
110 const T* data() const { return _data; }
111 // @}
112
113 // Size of the data, zero if empty.
114 size_t size() const { return _end - _data; }
115
116 // Returns the allocator associated with this Storage.
117 const Alloc& get_allocator() const { return static_cast<const Alloc&>(*this); }
118
119 // Whether this Storage owns its data.
120 // Returns @c true when this Storage was constructed with MakeFromSharedData().
121 bool is_shared() const { return _isShared; }
122
123 Storage(const Storage<T, Alloc>&) = delete;
125 Storage& operator=(const Storage&) = delete;
127
128private:
129 // Moving range constructor implementation. Parameter integral is only a place-holder.
130 Storage(T* startIter, T* endIter, const Alloc& allocator, std::false_type /*integral*/, std::true_type /*move*/) :
131 Alloc(allocator),
132 _data(construct_move(startIter, endIter)),
133 _end(_data + (endIter-startIter)),
134 _isShared(false)
135 { }
136
137 // Copying range constructor implementation for non-integral types
138 template<typename InputIterator>
139 Storage(InputIterator startIter, InputIterator endIter, const Alloc& allocator, std::false_type /*integral*/) :
140 Alloc(allocator),
141 _data(construct_range(startIter, endIter)),
142 _end(_data + std::distance(startIter, endIter)),
143 _isShared(false)
144 { }
145
146 // Copying range constructor implementation for integral types
147 template<typename Integral>
148 Storage(Integral n, Integral val, const Alloc& allocator, std::true_type /*integral*/) :
149 Alloc(allocator),
150 _data(construct(n, val)),
151 _end(_data + n),
152 _isShared(false)
153 { }
154
155 // These methods allocate the storage and construct the elements.
156 // When any element constructor throws, the already constructed elements are destructed in reverse
157 // and the allocated storage is deallocated.
158 // @{
159
160 T* construct(size_t n)
161 {
162 if(n == 0)
163 return nullptr;
164 else {
165 T* data = Alloc::allocate(n);
166 T* current = data;
167 try {
168 for (; current != data+n; ++current) {
169 new (current) T();
170 }
171 } catch(...) {
172 while(current != data)
173 {
174 --current;
175 current->~T();
176 }
177 Alloc::deallocate(data, n);
178 throw;
179 }
180 return data;
181 }
182 }
183
184 T* construct(size_t n, const T& val)
185 {
186 if(n == 0)
187 return nullptr;
188 else {
189 T* data = Alloc::allocate(n);
190 T* current = data;
191 try {
192 for (; current != data+n; ++current) {
193 new (current) T(val);
194 }
195 } catch(...) {
196 while(current != data)
197 {
198 --current;
199 current->~T();
200 }
201 Alloc::deallocate(data, n);
202 throw;
203 }
204 return data;
205 }
206 }
207
208 template<typename InputIterator>
209 T* construct_range(InputIterator startIter, InputIterator endIter)
210 {
211 if(startIter == endIter)
212 return nullptr;
213 else {
214 size_t n = std::distance(startIter, endIter);
215 T* data = Alloc::allocate(n);
216 T* current = data;
217 try {
218 for (; current != data+n; ++current) {
219 new (current) T(*startIter);
220 ++startIter;
221 }
222 } catch(...) {
223 while(current != data)
224 {
225 --current;
226 current->~T();
227 }
228 Alloc::deallocate(data, n);
229 throw;
230 }
231 return data;
232 }
233 }
234
235 T* construct_move(T* startIter, T* endIter)
236 {
237 if(startIter == endIter)
238 return nullptr;
239 else {
240 size_t n = endIter - startIter;
241 T* data = Alloc::allocate(n);
242 T* current = data;
243 try {
244 for (; current != data+n; ++current) {
245 new (current) T(std::move(*startIter));
246 ++startIter;
247 }
248 } catch(...) {
249 while(current != data)
250 {
251 --current;
252 current->~T();
253 }
254 Alloc::deallocate(data, n);
255 throw;
256 }
257 return data;
258 }
259 }
260
261 // @}
262
263 // Used by template code above
264 // These are already in C++17, but currently only using C++11...
265 template<class...> struct disjunction : std::false_type { };
266 template<class B1> struct disjunction<B1> : B1 { };
267 template<class B1, class... Bn>
268 struct disjunction<B1, Bn...>
269 : std::conditional<bool(B1::value), B1, disjunction<Bn...>>::type { };
270
271 template<class...> struct conjunction : std::true_type { };
272 template<class B1> struct conjunction<B1> : B1 { };
273 template<class B1, class... Bn>
274 struct conjunction<B1, Bn...>
275 : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
276
280};
281
282} }
283
284#endif
This class emplements a static (but run-time) sized array.
Definition Storage.h:17
T * construct_range(InputIterator startIter, InputIterator endIter)
Definition Storage.h:209
Storage(const Storage< T, Alloc > &)=delete
T * construct_move(T *startIter, T *endIter)
Definition Storage.h:235
size_t size() const
Size of the data, zero if empty.
Definition Storage.h:114
Storage & operator=(Storage &&)=delete
Storage(T *startIter, T *endIter, const Alloc &allocator, std::false_type, std::true_type)
Moving range constructor implementation.
Definition Storage.h:130
Storage(InputIterator startIter, InputIterator endIter, const Alloc &allocator)
Construct Storage from a range.
Definition Storage.h:52
~Storage() noexcept
Destructs the elements and deallocates the data.
Definition Storage.h:97
T * construct(size_t n, const T &val)
Definition Storage.h:184
const Alloc & get_allocator() const
Returns the allocator associated with this Storage.
Definition Storage.h:117
Storage(Integral n, Integral val, const Alloc &allocator, std::true_type)
Copying range constructor implementation for integral types.
Definition Storage.h:148
static std::unique_ptr< Storage< T, Alloc > > MakeFromSharedData(T *existingData, size_t n, const Alloc &allocator)
Construct a Storage from existing data.
Definition Storage.h:72
Storage(const Alloc &allocator)
Construct an empty Storage.
Definition Storage.h:20
T * construct(size_t n)
These methods allocate the storage and construct the elements.
Definition Storage.h:160
Storage(InputIterator startIter, InputIterator endIter, const Alloc &allocator, std::false_type)
Copying range constructor implementation for non-integral types.
Definition Storage.h:139
Storage(std::size_t n, const T &val, const Alloc &allocator)
Construct Storage with a given size.
Definition Storage.h:38
Storage(std::size_t n, const Alloc &allocator)
Construct Storage with a given size.
Definition Storage.h:29
Storage(Storage< T, Alloc > &&)=delete
bool is_shared() const
Whether this Storage owns its data.
Definition Storage.h:121
static std::unique_ptr< Storage< T, Alloc > > MakeFromMove(T *startIter, T *endIter, const Alloc &allocator)
Construct Storage from a range by moving.
Definition Storage.h:65
static std::unique_ptr< Storage< T, Alloc > > MakeUninitialized(size_t n, const Alloc &allocator)
Construct a Storage with uninitialized data.
Definition Storage.h:84
T * data()
Return a pointer to the storage data.
Definition Storage.h:109
Storage & operator=(const Storage &)=delete
this file contains all the compiler specific defines
Definition mainpage.dox:28
Define real & complex conjugation for non-complex types and put comparisons into std namespace.
Definition Complex.h:352
Used by template code above These are already in C++17, but currently only using C++11....
Definition Storage.h:265