1#ifndef NCLIST_NEAREST_HPP
2#define NCLIST_NEAREST_HPP
26template<
typename Index_>
33 State(Index_ cat, Index_ cend,
bool skip) : child_at(cat), child_end(cend), skip_search(skip) {}
34 Index_ child_at = 0, child_end = 0;
35 bool skip_search =
false;
37 std::vector<State> history;
47template<
typename Position_>
66template<
typename Index_,
typename Position_>
69 const Index_ root_index,
70 const Position_ end_position,
71 const bool quit_on_first,
72 std::vector<Index_>& matches)
74 Index_ current_subject = root_index;
76 const auto& current_node = subject.nodes[current_subject];
77 matches.push_back(current_node.id);
81 if (current_node.duplicates_start != current_node.duplicates_end) {
82 matches.insert(matches.end(), subject.duplicates.begin() + current_node.duplicates_start, subject.duplicates.begin() + current_node.duplicates_end);
84 if (current_node.children_start == current_node.children_end) {
87 current_subject = current_node.children_end - 1;
88 if (subject.ends[current_subject] != end_position) {
94template<
typename Index_,
typename Position_>
96 const Nclist<Index_, Position_>& subject,
97 const Index_ root_index,
98 const Position_ start_position,
99 const bool quit_on_first,
100 std::vector<Index_>& matches)
102 Index_ current_subject = root_index;
104 const auto& current_node = subject.nodes[current_subject];
105 matches.push_back(current_node.id);
109 if (current_node.duplicates_start != current_node.duplicates_end) {
110 matches.insert(matches.end(), subject.duplicates.begin() + current_node.duplicates_start, subject.duplicates.begin() + current_node.duplicates_end);
112 if (current_node.children_start == current_node.children_end) {
115 current_subject = current_node.children_start;
116 if (subject.starts[current_subject] != start_position) {
122template<
typename Index_,
typename Position_>
123Index_ nearest_overlaps(
124 const Nclist<Index_, Position_>& subject,
125 const Position_ query_start,
126 const Position_ query_end,
127 const bool quit_on_first,
128 const bool adjacent_equals_overlap,
129 NearestWorkspace<Index_>& workspace,
130 std::vector<Index_>& matches)
166 const auto find_first_child = [&](
const Index_ children_start,
const Index_ children_end) -> Index_ {
167 const auto ebegin = subject.ends.begin();
168 const auto estart = ebegin + children_start;
169 const auto eend = ebegin + children_end;
170 return std::upper_bound(estart, eend, query_start) - ebegin;
173 const auto can_skip_search = [&](
const Position_ subject_start) ->
bool {
174 return subject_start > query_start;
177 const auto is_finished = [&](
const Position_ subject_start) ->
bool {
178 return subject_start >= query_end;
181 Index_ root_child_at = 0;
182 const bool root_skip_search = can_skip_search(subject.starts[0]);
183 if (!root_skip_search) {
184 root_child_at = find_first_child(0, subject.root_children);
185 if (adjacent_equals_overlap && root_child_at) {
186 const Index_ previous_child = root_child_at - 1;
187 if (query_start == subject.ends[previous_child]) {
188 nearest_before(subject, previous_child, query_start, quit_on_first, matches);
189 if (quit_on_first && !matches.empty()) {
190 return root_child_at;
196 workspace.history.clear();
198 Index_ current_subject;
201 if (workspace.history.empty()) {
202 if (root_child_at == subject.root_children) {
205 const Position_ next_start = subject.starts[root_child_at];
206 if (is_finished(next_start)) {
207 if (adjacent_equals_overlap && next_start == query_end) {
208 nearest_after(subject, root_child_at, query_end, quit_on_first, matches);
214 current_subject = root_child_at;
215 skip_search = root_skip_search;
219 auto& current_state = workspace.history.back();
220 if (current_state.child_at == current_state.child_end) {
221 workspace.history.pop_back();
224 const Position_ next_start = subject.starts[current_state.child_at];
225 if (is_finished(next_start)) {
226 if (adjacent_equals_overlap && next_start == query_end) {
227 nearest_after(subject, current_state.child_at, query_end,
false, matches);
231 workspace.history.pop_back();
235 current_subject = current_state.child_at;
236 skip_search = current_state.skip_search;
237 ++(current_state.child_at);
240 const auto& current_node = subject.nodes[current_subject];
242 matches.push_back(current_node.id);
246 if (current_node.duplicates_start != current_node.duplicates_end) {
247 matches.insert(matches.end(), subject.duplicates.begin() + current_node.duplicates_start, subject.duplicates.begin() + current_node.duplicates_end);
250 if (current_node.children_start != current_node.children_end) {
252 workspace.history.emplace_back(current_node.children_start, current_node.children_end,
true);
254 const Index_ start_pos = find_first_child(current_node.children_start, current_node.children_end);
255 if (adjacent_equals_overlap && start_pos > current_node.children_start) {
256 const Index_ previous_child = start_pos - 1;
257 if (query_start == subject.ends[previous_child]) {
258 nearest_before(subject, previous_child, query_start,
false, matches);
263 if (start_pos != current_node.children_end) {
264 workspace.history.emplace_back(start_pos, current_node.children_end, can_skip_search(subject.starts[start_pos]));
270 return root_child_at;
298template<
typename Index_,
typename Position_>
301 const Position_ query_start,
302 const Position_ query_end,
305 std::vector<Index_>& matches)
308 if (subject.root_children == 0) {
312 const auto root_index = nearest_overlaps(
321 if (!matches.empty()) {
354 std::optional<Position_> to_previous, to_next;
356 to_previous = query_start - subject.ends[root_index - 1];
358 if (root_index < subject.root_children) {
359 to_next = subject.starts[root_index] - query_end;
362 if (to_previous.has_value() && (!to_next.has_value() || *to_previous <= *to_next)) {
363 const Index_ previous_child = root_index - 1;
364 nearest_before(subject, previous_child, subject.ends[previous_child], params.
quit_on_first, matches);
369 if (to_next.has_value() && (!to_previous.has_value() || *to_next <= *to_previous)) {
370 nearest_after(subject, root_index, subject.starts[root_index], params.
quit_on_first, matches);
Build a nested containment list.
Header-only library for nested containment lists.
Definition build.hpp:17
void nearest(const Nclist< Index_, Position_ > &subject, const Position_ query_start, const Position_ query_end, const NearestParameters< Position_ > ¶ms, NearestWorkspace< Index_ > &workspace, std::vector< Index_ > &matches)
Definition nearest.hpp:299
Pre-built nested containment list.
Definition build.hpp:28
Parameters for nearest().
Definition nearest.hpp:48
bool adjacent_equals_overlap
Definition nearest.hpp:60
bool quit_on_first
Definition nearest.hpp:53
Workspace for nearest().
Definition nearest.hpp:27