1. Aho-Corasick string matching algorithm
an example implementation using C++11
and behavior animation
Takatoshi Kondo
redboltz@gmail.com
http://www.linkedin.com/profile/view?id=38098978
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
5. Source Code
inner 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. Source Code
member 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. Source Code
member 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 (¤t.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. 2 Phase Trie Construction
• Phase1
– Construct Search Trie
• Phase2
– Create reverse link
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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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 }
}