ctrl-utils
tree.h
1 
10 #ifndef CTRL_UTILS_TREE_H_
11 #define CTRL_UTILS_TREE_H_
12 
13 #include <algorithm> // std::find
14 #include <exception> // std::invalid_argument
15 #include <functional> // std::function
16 #include <limits> // std::numeric_limits
17 #include <ostream> // std::ostream
18 #include <queue> // std::queue
19 #include <type_traits> // std::conditional_t
20 #include <unordered_map> // std::unordered_map
21 #include <utility> // std::pair
22 #include <vector> // std::vector
23 
24 #if __cplusplus >= 201703L
25 #include <optional> // std::optional
26 #else // __cplusplus
27 // #include <ctrl_utils/optional.h>
28 #include "optional.h"
29 #endif // __cplusplus
30 
31 namespace ctrl_utils {
32 
47 template <typename Key, typename T>
48 class Tree {
49  protected:
50  template <bool Const>
51  class ChainView;
52 
53  template <bool Const>
54  class DescendantView;
55 
56  template <bool Const>
57  class ChildView;
58 
59  template <bool Const>
60  class RootView;
61 
62  template <bool Const>
63  class Iterator;
64 
65  public:
73  using root_view = RootView<false>;
74 
75  enum class SearchType { kDepthFirstSearch, kBreadthFirstSearch };
76 
80  bool empty() const { return nodes().empty(); }
81 
85  size_t size() const { return nodes().size(); }
86 
90  const std::unordered_map<Key, T>& nodes() const { return nodes_; }
91  const std::unordered_map<Key, T>& values() const { return nodes_; }
92 
98  const_root_view roots() const { return const_root_view(this); }
99  root_view roots() { return root_view(this); }
100 
106  const T& at(const Key& id) const { return nodes_.at(id); }
107  T& at(const Key& id) { return nodes_.at(id); }
108 
129  chain_view ancestors(const Key& id) { return chain_view(this, id); }
130 
137  const_chain_view ancestors(const Key& id) const {
138  return const_chain_view(this, id);
139  }
140 
167  const Key& id, SearchType search_type = SearchType::kBreadthFirstSearch,
168  size_t max_depth = std::numeric_limits<size_t>::max()) {
169  return descendant_view(this, id, search_type, max_depth);
170  }
171 
179  const Key& id, SearchType search_type = SearchType::kBreadthFirstSearch,
180  size_t max_depth = std::numeric_limits<size_t>::max()) const {
181  return const_descendant_view(this, id, search_type, max_depth);
182  }
183 
192  descendant_view nodes(SearchType search_type,
193  size_t max_depth = std::numeric_limits<size_t>::max()) {
194  return descendant_view(this, search_type, max_depth);
195  }
196 
207  SearchType search_type,
208  size_t max_depth = std::numeric_limits<size_t>::max()) const {
209  return const_descendant_view(this, search_type, max_depth);
210  }
211 
217  bool contains(const Key& id) const {
218  return nodes().find(id) != nodes().end();
219  }
220 
227  size_t depth(const Key& id) const {
228  const std::optional<Key>& id_parent = parent(id);
229  return id_parent ? depth(*id_parent) + 1 : 0;
230  }
231 
237  void insert(const Key& id, const T& value) {
238  if (contains(id)) {
239  throw std::invalid_argument("Tree::insert_child(): Key already exists.");
240  }
241  nodes_[id] = value;
242  parents_[id].reset();
243  children_[id].clear();
244  }
245 
251  void insert(const Key& id, T&& value) {
252  if (contains(id)) {
253  throw std::invalid_argument("Tree::insert_child(): Key already exists.");
254  }
255  nodes_[id] = std::move(value);
256  parents_[id].reset();
257  children_[id].clear();
258  }
259 
267  void insert_child(const Key& id_parent, const Key& id, const T& value) {
268  if (contains(id)) {
269  throw std::invalid_argument("Tree::insert_child(): Key already exists.");
270  }
271  nodes_[id] = value;
272  parents_[id] = id_parent;
273  children_[id].clear();
274  children_.at(id_parent).push_back(id);
275  }
276 
282  void insert_child(const Key& id_parent, const Key& id, T&& value) {
283  if (contains(id)) {
284  throw std::invalid_argument("Tree::insert_child(): Key already exists.");
285  }
286  nodes_[id] = std::move(value);
287  parents_[id] = id_parent;
288  children_[id].clear();
289  children_.at(id_parent).push_back(id);
290  }
291 
298  const std::optional<Key>& parent(const Key& id) const {
299  return parents_.at(id);
300  }
301 
323  child_view children(const Key& id) { return child_view(this, id); }
324 
325  const_child_view children(const Key& id) const {
326  return const_child_view(this, id);
327  }
328 
334  void clear_parent(const Key& id) {
335  // Remove current node from parent's children.
336  const std::optional<Key>& id_parent_old = parents_.at(id);
337  if (id_parent_old) {
338  std::vector<Key>& siblings = children_.at(*id_parent_old);
339  auto it = std::find(siblings.begin(), siblings.end(), id);
340  if (it != siblings.end()) {
341  siblings.erase(it);
342  }
343  }
344 
345  // Reset parent of current node.
346  parents_.at(id).reset();
347  }
348 
354  void clear_children(const Key& id) {
355  // Reset parents of children
356  for (const Key& id_child : children_.at(id)) {
357  parents_.at(id_child).reset();
358  }
359 
360  // Reset children of current node
361  children_.at(id).clear();
362  }
363 
369  void set_parent(const Key& id, const Key& id_parent) {
370  // Clear previous parent
371  clear_parent(id);
372 
373  // Add new parent
374  parents_.at(id) = id_parent;
375  children_.at(id_parent).push_back(id);
376  }
377 
383  void add_child(const Key& id, const Key& id_child) {
384  return set_parent(id_child, id);
385  }
386 
394  bool is_ancestor(const Key& id_ancestor, const Key& id) const {
395  for (const auto& key_val : ancestors(id)) {
396  if (key_val.first == id_ancestor) return true;
397  }
398  return false;
399  }
400 
408  bool is_descendant(const Key& id_descendant, const Key& id) const {
409  return is_ancestor(id, id_descendant);
410  }
411 
418  void printf(std::ostream& os,
419  const std::function<std::string(const Key& key, const T& val)>&
420  StringifyValue) const {
421  for (const auto& key_val : nodes(SearchType::kDepthFirstSearch)) {
422  const Key& key = key_val.first;
423  for (size_t i = 0; i < depth(key); i++) {
424  os << " ";
425  }
426  os << "- " << key << ": " << StringifyValue(key, key_val.second) << std::endl;
427  }
428  os << std::endl;
429  }
430 
434  friend std::ostream& operator<<(std::ostream& os, const Tree<Key, T>& tree) {
435  for (const auto& key_val : tree.nodes(SearchType::kDepthFirstSearch)) {
436  const Key& key = key_val.first;
437  for (size_t i = 0; i < tree.depth(key); i++) {
438  os << " ";
439  }
440  os << key << ": " << key_val.second << std::endl;
441  }
442  os << std::endl;
443  return os;
444  }
445 
446  protected:
450  std::unordered_map<Key, T> nodes_;
451 
455  std::unordered_map<Key, std::optional<Key>> parents_;
456 
460  std::unordered_map<Key, std::vector<Key>> children_;
461 };
462 
463 template <typename Key, typename T>
464 template <bool Const>
465 class Tree<Key, T>::ChainView {
466  public:
467  using TreeT = std::conditional_t<Const, const Tree<Key, T>, Tree<Key, T>>;
468 
469  class iterator;
470 
471  ChainView(TreeT* tree, const Key& id) : tree_(tree), id_(id) {}
472 
473  iterator begin() const { return iterator(tree_, id_); }
474  iterator end() const { return iterator(tree_, std::optional<Key>()); }
475 
476  protected:
477  TreeT* tree_;
478  std::optional<Key> id_;
479 };
480 
481 template <typename Key, typename T>
482 template <bool Const>
483 class Tree<Key, T>::ChainView<Const>::iterator {
484  public:
485  using TreeT = std::conditional_t<Const, const Tree<Key, T>, Tree<Key, T>>;
486  using ValueT = std::conditional_t<Const, const std::pair<const Key, T>,
487  std::pair<const Key, T>>;
488 
489  // Iterator traits
490  using iterator_category = std::forward_iterator_tag;
491  using value_type = ValueT;
492  using difference_type = ptrdiff_t;
493  using pointer = value_type*;
494  using reference = value_type&;
495 
496  // Constructor
497  iterator(TreeT* tree, const std::optional<Key>& id) : tree_(tree), id_(id) {}
498 
499  // Forward iterator
500  iterator& operator++() {
501  id_ = tree_->parents_.at(*id_);
502  return *this;
503  }
504 
505  iterator operator++(int) {
506  iterator it(*this);
507  operator++();
508  return it;
509  }
510 
511  reference operator*() const { return *tree_->nodes_.find(*id_); }
512 
513  pointer operator->() const { return tree_->nodes_.find(*id_).operator->(); }
514 
515  bool operator==(const iterator& other) const {
516  return tree_ == other.tree_ && id_ == other.id_;
517  }
518 
519  bool operator!=(const iterator& other) const { return !(*this == other); }
520 
521  protected:
522  TreeT* tree_;
523  std::optional<Key> id_;
524 };
525 
526 template <typename Key, typename T>
527 template <bool Const>
528 class Tree<Key, T>::Iterator {
529  public:
530  using TreeT = std::conditional_t<Const, const Tree<Key, T>, Tree<Key, T>>;
531  using ValueT = std::conditional_t<Const, const std::pair<const Key, T>,
532  std::pair<const Key, T>>;
533 
534  // Iterator traits
535  using iterator_category = std::random_access_iterator_tag;
536  using value_type = ValueT;
537  using difference_type = ptrdiff_t;
538  using pointer = value_type*;
539  using reference = value_type&;
540 
541  // Constructor
542  Iterator(TreeT* tree, const std::vector<Key>* ids, size_t idx_id)
543  : tree_(tree), ids_(ids), idx_id_(idx_id) {}
544 
545  // Forward iterator
546  Iterator& operator++() { return operator+=(1); }
547 
548  Iterator operator++(int) {
549  Iterator it(*this);
550  operator++();
551  return it;
552  }
553 
554  reference operator*() const { return *tree_->nodes_.find((*ids_)[idx_id_]); }
555 
556  pointer operator->() const {
557  return tree_->nodes_.find((*ids_)[idx_id_]).operator->();
558  }
559 
560  bool operator==(const Iterator& rhs) const {
561  return tree_ == rhs.tree_ && ids_ == rhs.ids_ && idx_id_ == rhs.idx_id_;
562  }
563 
564  bool operator!=(const Iterator& rhs) const { return !(*this == rhs); }
565 
566  // Bidirectional iterator
567  Iterator& operator--() { return operator+=(-1); }
568 
569  Iterator operator--(int) {
570  Iterator it(*this);
571  operator--();
572  return it;
573  }
574 
575  // Random access iterator
576  Iterator& operator+=(difference_type n) {
577  idx_id_ += n;
578  return *this;
579  }
580 
581  Iterator operator+(difference_type n) const {
582  Iterator it(*this);
583  return it += n;
584  }
585 
586  Iterator& operator-=(difference_type n) { return operator+=(-n); }
587 
588  Iterator operator-(difference_type n) const { return operator+(-n); }
589 
590  difference_type operator-(const Iterator& rhs) const {
591  return idx_id_ - rhs.idx_id_;
592  }
593 
594  value_type operator[](difference_type n) const { return *(operator+(n)); }
595 
596  bool operator<(const Iterator& rhs) const {
597  return tree_ == rhs.tree_ && ids_ == rhs.ids_ && idx_id_ < rhs.idx_id_;
598  }
599 
600  bool operator<=(const Iterator& rhs) const {
601  return tree_ == rhs.tree_ && ids_ == rhs.ids_ && idx_id_ <= rhs.idx_id_;
602  }
603 
604  bool operator>(const Iterator& rhs) const { return rhs < *this; }
605 
606  bool operator>=(const Iterator& rhs) const { return rhs <= *this; }
607 
608  protected:
609  TreeT* tree_ = nullptr;
610  const std::vector<Key>* ids_ = nullptr;
611  size_t idx_id_ = 0;
612 };
613 
614 template <typename Key, typename T>
615 template <bool Const>
616 class Tree<Key, T>::DescendantView {
617  public:
618  using TreeT = std::conditional_t<Const, const Tree<Key, T>, Tree<Key, T>>;
619 
620  using iterator = Tree<Key, T>::Iterator<Const>;
621 
622  DescendantView(TreeT* tree, const Key& id, SearchType search_type,
623  size_t max_depth)
624  : tree_(tree) {
625  void (DescendantView::*AddDescendants)(const Key&, size_t) =
626  search_type == SearchType::kBreadthFirstSearch
627  ? &DescendantView::AddDescendantsBfs
628  : &DescendantView::AddDescendantsDfs;
629 
630  ids_.reserve(tree_->size());
631  (this->*AddDescendants)(id, max_depth);
632  }
633 
634  DescendantView(TreeT* tree, SearchType search_type, size_t max_depth)
635  : tree_(tree) {
636  void (DescendantView::*AddDescendants)(const Key&, size_t) =
637  search_type == SearchType::kBreadthFirstSearch
638  ? &DescendantView::AddDescendantsBfs
639  : &DescendantView::AddDescendantsDfs;
640 
641  ids_.reserve(tree_->size());
642  for (const auto& key_val : tree->roots()) {
643  (this->*AddDescendants)(key_val.first, max_depth);
644  }
645  }
646 
647  iterator begin() const { return iterator(tree_, &ids_, 0); }
648  iterator end() const { return iterator(tree_, &ids_, ids_.size()); }
649 
650  protected:
651  void AddDescendantsDfs(const Key& id, size_t max_depth) {
652  AddDescendantsDfsDepth(id, max_depth, 0);
653  }
654 
655  void AddDescendantsDfsDepth(const Key& id, size_t max_depth, size_t depth) {
656  ids_.push_back(id);
657  if (depth >= max_depth) return;
658  for (const Key& id_child : tree_->children_.at(id)) {
659  AddDescendantsDfsDepth(id_child, max_depth, depth + 1);
660  }
661  }
662 
663  void AddDescendantsBfs(const Key& id, size_t max_depth) {
664  std::queue<std::pair<size_t, Key>> bfs;
665  bfs.emplace(0, id);
666  while (!bfs.empty()) {
667  const size_t depth = bfs.front().first;
668  const Key& id_current = bfs.front().second;
669  ids_.push_back(id_current);
670  bfs.pop();
671  if (depth >= max_depth) continue;
672  for (const Key& id_child : tree_->children_.at(id_current)) {
673  bfs.emplace(depth + 1, id_child);
674  }
675  }
676  }
677 
678  TreeT* tree_;
679  std::vector<Key> ids_;
680 };
681 
682 template <typename Key, typename T>
683 template <bool Const>
684 class Tree<Key, T>::ChildView {
685  public:
686  using TreeT = std::conditional_t<Const, const Tree<Key, T>, Tree<Key, T>>;
687 
688  using iterator = Tree<Key, T>::Iterator<Const>;
689 
690  ChildView(TreeT* tree, const Key& id)
691  : tree_(tree), ids_(&tree->children_.at(id)) {}
692 
693  iterator begin() const { return iterator(tree_, ids_, 0); }
694  iterator end() const { return iterator(tree_, ids_, ids_->size()); }
695 
696  protected:
697  TreeT* tree_;
698  const std::vector<Key>* ids_;
699 };
700 
701 template <typename Key, typename T>
702 template <bool Const>
703 class Tree<Key, T>::RootView {
704  public:
705  using TreeT = std::conditional_t<Const, const Tree<Key, T>, Tree<Key, T>>;
706 
707  using iterator = Tree<Key, T>::Iterator<Const>;
708 
709  explicit RootView(TreeT* tree) : tree_(tree), ids_(FindRoots(tree)) {}
710 
711  iterator begin() const { return iterator(tree_, &ids_, 0); }
712  iterator end() const { return iterator(tree_, &ids_, ids_.size()); }
713 
714  protected:
715  std::vector<Key> FindRoots(TreeT* tree) {
716  std::vector<Key> roots;
717  for (const auto& key_val : tree->nodes()) {
718  const Key& key = key_val.first;
719  if (!tree->parent(key)) roots.push_back(key);
720  }
721  return roots;
722  }
723 
724  TreeT* tree_;
725  std::vector<Key> ids_;
726 };
727 
728 } // namespace ctrl_utils
729 
730 #endif // CTRL_UTILS_TREE_H_
Definition: tree.h:465
Definition: tree.h:684
Definition: tree.h:616
Definition: tree.h:528
Definition: tree.h:703
Definition: tree.h:48
chain_view ancestors(const Key &id)
Definition: tree.h:129
void insert(const Key &id, const T &value)
Definition: tree.h:237
const T & at(const Key &id) const
Definition: tree.h:106
std::unordered_map< Key, std::optional< Key > > parents_
Definition: tree.h:455
const_descendant_view descendants(const Key &id, SearchType search_type=SearchType::kBreadthFirstSearch, size_t max_depth=std::numeric_limits< size_t >::max()) const
Definition: tree.h:178
void clear_children(const Key &id)
Definition: tree.h:354
size_t depth(const Key &id) const
Definition: tree.h:227
void printf(std::ostream &os, const std::function< std::string(const Key &key, const T &val)> &StringifyValue) const
Definition: tree.h:418
child_view children(const Key &id)
Definition: tree.h:323
void set_parent(const Key &id, const Key &id_parent)
Definition: tree.h:369
void insert(const Key &id, T &&value)
Definition: tree.h:251
void insert_child(const Key &id_parent, const Key &id, const T &value)
Definition: tree.h:267
bool contains(const Key &id) const
Definition: tree.h:217
descendant_view nodes(SearchType search_type, size_t max_depth=std::numeric_limits< size_t >::max())
Definition: tree.h:192
const std::optional< Key > & parent(const Key &id) const
Definition: tree.h:298
descendant_view descendants(const Key &id, SearchType search_type=SearchType::kBreadthFirstSearch, size_t max_depth=std::numeric_limits< size_t >::max())
Definition: tree.h:166
bool is_ancestor(const Key &id_ancestor, const Key &id) const
Definition: tree.h:394
bool empty() const
Definition: tree.h:80
std::unordered_map< Key, std::vector< Key > > children_
Definition: tree.h:460
size_t size() const
Definition: tree.h:85
const std::unordered_map< Key, T > & nodes() const
Definition: tree.h:90
void insert_child(const Key &id_parent, const Key &id, T &&value)
Definition: tree.h:282
std::unordered_map< Key, T > nodes_
Definition: tree.h:450
const_descendant_view nodes(SearchType search_type, size_t max_depth=std::numeric_limits< size_t >::max()) const
Definition: tree.h:206
void clear_parent(const Key &id)
Definition: tree.h:334
friend std::ostream & operator<<(std::ostream &os, const Tree< Key, T > &tree)
Definition: tree.h:434
void add_child(const Key &id, const Key &id_child)
Definition: tree.h:383
const_root_view roots() const
Definition: tree.h:98
const_chain_view ancestors(const Key &id) const
Definition: tree.h:137
bool is_descendant(const Key &id_descendant, const Key &id) const
Definition: tree.h:408
Definition: ctrl_utils.cc:18