Blender V4.3
BLI_unique_sorted_indices.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
26#include <optional>
27#include <variant>
28
29#include "BLI_binary_search.hh"
30#include "BLI_vector.hh"
31
33
37template<typename T> inline bool non_empty_is_range(const Span<T> indices)
38{
39 BLI_assert(!indices.is_empty());
40 return indices.last() - indices.first() == indices.size() - 1;
41}
42
46template<typename T> inline IndexRange non_empty_as_range(const Span<T> indices)
47{
48 BLI_assert(!indices.is_empty());
50 return IndexRange(indices.first(), indices.size());
51}
52
56template<typename T> inline std::optional<IndexRange> non_empty_as_range_try(const Span<T> indices)
57{
58 if (non_empty_is_range(indices)) {
59 return non_empty_as_range(indices);
60 }
61 return std::nullopt;
62}
63
71template<typename T> inline int64_t find_size_of_next_range(const Span<T> indices)
72{
73 BLI_assert(!indices.is_empty());
75 [indices, offset = indices[0]](const T &value) {
76 const int64_t index = &value - indices.begin();
77 return value - offset > index;
78 });
79}
80
89template<typename T>
90inline int64_t find_size_until_next_range(const Span<T> indices, const int64_t min_range_size)
91{
92 BLI_assert(!indices.is_empty());
93 int64_t current_range_size = 1;
94 int64_t last_value = indices[0];
95 for (const int64_t i : indices.index_range().drop_front(1)) {
96 const T current_value = indices[i];
97 if (current_value == last_value + 1) {
98 current_range_size++;
99 if (current_range_size >= min_range_size) {
100 return i - min_range_size + 1;
101 }
102 }
103 else {
104 current_range_size = 1;
105 }
106 last_value = current_value;
107 }
108 return indices.size();
109}
110
117template<typename T, int64_t InlineBufferSize>
119 const Span<T> indices,
120 const int64_t range_threshold,
121 Vector<std::variant<IndexRange, Span<T>>, InlineBufferSize> &r_segments)
122{
123 BLI_assert(range_threshold >= 1);
124 const int64_t old_segments_num = r_segments.size();
125 Span<T> remaining_indices = indices;
126 while (!remaining_indices.is_empty()) {
127 if (const std::optional<IndexRange> range = non_empty_as_range_try(remaining_indices)) {
128 /* All remaining indices are range. */
129 r_segments.append(*range);
130 break;
131 }
132 if (non_empty_is_range(remaining_indices.take_front(range_threshold))) {
133 /* Next segment is a range. Now find the place where the range ends. */
134 const int64_t segment_size = find_size_of_next_range(remaining_indices);
135 r_segments.append(IndexRange(remaining_indices[0], segment_size));
136 remaining_indices = remaining_indices.drop_front(segment_size);
137 continue;
138 }
139 /* Next segment is just indices. Now find the place where the next range starts. */
140 const int64_t segment_size = find_size_until_next_range(remaining_indices, range_threshold);
141 const Span<T> segment_indices = remaining_indices.take_front(segment_size);
142 if (const std::optional<IndexRange> range = non_empty_as_range_try(segment_indices)) {
143 r_segments.append(*range);
144 }
145 else {
146 r_segments.append(segment_indices);
147 }
148 remaining_indices = remaining_indices.drop_front(segment_size);
149 }
150 return r_segments.size() - old_segments_num;
151}
152
153} // namespace blender::unique_sorted_indices
#define BLI_assert(a)
Definition BLI_assert.h:50
constexpr Span drop_front(int64_t n) const
Definition BLI_span.hh:172
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr Span take_front(int64_t n) const
Definition BLI_span.hh:194
constexpr bool is_empty() const
Definition BLI_span.hh:261
static ushort indices[]
int64_t find_predicate_begin(Iterator begin, Iterator end, Predicate &&predicate)
int64_t find_size_of_next_range(const Span< T > indices)
std::optional< IndexRange > non_empty_as_range_try(const Span< T > indices)
int64_t find_size_until_next_range(const Span< T > indices, const int64_t min_range_size)
int64_t split_to_ranges_and_spans(const Span< T > indices, const int64_t range_threshold, Vector< std::variant< IndexRange, Span< T > >, InlineBufferSize > &r_segments)
bool non_empty_is_range(const Span< T > indices)
IndexRange non_empty_as_range(const Span< T > indices)
__int64 int64_t
Definition stdint.h:89