• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Aho-Corasick string matching algorithm
 

Aho-Corasick string matching algorithm

on

  • 3,055 views

 

Statistics

Views

Total Views
3,055
Views on SlideShare
3,055
Embed Views
0

Actions

Likes
1
Downloads
114
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Aho-Corasick string matching algorithm Aho-Corasick string matching algorithm Presentation Transcript

    • 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
    • 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
    • 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
    • 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
    • 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)); }
    • 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(); } }
    • 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; }
    • 2 Phase Trie Construction• Phase1 – Construct Search Trie• Phase2 – Create reverse link
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 } }
    • 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
    • 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 } }
    • 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 } }
    • 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 } }
    • 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 C T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; C 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 } }
    • 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 C T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; C 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 } }
    • 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 C T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; C 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 } }
    • 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 C T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; C 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 } }
    • 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 C T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; C 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 } }
    • 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 C T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; C 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 } }
    • 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 C T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; C 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 } }
    • 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 C T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; C 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 } }
    • 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 C T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; C 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 } }
    • 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 C T a = subchild.first; node_t& subnode = subchild.second; queue.push_back(std::ref(subnode)); rw<node_t> v = elem.get().revert_link; C 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 } }
    • 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 C 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 } }
    • 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 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; 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 } }
    • 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 D 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 } }
    • Create reverse link ABCDE ABC CDE BCD BBBC B D C B C R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC B D C B C C R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC B D C B C C R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC B D C B C C R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC B D C B C C R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC B D C B C C R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC B D C B C C R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC B D C B C C R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC B D C B C C R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC D C B C C R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC D C B C R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC C B C E E R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC B C E D D R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC C E D B B R A B C D E ABC ABCDE C D E CDE B C D BCD B B C BBBC
    • 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) { E D 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 BCD 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 } } Copy the out string
    • Create reverse link ABCDE ABC CDE BCD BBBC B D R A B C D E ABC BCD ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC D C C R A B C D E ABC BCD ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC D C C R A B C D E ABC BCD ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC D C C R A B C D E ABC BCD ABCDE C D E CDE B C D BCD B B C BBBC C does not exist
    • Create reverse link ABCDE ABC CDE BCD BBBC D C C R A B C D E ABC BCD ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC D C C R A B C D E ABC BCD ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC D C C R A B C D E ABC BCD ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC D C C R A B C D E ABC BCD ABCDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC E E R A B C D E ABC BCD ABCDE CDE C D E CDE B C D Copy the out string BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC R A B C D E ABC BCD ABCDE CDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC R A B C D E ABC BCD ABCDE CDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC R A B C D E ABC BCD ABCDE CDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC R A B C D E ABC BCD ABCDE CDE C D E CDE B C D BCD B B C BBBC
    • Create reverse link ABCDE ABC CDE BCD BBBC R A B C D E ABC BCD ABCDE CDE C D E CDE B C D BCD B B C BBBC
    • Search Strings• Search strings using constructed trie structure with reverse links.
    • Search string ABCDE ABC Search strings CDE BCD BBBC Target string template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC
    • Search string ABCDE ABC CDE BCD BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); Forward link Z is not detected auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC
    • Search string ABCDE ABC CDE BCD BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); Forward link Z is not detected auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } Current node is root } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC
    • Search string ABCDE ABC CDE BCD BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); The forward link A is detected auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC
    • Search string ABCDE ABC CDE BCD BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); The forward link B is detected auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC
    • Search string ABCDE ABC CDE BCD BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); The forward link B is not detected auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } Trying reverse link else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC
    • Search string ABCDE ABC CDE BCD BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); The forward link B is not detected auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } Trying reverse link else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC Try forward link again
    • Search string ABCDE ABC CDE BCD BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC The forward link B is detected
    • Search string ABCDE ABC CDE BCD BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC The forward link B is not detected
    • Search string ABCDE ABC CDE BCD BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC Trying reverse link
    • Search string ABCDE ABC CDE BCD BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC Try forward link again
    • Search string ABCDE ABC CDE BCD BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC Try forward link again The forward link B is detected
    • Search string ABCDE ABC CDE BCD BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC The forward link C is detected
    • Search string ABCDE ABC CDE BCD BBBC BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC The link has an output The forward link C is detected
    • Search string ABCDE ABC CDE BCD BBBC BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC The forward link D is not detected Trying reverse link
    • Search string ABCDE ABC CDE BCD BCD BBBC BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } The link has an output } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } The forward link D is detected BBBC The forward link D is not detected Trying reverse link
    • Search string ABCDE ABC CDE BCD BCD BBBC BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } The forward link E is not detected } else { B C D current = nit->second; ++it; BCD Trying}reverse link for (auto const& elem : current.get().out) func(elem); B B C } } BBBC
    • Search string ABCDE ABC CDE BCD BCD BBBC BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); The forward link E is detected rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } The forward link E is not detected } else { B C D current = nit->second; ++it; BCD Trying}reverse link for (auto const& elem : current.get().out) func(elem); B B C } } BBBC
    • Search string ABCDE ABC CDE CDE BCD BCD BBBC BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); The forward link E is detected rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } C D E The link has an output else { current = current.get().revert_link.get(); CDE } The forward link E is not detected } else { B C D current = nit->second; ++it; BCD Trying}reverse link for (auto const& elem : current.get().out) func(elem); B B C } } BBBC
    • Search string ABCDE ABC CDE CDE BCD BCD BBBC BBBC ZABBBBCDEZ R A B C D E ABC BCD ABCDE CDE C D E CDE The forward link Z is not detected B C D BCD B B C BBBC
    • Search string ABCDE ABC CDE CDE BCD BCD BBBC BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } The forward link Z is not detected } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC Trying reverse link
    • Search string ABCDE ABC CDE CDE BCD BCD BBBC BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); The forward link Z is not detected rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } The forward link Z is not detected } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC Trying reverse link
    • Search string ABCDE ABC CDE CDE BCD BCD BBBC BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); The forward link Z is not detected rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } Current node is root The forward link Z is not detected } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC Trying reverse link
    • Search string ABCDE ABC CDE CDE BCD BCD BBBC BBBC template <typename TCol, typename Func> ZABBBBCDEZ void find(TCol const& target, Func const& func) const { auto it = boost::begin(target); auto end = boost::end(target); rw<node_t const> current = root_; while (it != end) { auto nit = current.get().children.find(*it); R A B C D E if (nit == current.get().children.end()) { ABC BCD ABCDE if (&current.get() == &root_) { ++it; CDE } else { C D E current = current.get().revert_link.get(); CDE } } else { B C D current = nit->second; ++it; BCD } for (auto const& elem : current.get().out) func(elem); B B C } } BBBC
    • Search string ABCDE ABC CDE CDE BCD BCD BBBC BBBC These three strings are detected ZABBBBCDEZ R A B C D E ABC BCD ABCDE CDE C D E CDE B C D BCD B B C BBBC