vsg: include/vsg/core/Array.h Source File

vsg 1.1.3 VulkanSceneGraph library

Loading...
Searching...
No Matches
Array.h
1#pragma once
2
3/* <editor-fold desc="MIT License">
4
5Copyright(c) 2018 Robert Osfield
6
7Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
9The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
11THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12
13</editor-fold> */
14
15#include <vsg/core/Data.h>
16
17#include <vsg/maths/mat4.h>
18#include <vsg/maths/vec2.h>
19#include <vsg/maths/vec3.h>
20#include <vsg/maths/vec4.h>
21
22#include <vsg/io/Input.h>
23#include <vsg/io/Output.h>
24
25#define VSG_array(N, T) \
26 using N = Array<T>; \
27 template<> \
28 constexpr const char* type_name<N>() noexcept { return "vsg::" #N; } \
29 template<> \
30 constexpr const char* type_name<const N>() noexcept { return "vsg::" #N; }
31
32namespace vsg
33{
34
35 template<typename T>
36 class Array : public Data
37 {
38 public:
39 using value_type = T;
40 using iterator = stride_iterator<value_type>;
41 using const_iterator = stride_iterator<const value_type>;
42
43 Array() :
44 _data(nullptr),
45 _size(0) {}
46
47 Array(const Array& rhs, const CopyOp copyop = {}) :
48 Data(rhs, copyop),
49 _data(nullptr),
50 _size(rhs._size)
51 {
52 if (_size != 0)
53 {
54 _data = _allocate(_size);
55 auto dest_v = _data;
56 for (auto& v : rhs) *(dest_v++) = v;
57 }
58 dirty();
59 }
60
61 explicit Array(uint32_t numElements, Properties in_properties = {}) :
62 Data(in_properties, sizeof(value_type)),
63 _data(_allocate(numElements)),
64 _size(numElements) { dirty(); }
65
66 Array(uint32_t numElements, value_type* data, Properties in_properties = {}) :
67 Data(in_properties, sizeof(value_type)),
68 _data(data),
69 _size(numElements) { dirty(); }
70
71 Array(uint32_t numElements, const value_type& value, Properties in_properties = {}) :
72 Data(in_properties, sizeof(value_type)),
73 _data(_allocate(numElements)),
74 _size(numElements)
75 {
76 for (auto& v : *this) v = value;
77 dirty();
78 }
79
80 Array(ref_ptr<Data> data, uint32_t offset, uint32_t stride, uint32_t numElements, Properties in_properties = {}) :
81 Data(),
82 _data(nullptr),
83 _size(0)
84 {
85 assign(data, offset, stride, numElements, in_properties);
86 }
87
88 explicit Array(std::initializer_list<value_type> l) :
89 _data(_allocate(l.size())),
90 _size(static_cast<uint32_t>(l.size()))
91 {
92 properties.stride = sizeof(value_type);
93
94 iterator itr = begin();
95 for (const value_type& v : l) { (*itr++) = v; }
96
97 dirty();
98 }
99
100 explicit Array(ref_ptr<Data> data, uint32_t offset, uint32_t stride, std::initializer_list<value_type> l) :
101 _data(nullptr),
102 _size(0)
103 {
104 assign(data, offset, stride, l.size());
105
106 iterator itr = begin();
107 for (const value_type& v : l) { (*itr++) = v; }
108
109 dirty();
110 }
111
112 template<typename... Args>
113 static ref_ptr<Array> create(Args&&... args)
114 {
115 return ref_ptr<Array>(new Array(std::forward<Args>(args)...));
116 }
117
118 static ref_ptr<Array> create(std::initializer_list<value_type> l)
119 {
120 return ref_ptr<Array>(new Array(l));
121 }
122
123 static ref_ptr<Array> create(ref_ptr<Data> data, uint32_t offset, uint32_t stride, std::initializer_list<value_type> l)
124 {
125 return ref_ptr<Array>(new Array(data, offset, stride, l));
126 }
127
128 ref_ptr<Object> clone(const CopyOp& copyop = {}) const override
129 {
130 return ref_ptr<Array>(new Array(*this, copyop));
131 }
132
133 size_t sizeofObject() const noexcept override { return sizeof(Array); }
134 const char* className() const noexcept override { return type_name<Array>(); }
135 const std::type_info& type_info() const noexcept override { return typeid(*this); }
136 bool is_compatible(const std::type_info& type) const noexcept override { return typeid(Array) == type || Data::is_compatible(type); }
137
138 // implementation provided by Visitor.h
139 void accept(Visitor& visitor) override;
140 void accept(ConstVisitor& visitor) const override;
141
142 void read(Input& input) override
143 {
144 size_t original_total_size = size();
145
146 Data::read(input);
147
148 uint32_t width_size = input.readValue<uint32_t>("size");
149
150 if (auto data_storage = input.readObject<Data>("storage"))
151 {
152 uint32_t offset = input.readValue<uint32_t>("offset");
153 assign(data_storage, offset, properties.stride, width_size, properties);
154 return;
155 }
156
157 if (input.matchPropertyName("data"))
158 {
159 size_t new_total_size = computeValueCountIncludingMipmaps(width_size, 1, 1, properties.maxNumMipmaps);
160
161 if (_data) // if data exists already may be able to reuse it
162 {
163 if (original_total_size != new_total_size) // if existing data is a different size delete old, and create new
164 {
165 clear();
166
167 _data = _allocate(new_total_size);
168 }
169 }
170 else // allocate space for data
171 {
172 _data = _allocate(new_total_size);
173 }
174
175 properties.stride = sizeof(value_type);
176 _size = width_size;
177 _storage = nullptr;
178
179 if (_data) input.read(new_total_size, _data);
180
181 dirty();
182 }
183 }
184
185 void write(Output& output) const override
186 {
187 Data::write(output);
188
189 output.writeValue<uint32_t>("size", _size);
190 output.writeObject("storage", _storage);
191 if (_storage)
192 {
193 auto offset = (reinterpret_cast<uintptr_t>(_data) - reinterpret_cast<uintptr_t>(_storage->dataPointer()));
194 output.writeValue<uint32_t>("offset", offset);
195 return;
196 }
197
198 output.writePropertyName("data");
199 output.write(size(), _data);
200 output.writeEndOfLine();
201 }
202
203 size_t size() const { return (properties.maxNumMipmaps <= 1) ? _size : computeValueCountIncludingMipmaps(_size, 1, 1, properties.maxNumMipmaps); }
204
205 bool available() const { return _data != nullptr; }
206 bool empty() const { return _data == nullptr; }
207
208 void clear()
209 {
210 _delete();
211
212 _size = 0;
213 _data = nullptr;
214 _storage = nullptr;
215 }
216
217 Array& operator=(const Array& rhs)
218 {
219 if (&rhs == this) return *this;
220
221 clear();
222
223 properties = rhs.properties;
224 _size = rhs._size;
225
226 if (_size != 0)
227 {
228 _data = _allocate(_size);
229 auto dest_v = _data;
230 for (auto& v : rhs) *(dest_v++) = v;
231 }
232
233 dirty();
234
235 return *this;
236 }
237
238 void assign(uint32_t numElements, value_type* data, Properties in_properties = {})
239 {
240 _delete();
241
242 properties = in_properties;
243 properties.stride = sizeof(value_type);
244 _size = numElements;
245 _data = data;
246 _storage = nullptr;
247
248 dirty();
249 }
250
251 void assign(ref_ptr<Data> storage, uint32_t offset, uint32_t stride, uint32_t numElements, Properties in_properties = {})
252 {
253 _delete();
254
255 _storage = storage;
256 properties = in_properties;
257 properties.stride = stride;
258 if (_storage && _storage->dataPointer())
259 {
260 _data = reinterpret_cast<value_type*>(reinterpret_cast<uint8_t*>(_storage->dataPointer()) + offset);
261 _size = numElements;
262 }
263 else
264 {
265 _data = nullptr;
266 _size = 0;
267 }
268
269 dirty();
270 }
271
272 // release the data so that ownership can be passed on, the local data pointer and size is set to 0 and destruction of Array will not result in the data being deleted.
273 // when the data is stored in a separate vsg::Data object then return nullptr and do not attempt to release data.
274 void* dataRelease() override
275 {
276 if (!_storage)
277 {
278 void* tmp = _data;
279 _data = nullptr;
280 _size = 0;
281 return tmp;
282 }
283 else
284 {
285 return nullptr;
286 }
287 }
288
289 size_t valueSize() const override { return sizeof(value_type); }
290 size_t valueCount() const override { return size(); }
291
292 bool dataAvailable() const override { return available(); }
293 size_t dataSize() const override { return size() * properties.stride; }
294
295 void* dataPointer() override { return _data; }
296 const void* dataPointer() const override { return _data; }
297
298 void* dataPointer(size_t i) override { return data(i); }
299 const void* dataPointer(size_t i) const override { return data(i); }
300
301 uint32_t dimensions() const override { return 1; }
302
303 uint32_t width() const override { return _size; }
304 uint32_t height() const override { return 1; }
305 uint32_t depth() const override { return 1; }
306
307 value_type* data() { return _data; }
308 const value_type* data() const { return _data; }
309
310 inline value_type* data(size_t i) { return reinterpret_cast<value_type*>(reinterpret_cast<uint8_t*>(_data) + i * properties.stride); }
311 inline const value_type* data(size_t i) const { return reinterpret_cast<const value_type*>(reinterpret_cast<const uint8_t*>(_data) + i * properties.stride); }
312
313 value_type& operator[](size_t i) { return *data(i); }
314 const value_type& operator[](size_t i) const { return *data(i); }
315
316 value_type& at(size_t i) { return *data(i); }
317 const value_type& at(size_t i) const { return *data(i); }
318
319 void set(size_t i, const value_type& v) { *data(i) = v; }
320
321 Data* storage() { return _storage; }
322 const Data* storage() const { return _storage; }
323
324 iterator begin() { return iterator{_data, properties.stride}; }
325 const_iterator begin() const { return const_iterator{_data, properties.stride}; }
326
327 iterator end() { return iterator{data(_size), properties.stride}; }
328 const_iterator end() const { return const_iterator{data(_size), properties.stride}; }
329
330 protected:
331 virtual ~Array()
332 {
333 _delete();
334 }
335
336 value_type* _allocate(size_t size) const
337 {
338 if (size == 0)
339 return nullptr;
340 else if (properties.allocatorType == ALLOCATOR_TYPE_NEW_DELETE)
341 return new value_type[size];
342 else if (properties.allocatorType == ALLOCATOR_TYPE_MALLOC_FREE)
343 return new (std::malloc(sizeof(value_type) * size)) value_type[size];
344 else
345 return new (vsg::allocate(sizeof(value_type) * size, ALLOCATOR_AFFINITY_DATA)) value_type[size];
346 }
347
348 void _delete()
349 {
350 if (!_storage && _data)
351 {
352 if (properties.allocatorType == ALLOCATOR_TYPE_NEW_DELETE)
353 delete[] _data;
354 else if (properties.allocatorType == ALLOCATOR_TYPE_MALLOC_FREE)
355 std::free(_data);
356 else if (properties.allocatorType != 0)
357 vsg::deallocate(_data);
358 }
359 }
360
361 private:
362 value_type* _data;
363 uint32_t _size;
364 ref_ptr<Data> _storage;
365 };
366
367 VSG_array(byteArray, int8_t);
368 VSG_array(ubyteArray, uint8_t);
369 VSG_array(shortArray, int16_t);
370 VSG_array(ushortArray, uint16_t);
371 VSG_array(intArray, int32_t);
372 VSG_array(uintArray, uint32_t);
373 VSG_array(floatArray, float);
374 VSG_array(doubleArray, double);
375
376 VSG_array(vec2Array, vec2);
377 VSG_array(vec3Array, vec3);
378 VSG_array(vec4Array, vec4);
379
380 VSG_array(dvec2Array, dvec2);
381 VSG_array(dvec3Array, dvec3);
382 VSG_array(dvec4Array, dvec4);
383
384 VSG_array(bvec2Array, bvec2);
385 VSG_array(bvec3Array, bvec3);
386 VSG_array(bvec4Array, bvec4);
387
388 VSG_array(ubvec2Array, ubvec2);
389 VSG_array(ubvec3Array, ubvec3);
390 VSG_array(ubvec4Array, ubvec4);
391
392 VSG_array(svec2Array, svec2);
393 VSG_array(svec3Array, svec3);
394 VSG_array(svec4Array, svec4);
395
396 VSG_array(usvec2Array, usvec2);
397 VSG_array(usvec3Array, usvec3);
398 VSG_array(usvec4Array, usvec4);
399
400 VSG_array(ivec2Array, ivec2);
401 VSG_array(ivec3Array, ivec3);
402 VSG_array(ivec4Array, ivec4);
403
404 VSG_array(uivec2Array, uivec2);
405 VSG_array(uivec3Array, uivec3);
406 VSG_array(uivec4Array, uivec4);
407
408 VSG_array(mat4Array, mat4);
409 VSG_array(dmat4Array, dmat4);
410
411 VSG_array(block64Array, block64);
412 VSG_array(block128Array, block128);
413
414} // namespace vsg
vsg::Array
Definition Array.h:37
vsg::Array::type_info
const std::type_info & type_info() const noexcept override
return the std::type_info of this Object
Definition Array.h:135
vsg::Array::clone
ref_ptr< Object > clone(const CopyOp &copyop={}) const override
Definition Array.h:128
vsg::CopyOp
Definition Object.h:42
vsg::Data
Definition Data.h:110
vsg::Data::properties
Properties properties
properties of the data such as format, origin, stride, dataVariance etc.
Definition Data.h:164
vsg::Data::dirty
void dirty()
increment the ModifiedCount to signify the data has been modified
Definition Data.h:197
vsg::Data::Properties
Definition Data.h:116
vsg::Data::Properties::allocatorType
AllocatorType allocatorType
hint as to how the data values may change during the lifetime of the vsg::Data.
Definition Data.h:131
vsg::allocator_affinity_nodes
std container adapter for allocating with MEMORY_AFFINITY_NODES
Definition Allocator.h:138