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>
308 auto&
self = this->Parent::template get<tag>();
309 auto found =
self.find(value);
310 return found !=
self.end();
315 template<
typename tag>
318 auto&
self = this->Parent::template get<tag>();
319 auto range =
self.equal_range(value);
320 return std::distance(range.first, range.second);
324 template<
typename tag>
327 auto&
self = this->Parent::template get<tag>();
328 auto to_erase =
self.equal_range(value);
331 if (to_erase.first == to_erase.second || to_erase.first ==
self.end())
336 self.erase(to_erase.first, to_erase.second);
342 template<
typename tag>
345 auto&
self = this->Parent::template get<tag>();
346 auto to_erase =
self.equal_range(value);
349 if (to_erase.first == to_erase.second || to_erase.first ==
self.end())
354 self.erase(to_erase.first, to_erase.second);
360 template<
typename tag>
365 auto linkIt = this->find(
id);
367 if (linkIt == this->end())
369 throw std::out_of_range(
"Links<id_type, left_type, right_type, role_type, "
370 "base_type>::set(const id_type&, const type& value) : "
371 "no link has this index");
374 bool modified =
false;
376 auto originalValue = traits::value(*linkIt);
378 if (originalValue != value)
382 Modify(
const typename traits::type& v)
387 void operator()(Link& link) { traits::setValue(link, value); }
389 const typename traits::type& value;
392 auto&
self = this->Parent::template get<tag>();
393 auto range =
self.equal_range(originalValue);
394 for (
auto it = range.first; it != range.second; ++it)
398 modified =
self.modify(it, Modify(value), Modify(originalValue));
402 assert(modified ==
true);
409 template<
typename tag>
410 const std::set<std::reference_wrapper<const id_type>>
ids(
413 std::set<std::reference_wrapper<const id_type>> ids;
415 auto&
self = this->Parent::template get<tag>();
416 auto range =
self.equal_range(value);
417 for (
auto it = range.first; it != range.second; ++it)
419 ids.insert(std::cref(it->id));
425 const Link&
at(
const id_type&
id)
const
427 auto it = this->find(
id);
429 if (it == this->end())
431 throw std::out_of_range(
432 "Links<id_type, left_type, right_type, role_type, base_type>::at(const id_type&) : "
433 "no link has this index");
440 LinkBase&
value(
const id_type&
id) {
return const_cast<Link&
>(this->at(
id)); }
441 const LinkBase& value(
const id_type&
id)
const {
return this->at(
id); }
445 template<
typename tag>
450 auto it = this->find(
id);
452 if (it == this->end())
454 throw std::out_of_range(
455 "Links<id_type, left_type, right_type, role_type, base_type>::at(const id_type&) : "
456 "no link has this index");
459 return traits::value(*it);
464 template<
typename tag>
466 std::reference_wrapper<const typename LinkTraits<tag>::other_type>,
467 std::less<const typename LinkTraits<tag>::other_type>>
473 std::reference_wrapper<const typename traits::other_type>,
474 std::less<const typename traits::other_type>>
477 auto&
self = this->Parent::template get<tag>();
478 auto range =
self.equal_range(std::make_tuple(value));
479 for (
auto it = range.first; it != range.second; ++it)
488 template<
typename tag>
490 std::reference_wrapper<const typename LinkTraits<tag>::other_type>,
491 std::less<const typename LinkTraits<tag>::other_type>>
497 std::reference_wrapper<const typename traits::other_type>,
498 std::less<const typename traits::other_type>>
501 auto&
self = this->Parent::template get<tag>();
502 auto range =
self.equal_range(std::make_tuple(value, role));
503 for (
auto it = range.first; it != range.second; ++it)
517 const role_type Links<id_type, left_type, right_type, role_type, base_type>::undefinedRole =
518 std::numeric_limits<role_type>::lowest();
526 std::pair<typename Links<id_type, left_type, right_type, role_type, base_type>::iterator,
bool>
528 const base_type& base,
530 const left_type& left,
531 const right_type& right,
532 const role_type& role)
534 return this->insert(Link(base,
id, left, right, role));
543 std::pair<typename Links<id_type, left_type, right_type, role_type, base_type>::iterator,
bool>
547 const left_type& left,
548 const right_type& right,
549 const role_type& role)
551 return this->insert(Link(std::forward<base_type>(base),
id, left, right, role));
556 #endif // smtk_common_Links_h