Blue Brain BioExplorer
PropertyMap.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-2024, EPFL/Blue Brain Project
3  *
4  * Responsible Author: Daniel.Nachbaur@epfl.ch
5  *
6  * This file is part of Blue Brain BioExplorer <https://github.com/BlueBrain/BioExplorer>
7  *
8  * This library is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU Lesser General Public License version 3.0 as published
10  * by the Free Software Foundation.
11  *
12  * This library is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15  * details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 #pragma once
23 
25 // NOTE: Replace with std::any when upgrading to c++17
26 #include <platform/core/common/Any.hpp>
27 
28 #include <algorithm>
29 #include <functional>
30 #include <memory>
31 #include <string>
32 #include <vector>
33 
34 namespace core
35 {
41 struct Property
42 {
43  enum class Type
44  {
45  Int,
46  Double,
47  String,
48  Bool,
49  Vec2i,
50  Vec2d,
51  Vec3i,
52  Vec3d,
53  Vec4d
54  };
55 
56  struct MetaData
57  {
58  MetaData(std::string label_ = {}, const std::string& description_ = "no-description")
59  : label(label_)
60  , description(description_)
61  {
62  }
63  const std::string label;
64  const std::string description;
65  };
66 
67  template <typename T>
68  void assertValidType() const
69  {
70  static_assert(std::is_same<T, double>::value || std::is_same<T, int32_t>::value ||
71  std::is_same<T, std::string>::value || std::is_same<T, bool>::value ||
72  std::is_same<T, std::array<double, 2>>::value ||
73  std::is_same<T, std::array<int32_t, 2>>::value ||
74  std::is_same<T, std::array<double, 3>>::value ||
75  std::is_same<T, std::array<int32_t, 3>>::value ||
76  std::is_same<T, std::array<double, 4>>::value,
77  "Invalid property type.");
78  }
79 
80  template <typename T>
81  void assertValidEnumType() const
82  {
83  static_assert(std::is_same<T, int32_t>::value || std::is_same<T, std::string>::value, "Invalid enum type.");
84  }
85 
86  template <typename T>
87  Type getType() const
88  {
89  assertValidType<T>();
90 
91  if (std::is_same<T, double>::value)
93  if (std::is_same<T, int32_t>::value)
94  return Property::Type::Int;
95  if (std::is_same<T, std::string>::value)
97  if (std::is_same<T, bool>::value)
98  return Property::Type::Bool;
99  if (std::is_same<T, std::array<double, 2>>::value)
100  return Property::Type::Vec2d;
101  if (std::is_same<T, std::array<int32_t, 2>>::value)
102  return Property::Type::Vec2i;
103  if (std::is_same<T, std::array<double, 3>>::value)
104  return Property::Type::Vec3d;
105  if (std::is_same<T, std::array<int32_t, 3>>::value)
106  return Property::Type::Vec3i;
107  if (std::is_same<T, std::array<double, 4>>::value)
108  return Property::Type::Vec4d;
109  throw std::runtime_error("Could not match type for '" + name + "'");
110  }
111 
112  template <typename T>
113  Property(const std::string& name_, const T value, const MetaData& metaData_ = {})
114  : name(name_)
115  , metaData(metaData_)
116  , type(getType<T>())
117  , _data(std::move(value))
118  , _min(T())
119  , _max(T())
120  {
121  assertValidType<T>();
122  }
123 
124  template <typename T>
125  Property(const std::string& name_, const T value, const T min_, const T max_, const MetaData& metaData_ = {})
126  : name(name_)
127  , metaData(metaData_)
128  , type(getType<T>())
129  , _data(std::move(value))
130  , _min(min_)
131  , _max(max_)
132  {
133  assertValidType<T>();
134  }
135 
140  template <typename T>
141  Property(const std::string& name_, const T value, const std::vector<std::string>& enums_, const MetaData& metaData_)
142  : name(name_)
143  , metaData(metaData_)
144  , type(getType<T>())
145  , enums(enums_)
146  , _data(std::move(value))
147  , _min(0)
148  , _max(enums_.size())
149  {
150  assertValidEnumType<T>();
151  }
152 
154  : name(std::move(other.name))
155  , metaData(std::move(other.metaData))
156  , type(other.type)
157  , enums(std::move(other.enums))
158  , _data(std::move(other._data))
159  , _min(std::move(other._min))
160  , _max(std::move(other._max))
161  , _readOnly(other._readOnly)
162  {
163  }
164 
165  Property(const Property& other) = default;
166 
167  using ModifiedCallback = std::function<void(const Property&)>;
168 
172  void onModified(const ModifiedCallback& callback) { _modifiedCallback = callback; }
173 
174  template <typename T>
175  void set(const T& v)
176  {
177  assertValidType<T>();
178  _checkType<T>();
179  _setData(v);
180  }
181 
182  template <typename T>
183  T get() const
184  {
185  assertValidType<T>();
186  return _castValue<T>(_data);
187  }
188 
189  template <typename T>
190  T min() const
191  {
192  assertValidType<T>();
193  return _castValue<T>(_min);
194  }
195 
196  template <typename T>
197  T max() const
198  {
199  assertValidType<T>();
200  return _castValue<T>(_max);
201  }
202 
207  void markReadOnly() { _readOnly = true; }
208  bool readOnly() const { return _readOnly; }
209  const std::string name;
211  const Type type;
212 
213  static Property makeReadOnly(Property property)
214  {
215  auto prop{std::move(property)};
216  prop._readOnly = true;
217  return prop;
218  }
219 
223  const std::vector<std::string> enums;
224 
225 private:
226  friend class PropertyMap;
227 
228  linb::any _data;
229  const linb::any _min;
230  const linb::any _max;
231  bool _readOnly{false};
232  ModifiedCallback _modifiedCallback;
233 
234  template <typename T>
235  void _checkType() const
236  {
237  const auto requestedType = getType<T>();
238  if (requestedType != type)
239  throw std::runtime_error("Type mismatch for property '" + name + "'");
240  }
241  template <typename T>
242  T _castValue(const linb::any& v) const
243  {
244  _checkType<T>();
245  return linb::any_cast<T>(v);
246  }
247 
248  void _setData(const linb::any& data)
249  {
250  _data = data;
251  if (_modifiedCallback)
252  _modifiedCallback(*this);
253  }
254 
255  void _copy(const Property& from);
256 };
257 
263 {
264 public:
265  PropertyMap() = default;
266  PropertyMap(const std::string& name)
267  : _name(name)
268  {
269  }
270 
271  PropertyMap(const PropertyMap& other) = default;
272 
273  // std::vector move constructor is not noexcept until C++17, if we want
274  // this class to be movable we have to do it by hand.
275  PropertyMap(PropertyMap&& other) noexcept
276  : _name(std::move(other._name))
277  , _properties(std::move(other._properties))
278  {
279  }
280  // Assignment operator valid for both copy and move assignment.
282  {
283  std::swap(_name, other._name);
284  std::swap(_properties, other._properties);
285  return *this;
286  }
287 
288  bool empty() const { return _properties.empty(); }
293  const auto& getName() const { return _name; }
295  template <typename T>
296  inline void updateProperty(const std::string& name, const T& t)
297  {
298  if (auto property = find(name))
299  {
300  if (property->type != property->getType<T>())
301  throw std::runtime_error("updateProperty does not allow for changing the type");
302  property->set(t);
303  }
304  }
305 
307  void setProperty(const Property& newProperty)
308  {
309  if (auto property = find(newProperty.name))
310  {
311  if (property->type != newProperty.type)
312  throw std::runtime_error("setProperty does not allow for changing the type");
313  property->_setData(newProperty._data);
314  }
315  else
316  _properties.push_back(std::make_shared<Property>(newProperty));
317  }
318 
322  template <typename T>
323  inline T getProperty(const std::string& name, T valIfNotFound) const
324  {
325  if (auto property = find(name))
326  return property->get<T>();
327  return valIfNotFound;
328  }
329 
334  template <typename T>
335  inline T getProperty(const std::string& name) const
336  {
337  if (auto property = find(name))
338  return property->get<T>();
339  throw std::runtime_error("No property found with name " + name);
340  }
341 
343  bool hasProperty(const std::string& name) const { return find(name) != nullptr; }
344 
349  const auto& getEnums(const std::string& name) const
350  {
351  if (auto property = find(name))
352  return property->enums;
353  throw std::runtime_error("No property found with name " + name);
354  }
355 
357  Property::Type getPropertyType(const std::string& name) const
358  {
359  if (auto property = find(name))
360  return property->type;
361  throw std::runtime_error("No property found with name " + name);
362  }
363 
365  const auto& getMetaData(const std::string& name) const
366  {
367  if (auto property = find(name))
368  return property->metaData;
369  throw std::runtime_error("No property found with name " + name);
370  }
371 
373  const auto& getProperties() const { return _properties; }
378  void merge(const PropertyMap& input);
379 
385  void update(const PropertyMap& input);
386 
401  bool parse(int argc, const char** argv);
402 
403 private:
404  Property* find(const std::string& name) const
405  {
406  auto foundProperty =
407  std::find_if(_properties.begin(), _properties.end(), [&](const auto& p) { return p->name == name; });
408 
409  return foundProperty != _properties.end() ? foundProperty->get() : nullptr;
410  }
411 
412  std::string _name;
413  std::vector<std::shared_ptr<Property>> _properties;
414 };
415 } // namespace core
void setProperty(const Property &newProperty)
Definition: PropertyMap.h:307
void updateProperty(const std::string &name, const T &t)
Definition: PropertyMap.h:296
void update(const PropertyMap &input)
const auto & getProperties() const
Definition: PropertyMap.h:373
const auto & getName() const
Definition: PropertyMap.h:293
PropertyMap(const PropertyMap &other)=default
const auto & getMetaData(const std::string &name) const
Definition: PropertyMap.h:365
bool hasProperty(const std::string &name) const
Definition: PropertyMap.h:343
PropertyMap()=default
const auto & getEnums(const std::string &name) const
Definition: PropertyMap.h:349
PropertyMap(PropertyMap &&other) noexcept
Definition: PropertyMap.h:275
T getProperty(const std::string &name) const
Definition: PropertyMap.h:335
bool empty() const
Definition: PropertyMap.h:288
T getProperty(const std::string &name, T valIfNotFound) const
Definition: PropertyMap.h:323
bool parse(int argc, const char **argv)
void merge(const PropertyMap &input)
PropertyMap(const std::string &name)
Definition: PropertyMap.h:266
Property::Type getPropertyType(const std::string &name) const
Definition: PropertyMap.h:357
PropertyMap & operator=(PropertyMap other) noexcept
Definition: PropertyMap.h:281
const std::string description
Definition: PropertyMap.h:64
MetaData(std::string label_={}, const std::string &description_="no-description")
Definition: PropertyMap.h:58
const std::string label
Definition: PropertyMap.h:63
Property(Property &&other)
Definition: PropertyMap.h:153
bool readOnly() const
Definition: PropertyMap.h:208
std::function< void(const Property &)> ModifiedCallback
Definition: PropertyMap.h:167
Property(const std::string &name_, const T value, const T min_, const T max_, const MetaData &metaData_={})
Definition: PropertyMap.h:125
const std::vector< std::string > enums
Definition: PropertyMap.h:223
void assertValidType() const
Definition: PropertyMap.h:68
T get() const
Definition: PropertyMap.h:183
void onModified(const ModifiedCallback &callback)
Definition: PropertyMap.h:172
const Type type
Definition: PropertyMap.h:211
void markReadOnly()
Definition: PropertyMap.h:207
Type getType() const
Definition: PropertyMap.h:87
static Property makeReadOnly(Property property)
Definition: PropertyMap.h:213
Property(const Property &other)=default
Property(const std::string &name_, const T value, const std::vector< std::string > &enums_, const MetaData &metaData_)
Definition: PropertyMap.h:141
void assertValidEnumType() const
Definition: PropertyMap.h:81
Property(const std::string &name_, const T value, const MetaData &metaData_={})
Definition: PropertyMap.h:113
T max() const
Definition: PropertyMap.h:197
const MetaData metaData
user-friendly name and description
Definition: PropertyMap.h:210
T min() const
Definition: PropertyMap.h:190
const std::string name
Definition: PropertyMap.h:209
void set(const T &v)
Definition: PropertyMap.h:175