SMTK  @SMTK_VERSION@
Simulation Modeling Tool Kit
TypeMap.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_common_TypeMap_h
12 #define smtk_common_TypeMap_h
13 
14 #include "smtk/CoreExports.h"
15 
16 #include "smtk/SystemConfig.h"
17 
18 #include "smtk/common/CompilerInformation.h"
19 #include "smtk/common/TypeName.h"
20 
21 SMTK_THIRDPARTY_PRE_INCLUDE
22 #include "nlohmann/json.hpp"
23 SMTK_THIRDPARTY_POST_INCLUDE
24 
25 #include <memory>
26 #include <string>
27 #include <type_traits>
28 #include <unordered_map>
29 
30 namespace smtk
31 {
32 namespace common
33 {
38 class SMTKCORE_EXPORT TypeMapEntryBase
39 {
40 public:
41  virtual ~TypeMapEntryBase() = default;
42 
43  virtual void to_json(nlohmann::json&) const {}
44  virtual void from_json(const nlohmann::json&) {}
45 
46  virtual void clear() {}
47  virtual std::size_t size() const { return 0; }
48 };
49 
50 template<typename KeyType>
51 class TypeMap;
52 
57 template<typename KeyType, typename Type>
58 class SMTK_ALWAYS_EXPORT TypeMapEntry : public TypeMapEntryBase
59 {
60  friend class TypeMap<KeyType>;
61 
62 protected:
64  TypeMapEntry() = default;
65 
66 public:
67  typedef KeyType key_type;
68  typedef Type mapped_type;
69 
72  TypeMapEntry(const TypeMapEntry&) = delete;
73  TypeMapEntry(TypeMapEntry&&) = delete;
74  TypeMapEntry& operator=(const TypeMapEntry&) = delete;
75  TypeMapEntry& operator=(TypeMapEntry&&) = delete;
76 
78  bool contains(const KeyType& key) const { return (m_data.find(key) != m_data.end()); }
79 
81  bool insert(const KeyType& key, const Type& value)
82  {
83  return m_data.insert(std::make_pair(key, value)).second;
84  }
85 
87  bool emplace(const KeyType& key, Type&& value)
88  {
89  return m_data.emplace(std::make_pair(key, std::move(value))).second;
90  }
91 
93  void erase(const KeyType& key) { m_data.erase(key); }
94 
96  Type& operator[](const KeyType& key) { return m_data[key]; }
97 
99  Type& at(const KeyType& key) { return m_data.at(key); }
100 
102  const Type& at(const KeyType& key) const { return m_data.at(key); }
103 
105  std::unordered_map<KeyType, Type>& data() { return m_data; }
106  const std::unordered_map<KeyType, Type>& data() const { return m_data; }
107 
108  std::size_t size() const override { return m_data.size(); }
109  void clear() override { m_data.clear(); }
110 
111  void to_json(nlohmann::json& j) const override { return to_json<Type>(j); }
112 
113  void from_json(const nlohmann::json& j) override { return from_json<Type>(j); }
114 
115 private:
116  template<typename T>
117  typename std::enable_if<nlohmann::detail::is_compatible_type<nlohmann::json, T>::value>::type
118  to_json(nlohmann::json& j) const
119  {
120  j = m_data;
121  }
122 
123  template<typename T>
124  typename std::enable_if<!nlohmann::detail::is_compatible_type<nlohmann::json, T>::value>::type
125  to_json(nlohmann::json&) const
126  {
127  }
128 
129  template<typename T>
130  typename std::enable_if<nlohmann::detail::is_compatible_type<nlohmann::json, T>::value>::type
131  from_json(const nlohmann::json& j)
132  {
133  m_data = j.get<decltype(m_data)>();
134  }
135 
136  template<typename T>
137  typename std::enable_if<!nlohmann::detail::is_compatible_type<nlohmann::json, T>::value>::type
138  from_json(const nlohmann::json&) const
139  {
140  }
141 
142  std::unordered_map<KeyType, Type> m_data;
143 };
144 
150 template<typename KeyType>
151 class SMTK_ALWAYS_EXPORT TypeMapBase
152 {
153 public:
154  virtual ~TypeMapBase() = 0;
155 
159  template<typename Type>
160  bool contains(const KeyType& key) const
161  {
162  auto it = m_data.find(smtk::common::typeName<Type>());
163  if (it == m_data.end())
164  {
165  return false;
166  }
167 
168  return static_cast<const TypeMapEntry<KeyType, Type>&>(*it->second).contains(key);
169  }
170 
172  template<typename Type>
173  bool insert(const KeyType& key, const Type& value)
174  {
175  return get<Type>().insert(key, value);
176  }
177 
179  template<typename Type>
180  bool emplace(const KeyType& key, Type&& value)
181  {
182  return get<Type>().emplace(key, std::forward<Type>(value));
183  }
184 
186  template<typename Type>
187  void erase(const KeyType& key)
188  {
189  auto& property = get<Type>();
190  property.erase(key);
191  }
192 
196  template<typename Type>
197  Type& at(const KeyType& key)
198  {
199  return get<Type>().at(key);
200  }
201 
205  template<typename Type>
206  const Type& at(const KeyType& key) const
207  {
208  return get<Type>().at(key);
209  }
210 
212  template<typename Type>
214  {
215  std::string name = smtk::common::typeName<Type>();
216  auto it = m_data.find(name);
217  if (it == m_data.end())
218  {
219  throw std::domain_error("No entry with given type");
220  }
221 
222  return static_cast<TypeMapEntry<KeyType, Type>&>(*it->second);
223  }
224 
226  template<typename Type>
228  {
229  auto it = m_data.find(smtk::common::typeName<Type>());
230  if (it == m_data.end())
231  {
232  throw std::domain_error("No entry with given type");
233  }
234 
235  return static_cast<const TypeMapEntry<KeyType, Type>&>(*it->second);
236  }
237 
239  template<typename Type>
240  bool containsType() const
241  {
242  return (m_data.find(smtk::common::typeName<Type>()) != m_data.end());
243  }
244 
246  std::unordered_map<std::string, TypeMapEntryBase*>& data() { return m_data; }
247  const std::unordered_map<std::string, TypeMapEntryBase*>& data() const { return m_data; }
248 
249 private:
250  std::unordered_map<std::string, TypeMapEntryBase*> m_data;
251 };
252 
253 template<typename KeyType>
254 inline TypeMapBase<KeyType>::~TypeMapBase()
255 {
256  for (auto& pair : m_data)
257  {
258  delete pair.second;
259  }
260 }
261 
269 template<typename KeyType = std::string>
270 class SMTK_ALWAYS_EXPORT TypeMap : public TypeMapBase<KeyType>
271 {
272 public:
273  typedef KeyType key_type;
274 
275  // MSVC sees `= default` as a duplicate of the template version.
276  // NOLINTNEXTLINE(modernize-use-equals-default)
277  TypeMap() {}
278 
279  template<typename List>
280  TypeMap()
281  {
282  insertTypes<List>();
283  }
284 
285  template<typename List>
286  TypeMap(identity<List>)
287  {
288  insertTypes<List>();
289  }
290 
291  ~TypeMap() override = default;
292 
293 protected:
294  template<typename Type>
295  void insertType()
296  {
297  std::string key = smtk::common::typeName<Type>();
298  auto it = TypeMapBase<KeyType>::data().find(key);
299  if (it == TypeMapBase<KeyType>::data().end())
300  {
302  .emplace(std::make_pair(key, new TypeMapEntry<key_type, Type>))
303  .first;
304  }
305  }
306 
307  template<typename Tuple>
308  void insertTypes()
309  {
310  TypeMap::insertTypes<0, Tuple>();
311  }
312 
313 private:
314  template<std::size_t I, typename Tuple>
315  inline typename std::enable_if<I != std::tuple_size<Tuple>::value>::type insertTypes()
316  {
317  this->insertType<typename std::tuple_element<I, Tuple>::type>();
318  TypeMap::insertTypes<I + 1, Tuple>();
319  }
320 
321  template<std::size_t I, typename Tuple>
322  inline typename std::enable_if<I == std::tuple_size<Tuple>::value>::type insertTypes()
323  {
324  }
325 };
326 } // namespace common
327 } // namespace smtk
328 
329 #endif
smtk
The main namespace for the Simulation Modeling Tool Kit (SMTK).
Definition: doc.h:33
smtk::common::TypeMapBase::erase
void erase(const KeyType &key)
Erase value of type Type indexed by key from the map.
Definition: TypeMap.h:187
smtk::common::TypeMapEntry::contains
bool contains(const KeyType &key) const
Check whether a value associated with key is present.
Definition: TypeMap.h:78
smtk::common::TypeMapBase::get
TypeMapEntry< KeyType, Type > & get()
Access values of type Type.
Definition: TypeMap.h:213
smtk::common::TypeMapBase
The TypeMapBase class holds the storage and API for TypeMap.
Definition: TypeMap.h:151
smtk::common::TypeMapBase::at
const Type & at(const KeyType &key) const
Access value of type Type indexed by key.
Definition: TypeMap.h:206
smtk::common::TypeMapEntryBase
A common base class for properties of a given type.
Definition: TypeMap.h:38
smtk::common::TypeMapBase::insert
bool insert(const KeyType &key, const Type &value)
Insert (Type, key, value ) into the map.
Definition: TypeMap.h:173
smtk::common::TypeMapEntry::emplace
bool emplace(const KeyType &key, Type &&value)
Emplace (key, value ) into the map.
Definition: TypeMap.h:87
smtk::common::TypeMapBase::data
std::unordered_map< std::string, TypeMapEntryBase * > & data()
Access the class's underlying data.
Definition: TypeMap.h:246
TypeName.h
Named type functions.
smtk::common::TypeMapBase::containsType
bool containsType() const
Check whether type Type is supported.
Definition: TypeMap.h:240
smtk::common::TypeMapEntry::erase
void erase(const KeyType &key)
Erase value indexed by key from the map.
Definition: TypeMap.h:93
smtk::common::TypeMapBase::get
const TypeMapEntry< KeyType, Type > & get() const
Access values of type Type.
Definition: TypeMap.h:227
smtk::common::TypeMapBase::emplace
bool emplace(const KeyType &key, Type &&value)
Emplace (Type, key, value ) into the map.
Definition: TypeMap.h:180
smtk::common::TypeMapBase::at
Type & at(const KeyType &key)
Access value of type Type indexed by key.
Definition: TypeMap.h:197
smtk::common::TypeMapEntry
A specialization of the TypeMapBase for a single type.
Definition: TypeMap.h:58
smtk::common::TypeMapEntry::operator[]
Type & operator[](const KeyType &key)
Access value indexed by key.
Definition: TypeMap.h:96
smtk::common::TypeMapEntry::at
Type & at(const KeyType &key)
Access value indexed by key.
Definition: TypeMap.h:99
smtk::common::TypeMapEntry::data
std::unordered_map< KeyType, Type > & data()
Access the class's underlying data.
Definition: TypeMap.h:105
smtk::common::TypeMapBase::contains
bool contains(const KeyType &key) const
Check whether a value of type Type associated with key is present.
Definition: TypeMap.h:160
smtk::common::TypeMap
TypeMap is a generalized map for storing and accessing data using a key.
Definition: TypeMap.h:51
smtk::common::TypeMapEntry::insert
bool insert(const KeyType &key, const Type &value)
Insert (key, value ) into the map.
Definition: TypeMap.h:81
smtk::common::TypeMapEntry::at
const Type & at(const KeyType &key) const
Access value indexed by key.
Definition: TypeMap.h:102