Upcoming SlideShare
×

# Aho-Corasick string matching algorithm

4,866 views
4,760 views

Published on

3 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

Views
Total views
4,866
On SlideShare
0
From Embeds
0
Number of Embeds
10
Actions
Shares
0
114
0
Likes
3
Embeds 0
No embeds

No notes for slide

### Aho-Corasick string matching algorithm

1. 1. Aho-Corasick string matching algorithman example implementation using C++11 and behavior animation Takatoshi Kondo redboltz@gmail.com http://www.linkedin.com/profile/view?id=38098978
2. 2. Aho-Corasick string matching algorithm• When we want to match many fixed candidate strings, Aho-Corasick algorithm is efficient. – http://en.wikipedia.org/wiki/Aho%E2%80%93Cora sick_string_matching_algorithm
3. 3. Source Codeclass trietemplate <typename T, template <class...> class KV = std::map, typename... Extra>class trie {public: // member functions template <typename TCol> void add(TCol const& keyCol) { ... } void create_revert_link() { ... } template <typename TCol> std::vector<TCol> find(TCol const& target) const { ... } template <typename TCol, typename Func> void find(TCol const& target, Func const& func) const { ... }private: // types template <typename U> using rw = std::reference_wrapper<U>; struct node_t { ... }; // Function object that returns collected outputs template <typename TCol> struct gather { ... };private: // member variables node_t root_;}; https://gist.github.com/fcd8d77a1e0ef26ad360
4. 4. Source Codeclass trietemplate <typename T, template <class...> class KV = std::map, typename... Extra>class trie {public: // member functions template <typename TCol> void add(TCol const& keyCol) { ... } void create_revert_link() { ... } template <typename TCol> std::vector<TCol> find(TCol const& target) const { ... } template <typename TCol, typename Func> void find(TCol const& target, Func const& func) const { ... }private: // types template <typename U> using rw = std::reference_wrapper<U>; struct node_t { ... }; // Function object that returns collected outputs template <typename TCol> struct gather { ... };private: // member variables node_t root_;}; https://gist.github.com/fcd8d77a1e0ef26ad360
5. 5. Source Codeinner class trie::node_t struct node_t { using children_col_t = KV<T, node_t, Extra...>; node_t():revert_link(*this), val() {} node_t(T const& val):revert_link(*this), val(val) {} node_t(node_t&&) = default; // Movable node_t(node_t const&) = delete; // Non copyable std::vector<std::vector<T>> out; children_col_t children; rw<node_t> revert_link; T val; };member function trie::add() template <typename TCol> void add(TCol const& keyCol) { static_assert(std::is_convertible<typename TCol::value_type, T>::value ,""); auto begin = boost::begin(keyCol); auto end = boost::end(keyCol); rw<node_t> current = root_; for (auto it = begin; it != end; ++it) { auto match = current.get().children.find(*it); if (match == current.get().children.end()) { auto ret = current.get().children.insert(std::make_pair(*it, node_t(*it))); current = ret.first->second; // Added node } else { current = match->second; } } current.get().out.push_back(std::vector<T>(begin, end)); }
6. 6. Source Codemember function trie::create_revert_link() void create_revert_link() { std::deque<rw<node_t>> queue; for (auto& child : root_.children) { node_t& node = child.second; queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); break; } v = v.get().revert_link; } else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); } break; } } } queue.pop_front(); } }
7. 7. Source Codemember function trie::find() - callback interface template <typename TCol, typename Func> void find(TCol const& target, Func const& func) const { static_assert(std::is_convertible<typename TCol::value_type, T>::value ,""); auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; functor gather while (it != end) { // Function object that returns collected outputs auto nit = current.get().children.find(*it); template <typename TCol> if (nit == current.get().children.end()) { struct gather { if (&current.get() == &root_) { gather(std::vector<TCol>& col):col(col) {} ++it; template <typename U> } void operator()(U const& u) const { else { col.push_back(TCol(boost::begin(u), boost::end(u))); current = current.get().revert_link.get(); } } private: } std::vector<TCol>& col; else { }; current = nit->second; ++it; } for (auto const& elem : current.get().out) member function trie::find() - return vector func(elem); template <typename TCol> } std::vector<TCol> find(TCol const& target) const { } std::vector<TCol> ret; find(target, gather<TCol>(ret)); return ret; }
8. 8. 2 Phase Trie Construction• Phase1 – Construct Search Trie• Phase2 – Create reverse link
9. 9. template <typename TCol>Constructing search trie void add(TCol const& keyCol) { static_assert(std::is_convertible<typename TCol::value_type, T>::value ,""); ABCDE auto begin = boost::begin(keyCol); ABC auto end = boost::end(keyCol); rw<node_t> current = root_; CDE for (auto it = begin; it != end; ++it) { auto match = current.get().children.find(*it); Search strings BCD if (match == current.get().children.end()) { BBBC auto ret = current.get().children.insert(std::make_pair(*it, node_t(*it))); current = ret.first->second; // Added node } else { current = match->second; } } current.get().out.push_back(std::vector<T>(begin, end)); Root } R
10. 10. template <typename TCol>Constructing search trie void add(TCol const& keyCol) { static_assert(std::is_convertible<typename TCol::value_type, T>::value ,""); ABCDE auto begin = boost::begin(keyCol); ABC auto end = boost::end(keyCol); rw<node_t> current = root_; CDE for (auto it = begin; it != end; ++it) { auto match = current.get().children.find(*it); BCD if (match == current.get().children.end()) { BBBC auto ret = current.get().children.insert(std::make_pair(*it, node_t(*it))); current = ret.first->second; // Added node } else { current = match->second; } } current.get().out.push_back(std::vector<T>(begin, end)); } R A B C D E
11. 11. template <typename TCol>Constructing search trie void add(TCol const& keyCol) { static_assert(std::is_convertible<typename TCol::value_type, T>::value ,""); ABCDE auto begin = boost::begin(keyCol); ABC auto end = boost::end(keyCol); rw<node_t> current = root_; CDE for (auto it = begin; it != end; ++it) { auto match = current.get().children.find(*it); BCD if (match == current.get().children.end()) { BBBC auto ret = current.get().children.insert(std::make_pair(*it, node_t(*it))); current = ret.first->second; // Added node } else { current = match->second; } } current.get().out.push_back(std::vector<T>(begin, end)); } R A B C D E ABCDE
12. 12. template <typename TCol>Constructing search trie void add(TCol const& keyCol) { static_assert(std::is_convertible<typename TCol::value_type, T>::value ,""); ABCDE auto begin = boost::begin(keyCol); ABC auto end = boost::end(keyCol); rw<node_t> current = root_; CDE for (auto it = begin; it != end; ++it) { auto match = current.get().children.find(*it); BCD if (match == current.get().children.end()) { BBBC auto ret = current.get().children.insert(std::make_pair(*it, node_t(*it))); current = ret.first->second; // Added node } else { current = match->second; } } current.get().out.push_back(std::vector<T>(begin, end)); } R A B C D E ABCDE
13. 13. template <typename TCol>Constructing search trie void add(TCol const& keyCol) { static_assert(std::is_convertible<typename TCol::value_type, T>::value ,""); ABCDE auto begin = boost::begin(keyCol); ABC auto end = boost::end(keyCol); rw<node_t> current = root_; CDE for (auto it = begin; it != end; ++it) { auto match = current.get().children.find(*it); BCD if (match == current.get().children.end()) { BBBC auto ret = current.get().children.insert(std::make_pair(*it, node_t(*it))); current = ret.first->second; // Added node } else { current = match->second; } } current.get().out.push_back(std::vector<T>(begin, end)); } R A B C D E ABC ABCDE
14. 14. template <typename TCol>Constructing search trie void add(TCol const& keyCol) { static_assert(std::is_convertible<typename TCol::value_type, T>::value ,""); ABCDE auto begin = boost::begin(keyCol); ABC auto end = boost::end(keyCol); rw<node_t> current = root_; CDE for (auto it = begin; it != end; ++it) { auto match = current.get().children.find(*it); BCD if (match == current.get().children.end()) { BBBC auto ret = current.get().children.insert(std::make_pair(*it, node_t(*it))); current = ret.first->second; // Added node } else { current = match->second; } } current.get().out.push_back(std::vector<T>(begin, end)); } R A B C D E ABC ABCDE C D E CDE
15. 15. template <typename TCol>Constructing search trie void add(TCol const& keyCol) { static_assert(std::is_convertible<typename TCol::value_type, T>::value ,""); ABCDE auto begin = boost::begin(keyCol); ABC auto end = boost::end(keyCol); rw<node_t> current = root_; CDE for (auto it = begin; it != end; ++it) { auto match = current.get().children.find(*it); BCD if (match == current.get().children.end()) { BBBC auto ret = current.get().children.insert(std::make_pair(*it, node_t(*it))); current = ret.first->second; // Added node } else { current = match->second; } } current.get().out.push_back(std::vector<T>(begin, end)); } R A B C D E ABC ABCDE C D E CDE B C D BCD
16. 16. template <typename TCol>Constructing search trie void add(TCol const& keyCol) { static_assert(std::is_convertible<typename TCol::value_type, T>::value ,""); ABCDE auto begin = boost::begin(keyCol); ABC auto end = boost::end(keyCol); rw<node_t> current = root_; CDE for (auto it = begin; it != end; ++it) { auto match = current.get().children.find(*it); BCD if (match == current.get().children.end()) { BBBC auto ret = current.get().children.insert(std::make_pair(*it, node_t(*it))); current = ret.first->second; // Added node } else { current = match->second; } } current.get().out.push_back(std::vector<T>(begin, end)); } R A B C D E ABC ABCDE C D E CDE B C D BCD
17. 17. template <typename TCol>Constructing search trie void add(TCol const& keyCol) { static_assert(std::is_convertible<typename TCol::value_type, T>::value ,""); ABCDE auto begin = boost::begin(keyCol); ABC auto end = boost::end(keyCol); rw<node_t> current = root_; CDE for (auto it = begin; it != end; ++it) { auto match = current.get().children.find(*it); BCD if (match == current.get().children.end()) { BBBC auto ret = current.get().children.insert(std::make_pair(*it, node_t(*it))); current = ret.first->second; // Added node } else { current = match->second; } } current.get().out.push_back(std::vector<T>(begin, end)); } R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
18. 18. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
19. 19. Create reverse link Breadth first seach ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
20. 20. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { A C B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
21. 21. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { A C B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
22. 22. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { A C B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
23. 23. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { A C B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
24. 24. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { A C B B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; B while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
25. 25. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { A C B B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; B while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
26. 26. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { A C B B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; B while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
27. 27. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { A C B B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; B while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
28. 28. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { A C B B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; B while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
29. 29. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { A C B B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; B while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
30. 30. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { A C B B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; B while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
31. 31. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { A C B B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; B while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
32. 32. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { A C B B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; B while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
33. 33. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { C B B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; B while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
34. 34. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { C B B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
35. 35. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { C B B T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
36. 36. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { C B B D T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; D while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
37. 37. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { C B B D T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; D while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
38. 38. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { C B B D T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; D while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
39. 39. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { C B B D T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; D while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
40. 40. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { C B B D T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; D while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
41. 41. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { C B B D T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; D while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } } D does not exist
42. 42. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { B B D T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; D while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
43. 43. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { B B D T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }
44. 44. Create reverse link ABCDE void create_revert_link() { ABC std::deque<rw<node_t>> queue; for (auto& child : root_.children) { CDE node_t& node = child.second; BCD queue.push_back(std::ref(node)); node.revert_link = std::ref(root_); BBBC } while (!queue.empty()) { rw<node_t> elem = queue.front(); for (auto& subchild : elem.get().children) { B B D T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; while (true) { auto const& it = v.get().children.find(a); if (it == v.get().children.end()) { R A B C D E if (&v.get() == &root_) { subnode.revert_link = std::ref(root_); ABC ABCDE break; } v = v.get().revert_link; C D E } CDE else { subnode.revert_link = std::ref(it->second); for (auto const& o : subnode.revert_link.get().out) { subnode.out.push_back(o); B C D } BCD break; } } } B B C queue.pop_front(); BBBC } }