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