11 #ifndef smtk_common_Links_h
12 #define smtk_common_Links_h
14 #include "smtk/common/CompilerInformation.h"
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
28 #include <type_traits>
29 #include <unordered_set>
57 const base_type& base_,
59 const left_type& left_,
60 const right_type& right_,
61 const role_type& role_)
73 const left_type& left_,
74 const right_type& right_,
75 const role_type& role_)
84 ~
Link()
override =
default;
112 using namespace boost::multi_index;
124 using LinkContainer = boost::multi_index_container<
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; }
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; }
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; }
231 typename left_type = id_type,
232 typename right_type = left_type,
233 typename role_type = int,
235 class Links :
public detail::LinkContainer<id_type, left_type, right_type, role_type, base_type>
237 using Parent = detail::LinkContainer<id_type, left_type, right_type, role_type, base_type>;
238 template<
typename tag>
242 static const role_type undefinedRole;
244 virtual ~
Links() =
default;
257 using Link =
typename Parent::value_type;
258 using LinkBase = base_type;
259 using Parent::insert;
266 using RoleType = role_type;
270 std::pair<iterator, bool> insert(
275 const role_type& role = undefinedRole);
279 std::pair<iterator, bool> insert(
284 const role_type& role = undefinedRole);
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
293 const left_type& left,
294 const right_type& right,
295 const role_type& role = undefinedRole)
297 return insert(std::move(base_type()),
id, left, right, role);
301 bool contains(
const id_type& key)
const {
return this->find(key) != this->end(); }
305 template<
typename tag>
306 bool contains(
const typename LinkTraits<tag>::type&)
const;
310 template<
typename tag>
311 std::size_t size(
const typename LinkTraits<tag>::type&)
const;
314 template<
typename tag>
315 bool erase_all(
const typename LinkTraits<tag>::type&);
319 template<
typename tag>
320 bool erase_all(
const std::tuple<
typename LinkTraits<tag>::type, role_type>&);
324 template<
typename tag>
325 bool set(
const id_type&,
const typename LinkTraits<tag>::type&);
329 template<
typename tag>
330 const std::set<std::reference_wrapper<const id_type>> ids(
331 const typename LinkTraits<tag>::type&)
const;
334 const Link& at(
const id_type&)
const;
337 LinkBase& value(
const id_type&);
338 const LinkBase& value(
const id_type&)
const;
342 template<
typename tag>
343 const typename LinkTraits<tag>::type& at(
const id_type&)
const;
347 template<
typename tag>
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;
355 template<
typename tag>
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;
368 const role_type Links<id_type, left_type, right_type, role_type, base_type>::undefinedRole =
369 std::numeric_limits<role_type>::lowest();
377 std::pair<typename Links<id_type, left_type, right_type, role_type, base_type>::iterator,
bool>
379 const base_type& base,
381 const left_type& left,
382 const right_type& right,
383 const role_type& role)
385 return this->insert(Link(base,
id, left, right, role));
394 std::pair<typename Links<id_type, left_type, right_type, role_type, base_type>::iterator,
bool>
398 const left_type& left,
399 const right_type& right,
400 const role_type& role)
402 return this->insert(Link(std::forward<base_type>(base),
id, left, right, role));
411 template<
typename tag>
416 auto&
self = this->Parent::template get<tag>();
417 auto found =
self.find(value);
418 return found !=
self.end();
427 template<
typename tag>
429 const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::
432 auto&
self = this->Parent::template get<tag>();
433 auto range =
self.equal_range(value);
434 return std::distance(range.first, range.second);
443 template<
typename tag>
445 const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::
448 auto&
self = this->Parent::template get<tag>();
449 auto to_erase =
self.equal_range(value);
452 if (to_erase.first == to_erase.second || to_erase.first ==
self.end())
457 self.erase(to_erase.first, to_erase.second);
467 template<
typename tag>
470 typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::type,
473 auto&
self = this->Parent::template get<tag>();
474 auto to_erase =
self.equal_range(value);
477 if (to_erase.first == to_erase.second || to_erase.first ==
self.end())
482 self.erase(to_erase.first, to_erase.second);
492 template<
typename tag>
495 const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::
498 typedef LinkTraits<tag> traits;
500 auto linkIt = this->find(
id);
502 if (linkIt == this->end())
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");
509 bool modified =
false;
511 auto originalValue = traits::value(*linkIt);
513 if (originalValue != value)
517 Modify(
const typename traits::type& v)
522 void operator()(Link& link) { traits::setValue(link, value); }
524 const typename traits::type& value;
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)
533 modified =
self.modify(it, Modify(value), Modify(originalValue));
537 assert(modified ==
true);
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>::
554 std::set<std::reference_wrapper<const id_type>> ids;
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)
560 ids.insert(std::cref(it->id));
571 const typename Links<id_type, left_type, right_type, role_type, base_type>::Link&
574 auto it = this->find(
id);
576 if (it == this->end())
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");
594 return const_cast<Link&
>(this->at(
id));
604 const id_type&
id)
const
615 template<
typename tag>
616 const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::type&
619 typedef LinkTraits<tag> traits;
621 auto it = this->find(
id);
623 if (it == this->end())
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");
630 return traits::value(*it);
639 template<
typename tag>
641 std::reference_wrapper<
642 const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::
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>::
650 typedef LinkTraits<tag> traits;
653 std::reference_wrapper<const typename traits::other_type>,
654 std::less<const typename traits::other_type>>
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)
661 values.insert(std::cref(LinkTraits<typename traits::OtherTag>::value(*it)));
672 template<
typename tag>
674 std::reference_wrapper<
675 const typename detail::LinkTraits<id_type, left_type, right_type, role_type, base_type, tag>::
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>::
682 const role_type& role)
const
684 typedef LinkTraits<tag> traits;
687 std::reference_wrapper<const typename traits::other_type>,
688 std::less<const typename traits::other_type>>
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)
695 values.insert(std::cref(LinkTraits<typename traits::OtherTag>::value(*it)));
702 #endif // smtk_common_Links_h