libime
segmentgraph.cpp
1 /*
2  * SPDX-FileCopyrightText: 2017-2017 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  */
6 
7 #include "segmentgraph.h"
8 #include <cassert>
9 #include <cstddef>
10 #include <queue>
11 #include <unordered_set>
12 #include <utility>
13 #include <vector>
14 #include <boost/range/combine.hpp>
15 #include <boost/tuple/tuple.hpp>
16 
17 namespace libime {
18 
20  bool operator()(const std::pair<const SegmentGraphNode *,
21  const SegmentGraphNode *> &lhs,
22  const std::pair<const SegmentGraphNode *,
23  const SegmentGraphNode *> &rhs) const {
24  return lhs.first->index() > rhs.first->index();
25  }
26 };
28  bool operator()(const SegmentGraphNode *lhs,
29  const SegmentGraphNode *rhs) const {
30  return lhs->index() > rhs->index();
31  }
32 };
33 
34 bool SegmentGraphBase::bfs(const SegmentGraphNode *from,
35  const SegmentGraphBFSCallback &callback) const {
36  std::priority_queue<const SegmentGraphNode *,
37  std::vector<const SegmentGraphNode *>,
39  q;
40  q.push(from);
41  std::unordered_set<const SegmentGraphNode *> visited;
42  while (!q.empty()) {
43  const auto *node = q.top();
44  q.pop();
45  if (!visited.contains(node)) {
46  visited.insert(node);
47  } else {
48  continue;
49  }
50 
51  if (!callback(*this, node)) {
52  return false;
53  }
54  for (const auto &next : node->nexts()) {
55  q.push(&next);
56  }
57  }
58  return true;
59 }
60 
61 size_t SegmentGraph::check(const SegmentGraph &graph) const {
62  std::priority_queue<
63  std::pair<const SegmentGraphNode *, const SegmentGraphNode *>,
64  std::vector<
65  std::pair<const SegmentGraphNode *, const SegmentGraphNode *>>,
67  q;
68 
69  q.emplace(&start(), &graph.start());
70  while (!q.empty()) {
71  auto [old, now] = q.top();
72  q.pop();
73  do {
74  assert(old->index() == now->index());
75  if (old->nextSize() != now->nextSize()) {
76  return old->index();
77  }
78 
79  const SegmentGraphNode *nold;
80  const SegmentGraphNode *nnow;
81  for (auto t : boost::combine(old->nexts(), now->nexts())) {
82  nold = &boost::get<0>(t);
83  nnow = &boost::get<1>(t);
84  if (nold->index() != nnow->index() ||
85  segment(*old, *nold) != graph.segment(*now, *nnow)) {
86  return old->index();
87  }
88  }
89 
90  for (auto t : boost::combine(old->nexts(), now->nexts())) {
91  nold = &boost::get<0>(t);
92  nnow = &boost::get<1>(t);
93  q.emplace(nold, nnow);
94  }
95  } while (0);
96  }
97 
98  return end().index() + 1;
99 }
100 
101 void SegmentGraph::merge(SegmentGraph &graph,
102  const DiscardCallback &discardCallback) {
103  if (&graph == this) {
104  return;
105  }
106  auto since = check(graph);
107  std::unordered_set<const SegmentGraphNode *> nodeToDiscard;
108  for (size_t i = 0; i < since; i++) {
109  for (auto &node : mutableNodes(i)) {
110  std::vector<SegmentGraphNode *> newNext;
111  for (auto &next : node.mutableNexts()) {
112  SegmentGraphNode *n;
113  if (next.index() >= since) {
114  n = graph.graph_[next.index()].get();
115  } else {
116  n = &next;
117  }
118  newNext.push_back(n);
119  }
120  while (node.nextSize()) {
121  node.removeEdge(node.mutableNexts().front());
122  }
123  for (auto *n : newNext) {
124  node.addEdge(*n);
125  }
126  }
127  graph.graph_[i].reset();
128  }
129 
130  mutableData() = graph.data();
131 
132  // these nodes will be discarded by resize()
133  if (data().size() + 1 < graph_.size()) {
134  for (size_t i = data().size() + 1; i < graph_.size(); i++) {
135  for (const auto &node : nodes(i)) {
136  nodeToDiscard.insert(&node);
137  }
138  }
139  }
140 
141  resize(data().size() + 1);
142  for (size_t i = since; i <= size(); i++) {
143  for (const auto &node : nodes(i)) {
144  nodeToDiscard.insert(&node);
145  }
146  std::swap(graph_[i], graph.graph_[i]);
147  graph.graph_[i].reset();
148  }
149 
150  if (discardCallback) {
151  discardCallback(nodeToDiscard);
152  }
153 }
154 } // namespace libime