Pioneer
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 
20 class PropertyMap;
21 class PropertyArray;
22 
23 // little indirection class to allow nesting refcounted property maps in a property
24 // without direct circular compilation dependency
26 public:
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 
48 private:
49  mutable PropertyMap *m_map;
50 };
51 
52 using PropertyBase = std::variant<
53  std::nullptr_t,
54  bool,
55  double,
56  int64_t,
57  vector2d,
58  vector3d,
59  Color,
61  StringName,
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  */
73 class Property : public PropertyBase {
74 public:
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 
147 private:
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
159 void from_json(const Json &obj, Property &n);
160 void 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  */
171 class PropertyMap : public RefCounted {
172 public:
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 
201 public:
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 
241 private:
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 
253 inline auto PropertyMapWrapper::begin() { return m_map->begin(); }
254 inline 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
void Set(std::string_view str, Property &&prop)
Definition: Property.h:224
iterator end()
Definition: Property.h:235
const Property & Get(const StringName &str) const
Definition: Property.h:220
PropertyMap()
Definition: Property.cpp:132
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
std::pair< StringName, Property > value_type
Definition: Property.h:173
const Property & Get(const char str[N]) const
Definition: Property.h:214
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
const Property & Get(std::string_view str) const
Definition: Property.h:221
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
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
PropertyMap * get_map(PropertyMap *def={}) const
Definition: Property.h:129
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
auto begin()
Definition: Property.h:253
PropertyMap * operator->() const
Definition: Property.h:41
~PropertyMapWrapper()
Definition: Property.cpp:16
PropertyMapWrapper()
Definition: Property.h:27
auto end()
Definition: Property.h:254
PropertyMap * operator*() const
Definition: Property.h:40
PropertyMap * get() const
Definition: Property.h:43
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