SMTK  @SMTK_VERSION@
Simulation Modeling Tool Kit
Properties.h
1 //=========================================================================
2 // Copyright (c) Kitware, Inc.
3 // All rights reserved.
4 // See LICENSE.txt for details.
5 //
6 // This software is distributed WITHOUT ANY WARRANTY; without even
7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8 // PURPOSE. See the above copyright notice for more information.
9 //=========================================================================
10 
11 #ifndef smtk_resource_Properties_h
12 #define smtk_resource_Properties_h
13 
14 #include "smtk/CoreExports.h"
15 #include "smtk/common/TypeMap.h"
16 #include "smtk/common/UUID.h"
17 #include "smtk/string/Token.h"
18 
19 #include "smtk/common/json/jsonUUID.h"
20 #include "smtk/string/json/jsonToken.h"
21 
22 #include "smtk/resource/json/jsonPropertyCoordinateFrame.h"
23 #include "smtk/resource/properties/CoordinateFrame.h"
24 
25 #include <algorithm>
26 
27 namespace smtk
28 {
29 namespace resource
30 {
35 namespace detail
36 {
40 
44 class SMTKCORE_EXPORT PropertiesBase
45 {
46 public:
47  virtual ~PropertiesBase() = default;
48 
49  virtual std::size_t eraseId(const smtk::common::UUID&) = 0;
50 };
51 
52 template<typename Type>
54 
59 template<typename Type>
60 class PropertiesOfType<std::unordered_map<smtk::common::UUID, Type>>
61  : public smtk::common::TypeMapEntry<std::string, std::unordered_map<smtk::common::UUID, Type>>
62  , public PropertiesBase
63 {
64  friend class Properties;
67  , PropertiesBase()
68  {
69  }
70 
71 public:
72  std::size_t eraseId(const smtk::common::UUID& id) override
73  {
74  std::size_t count = 0;
75  for (auto& pair : this->data())
76  {
77  count += pair.second.erase(id);
78  }
79  return count;
80  }
81 };
82 
87 class SMTKCORE_EXPORT Properties : public smtk::common::TypeMapBase<std::string>
88 {
89 public:
90  // MSVC sees `= default` as a duplicate of the template version.
91  // NOLINTNEXTLINE(modernize-use-equals-default)
92  Properties() {}
93 
94  template<typename List>
95  Properties()
96  {
97  insertPropertyTypes<List>();
98  }
99 
100  template<typename List>
102  {
103  insertPropertyTypes<List>();
104  }
105 
106  std::size_t eraseId(const smtk::common::UUID& id)
107  {
108  std::size_t count = 0;
109  auto& map = this->data();
110  for (auto& pair : map)
111  {
112  count += dynamic_cast<PropertiesBase*>(pair.second)->eraseId(id);
113  }
114  return count;
115  }
116 
117  template<typename Type>
118  std::size_t eraseIdForType(const smtk::common::UUID& id)
119  {
120  return dynamic_cast<PropertiesBase&>(this->get<Type>()).eraseId(id);
121  }
122 
123  // TODO: Putting the following two methods in the public API breaks RAII.
124  // There needs to be a way for a derived resource to augment its types of
125  // properties, though.
126  template<typename Type>
127  void insertPropertyType()
128  {
129  std::string key = smtk::common::typeName<Type>();
130  auto it = data().find(key);
131  if (it == data().end())
132  {
133  it = data().emplace(std::make_pair(key, new detail::PropertiesOfType<Type>)).first;
134  }
135  }
136 
137  template<typename Tuple>
138  void insertPropertyTypes()
139  {
140  Properties::insertPropertyTypes<0, Tuple>();
141  }
142 
143 private:
144  template<std::size_t I, typename Tuple>
145  inline typename std::enable_if<I != std::tuple_size<Tuple>::value>::type insertPropertyTypes()
146  {
147  this->insertPropertyType<typename std::tuple_element<I, Tuple>::type>();
148  Properties::insertPropertyTypes<I + 1, Tuple>();
149  }
150 
151  template<std::size_t I, typename Tuple>
152  inline typename std::enable_if<I == std::tuple_size<Tuple>::value>::type insertPropertyTypes()
153  {
154  }
155 };
156 } // namespace detail
157 
158 class Component;
159 class Resource;
160 class Properties;
161 
165 template<typename Type>
167 {
168  using IndexedType = std::unordered_map<smtk::common::UUID, Type>;
169 
170  friend class Properties;
172  const smtk::common::UUID& id,
173  const detail::PropertiesOfType<IndexedType>& properties)
174  : m_id(id)
175  , m_properties(properties)
176  {
177  }
178 
179 public:
181  bool contains(const std::string& key) const
182  {
183  if (!m_properties.contains(key))
184  {
185  return false;
186  }
187  const std::unordered_map<smtk::common::UUID, Type>& data = get(key);
188  return (data.find(m_id) != data.end());
189  }
190 
192  const Type& at(const std::string& key) const { return get(key).at(m_id); }
193 
195  bool empty() const
196  {
197  using PropertyDataMap =
198  std::unordered_map<std::string, std::unordered_map<smtk::common::UUID, Type>>;
199  const PropertyDataMap& data = m_properties.data();
200  return std::all_of(
201  data.begin(), data.end(), [this](const typename PropertyDataMap::value_type& pair) {
202  return pair.second.find(m_id) == pair.second.end();
203  });
204  }
205 
206  std::set<std::string> keys() const
207  {
208  std::set<std::string> keys;
209  for (auto& pair : m_properties.data())
210  {
211  if (pair.second.find(m_id) != pair.second.end())
212  {
213  keys.insert(pair.first);
214  }
215  }
216  return keys;
217  }
218 
219 private:
220  const std::unordered_map<smtk::common::UUID, Type>& get(const std::string& key) const
221  {
222  return m_properties.at(key);
223  }
224 
225  const smtk::common::UUID& m_id;
226  const detail::PropertiesOfType<IndexedType>& m_properties;
227 };
228 
232 template<typename Type>
234 {
235  using IndexedType = std::unordered_map<smtk::common::UUID, Type>;
236 
237  friend class Properties;
239  : m_id(id)
240  , m_properties(properties)
241  {
242  }
243 
244 public:
246  bool contains(const std::string& key) const
247  {
248  if (!m_properties.contains(key))
249  {
250  return false;
251  }
252  const std::unordered_map<smtk::common::UUID, Type>& data = get(key);
253  return (data.find(m_id) != data.end());
254  }
255 
257  bool insert(const std::string& key, const Type& value)
258  {
259  return get(key).insert(std::make_pair(m_id, value)).second;
260  }
261 
263  bool emplace(const std::string& key, Type&& value)
264  {
265  return get(key).emplace(std::make_pair(m_id, std::move(value))).second;
266  }
267 
269  void erase(const std::string& key)
270  {
271  get(key).erase(m_id);
272  if (get(key).empty())
273  {
274  m_properties.erase(key);
275  }
276  }
277 
279  Type& operator[](const std::string& key) { return get(key)[m_id]; }
280 
282  Type& at(const std::string& key) { return get(key).at(m_id); }
283 
285  const Type& at(const std::string& key) const { return get(key).at(m_id); }
286 
288  bool empty() const
289  {
290  for (auto& pair : m_properties.data())
291  {
292  if (pair.second.find(m_id) != pair.second.end())
293  {
294  return false;
295  }
296  }
297  return true;
298  }
299 
303  std::size_t clear()
304  {
305  std::size_t count = m_properties.eraseId(m_id);
306  return count;
307  }
308 
309  std::set<std::string> keys() const
310  {
311  std::set<std::string> keys;
312  for (auto& pair : m_properties.data())
313  {
314  if (pair.second.find(m_id) != pair.second.end())
315  {
316  keys.insert(pair.first);
317  }
318  }
319  return keys;
320  }
321 
322 private:
323  const std::unordered_map<smtk::common::UUID, Type>& get(const std::string& key) const
324  {
325  return m_properties.at(key);
326  }
327  std::unordered_map<smtk::common::UUID, Type>& get(const std::string& key)
328  {
329  if (!m_properties.contains(key))
330  {
331  m_properties.emplace(key, typename detail::PropertiesOfType<IndexedType>::mapped_type());
332  }
333  return m_properties.at(key);
334  }
335 
336  const smtk::common::UUID& m_id;
337  detail::PropertiesOfType<IndexedType>& m_properties;
338 };
339 
346 class SMTKCORE_EXPORT Properties
347 {
348 public:
349  template<typename Type>
350  using Indexed = std::unordered_map<smtk::common::UUID, Type>;
351 
353  template<typename Type>
354  bool contains(const std::string& key) const
355  {
356  return get<Type>().contains(key);
357  }
358 
360  template<typename Type>
361  bool insert(const std::string& key, const Type& value)
362  {
363  return get<Type>().insert(key, value);
364  }
365 
367  template<typename Type>
368  bool emplace(const std::string& key, Type&& value)
369  {
370  return get<Type>().emplace(key, std::forward<Type>(value));
371  }
372 
374  template<typename Type>
375  void erase(const std::string& key)
376  {
377  return get<Type>().erase(key);
378  }
379 
381  template<typename Type>
382  Type& at(const std::string& key)
383  {
384  return get<Type>().at(key);
385  }
386 
388  template<typename Type>
389  const Type& at(const std::string& key) const
390  {
391  return get<Type>().at(key);
392  }
393 
395  template<typename Type>
397  {
398  return PropertiesOfType<Type>(
399  id(),
400  static_cast<detail::PropertiesOfType<Indexed<Type>>&>(properties().get<Indexed<Type>>()));
401  }
402 
404  template<typename Type>
406  {
408  id(),
409  static_cast<const detail::PropertiesOfType<Indexed<Type>>&>(
410  properties().get<Indexed<Type>>()));
411  }
412 
414  virtual std::size_t clear() = 0;
415 
416 private:
417  virtual const smtk::common::UUID& id() const = 0;
418  virtual smtk::common::TypeMapBase<std::string>& properties() = 0;
419  virtual const smtk::common::TypeMapBase<std::string>& properties() const = 0;
420 
421  struct EraseProperties
422  {
423  template<typename Data>
424  void operator()(Data propertiesOfType, const smtk::common::UUID& uid, std::size_t& count)
425  {
426  std::cout << "Erase " << uid << " from " << propertiesOfType.keys().size() << "\n";
427  count += propertiesOfType.clear();
428  }
429  };
430 
437  template<typename Tuple, typename Functor, typename... Args>
438  void invoke(Args&&... args) const
439  {
440  smtk::resource::Properties::invokeFunctors<0, Tuple, Functor>(std::forward<Args>(args)...);
441  }
442 
443  template<typename Tuple, typename Functor, typename... Args>
444  void invoke(Args&&... args)
445  {
446  smtk::resource::Properties::invokeFunctors<0, Tuple, Functor>(std::forward<Args>(args)...);
447  }
449 
450  // const version
451  template<typename Entry, typename Functor, typename... Args>
452  void invokeFunctor(Args&&... args) const
453  {
454  Functor f;
455  f(std::forward<Args>(args)...);
456  }
457 
458  // non-const version
459  template<typename Entry, typename Functor, typename... Args>
460  void invokeFunctor(Args&&... args)
461  {
462  Functor f;
463  f(std::forward<Args>(args)...);
464  }
465 
466  // const versions
467  template<std::size_t I, typename Tuple, typename Functor, typename... Args>
468  inline typename std::enable_if<I != std::tuple_size<Tuple>::value>::type invokeFunctors(
469  Args&&... args) const
470  {
471  this->invokeFunctor<typename std::tuple_element<I, Tuple>::type, Functor>(
472  // First argument is always PropertiesOfType<tuple_element<I, Tuple>>:
473  this->template get<typename std::tuple_element<I, Tuple>::type>(),
474  // Subsequent arguments are whatever is passed in:
475  std::forward<Args>(args)...);
476  smtk::resource::Properties::invokeFunctors<I + 1, Tuple, Functor>(std::forward<Args>(args)...);
477  }
478 
479  // non-const version
480  template<std::size_t I, typename Tuple, typename Functor, typename... Args>
481  inline typename std::enable_if<I != std::tuple_size<Tuple>::value>::type invokeFunctors(
482  Args&&... args)
483  {
484  this->invokeFunctor<typename std::tuple_element<I, Tuple>::type, Functor>(
485  // First argument is always PropertiesOfType<tuple_element<I, Tuple>>:
486  this->template get<typename std::tuple_element<I, Tuple>::type>(),
487  // Subsequent arguments are whatever is passed in:
488  std::forward<Args>(args)...);
489  smtk::resource::Properties::invokeFunctors<I + 1, Tuple, Functor>(std::forward<Args>(args)...);
490  }
491 
492  // This only needs a const version.
493  template<std::size_t I, typename Tuple, typename Functor, typename... Args>
494  inline typename std::enable_if<I == std::tuple_size<Tuple>::value>::type invokeFunctors(
495  Args&&...) const
496  {
497  }
498 
499 protected:
503  template<typename PropertyTypeTuple>
504  std::size_t clearInternal(const smtk::common::UUID& uid)
505  {
506  std::size_t count = 0;
507  // auto& propertiesByTypeThenId = this->properties();
508  this->invoke<PropertyTypeTuple, EraseProperties>(uid, count);
509  return count;
510  }
511 };
512 
513 namespace detail
514 {
518 class SMTKCORE_EXPORT ResourceProperties : public smtk::resource::Properties
519 {
520  friend Resource;
521 
523 
524 public:
529  typedef std::tuple<
530  Indexed<bool>,
531  Indexed<int>,
532  Indexed<long>,
533  Indexed<double>,
534  Indexed<std::string>,
535  Indexed<smtk::string::Token>,
536  Indexed<std::set<smtk::string::Token>>,
537  Indexed<std::set<int>>,
538  Indexed<std::vector<bool>>,
539  Indexed<std::vector<int>>,
540  Indexed<std::vector<long>>,
541  Indexed<std::vector<double>>,
542  Indexed<std::vector<std::string>>,
543  Indexed<smtk::resource::properties::CoordinateFrame>,
544  Indexed<std::map<std::string, smtk::resource::properties::CoordinateFrame>>>
546 
547  ResourcePropertiesData& data() { return m_data; }
548  const ResourcePropertiesData& data() const { return m_data; }
549 
550  // TODO: Putting the following method in the public API breaks RAII. There
551  // needs to be a way for a derived resource to augment its types of
552  // properties, though.
553  template<typename Type>
554  void insertPropertyType()
555  {
556  m_data.insertPropertyType<Indexed<Type>>();
557  }
558 
559  // Remove all properties on the resource
560  std::size_t clear() override
561  {
562  std::size_t count = this->clearInternal<PropertyTypes>(this->id());
563  return count;
564  }
565 
566 private:
567  ResourceProperties(Resource* resource);
568 
569  const smtk::common::UUID& id() const override;
570  smtk::common::TypeMapBase<std::string>& properties() override { return m_data; }
571  const smtk::common::TypeMapBase<std::string>& properties() const override { return m_data; }
572 
573  Resource* m_resource;
574  ResourcePropertiesData m_data;
575 };
576 
580 class SMTKCORE_EXPORT ComponentProperties : public smtk::resource::Properties
581 {
582 public:
583  // Remove all properties on the resource
584  std::size_t clear() override
585  {
586  std::size_t count = this->clearInternal<ResourceProperties::PropertyTypes>(this->id());
587  return count;
588  }
589 
590 protected:
591  friend Component;
592 
593  ComponentProperties(const Component* component);
595 
596  const smtk::common::UUID& id() const override;
597  smtk::common::TypeMapBase<std::string>& properties() override;
598  const smtk::common::TypeMapBase<std::string>& properties() const override;
599 
600  const Component* m_component;
601 };
602 } // namespace detail
603 } // namespace resource
604 } // namespace smtk
605 
606 #endif
smtk
The main namespace for the Simulation Modeling Tool Kit (SMTK).
Definition: doc.h:33
smtk::resource::Properties::get
PropertiesOfType< Type > get()
Access properties of type Type.
Definition: Properties.h:396
smtk::resource::detail::ResourceProperties::PropertyTypes
std::tuple< Indexed< bool >, Indexed< int >, Indexed< long >, Indexed< double >, Indexed< std::string >, Indexed< smtk::string::Token >, Indexed< std::set< smtk::string::Token > >, Indexed< std::set< int > >, Indexed< std::vector< bool > >, Indexed< std::vector< int > >, Indexed< std::vector< long > >, Indexed< std::vector< double > >, Indexed< std::vector< std::string > >, Indexed< smtk::resource::properties::CoordinateFrame >, Indexed< std::map< std::string, smtk::resource::properties::CoordinateFrame > > > PropertyTypes
The default value types for all resources and components are.
Definition: Properties.h:545
smtk::resource::PropertiesOfType::erase
void erase(const std::string &key)
Erase property indexed by key from the container.
Definition: Properties.h:269
smtk::resource::PropertiesOfType::at
const Type & at(const std::string &key) const
Access property indexed by key.
Definition: Properties.h:285
smtk::resource::PropertiesOfType::emplace
bool emplace(const std::string &key, Type &&value)
Emplace (key, value ) into the container.
Definition: Properties.h:263
smtk::resource::ConstPropertiesOfType
A specialization of the Properties container for a single type.
Definition: Properties.h:166
smtk::resource::detail::PropertiesBase
The Properties classes defined in this namespace closely correlate to counterparts in smtk::common::T...
Definition: Properties.h:44
smtk::resource::PropertiesOfType::insert
bool insert(const std::string &key, const Type &value)
Insert (key, value ) into the container.
Definition: Properties.h:257
smtk::common::TypeMapBase
The TypeMapBase class holds the storage and API for TypeMap.
Definition: TypeMap.h:151
smtk::resource::detail::ResourceProperties::clear
std::size_t clear() override
Remove all properties this object manages.
Definition: Properties.h:560
smtk::resource::PropertiesOfType::operator[]
Type & operator[](const std::string &key)
Access property indexed by key.
Definition: Properties.h:279
smtk::common::UUID
Definition: UUID.h:38
smtk::resource::detail::ResourceProperties
This specialization of smtk::resource::Properties completes aforementioned class's implementation by ...
Definition: Properties.h:518
smtk::resource::Properties::at
const Type & at(const std::string &key) const
Access property indexed by key.
Definition: Properties.h:389
smtk::resource::PropertiesOfType::at
Type & at(const std::string &key)
Access property indexed by key.
Definition: Properties.h:282
smtk::resource::PropertiesOfType::clear
std::size_t clear()
Remove all properties of this type corresponding to our ID.
Definition: Properties.h:303
smtk::resource::detail::ComponentProperties::clear
std::size_t clear() override
Remove all properties this object manages.
Definition: Properties.h:584
smtk::resource::Properties::emplace
bool emplace(const std::string &key, Type &&value)
Emplace (key, value ) into the container.
Definition: Properties.h:368
smtk::resource::PropertiesOfType
A specialization of the Properties container for a single type.
Definition: Properties.h:233
smtk::resource::Properties::at
Type & at(const std::string &key)
Access property indexed by key.
Definition: Properties.h:382
smtk::resource::PropertiesOfType::contains
bool contains(const std::string &key) const
Check whether a property associated with key is present.
Definition: Properties.h:246
smtk::resource::detail::PropertiesOfType
Definition: Properties.h:53
smtk::resource::PropertiesOfType::empty
bool empty() const
Check if any properties of this type are associated with m_id.
Definition: Properties.h:288
smtk::resource::Properties::erase
void erase(const std::string &key)
Erase property indexed by key from the container.
Definition: Properties.h:375
smtk::resource::detail::ComponentProperties
This specialization of smtk::resource::Properties completes aforementioned class's implementation by ...
Definition: Properties.h:580
smtk::resource::detail::Properties
Properties is a generalized container for storing and accessing data using a std::string key.
Definition: Properties.h:87
smtk::resource::ConstPropertiesOfType::contains
bool contains(const std::string &key) const
Check whether a property associated with key is present.
Definition: Properties.h:181
smtk::resource::Resource
An abstract base class for SMTK resources.
Definition: Resource.h:59
smtk::resource::Properties::clearInternal
std::size_t clearInternal(const smtk::common::UUID &uid)
This is a method subclasses may call from their implementation of clear() in order to iterate over al...
Definition: Properties.h:504
smtk::resource::Properties
Resource/Component properties store data as maps from UUIDs to values and present data as key/value p...
Definition: Properties.h:346
smtk::common::TypeMapEntry
A specialization of the TypeMapBase for a single type.
Definition: TypeMap.h:58
smtk::resource::Component
Component is the base class for records stored in an smtk::resource::Resource.
Definition: Component.h:43
smtk::resource::ConstPropertiesOfType::at
const Type & at(const std::string &key) const
Access property indexed by key.
Definition: Properties.h:192
smtk::resource::Properties::get
const ConstPropertiesOfType< Type > get() const
Access properties of type Type.
Definition: Properties.h:405
smtk::resource::ConstPropertiesOfType::empty
bool empty() const
Check if any properties of this type are associated with m_id.
Definition: Properties.h:195
smtk::resource::Properties::contains
bool contains(const std::string &key) const
Check whether a property associated with key is present.
Definition: Properties.h:354
smtk::resource::Properties::insert
bool insert(const std::string &key, const Type &value)
Insert (key, value ) into the container.
Definition: Properties.h:361
smtk::identity
Embeds a type in another class so its type information can be passed as a parameter.
Definition: TupleTraits.h:340