Blender V5.0
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
25
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{
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());
74 return binary_search::first_if(indices, [indices, offset = indices[0]](const T &value) {
75 const int64_t index = &value - indices.begin();
76 return value - offset > index;
77 });
78}
79
88template<typename T>
89inline int64_t find_size_until_next_range(const Span<T> indices, const int64_t min_range_size)
90{
91 BLI_assert(!indices.is_empty());
92 int64_t current_range_size = 1;
93 int64_t last_value = indices[0];
94 for (const int64_t i : indices.index_range().drop_front(1)) {
95 const T current_value = indices[i];
96 if (current_value == last_value + 1) {
97 current_range_size++;
98 if (current_range_size >= min_range_size) {
99 return i - min_range_size + 1;
100 }
101 }
102 else {
103 current_range_size = 1;
104 }
105 last_value = current_value;
106 }
107 return indices.size();
108}
109
116template<typename T, int64_t InlineBufferSize>
118 const Span<T> indices,
119 const int64_t range_threshold,
120 Vector<std::variant<IndexRange, Span<T>>, InlineBufferSize> &r_segments)
121{
122 BLI_assert(range_threshold >= 1);
123 const int64_t old_segments_num = r_segments.size();
124 Span<T> remaining_indices = indices;
125 while (!remaining_indices.is_empty()) {
126 if (const std::optional<IndexRange> range = non_empty_as_range_try(remaining_indices)) {
127 /* All remaining indices are range. */
128 r_segments.append(*range);
129 break;
130 }
131 if (non_empty_is_range(remaining_indices.take_front(range_threshold))) {
132 /* Next segment is a range. Now find the place where the range ends. */
133 const int64_t segment_size = find_size_of_next_range(remaining_indices);
134 r_segments.append(IndexRange(remaining_indices[0], segment_size));
135 remaining_indices = remaining_indices.drop_front(segment_size);
136 continue;
137 }
138 /* Next segment is just indices. Now find the place where the next range starts. */
139 const int64_t segment_size = find_size_until_next_range(remaining_indices, range_threshold);
140 const Span<T> segment_indices = remaining_indices.take_front(segment_size);
141 if (const std::optional<IndexRange> range = non_empty_as_range_try(segment_indices)) {
142 r_segments.append(*range);
143 }
144 else {
145 r_segments.append(segment_indices);
146 }
147 remaining_indices = remaining_indices.drop_front(segment_size);
148 }
149 return r_segments.size() - old_segments_num;
150}
151
152} // namespace blender::unique_sorted_indices
#define BLI_assert(a)
Definition BLI_assert.h:46
long long int int64_t
constexpr Span drop_front(int64_t n) const
Definition BLI_span.hh:171
constexpr Span take_front(int64_t n) const
Definition BLI_span.hh:193
constexpr bool is_empty() const
Definition BLI_span.hh:260
static ushort indices[]
#define T
static int64_t first_if(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)
i
Definition text_draw.cc:230