Cogs.Core
PropertiesManager.cpp
1#include "PropertiesManager.h"
2
3Cogs::Core::PropertyStore::PropertyStore(MemBlockType memType)
4 : headers(memType),
5 data(memType)
6{
7
8}
9
10Cogs::Core::PropertyStore::PropertyStore(const PropertyStore & other)
11{
12 headers.copy(other.headers);
13 data.copy(other.data);
14 dataSize = other.dataSize;
15}
16
17Cogs::Core::PropertyStore::PropertyStore(PropertyStore&& other) noexcept
18{
19 headers = std::move(other.headers);
20 data = std::move(other.data);
21 dataSize = other.dataSize;
22}
23
24Cogs::Core::PropertyStore & Cogs::Core::PropertyStore::operator=(const PropertyStore & other)
25{
26 headers.copy(other.headers);
27 data.copy(other.data);
28 dataSize = other.dataSize;
29 return *this;
30}
31
32Cogs::Core::PropertyStore& Cogs::Core::PropertyStore::operator=(PropertyStore&& other) noexcept
33{
34 headers = std::move(other.headers);
35 data = std::move(other.data);
36 dataSize = other.dataSize;
37 return *this;
38}
39
40uint32_t Cogs::Core::PropertyStore::addProperty(StringView key, bool value)
41{
42 auto & p = addProperty(key, PropertyType::Bool);
43 p.boolValue = value;
44 return p.index;
45}
46
47uint32_t Cogs::Core::PropertyStore::addProperty(StringView key, float value)
48{
49 auto & p = addProperty(key, PropertyType::Float);
50 p.floatValue = value;
51 return p.index;
52}
53
54uint32_t Cogs::Core::PropertyStore::addProperty(StringView key, double value)
55{
56 auto& p = addProperty(key, PropertyType::Double);
57 p.doubleValue = value;
58 return p.index;
59}
60
61uint32_t Cogs::Core::PropertyStore::addProperty(StringView key, int32_t value)
62{
63 auto & p = addProperty(key, PropertyType::Integer);
64 p.intValue = value;
65 return p.index;
66}
67
68uint32_t Cogs::Core::PropertyStore::addProperty(StringView key, uint32_t value)
69{
70 auto& p = addProperty(key, PropertyType::UnsignedInteger);
71 p.uintValue = value;
72 return p.index;
73}
74
75uint32_t Cogs::Core::PropertyStore::addProperty(StringView key, std::span<const float> values)
76{
77 size_t n = values.size();
78 if (n == 0) {
79 PropertyInfo& p = addProperty(key, PropertyType::FloatArray);
80 p.data.offset = 0;
81 p.data.size = 0;
82 return p.index;
83 }
84
85 if (n == 1) {
86 PropertyInfo& p = addProperty(key, PropertyType::Float);
87 p.floatValue = values[0];
88 return p.index;
89 }
90
91 if (n == 2) {
92 PropertyInfo& p = addProperty(key, PropertyType::Float2);
93 p.float2Value[0] = values[0];
94 p.float2Value[1] = values[1];
95 return p.index;
96 }
97
98 PropertyInfo& p = addProperty(key, PropertyType::FloatArray);
99 addPropertyData(p, values.data(), values.size_bytes());
100 return p.index;
101}
102
103uint32_t Cogs::Core::PropertyStore::addProperty(StringView key, std::span<const double> values)
104{
105 size_t n = values.size();
106 if (n == 0) {
107 PropertyInfo& p = addProperty(key, PropertyType::DoubleArray);
108 p.data.offset = 0;
109 p.data.size = 0;
110 return p.index;
111 }
112
113 if (n == 1) {
114 PropertyInfo& p = addProperty(key, PropertyType::Double);
115 p.doubleValue = values[0];
116 return p.index;
117 }
118
119 PropertyInfo& p = addProperty(key, PropertyType::DoubleArray);
120 addPropertyData(p, values.data(), values.size_bytes());
121 return p.index;
122}
123
124uint32_t Cogs::Core::PropertyStore::addProperty(StringView key, std::span<const int32_t> values)
125{
126 size_t n = values.size();
127 if (n == 0) {
128 PropertyInfo& p = addProperty(key, PropertyType::IntArray);
129 p.data.offset = 0;
130 p.data.size = 0;
131 return p.index;
132 }
133
134 if (n == 1) {
135 PropertyInfo& p = addProperty(key, PropertyType::Integer);
136 p.intValue = values[0];
137 return p.index;
138 }
139
140 if (n == 2) {
141 PropertyInfo& p = addProperty(key, PropertyType::Int2);
142 p.int2Value[0] = values[0];
143 p.int2Value[1] = values[1];
144 return p.index;
145 }
146
147 PropertyInfo& p = addProperty(key, PropertyType::IntArray);
148 addPropertyData(p, values.data(), values.size_bytes());
149 return p.index;
150}
151
152uint32_t Cogs::Core::PropertyStore::addProperty(StringView key, std::span<const uint32_t> values)
153{
154 size_t n = values.size();
155 if (n == 0) {
156 PropertyInfo& p = addProperty(key, PropertyType::UIntArray);
157 p.data.offset = 0;
158 p.data.size = 0;
159 return p.index;
160 }
161
162 if (n == 1) {
163 PropertyInfo& p = addProperty(key, PropertyType::UnsignedInteger);
164 p.uintValue = values[0];
165 return p.index;
166 }
167
168 if (n == 2) {
169 PropertyInfo& p = addProperty(key, PropertyType::UInt2);
170 p.uint2Value[0] = values[0];
171 p.uint2Value[1] = values[1];
172 return p.index;
173 }
174
175 PropertyInfo& p = addProperty(key, PropertyType::UIntArray);
176 addPropertyData(p, values.data(), values.size_bytes());
177 return p.index;
178}
179
180uint32_t Cogs::Core::PropertyStore::addProperty(StringView key, const glm::vec3& values)
181{
182 return addProperty(key, std::span(&values[0], 3));
183}
184
185bool Cogs::Core::PropertyStore::getProperty(StringView key, bool defaultValue)
186{
187 auto & p = getProperty(key);
188
189 if (p.type == PropertyType::Bool) return p.boolValue;
190
191 return defaultValue;
192}
193
194float Cogs::Core::PropertyStore::getProperty(StringView key, float defaultValue)
195{
196 auto & p = getProperty(key);
197
198 if (p.type == PropertyType::Float) return p.floatValue;
199 else if (p.type == PropertyType::Integer) return (float)p.intValue;
200
201 return defaultValue;
202}
203
204int Cogs::Core::PropertyStore::getProperty(StringView key, int defaultValue)
205{
206 auto & p = getProperty(key);
207
208 if (p.type == PropertyType::Integer) return p.intValue;
209 else if (p.type == PropertyType::Float) return static_cast<int>(p.floatValue);
210
211 return defaultValue;
212}
213
214uint32_t Cogs::Core::PropertyStore::getProperty(StringView key, uint32_t defaultValue)
215{
216 const PropertyInfo& p = getProperty(key);
217 if (p.type == PropertyType::UnsignedInteger) return p.uintValue;
218 else if (p.type == PropertyType::Integer && 0 <= p.intValue) return p.intValue;
219 else if (p.type == PropertyType::Float && 0.f <= p.floatValue) return static_cast<int>(p.floatValue);
220 return defaultValue;
221}
222
223uint32_t Cogs::Core::PropertyStore::addProperty(StringView key, StringRef value)
224{
225 PropertyInfo& p = addProperty(key, PropertyType::StringRef);
226 p.stringRefValue = value;
227 return p.index;
228}
229
230uint32_t Cogs::Core::PropertyStore::addProperty(StringView key, StringView value)
231{
232 auto & p = addProperty(key, PropertyType::String);
233
234 if (!value.empty()) {
235 // Allocate enough space for string + null termination.
236 addPropertyData(p, value.data(), value.size() + 1);
237 // Null terminate string data as additional safety measure.
238 getPropertyData(p)[value.size()] = 0;
239 } else {
240 p.data.size = 0;
241 p.data.offset = 0;
242 }
243
244 return p.index;
245}
246
247Cogs::StringView Cogs::Core::PropertyStore::getProperty(StringView key, StringView defaultValue)
248{
249 PropertyInfo& p = getProperty(key);
250 return p.type != PropertyType::Unknown ? getString(p) : defaultValue;
251}
252
253std::span<const float> Cogs::Core::PropertyStore::getProperty(StringView key, std::span<const float> defaultValue)
254{
255 PropertyInfo& p = getProperty(key);
256 switch (p.type) {
257 case PropertyType::Float:
258 case PropertyType::Float2:
259 case PropertyType::FloatArray:
260 return getFloatArray(p.index);
261 default:
262 return defaultValue;
263 }
264}
265
266glm::vec3 Cogs::Core::PropertyStore::getProperty(StringView key, glm::vec3 defaultValue)
267{
268 auto& p = getProperty(key);
269
270 if (p.type == PropertyType::FloatArray) {
271 const auto array = getFloatArray(p.index);
272 if (array.size() == 3 || array.size() == 4) {
273 // Consistent with Variables access.
274 return glm::vec3(array[0], array[1], array[2]);
275 }
276 }
277
278 return defaultValue;
279}
280
281Cogs::Core::PropertyInfo & Cogs::Core::PropertyStore::getProperty(StringView key)
282{
283 return getProperty(Strings::add(key));
284}
285
286Cogs::Core::PropertyInfo & Cogs::Core::PropertyStore::getProperty(StringRef key)
287{
288 static PropertyInfo unknown = {};
289
290 for (auto & p : headers) {
291 if (key == p.key) {
292 return p;
293 }
294 }
295
296 return unknown;
297}
298
299Cogs::Core::PropertyInfo & Cogs::Core::PropertyStore::getPropertyByIndex(uint32_t index)
300{
301 return headers[index];
302}
303
304const Cogs::Core::PropertyInfo & Cogs::Core::PropertyStore::getPropertyByIndex(uint32_t index) const
305{
306 return headers[index];
307}
308
309uint32_t Cogs::Core::PropertyStore::findProperty(StringView key) const
310{
311 return findProperty(0, size(), Strings::add(key));
312}
313
314uint32_t Cogs::Core::PropertyStore::findProperty(uint32_t first, uint32_t count, StringRef key) const
315{
316 uint32_t last = first + count;
317 for (uint32_t i = first; i < last; ++i) {
318 auto & p = headers[i];
319 if (p.key == key) return i;
320 }
321
323}
324
325Cogs::StringView Cogs::Core::PropertyStore::getKey(const PropertyInfo & p) const
326{
327 return Strings::get(headers[p.index].key);
328}
329
330Cogs::StringView Cogs::Core::PropertyStore::getString(const PropertyInfo & p) const
331{
332 if (p.type == PropertyType::StringRef) {
333 return Strings::get(p.stringRefValue);
334 }
335
336 if (p.type == PropertyType::String) {
337 if (p.data.size) {
338 return StringView{static_cast<const char *>(data.data()) + p.data.offset, p.data.size - 1 };
339 } else {
340 return StringView{};
341 }
342 }
343
344 //TODO: Log warning (?)
345
346 return {};
347}
348
349Cogs::StringView Cogs::Core::PropertyStore::getString(uint32_t index) const
350{
351 return getString(getPropertyByIndex(index));
352}
353
354std::span<float> Cogs::Core::PropertyStore::getFloatArray(uint32_t index)
355{
356 PropertyInfo& p = getPropertyByIndex(index);
357 if (p.type == PropertyType::Float) {
358 return std::span(&p.floatValue, &p.floatValue + 1);
359 }
360 if (p.type == PropertyType::Float2) {
361 return std::span(p.float2Value);
362 }
363 if (p.type == PropertyType::FloatArray) {
364 void* data = getPropertyData(p);
365 size_t size = p.data.size / sizeof(float);
366 return std::span(static_cast<float*>(data), size);
367 }
368 return {};
369}
370
371std::span<const float> Cogs::Core::PropertyStore::getFloatArray(uint32_t index) const
372{
373 if (index != PropertyStore::NoProperty) {
374 return getFloatArray(getPropertyByIndex(index));
375 }
376 return {};
377}
378
379std::span<const double> Cogs::Core::PropertyStore::getDoubleArray(const PropertyInfo& p) const
380{
381 if (p.type == PropertyType::Double) {
382 return std::span(&p.doubleValue, &p.doubleValue + 1);
383 }
384 if (p.type == PropertyType::DoubleArray) {
385 const void* data = getPropertyData(p);
386 size_t size = p.data.size / sizeof(double);
387 return std::span(static_cast<const double*>(data), size);
388 }
389 return {};
390}
391
392std::span<const double> Cogs::Core::PropertyStore::getDoubleArray(uint32_t index) const
393{
394 if (index != PropertyStore::NoProperty) {
395 return getDoubleArray(getPropertyByIndex(index));
396 }
397 return {};
398}
399
400std::span<const float> Cogs::Core::PropertyStore::getFloatArray(const PropertyInfo& p) const
401{
402 if (p.type == PropertyType::Float) {
403 return std::span(&p.floatValue, &p.floatValue + 1);
404 }
405 if (p.type == PropertyType::Float2) {
406 return std::span(p.float2Value);
407 }
408 if (p.type == PropertyType::FloatArray) {
409 const void* data = getPropertyData(p);
410 size_t size = p.data.size / sizeof(float);
411 return std::span(static_cast<const float*>(data), size);
412 }
413 return {};
414}
415
416std::span<const int32_t> Cogs::Core::PropertyStore::getIntArray(const PropertyInfo& p) const
417{
418 if (p.type == PropertyType::Integer) {
419 return std::span(&p.intValue, 1);
420 }
421 else if (p.type == PropertyType::Int2) {
422 return std::span(p.int2Value);
423 }
424 else if (p.type == PropertyType::IntArray) {
425 const void* data = getPropertyData(p);
426 size_t size = p.data.size / sizeof(int32_t);
427 return std::span(static_cast<const int32_t*>(data), size);
428 }
429 return {};
430}
431
432std::span<const int32_t> Cogs::Core::PropertyStore::getIntArray(uint32_t index) const
433{
434 if (index != PropertyStore::NoProperty) {
435 return getIntArray(getPropertyByIndex(index));
436 }
437 return {};
438}
439
440std::span<const uint32_t> Cogs::Core::PropertyStore::getUIntArray(const PropertyInfo& p) const
441{
442 if (p.type == PropertyType::UnsignedInteger) {
443 return std::span(&p.uintValue, 1);
444 }
445 else if (p.type == PropertyType::UInt2) {
446 return std::span(p.uint2Value);
447 }
448 else if (p.type == PropertyType::UIntArray) {
449 const void* data = getPropertyData(p);
450 size_t size = p.data.size / sizeof(uint32_t);
451 return std::span(static_cast<const uint32_t*>(data), size);
452 }
453 return {};
454}
455
456std::span<const uint32_t> Cogs::Core::PropertyStore::getUIntArray(uint32_t index) const
457{
458 if (index != PropertyStore::NoProperty) {
459 return getUIntArray(getPropertyByIndex(index));
460 }
461 return {};
462}
463
464Cogs::Core::PropertyInfo & Cogs::Core::PropertyStore::addProperty(StringView key, PropertyType type)
465{
466 uint32_t index = static_cast<uint32_t>(headers.size());
467
468 PropertyInfo& p = headers.grow();
469 p.index = index;
470 p.key = Strings::add(key);
471 p.type = type;
472
473 return p;
474}
475
476void Cogs::Core::PropertyStore::addPropertyData(PropertyInfo & p, const void * data, size_t size)
477{
478 auto[ptr, offset] = allocate(size);
479 std::memcpy(ptr, data, size);
480 p.data.offset = offset;
481 p.data.size = static_cast<uint32_t>(size);
482}
483
484uint8_t * Cogs::Core::PropertyStore::getPropertyData(const PropertyInfo & p)
485{
486 return static_cast<uint8_t *>(data.data()) + p.data.offset;
487}
488
489const uint8_t * Cogs::Core::PropertyStore::getPropertyData(const PropertyInfo & p) const
490{
491 return static_cast<const uint8_t*>(data.data()) + p.data.offset;
492}
493
494uint32_t Cogs::Core::PropertyStore::addProperty(const PropertyStore& other, uint32_t otherIndex)
495{
496 if (otherIndex == NoProperty) {
497 return NoProperty;
498 }
499 const PropertyInfo& otherInfo = other.getPropertyByIndex(otherIndex);
500 PropertyInfo& pInfo = addProperty(other.getKey(otherInfo), otherInfo.type);
501 if (otherInfo.type == PropertyType::Unknown) {
502 //Error
503 }
504 else if (PropertyType::FirstInlineType <= otherInfo.type && otherInfo.type < PropertyType::LastInlineType) {
505 // 2 x uint32, large enough for all inline types
506 pInfo.data = otherInfo.data;
507 }
508 else {
509 addPropertyData(pInfo, other.getData() + otherInfo.data.offset, otherInfo.data.size);
510 }
511 return pInfo.index;
512}
513
514
515void Cogs::Core::PropertyStore::copyProperties(const PropertyStore & other, uint32_t offset, uint32_t count)
516{
517 for (uint32_t i = 0; i < count; ++i) {
518 auto & otherP = other.getPropertyByIndex(offset + i);
519
520 if (PropertyInfo& existing = getProperty(otherP.key); existing.key == otherP.key) {
521
522 // Overwrite existing data, update type making sure it matches
523 existing.type = otherP.type;
524 if (PropertyType::FirstInlineType <= otherP.type && otherP.type < PropertyType::LastInlineType) {
525 // 2 x uint32, large enough for all inline types
526 existing.data = otherP.data;
527 }
528 else {
529 //NOTE: The existing property data is left untouched in the data storage for the sake of simplicity at the
530 // cost of some additional memory.
531 addPropertyData(existing, other.getData() + otherP.data.offset, otherP.data.size);
532 }
533 continue;
534 }
535
536 PropertyInfo& p = addProperty(other.getKey(otherP), otherP.type);
537 if (otherP.type == PropertyType::Unknown) {
538 //Error
539 continue;
540 }
541
542 if (PropertyType::FirstInlineType <= otherP.type && otherP.type < PropertyType::LastInlineType) {
543 // 2 x uint32, large enough for all inline types
544 p.data = otherP.data;
545 } else {
546 addPropertyData(p, other.getData() + otherP.data.offset, otherP.data.size);
547 }
548 }
549}
550
551Cogs::Core::PropertyStore::PropertyAlloc Cogs::Core::PropertyStore::allocate(size_t propertySize)
552{
553 const size_t currentCapacity = data.size();
554 const size_t requiredCapacity = dataSize + propertySize;
555
556 if (currentCapacity < requiredCapacity) {
557 constexpr size_t alignment = 0x1f;
558 size_t newCapacity = (((requiredCapacity * 3) / 2) + alignment) & ~alignment;
559 data.resize(newCapacity, true);
560 }
561 assert(requiredCapacity <= data.size());
562
563 const uint32_t offset = static_cast<uint32_t>(dataSize);
564 auto ptr = static_cast<uint8_t *>(data.data()) + offset;
565
566 dataSize += propertySize;
567
568#ifdef EMSCRIPTEN
569 // avoid alignment error in getFloatArray with -s SAFE_HEAP
570 dataSize = 4 * ((dataSize + 3) / 4);
571#endif
572
573 return { ptr, offset };
574}
575
576uint32_t Cogs::Core::PropertyRange::getPropertyIndex(StringRef key) const
577{
578 return store->findProperty(firstProperty, numProperties, key);
579}
580
581float Cogs::Core::PropertyRange::getProperty(StringRef key, float defaultValue) const
582{
583 auto index = store->findProperty(firstProperty, numProperties, key);
584 if (index == PropertyStore::NoProperty) return defaultValue;
585 auto & p = store->getPropertyByIndex(index);
586
587 if (p.type == PropertyType::Float) return p.floatValue;
588
589 return defaultValue;
590}
591
592int Cogs::Core::PropertyRange::getProperty(StringRef key, int defaultValue) const
593{
594 auto index = store->findProperty(firstProperty, numProperties, key);
595 if (index == PropertyStore::NoProperty) return defaultValue;
596 auto & p = store->getPropertyByIndex(index);
597
598 if (p.type == PropertyType::Integer) return p.intValue;
599
600 return defaultValue;
601}
602
603Cogs::StringView Cogs::Core::PropertyRange::getProperty(StringRef key, StringView defaultValue) const
604{
605 auto index = store->findProperty(firstProperty, numProperties, key);
606 if (index == PropertyStore::NoProperty) return defaultValue;
607 auto & p = store->getPropertyByIndex(index);
608
609 if (p.type == PropertyType::String) return store->getString(index);
610
611 return defaultValue;
612}
613
614std::span<const float> Cogs::Core::PropertyRange::getProperty(StringRef key, std::span<const float> defaultValue) const
615{
616 auto index = store->findProperty(firstProperty, numProperties, key);
617 if (index != PropertyStore::NoProperty) return store->getFloatArray(index);
618 else return defaultValue;
619}
620
621std::span<const uint32_t> Cogs::Core::PropertyRange::getProperty(StringRef key, std::span<const uint32_t> defaultValue) const
622{
623 if (uint32_t index = store->findProperty(firstProperty, numProperties, key); index != PropertyStore::NoProperty) {
624 return store->getUIntArray(index);
625 }
626 return defaultValue;
627}
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
static constexpr uint32_t NoProperty
Return from findProperty if key not found.