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