Pioneer
Loading...
Searching...
No Matches
Property.h
Go to the documentation of this file.
1// Copyright © 2008-2023 Pioneer Developers. See AUTHORS.txt for details
2// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
3
4#pragma once
5
6#include "Color.h"
7#include "JsonFwd.h"
8#include "Quaternion.h"
9#include "RefCounted.h"
10#include "core/StringName.h"
11#include "vector2.h"
12#include "vector3.h"
13
14#include <string>
15#include <string_view>
16#include <type_traits>
17#include <variant>
18#include <vector>
19
20class PropertyMap;
21class PropertyArray;
22
23// little indirection class to allow nesting refcounted property maps in a property
24// without direct circular compilation dependency
26public:
28 m_map(nullptr) {}
31
33 PropertyMapWrapper(rhs.m_map) {}
35
36 // implicit conversion
37 operator PropertyMap *() const { return m_map; }
38
39 // pointer mimic operators
40 PropertyMap *operator*() const { return m_map; }
41 PropertyMap *operator->() const { return m_map; }
42
43 PropertyMap *get() const { return m_map; }
44
45 auto begin();
46 auto end();
47
48private:
49 mutable PropertyMap *m_map;
50};
51
52using PropertyBase = std::variant<
53 std::nullptr_t,
54 bool,
55 double,
56 int64_t,
59 Color,
63
64/*
65 * A property is a simple tagged union type, storing the most common datatypes
66 * interchanged between C++ <-> Lua. It's meant to be small (32 bytes),
67 * efficient, and flexible.
68 *
69 * It purposefully does not store matrix types, arbitrary pointers, classes,
70 * or LuaObjects, as those should be handled by more domain-specific structures
71 * and interfaces.
72 */
73class Property : public PropertyBase {
74public:
75 using PropertyBase::PropertyBase;
76
77 // Overloads for integral and floating-point type construction for GCC 9/MSVC
78 template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
79 Property(const T &arg) : PropertyBase(int64_t(arg)) {}
80 template<typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
81 Property(const T &arg) : PropertyBase(double(arg)) {}
82
83 // Promoting overload for PropertyMap*, because GCC 9 converts it to bool instead...
85
86 // construction from string literal
87 template <size_t N>
88 Property(const char (&s)[N]) :
89 Property(StringName(std::string_view(s, N - 1), hash_32_fnv1a(s, N - 1))) {}
90 // have to have all of these string constructors to get around the one-implicit-conversion rule
91 Property(const char *s) :
92 Property(std::string_view(s)) {}
93 Property(std::string_view s) :
94 Property(StringName(s)) {}
95 Property(const std::string &s) :
96 Property(StringName(std::string_view(s))) {}
97
98 bool is_null() const { return index() == 0 || index() == std::variant_npos; }
99 bool is_bool() const { return index() == 1; }
100 bool is_number() const { return index() == 2 || index() == 3; }
101 bool is_integer() const { return index() == 2 || index() == 3; }
102 bool is_vector2() const { return index() == 4; }
103 bool is_vector3() const { return index() == 5; }
104 bool is_color() const { return index() == 6; }
105 bool is_quat() const { return index() == 7; }
106 bool is_string() const { return index() == 8; }
107 bool is_map() const { return index() == 9; }
108
109 bool get_bool(bool def = false) const { return _get(std::move(def)); }
110 double get_number(double def = 0.0) const
111 {
112 if (index() == 3)
113 return double(_get(int64_t(def)));
114 else
115 return _get(std::move(def));
116 }
117 int64_t get_integer(int64_t def = 0) const
118 {
119 if (index() == 2)
120 return int64_t(_get(double(def)));
121 else
122 return _get(std::move(def));
123 }
124 vector2d get_vector2(vector2d def = {}) const { return _get(std::move(def)); }
125 vector3d get_vector3(vector3d def = {}) const { return _get(std::move(def)); }
126 Color get_color(Color def = {}) const { return _get(std::move(def)); }
127 Quaternionf get_quat(Quaternionf def = {}) const { return _get(std::move(def)); }
128 StringName get_string(std::string_view def = {}) const { return _get<std::string_view, StringName>(std::move(def)); }
129 PropertyMap *get_map(PropertyMap *def = {}) const { return _get<PropertyMapWrapper>(std::move(def)); }
130
131 // helpers for common conversions
132 template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
133 operator T() const { return get_integer(); }
134 template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
135 operator T() const { return get_number(); }
136
137 operator bool() const { return get_bool(); }
138 operator double() const { return get_number(); }
139 operator int64_t() const { return get_integer(); }
140 operator vector2d() const { return get_vector2(); }
141 operator vector3d() const { return get_vector3(); }
142 operator Color() const { return get_color(); }
143 operator Quaternionf() const { return get_quat(); }
144 operator StringName() const { return get_string(); }
145 operator PropertyMap *() const { return get_map(); }
146
147private:
148 template <typename T, typename U = T>
149 U _get(T &&def) const
150 {
151 if (auto *ptr = std::get_if<U>(this))
152 return *ptr;
153 else
154 return std::move(def);
155 }
156};
157
158// JSON overloads for Property types
159void from_json(const Json &obj, Property &n);
160void to_json(Json &obj, const Property &n);
161
162/*
163 * PropertyMap implements an efficient key-value store of Properties that can
164 * be shared between Lua and C++ and persisted across the destruction of a Lua
165 * VM.
166 *
167 * Internally, a power-of-two based Robin-Hood hash map is used to associate
168 * StringName keys with Property values with extremely low hashing and lookup
169 * overhead.
170 */
171class PropertyMap : public RefCounted {
172public:
173 using value_type = std::pair<StringName, Property>;
174 using reference = const value_type &;
175 using pointer = const value_type *;
176
177 struct iterator {
178 iterator(const PropertyMap *m, uint32_t i) :
179 map(m),
180 idx(i)
181 {
182 if (map && map->m_keys.size() > idx && !map->m_keys[idx])
183 ++(*this);
184 }
185
186 pointer operator->() { return &(**this); }
187 reference operator*() { return map->m_values[idx]; }
188
189 operator bool() { return map && idx < map->Capacity(); }
190
191 bool operator==(const iterator &rhs) { return map == rhs.map && idx == rhs.idx; }
192 bool operator!=(const iterator &rhs) { return !(*this == rhs); }
194 iterator operator++(int);
195
196 private:
197 const PropertyMap *map;
198 uint32_t idx;
199 };
200
201public:
202 PropertyMap();
203 ~PropertyMap();
204
205 void SaveToJson(Json &obj);
206 void LoadFromJson(const Json &obj);
207
208 size_t Size() const { return m_entries; }
209 size_t Capacity() const { return m_keys.size(); }
210 bool Empty() const { return !m_entries; }
211
212 // Explicit literal string overload to ensure hashing is run at compile time
213 template <size_t N>
214 const Property &Get(const char str[N]) const
215 {
216 constexpr uint32_t hash = hash_32_fnv1a(str, N - 1);
217 return GetRef(hash).second;
218 }
219
220 const Property &Get(const StringName &str) const { return GetRef(str.hash()).second; }
221 const Property &Get(std::string_view str) const { return GetRef(hash_32_fnv1a(str.data(), str.size())).second; }
222
223 void Set(const StringName &key, Property &&prop) { SetRef(key.hash(), { key, std::move(prop) }); }
224 void Set(std::string_view str, Property &&prop) { Set(StringName(str), std::move(prop)); }
225
226 // Use template-based forwarding for older compilers which cannot convert e.g. int to Property&&
227 template<typename T>
228 void Set(const StringName &key, const T &prop) { Set(key, Property(prop)); }
229 template<typename T>
230 void Set(std::string_view str, const T &prop) { Set(StringName(str), Property(prop)); }
231
232 void Clear();
233
234 iterator begin() { return iterator{ this, 0 }; }
235 iterator end() { return iterator{ this, uint32_t(m_keys.size()) }; }
236 iterator cbegin() const { return iterator{ this, 0 }; }
237 iterator cend() const { return iterator{ this, uint32_t(m_keys.size()) }; }
238
239 operator PropertyMapWrapper() { return PropertyMapWrapper(this); }
240
241private:
242 reference GetRef(uint32_t hash) const;
243 void SetRef(uint32_t hash, value_type &&value);
244
245 PropertyMap(uint32_t size);
246 void Grow();
247
248 std::vector<uint32_t> m_keys;
249 std::vector<value_type> m_values;
250 uint32_t m_entries;
251};
252
253inline auto PropertyMapWrapper::begin() { return m_map->begin(); }
254inline auto PropertyMapWrapper::end() { return m_map->end(); }
Color4ub Color
Definition Color.h:212
constexpr uint32_t hash_32_fnv1a(const char *const data, size_t len)
Definition FNV1a.h:13
nlohmann::json Json
Definition Json.h:8
void from_json(const Json &obj, Property &n)
Definition Property.cpp:35
void to_json(Json &obj, const Property &n)
Definition Property.cpp:76
std::variant< std::nullptr_t, bool, double, int64_t, vector2d, vector3d, Color, Quaternionf, StringName, PropertyMapWrapper > PropertyBase
Definition Property.h:62
Quaternion< float > Quaternionf
Definition Quaternion.h:277
Definition Property.h:171
bool Empty() const
Definition Property.h:210
const value_type * pointer
Definition Property.h:175
iterator cbegin() const
Definition Property.h:236
void SaveToJson(Json &obj)
Definition Property.cpp:162
size_t Capacity() const
Definition Property.h:209
const Property & Get(std::string_view str) const
Definition Property.h:221
void Set(std::string_view str, Property &&prop)
Definition Property.h:224
iterator end()
Definition Property.h:235
PropertyMap()
Definition Property.cpp:132
const Property & Get(const StringName &str) const
Definition Property.h:220
void Set(std::string_view str, const T &prop)
Definition Property.h:230
void Set(const StringName &key, Property &&prop)
Definition Property.h:223
void Clear()
Definition Property.cpp:211
void LoadFromJson(const Json &obj)
Definition Property.cpp:151
const Property & Get(const char str[N]) const
Definition Property.h:214
std::pair< StringName, Property > value_type
Definition Property.h:173
void Set(const StringName &key, const T &prop)
Definition Property.h:228
iterator cend() const
Definition Property.h:237
const value_type & reference
Definition Property.h:174
iterator begin()
Definition Property.h:234
~PropertyMap()
Definition Property.cpp:144
size_t Size() const
Definition Property.h:208
Definition Property.h:73
bool is_number() const
Definition Property.h:100
bool is_color() const
Definition Property.h:104
bool is_null() const
Definition Property.h:98
Property(PropertyMap *map)
Definition Property.h:84
bool is_vector2() const
Definition Property.h:102
bool get_bool(bool def=false) const
Definition Property.h:109
vector3d get_vector3(vector3d def={}) const
Definition Property.h:125
Quaternionf get_quat(Quaternionf def={}) const
Definition Property.h:127
Property(const char(&s)[N])
Definition Property.h:88
int64_t get_integer(int64_t def=0) const
Definition Property.h:117
bool is_map() const
Definition Property.h:107
bool is_quat() const
Definition Property.h:105
bool is_vector3() const
Definition Property.h:103
bool is_bool() const
Definition Property.h:99
StringName get_string(std::string_view def={}) const
Definition Property.h:128
Property(const char *s)
Definition Property.h:91
double get_number(double def=0.0) const
Definition Property.h:110
bool is_string() const
Definition Property.h:106
PropertyMap * get_map(PropertyMap *def={}) const
Definition Property.h:129
bool is_integer() const
Definition Property.h:101
Property(const T &arg)
Definition Property.h:79
Color get_color(Color def={}) const
Definition Property.h:126
vector2d get_vector2(vector2d def={}) const
Definition Property.h:124
Property(std::string_view s)
Definition Property.h:93
Property(const std::string &s)
Definition Property.h:95
Definition RefCounted.h:11
Definition StringName.h:18
uint32_t hash() const
Definition StringName.h:43
Definition Color.h:66
Definition Property.h:25
PropertyMapWrapper & operator=(const PropertyMapWrapper &rhs)
Definition Property.cpp:22
PropertyMap * get() const
Definition Property.h:43
auto begin()
Definition Property.h:253
~PropertyMapWrapper()
Definition Property.cpp:16
PropertyMap * operator*() const
Definition Property.h:40
PropertyMapWrapper()
Definition Property.h:27
auto end()
Definition Property.h:254
PropertyMap * operator->() const
Definition Property.h:41
PropertyMapWrapper(const PropertyMapWrapper &rhs)
Definition Property.h:32
Definition Property.h:177
pointer operator->()
Definition Property.h:186
iterator(const PropertyMap *m, uint32_t i)
Definition Property.h:178
bool operator!=(const iterator &rhs)
Definition Property.h:192
bool operator==(const iterator &rhs)
Definition Property.h:191
iterator operator++()
Definition Property.cpp:114
reference operator*()
Definition Property.h:187
vector2< double > vector2d
Definition vector2.h:134
vector3< double > vector3d
Definition vector3.h:290