SMTK  @SMTK_VERSION@
Simulation Modeling Tool Kit
Links.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_Links_h
12 #define smtk_common_Links_h
13 
14 #include "smtk/common/CompilerInformation.h"
15 
16 SMTK_THIRDPARTY_PRE_INCLUDE
17 #include <boost/multi_index/composite_key.hpp>
18 #include <boost/multi_index/global_fun.hpp>
19 #include <boost/multi_index/member.hpp>
20 #include <boost/multi_index/ordered_index.hpp>
21 #include <boost/multi_index_container.hpp>
22 SMTK_THIRDPARTY_POST_INCLUDE
23 
24 #include <functional>
25 #include <limits>
26 #include <set>
27 #include <string>
28 #include <type_traits>
29 #include <unordered_set>
30 #include <utility>
31 
32 namespace smtk
33 {
34 namespace common
35 {
36 template<
37  typename id_type,
38  typename left_type,
39  typename right_type,
40  typename role_type,
41  typename base_type>
42 class Links;
43 
48 template<
49  typename id_type,
50  typename left_type,
51  typename right_type,
52  typename role_type,
53  typename base_type>
54 struct Link : base_type
55 {
56  Link(
57  const base_type& base_,
58  const id_type& id_,
59  const left_type& left_,
60  const right_type& right_,
61  const role_type& role_)
62  : base_type(base_)
63  , id(id_)
64  , left(left_)
65  , right(right_)
66  , role(role_)
67  {
68  }
69 
70  Link(
71  base_type&& base_,
72  const id_type& id_,
73  const left_type& left_,
74  const right_type& right_,
75  const role_type& role_)
76  : base_type(base_)
77  , id(id_)
78  , left(left_)
79  , right(right_)
80  , role(role_)
81  {
82  }
83 
84  ~Link() override = default;
85 
86  id_type id;
87  left_type left;
88  right_type right;
89  role_type role;
90 };
91 
92 namespace detail
93 {
95 {
96 };
97 
99 struct Id
100 {
101 };
102 struct Left
103 {
104 };
105 struct Right
106 {
107 };
108 struct Role
109 {
110 };
111 
112 using namespace boost::multi_index;
113 
118 template<
119  typename id_type,
120  typename left_type,
121  typename right_type,
122  typename role_type,
123  typename base_type>
124 using LinkContainer = boost::multi_index_container<
126  indexed_by<
127  ordered_unique<
128  tag<Id>,
129  member<
131  id_type,
133  ordered_non_unique<
134  tag<Role>,
135  member<
137  role_type,
139  ordered_non_unique<
140  tag<Left>,
141  composite_key<
143  member<
145  left_type,
147  member<
149  role_type,
151  ordered_non_unique<
152  tag<Right>,
153  composite_key<
155  member<
157  right_type,
159  member<
161  role_type,
163 
166 template<
167  typename id_type,
168  typename left_type,
169  typename right_type,
170  typename role_type,
171  typename base_type,
172  typename tag>
173 struct LinkTraits;
174 
175 template<
176  typename id_type,
177  typename left_type,
178  typename right_type,
179  typename role_type,
180  typename base_type>
181 struct LinkTraits<id_type, left_type, right_type, role_type, base_type, Left>
182 {
184  typedef Right OtherTag;
185  typedef left_type type;
186  typedef right_type other_type;
187  static const type& value(const Link_& a) { return a.left; }
188  static void setValue(Link_& a, const type& v) { a.left = v; }
189 };
190 
191 template<
192  typename id_type,
193  typename left_type,
194  typename right_type,
195  typename role_type,
196  typename base_type>
197 struct LinkTraits<id_type, left_type, right_type, role_type, base_type, Right>
198 {
200  typedef Left OtherTag;
201  typedef right_type type;
202  typedef left_type other_type;
203  static const type& value(const Link_& a) { return a.right; }
204  static void setValue(Link_& a, const type& v) { a.right = v; }
205 };
206 
207 template<
208  typename id_type,
209  typename left_type,
210  typename right_type,
211  typename role_type,
212  typename base_type>
213 struct LinkTraits<id_type, left_type, right_type, role_type, base_type, Role>
214 {
216  typedef role_type type;
217  static const type& value(const Link_& a) { return a.role; }
218  static void setValue(Link_& a, const type& v) { a.role = v; }
219 };
220 } // namespace detail
221 
229 template<
230  typename id_type,
231  typename left_type = id_type,
232  typename right_type = left_type,
233  typename role_type = int,
234  typename base_type = detail::NullLinkBase>
235 class Links : public detail::LinkContainer<id_type, left_type, right_type, role_type, base_type>
236 {
237  using Parent = detail::LinkContainer<id_type, left_type, right_type, role_type, base_type>;
238  template<typename tag>
240 
241 public:
242  static const role_type undefinedRole;
243 
244  virtual ~Links() = default;
245 
250  using Right = detail::Right;
251  using Role = detail::Role;
252 
256  using iterator = typename Parent::iterator;
257  using Link = typename Parent::value_type;
258  using LinkBase = base_type;
259  using Parent::insert;
260  using Parent::size;
261 
263  using IdType = id_type;
264  using LeftType = left_type;
265  using RightType = right_type;
266  using RoleType = role_type;
267 
270  std::pair<iterator, bool> insert(
271  const base_type&,
272  const id_type&,
273  const left_type&,
274  const right_type&,
275  const role_type& role = undefinedRole);
276 
279  std::pair<iterator, bool> insert(
280  base_type&&,
281  const id_type&,
282  const left_type&,
283  const right_type&,
284  const role_type& role = undefinedRole);
285 
289  template<typename return_value = typename std::pair<iterator, bool>>
290  typename std::enable_if<std::is_default_constructible<base_type>::value, return_value>::type
292  const id_type& id,
293  const left_type& left,
294  const right_type& right,
295  const role_type& role = undefinedRole)
296  {
297  return insert(std::move(base_type()), id, left, right, role);
298  }
299 
301  bool contains(const id_type& key) const { return this->find(key) != this->end(); }
302 
305  template<typename tag>
306  bool contains(const typename LinkTraits<tag>::type&) const;
307 
310  template<typename tag>
311  std::size_t size(const typename LinkTraits<tag>::type&) const;
312 
314  template<typename tag>
315  bool erase_all(const typename LinkTraits<tag>::type&);
316 
319  template<typename tag>
320  bool erase_all(const std::tuple<typename LinkTraits<tag>::type, role_type>&);
321 
324  template<typename tag>
325  bool set(const id_type&, const typename LinkTraits<tag>::type&);
326 
329  template<typename tag>
330  const std::set<std::reference_wrapper<const id_type>> ids(
331  const typename LinkTraits<tag>::type&) const;
332 
334  const Link& at(const id_type&) const;
335 
337  LinkBase& value(const id_type&);
338  const LinkBase& value(const id_type&) const;
339 
342  template<typename tag>
343  const typename LinkTraits<tag>::type& at(const id_type&) const;
344 
347  template<typename tag>
348  const std::set<
349  std::reference_wrapper<const typename LinkTraits<tag>::other_type>,
350  std::less<const typename LinkTraits<tag>::other_type>>
351  linked_to(const typename LinkTraits<tag>::type&) const;
352 
355  template<typename tag>
356  const std::set<
357  std::reference_wrapper<const typename LinkTraits<tag>::other_type>,
358  std::less<const typename LinkTraits<tag>::other_type>>
359  linked_to(const typename LinkTraits<tag>::type&, const role_type& role) const;
360 };
361 
362 template<
363  typename id_type,
364  typename left_type,
365  typename right_type,
366  typename role_type,
367  typename base_type>
368 const role_type Links<id_type, left_type, right_type, role_type, base_type>::undefinedRole =
369  std::numeric_limits<role_type>::lowest();
370 
371 template<
372  typename id_type,
373  typename left_type,
374  typename right_type,
375  typename role_type,
376  typename base_type>
377 std::pair<typename Links<id_type, left_type, right_type, role_type, base_type>::iterator, bool>
379  const base_type& base,
380  const id_type& id,
381  const left_type& left,
382  const right_type& right,
383  const role_type& role)
384 {
385  return this->insert(Link(base, id, left, right, role));
386 }
387 
388 template<
389  typename id_type,
390  typename left_type,
391  typename right_type,
392  typename role_type,
393  typename base_type>
394 std::pair<typename Links<id_type, left_type, right_type, role_type, base_type>::iterator, bool>
396  base_type&& base,
397  const id_type& id,
398  const left_type& left,
399  const right_type& right,
400  const role_type& role)
401 {
402  return this->insert(Link(std::forward<base_type>(base), id, left, right, role));
403 }
404 
405 template<
406  typename id_type,
407  typename left_type,
408  typename right_type,
409  typename role_type,
410  typename base_type>
411 template<typename tag>
414  type& value) const
415 {
416  auto& self = this->Parent::template get<tag>();
417  auto found = self.find(value);
418  return found != self.end();
419 }
420 
421 template<
422  typename id_type,
423  typename left_type,
424  typename right_type,
425  typename role_type,
426  typename base_type>
427 template<typename tag>
429  const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::
430  type& value) const
431 {
432  auto& self = this->Parent::template get<tag>();
433  auto range = self.equal_range(value);
434  return std::distance(range.first, range.second);
435 }
436 
437 template<
438  typename id_type,
439  typename left_type,
440  typename right_type,
441  typename role_type,
442  typename base_type>
443 template<typename tag>
445  const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::
446  type& value)
447 {
448  auto& self = this->Parent::template get<tag>();
449  auto to_erase = self.equal_range(value);
450 
451  // No elements match |value|, or |self| is empty.
452  if (to_erase.first == to_erase.second || to_erase.first == self.end())
453  {
454  return false;
455  }
456 
457  self.erase(to_erase.first, to_erase.second);
458  return true;
459 }
460 
461 template<
462  typename id_type,
463  typename left_type,
464  typename right_type,
465  typename role_type,
466  typename base_type>
467 template<typename tag>
469  const std::tuple<
470  typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::type,
471  role_type>& value)
472 {
473  auto& self = this->Parent::template get<tag>();
474  auto to_erase = self.equal_range(value);
475 
476  // No elements match |value|, or |self| is empty.
477  if (to_erase.first == to_erase.second || to_erase.first == self.end())
478  {
479  return false;
480  }
481 
482  self.erase(to_erase.first, to_erase.second);
483  return true;
484 }
485 
486 template<
487  typename id_type,
488  typename left_type,
489  typename right_type,
490  typename role_type,
491  typename base_type>
492 template<typename tag>
494  const id_type& id,
495  const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::
496  type& value)
497 {
498  typedef LinkTraits<tag> traits;
499 
500  auto linkIt = this->find(id);
501 
502  if (linkIt == this->end())
503  {
504  throw std::out_of_range("Links<id_type, left_type, right_type, role_type, "
505  "base_type>::set(const id_type&, const type& value) : "
506  "no link has this index");
507  }
508 
509  bool modified = false;
510 
511  auto originalValue = traits::value(*linkIt);
512 
513  if (originalValue != value)
514  {
515  struct Modify
516  {
517  Modify(const typename traits::type& v)
518  : value(v)
519  {
520  }
521 
522  void operator()(Link& link) { traits::setValue(link, value); }
523 
524  const typename traits::type& value;
525  };
526 
527  auto& self = this->Parent::template get<tag>();
528  auto range = self.equal_range(originalValue);
529  for (auto it = range.first; it != range.second; ++it)
530  {
531  if (it->id == id)
532  {
533  modified = self.modify(it, Modify(value), Modify(originalValue));
534  break;
535  }
536  }
537  assert(modified == true);
538  }
539  return modified;
540 }
541 
542 template<
543  typename id_type,
544  typename left_type,
545  typename right_type,
546  typename role_type,
547  typename base_type>
548 template<typename tag>
549 const std::set<std::reference_wrapper<const id_type>>
551  const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::
552  type& value) const
553 {
554  std::set<std::reference_wrapper<const id_type>> ids;
555 
556  auto& self = this->Parent::template get<tag>();
557  auto range = self.equal_range(value);
558  for (auto it = range.first; it != range.second; ++it)
559  {
560  ids.insert(std::cref(it->id));
561  }
562  return ids;
563 }
564 
565 template<
566  typename id_type,
567  typename left_type,
568  typename right_type,
569  typename role_type,
570  typename base_type>
571 const typename Links<id_type, left_type, right_type, role_type, base_type>::Link&
573 {
574  auto it = this->find(id);
575 
576  if (it == this->end())
577  {
578  throw std::out_of_range(
579  "Links<id_type, left_type, right_type, role_type, base_type>::at(const id_type&) : "
580  "no link has this index");
581  }
582 
583  return *it;
584 }
585 
586 template<
587  typename id_type,
588  typename left_type,
589  typename right_type,
590  typename role_type,
591  typename base_type>
593 {
594  return const_cast<Link&>(this->at(id));
595 }
596 
597 template<
598  typename id_type,
599  typename left_type,
600  typename right_type,
601  typename role_type,
602  typename base_type>
604  const id_type& id) const
605 {
606  return this->at(id);
607 }
608 
609 template<
610  typename id_type,
611  typename left_type,
612  typename right_type,
613  typename role_type,
614  typename base_type>
615 template<typename tag>
616 const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::type&
618 {
619  typedef LinkTraits<tag> traits;
620 
621  auto it = this->find(id);
622 
623  if (it == this->end())
624  {
625  throw std::out_of_range(
626  "Links<id_type, left_type, right_type, role_type, base_type>::at(const id_type&) : "
627  "no link has this index");
628  }
629 
630  return traits::value(*it);
631 }
632 
633 template<
634  typename id_type,
635  typename left_type,
636  typename right_type,
637  typename role_type,
638  typename base_type>
639 template<typename tag>
640 const std::set<
641  std::reference_wrapper<
642  const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::
643  other_type>,
644  std::less<const typename detail::
645  LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::other_type>>
647  const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::
648  type& value) const
649 {
650  typedef LinkTraits<tag> traits;
651 
652  std::set<
653  std::reference_wrapper<const typename traits::other_type>,
654  std::less<const typename traits::other_type>>
655  values;
656 
657  auto& self = this->Parent::template get<tag>();
658  auto range = self.equal_range(std::make_tuple(value));
659  for (auto it = range.first; it != range.second; ++it)
660  {
661  values.insert(std::cref(LinkTraits<typename traits::OtherTag>::value(*it)));
662  }
663  return values;
664 }
665 
666 template<
667  typename id_type,
668  typename left_type,
669  typename right_type,
670  typename role_type,
671  typename base_type>
672 template<typename tag>
673 const std::set<
674  std::reference_wrapper<
675  const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::
676  other_type>,
677  std::less<const typename detail::
678  LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::other_type>>
680  const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::
681  type& value,
682  const role_type& role) const
683 {
684  typedef LinkTraits<tag> traits;
685 
686  std::set<
687  std::reference_wrapper<const typename traits::other_type>,
688  std::less<const typename traits::other_type>>
689  values;
690 
691  auto& self = this->Parent::template get<tag>();
692  auto range = self.equal_range(std::make_tuple(value, role));
693  for (auto it = range.first; it != range.second; ++it)
694  {
695  values.insert(std::cref(LinkTraits<typename traits::OtherTag>::value(*it)));
696  }
697  return values;
698 }
699 } // namespace common
700 } // namespace smtk
701 
702 #endif // smtk_common_Links_h
smtk
The main namespace for the Simulation Modeling Tool Kit (SMTK).
Definition: doc.h:33
smtk::common::detail::LinkTraits
Traits classes for Links.
Definition: Links.h:173
smtk::common::UUID
Definition: UUID.h:38
smtk::common::detail::Right
Definition: Links.h:105
smtk::common::detail::Id
Tags for access.
Definition: Links.h:99
smtk::common::detail::NullLinkBase
Definition: Links.h:94
smtk::common::detail::Role
Definition: Links.h:108
smtk::common::detail::Left
Definition: Links.h:102