42 [&](
const T src,
const T dst) { r_map[src] = dst; });
49 std::array<int16_t, max_segment_size>
data;
58 static constexpr int64_t size_shift = 31;
79 for (
const int64_t segment_i : range) {
80 indices_by_segment[segment_i] = static_offsets;
85 segment_offsets.
last() = max_size;
89 data.indices_num_ = max_size;
90 data.segments_num_ = segments_num;
91 data.indices_by_segment_ = indices_by_segment.
data();
92 data.segment_offsets_ = segment_offsets.
data();
93 data.cumulative_segment_sizes_ = segment_offsets.
data();
94 data.begin_index_in_segment_ = 0;
110 if (std::holds_alternative<IndexRange>(segment)) {
111 const IndexRange range = std::get<IndexRange>(segment);
115 const Span<int64_t> segment_indices = std::get<Span<int64_t>>(segment);
116 parts.
append(fmt::format(
"{}", fmt::join(segment_indices,
", ")));
119 stream << fmt::format(
"(Size: {} | {})",
mask.size(), fmt::join(parts,
", "));
132 sliced.indices_num_ =
size;
134 sliced.indices_by_segment_ += first_it.
segment_i;
135 sliced.segment_offsets_ += first_it.
segment_i;
136 sliced.cumulative_segment_sizes_ += first_it.
segment_i;
148 sliced.indices_num_ =
size;
150 sliced.indices_by_segment_ += first_it.
segment_i;
151 sliced.segment_offsets_ += first_it.
segment_i;
152 sliced.cumulative_segment_sizes_ += first_it.
segment_i;
170 if (!first_it || !last_it) {
175 if (last_index < first_index) {
178 const int64_t sliced_mask_size = last_index - first_index + 1;
179 return this->
slice(*first_it, *last_it, sliced_mask_size);
197 if (std::optional<IndexRange> range = this->
to_range()) {
198 return range->slice(start,
size).shift(offset);
212 if (std::optional<IndexRange> range = this->
to_range()) {
213 return range->shift(offset);
220 shifted_mask.segment_offsets_ = new_segment_offsets.
data();
234 int64_t group_start_segment_i = 0;
235 int64_t group_first = segments[0][0];
239 auto finish_group = [&](
const int64_t last_segment_i) {
240 if (group_start_segment_i == last_segment_i) {
247 for (
int64_t i = group_start_segment_i + 1;
i <= last_segment_i;
i++) {
254 const std::optional<IndexRange> segment_base_range =
256 const bool segment_is_range = segment_base_range.has_value();
258 if (group_as_range && segment_is_range) {
259 if (group_last + 1 == segment[0]) {
262 group_last = segment.last();
267 finish_group(segment_i - 1);
269 group_start_segment_i = segment_i;
270 group_first = segment[0];
271 group_last = segment.last();
272 group_as_range = segment_is_range;
274 finish_group(segments.
size() - 1);
277 const int64_t new_segments_num = std::remove_if(segments.
begin(),
280 return segment.is_empty();
283 return new_segments_num;
310 cumulative_segment_sizes[0] = 0;
313 indices_by_segment[segment_i] =
segment.base_span().data();
314 segment_offsets[segment_i] =
segment.offset();
315 cumulative_segment_sizes[segment_i + 1] = cumulative_segment_sizes[segment_i] +
segment.size();
321 data.indices_num_ = cumulative_segment_sizes.last();
323 data.indices_by_segment_ = indices_by_segment.
data();
324 data.segment_offsets_ = segment_offsets.data();
325 data.cumulative_segment_sizes_ = cumulative_segment_sizes.data();
326 data.begin_index_in_segment_ = 0;
327 data.end_index_in_segment_ = segments.
last().size();
335template<
typename T,
int64_t InlineBufferSize>
349 for (
const auto &segment : segments) {
350 if (std::holds_alternative<IndexRange>(segment)) {
351 const IndexRange segment_range = std::get<IndexRange>(segment);
355 Span<T> segment_indices = std::get<Span<T>>(segment);
357 segment_indices.
size());
358 while (!segment_indices.
is_empty()) {
359 const int64_t offset = segment_indices[0];
362 [&](
const T value) { return value - offset >= max_segment_size; });
364 const int64_t offset_index = segment_indices[
i] - offset;
369 segment_indices = segment_indices.
drop_front(next_segment_size);
426 constexpr int64_t min_grain_size = 4096;
428 if (
indices.size() <= min_grain_size) {
434 const int64_t grain_size = std::clamp(
435 indices.size() / (threads_num * 4), min_grain_size, max_grain_size);
439 ParallelSegmentsCollector::LocalData &local_data = segments_collector.data_by_thread.local();
440 segments_from_indices(indices.slice(range), local_data.allocator, local_data.segments);
442 segments_collector.
reduce(memory, segments);
445 segments.
resize(consolidated_segments_num);
458 const int64_t segment_start = universe_segment[0];
465 const int64_t segment_end = universe_segment.
last() + 1;
468 const int64_t global_index = universe_segment[
i];
469 const int64_t local_index = global_index - segment_start;
473 if (bits_slice[local_index]) {
474 local_bits[local_index].set();
479 return segment_start;
494 universe_segment.
last());
508 const int64_t segment_shift = batch_predicate(universe_segment, builder);
518 constexpr int64_t threshold = 64;
519 int64_t next_range_to_process = 0;
520 int64_t skipped_indices_num = 0;
524 auto consolidate_skipped_ranges = [&](
int64_t end_range_i) {
525 if (skipped_indices_num == 0) {
533 counter += range.
size();
540 if (range.
size() > threshold || builder.
size() == 1) {
541 consolidate_skipped_ranges(
i);
543 next_range_to_process =
i + 1;
544 skipped_indices_num = 0;
547 skipped_indices_num += range.
size();
550 consolidate_skipped_ranges(builder.
size());
565 if (universe.
size() <= grain_size.
value) {
576 universe_segment,
data.allocator, batch_predicate,
data.segments);
578 segments_collector.
reduce(memory, segments);
611 universe_segment.
last());
615 const int64_t allowed_overshoot = std::min<int64_t>(
bits.capacity() -
slice.size(),
643 return *
static_cast<const bool *
>(info.
data) ? universe :
IndexMask();
650 universe,
GrainSize(512), memory, [&](
const int64_t index) {
return bools[index]; });
659 return *
static_cast<const bool *
>(info.
data) ?
IndexMask() : universe;
666 universe,
GrainSize(512), memory, [&](
const int64_t index) {
return !bools[index]; });
705 const Expr &expr = builder.
subtract({&mask_a}, {&mask_b});
723 if (
const auto *range = std::get_if<IndexRange>(&item)) {
728 else if (
const auto *span_i64 = std::get_if<
Span<int64_t>>(&item)) {
733 else if (
const auto *span_i32 = std::get_if<
Span<int>>(&item)) {
734 for (
const int i : *span_i32) {
738 else if (
const auto *index = std::get_if<int64_t>(&item)) {
744 std::sort(values_vec.
begin(), values_vec.
end());
753 r_indices[pos] = T(i);
769 for (
const int64_t i : shifted_indices) {
788 [&](
const int64_t i) { r_bools[
i] =
true; });
816 std::array<int16_t, max_segment_size> indices_array;
817 const int64_t true_indices_num = filter_indices(universe_segment, indices_array.data());
818 if (true_indices_num == 0) {
821 const Span<int16_t> true_indices{indices_array.data(), true_indices_num};
827 for (
const auto &true_segment : true_segments) {
828 if (std::holds_alternative<IndexRange>(true_segment)) {
829 const IndexRange segment_range = std::get<IndexRange>(true_segment);
833 const Span<int16_t> segment_indices = std::get<Span<int16_t>>(true_segment);
851 if (universe.
size() <= grain_size.
value) {
862 universe_segment,
data.allocator, filter_indices,
data.segments);
864 segments_collector.
reduce(memory, segments);
868 segments.
resize(consolidated_segments_num);
875 if (
const std::optional<RawMaskIterator> it = this->
find_larger_equal(query_index)) {
876 if ((*
this)[*it] == query_index) {
894 if (query_index <
segment[0]) {
896 const int64_t index_in_segment = segment_begin_index;
903 segment.base_span(), [&](
const int16_t
i) { return i >= local_index; });
904 const int64_t actual_index_in_segment = index_in_segment + segment_begin_index;
914 const std::optional<RawMaskIterator> larger_equal_it = this->
find_larger_equal(query_index);
915 if (!larger_equal_it) {
919 if ((*
this)[*larger_equal_it] == query_index) {
921 return larger_equal_it;
923 if (larger_equal_it->segment_i > 0) {
924 if (larger_equal_it->index_in_segment > 0) {
927 int16_t(larger_equal_it->index_in_segment - 1)};
936 return RawMaskIterator{0, int16_t(larger_equal_it->index_in_segment - 1)};
943 return this->
find(query_index).has_value();
952 data[
i] = int16_t(index);
972 return data.as_span().take_front(repetitions);
976 return data.as_span().take_front(repetitions);
980 return data.as_span().take_front(repetitions);
987 data[
i] = int16_t(index);
1004 if (repetitions == 0) {
1007 if (repetitions == 1 && initial_offset == 0) {
1009 return mask_to_repeat;
1011 const std::optional<IndexRange> range_to_repeat = mask_to_repeat.
to_range();
1012 if (range_to_repeat && range_to_repeat->first() == 0 && range_to_repeat->size() == stride) {
1014 return IndexRange(initial_offset, repetitions * stride);
1026 if (src_segment.
size() == 1) {
1033 inline_repetitions_num * src_segment.
size());
1036 const int64_t index = src_segment[
i] - src_segment[0] + repetition * stride;
1038 repeated_indices_mut[repetition * src_segment.
size() +
i] = int16_t(index);
1041 repeated_indices = repeated_indices_mut;
1048 const int64_t used_repetitions = std::min(inline_repetitions_num,
1049 repetitions -
i * inline_repetitions_num);
1050 repeated_segments.
append(
1052 repeated_indices.
take_front(used_repetitions * src_segment.
size())));
1063 segment.offset() + repetition * stride + initial_offset,
segment.base_span()));
1083 return masks[0].size() == maks.size();
1098 if (start_iter[mask_i] == 0) {
1099 segments[mask_i] = masks[mask_i].segment(segment_iter[mask_i]);
1103 int16_t next_common_sequence_size = std::numeric_limits<int16_t>::max();
1105 next_common_sequence_size =
math::min(next_common_sequence_size,
1106 int16_t(segments[mask_i].
size() - start_iter[mask_i]));
1110 sequences[mask_i] = segments[mask_i].
slice(start_iter[mask_i], next_common_sequence_size);
1113 if (!
fn(sequences)) {
1118 if (segments[mask_i].
size() - start_iter[mask_i] == next_common_sequence_size) {
1119 segment_iter[mask_i]++;
1120 start_iter[mask_i] = 0;
1123 start_iter[mask_i] += next_common_sequence_size;
1131 if (a.
size() !=
b.size()) {
1144 if (a_is_range || b_is_range) {
1145 return a_is_range && b_is_range;
1151 const int64_t offset_difference = int16_t(
b.offset() - a.
offset());
1153 BLI_assert(a_indices[0] >= 0 && b_indices[0] >= 0);
1154 BLI_assert(b_indices[0] == a_indices[0] - offset_difference);
1156 return std::equal(a_indices.
begin(),
1158 b.base_span().begin(),
1159 [offset_difference](
const int16_t a_index,
const int16_t b_index) ->
bool {
1160 return a_index - offset_difference == b_index;
1166 if (a.
size() !=
b.size()) {
1170 const std::optional<IndexRange> a_as_range = a.
to_range();
1171 const std::optional<IndexRange> b_as_range =
b.to_range();
1172 if (a_as_range.has_value() || b_as_range.has_value()) {
1173 return a_as_range == b_as_range;
1192 if (
const std::optional<int> single_group_id = group_ids.
get_if_single()) {
1195 const int64_t groups_num = r_index_by_group_id.
size();
1196 result_masks.
resize(groups_num);
1197 result_masks[group_index] = universe;
1198 return result_masks;
1203 const int64_t groups_num = r_index_by_group_id.
size();
1204 result_masks.
resize(groups_num);
1209 const int group_id = group_ids_span[
i];
1210 return r_index_by_group_id.
index_of(group_id);
1213 return result_masks;
1221 IndexMask(group_ids.
size()), group_ids, memory, r_index_by_group_id);
1237 const uint32_t random_seed,
1238 const float probability,
1242 const auto next_bool_random_value = [&]() {
return rng.
get_float() <= probability; };
1252 const uint32_t random_seed,
1253 const float probability,
1257 return random_mask(selection, universe_size, random_seed, probability, memory);
int BLI_system_thread_count(void)
#define UNUSED_VARS_NDEBUG(...)
BMesh const char void * data
const T & last(const int64_t n=0) const
constexpr int64_t first() const
constexpr IndexRange shift(int64_t n) const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
static constexpr IndexRange from_begin_end(const int64_t begin, const int64_t end)
constexpr int64_t start() const
static constexpr IndexRange from_begin_end_inclusive(const int64_t begin, const int64_t last)
constexpr IndexRange drop_front(int64_t n) const
IndexRange index_range() const
MutableSpan< T > allocate_array(int64_t size)
MutableSpan< T > construct_array_copy(Span< T > src)
void transfer_ownership_from(LinearAllocator<> &other)
constexpr int64_t size() const
constexpr bool is_empty() const
constexpr T * data() const
constexpr void fill(const T &value) const
constexpr T * end() const
constexpr T * begin() const
constexpr IndexRange index_range() const
constexpr T & last(const int64_t n=0) const
IndexRange index_range() const
T last(const int64_t n=0) const
Span< BaseT > base_span() const
constexpr Span drop_front(int64_t n) const
constexpr Span slice(int64_t start, int64_t size) const
constexpr int64_t size() const
constexpr const T & last(const int64_t n=0) const
constexpr const T * end() const
constexpr IndexRange index_range() const
constexpr const T * begin() const
constexpr Span take_front(int64_t n) const
constexpr bool is_empty() const
std::optional< T > get_if_single() const
IndexRange index_range() const
CommonVArrayInfo common_info() const
int64_t index_of_or_add(const Key &key)
int64_t index_of(const Key &key) const
void append(const T &value)
void resize(const int64_t new_size)
void extend(Span< T > array)
Span< T > as_span() const
void append_as(ForwardValue &&...value)
MutableBitSpan slice(const IndexRange range) const
const IntersectionExpr & intersect(const Span< Term > terms)
const UnionExpr & merge(const Span< Term > terms)
const DifferenceExpr & subtract(const Term &main_term, const Span< Term > subtract_terms)
IndexMask slice_and_shift(IndexRange range, int64_t offset, IndexMaskMemory &memory) const
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
static IndexMask from_every_nth(int64_t n, int64_t indices_num, const int64_t initial_offset, IndexMaskMemory &memory)
IndexMaskSegment segment(int64_t segment_i) const
void to_indices(MutableSpan< T > r_indices) const
IndexMask slice_content(IndexRange range) const
Vector< IndexRange > to_ranges_invert(IndexRange universe) const
static IndexMask from_bits(BitSpan bits, IndexMaskMemory &memory)
Vector< IndexRange > to_ranges() const
std::optional< RawMaskIterator > find(int64_t query_index) const
std::optional< IndexRange > to_range() const
static Vector< IndexMask, 4 > from_group_ids(const VArray< int > &group_ids, IndexMaskMemory &memory, VectorSet< int > &r_index_by_group_id)
static IndexMask from_repeating(const IndexMask &mask_to_repeat, int64_t repetitions, int64_t stride, int64_t initial_offset, IndexMaskMemory &memory)
static IndexMask from_union(const IndexMask &mask_a, const IndexMask &mask_b, IndexMaskMemory &memory)
IndexMask shift(const int64_t offset, IndexMaskMemory &memory) const
void foreach_index_optimized(Fn &&fn) const
std::optional< RawMaskIterator > find_larger_equal(int64_t query_index) const
IndexMask slice(IndexRange range) const
static IndexMask from_ranges(OffsetIndices< T > offsets, const IndexMask &mask, IndexMaskMemory &memory)
static IndexMask from_intersection(const IndexMask &mask_a, const IndexMask &mask_b, IndexMaskMemory &memory)
static IndexMask from_indices(Span< T > indices, IndexMaskMemory &memory)
IndexRange bounds() const
int64_t iterator_to_index(const RawMaskIterator &it) const
static IndexMask from_segments(Span< IndexMaskSegment > segments, IndexMaskMemory &memory)
int64_t min_array_size() const
static void from_groups(const IndexMask &universe, IndexMaskMemory &memory, Fn &&get_group_index, MutableSpan< IndexMask > r_masks)
static IndexMask from_batch_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, FunctionRef< int64_t(const IndexMaskSegment &universe_segment, IndexRangesBuilder< int16_t > &builder)> batch_predicate)
static IndexMask from_initializers(const Span< Initializer > initializers, IndexMaskMemory &memory)
void set_bits(MutableBitSpan r_bits, int64_t offset=0) const
std::optional< RawMaskIterator > find_smaller_equal(int64_t query_index) const
bool contains(int64_t query_index) const
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
void foreach_range(Fn &&fn) const
void to_bits(MutableBitSpan r_bits, int64_t offset=0) const
static IndexMask from_bools_inverse(const VArray< bool > &bools, IndexMaskMemory &memory)
void foreach_segment_optimized(Fn &&fn) const
void to_bools(MutableSpan< bool > r_bools) const
void foreach_index(Fn &&fn) const
RawMaskIterator index_to_iterator(int64_t index) const
static void foreach_segment_zipped(Span< IndexMask > masks, FunctionRef< bool(Span< IndexMaskSegment > segments)> fn)
int64_t segments_num() const
static IndexMask from_difference(const IndexMask &mask_a, const IndexMask &mask_b, IndexMaskMemory &memory)
std::variant< IndexRange, Span< int64_t >, Span< int >, int64_t > Initializer
void foreach_segment(Fn &&fn) const
IMETHOD void random(Vector &a)
addDelta operator for displacement rotational velocity.
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void fill_index_range(MutableSpan< T > span, const T start=0)
static int64_t first_if(Iterator begin, Iterator end, Predicate &&predicate)
bool or_bools_into_bits(Span< bool > bools, MutableBitSpan r_bits, int64_t allowed_overshoot=0)
void bits_to_index_ranges(const BitSpan bits, IndexRangesBuilder< IntT > &builder)
void invert(BitSpanT &&data)
static void segments_from_predicate_filter(const IndexMaskSegment universe_segment, LinearAllocator<> &allocator, const FunctionRef< int64_t(IndexMaskSegment indices, int16_t *r_true_indices)> filter_indices, Vector< IndexMaskSegment, 16 > &r_segments)
IndexMask from_predicate_impl(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, FunctionRef< int64_t(IndexMaskSegment indices, int16_t *r_true_indices)> filter_indices)
IndexMask evaluate_expression(const Expr &expression, IndexMaskMemory &memory)
void index_range_to_mask_segments(const IndexRange range, Vector< IndexMaskSegment, N > &r_segments)
static constexpr int64_t max_segment_size
static void segments_from_batch_predicate(const IndexMaskSegment universe_segment, LinearAllocator<> &allocator, const FunctionRef< int64_t(const IndexMaskSegment &universe_segment, IndexRangesBuilder< int16_t > &builder)> batch_predicate, Vector< IndexMaskSegment, 16 > &r_segments)
static void segments_from_indices(const Span< T > indices, LinearAllocator<> &allocator, Vector< IndexMaskSegment, InlineBufferSize > &r_segments)
static Span< int16_t > get_every_nth_index(const int64_t n, const int64_t repetitions, IndexMaskMemory &memory)
void build_reverse_map(const IndexMask &mask, MutableSpan< T > r_map)
std::ostream & operator<<(std::ostream &stream, const IndexMask &mask)
bool operator==(const RawMaskIterator &a, const RawMaskIterator &b)
std::array< int16_t, max_segment_size > build_static_indices_array()
static Array< int16_t > build_every_nth_index_array(const int64_t n)
static int64_t from_bits_batch_predicate(const IndexMaskSegment universe_segment, IndexRangesBuilder< int16_t > &builder, const BitSpan bits_slice)
const IndexMask & get_static_index_mask_for_min_size(const int64_t min_size)
int64_t consolidate_index_mask_segments(MutableSpan< IndexMaskSegment > segments, IndexMaskMemory &memory)
static bool segments_is_equal(const IndexMaskSegment &a, const IndexMaskSegment &b)
template void build_reverse_map< int >(const IndexMask &mask, MutableSpan< int > r_map)
IndexMask random_mask(const IndexMask &mask, const int64_t universe_size, const uint32_t random_seed, const float probability, IndexMaskMemory &memory)
const std::array< int16_t, max_segment_size > & get_static_indices_array()
T min(const T &a, const T &b)
void isolate_task(const Function &function)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
std::optional< IndexRange > non_empty_as_range_try(const Span< T > indices)
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)
void parallel_sort(RandomAccessIterator begin, RandomAccessIterator end)
constexpr IntT ceil_division(const IntT x, const IntT y)
const int64_t * cumulative_segment_sizes_
const int16_t ** indices_by_segment_
int64_t end_index_in_segment_
int64_t begin_index_in_segment_
const int64_t * segment_offsets_
LinearAllocator allocator
Vector< IndexMaskSegment, 16 > segments
threading::EnumerableThreadSpecific< LocalData > data_by_thread
void reduce(LinearAllocator<> &main_allocator, Vector< IndexMaskSegment, 16 > &main_segments)