BLI: refactor IndexMask for better performance and memory usage #104629
|
@ -2,9 +2,14 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_vector.hh"
|
||||
#include <array>
|
||||
|
||||
namespace blender::index_mask {
|
||||
#include "BLI_index_range.hh"
|
||||
|
||||
namespace blender {
|
||||
namespace index_mask {
|
||||
|
||||
class IndexMask;
|
||||
|
||||
/* Chunks contain up to 2^14 = 16384 indices. */
|
||||
static constexpr int64_t chunk_size_shift = 14;
|
||||
|
@ -20,4 +25,159 @@ inline const std::array<int16_t, max_chunk_size> &get_static_offsets_array()
|
|||
return data;
|
||||
}
|
||||
|
||||
} // namespace blender::index_mask
|
||||
/**
|
||||
* A #Chunk contains an ordered list of segments. Each segment is an array of 16-bit integers.
|
||||
*/
|
||||
struct Chunk {
|
||||
int16_t segments_num;
|
||||
const int16_t **segment_indices;
|
||||
const int16_t *segment_sizes;
|
||||
const int16_t *accumulated_sizes;
|
||||
};
|
||||
|
||||
struct ChunkIteratorData {
|
||||
int16_t segment_index;
|
||||
int16_t index_in_segment;
|
||||
};
|
||||
|
||||
struct IndexMaskData {
|
||||
int64_t chunks_num;
|
||||
const Chunk *chunks;
|
||||
const int64_t *chunk_offsets;
|
||||
const int64_t *accumulated_sizes;
|
||||
ChunkIteratorData begin_it;
|
||||
ChunkIteratorData end_it;
|
||||
};
|
||||
|
||||
struct IndexMaskIteratorData {
|
||||
int64_t chunk_index;
|
||||
ChunkIteratorData chunk_it;
|
||||
};
|
||||
|
||||
class IndexMaskIterator {
|
||||
private:
|
||||
IndexMaskIteratorData data_;
|
||||
const IndexMask *mask_;
|
||||
|
||||
friend IndexMask;
|
||||
|
||||
public:
|
||||
IndexMaskIterator &operator++();
|
||||
|
||||
friend bool operator!=(const IndexMaskIterator &a, const IndexMaskIterator &b);
|
||||
friend bool operator==(const IndexMaskIterator &a, const IndexMaskIterator &b);
|
||||
};
|
||||
|
||||
class IndexMask {
|
||||
private:
|
||||
IndexMaskData data_;
|
||||
|
||||
friend IndexMaskIterator;
|
||||
|
||||
public:
|
||||
IndexMask();
|
||||
IndexMask(int64_t size);
|
||||
IndexMask(IndexRange range);
|
||||
|
||||
IndexMaskIterator begin() const;
|
||||
IndexMaskIterator end() const;
|
||||
|
||||
const IndexMaskData &data() const;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name #ChunkIteratorData Inline Methods
|
||||
* \{ */
|
||||
|
||||
inline bool operator!=(const ChunkIteratorData &a, const ChunkIteratorData &b)
|
||||
{
|
||||
return a.index_in_segment != b.index_in_segment || a.segment_index != b.segment_index;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name #IndexMaskIteratorData Inline Methods
|
||||
* \{ */
|
||||
|
||||
inline bool operator!=(const IndexMaskIteratorData &a, const IndexMaskIteratorData &b)
|
||||
{
|
||||
return a.chunk_it != b.chunk_it || a.chunk_index != b.chunk_index;
|
||||
}
|
||||
|
||||
inline bool operator==(const IndexMaskIteratorData &a, const IndexMaskIteratorData &b)
|
||||
{
|
||||
return !(a != b);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name #IndexMaskIterator Inline Methods
|
||||
* \{ */
|
||||
|
||||
inline IndexMaskIterator &IndexMaskIterator::operator++()
|
||||
{
|
||||
const Chunk ¤t_chunk = mask_->data_.chunks[data_.chunk_index];
|
||||
const int16_t current_segment_size = current_chunk.segment_sizes[data_.chunk_it.segment_index];
|
||||
data_.chunk_it.index_in_segment++;
|
||||
if (data_.chunk_it.index_in_segment == current_segment_size) {
|
||||
data_.chunk_it.segment_index++;
|
||||
data_.chunk_it.index_in_segment = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator!=(const IndexMaskIterator &a, const IndexMaskIterator &b)
|
||||
{
|
||||
return a.data_ != b.data_;
|
||||
}
|
||||
|
||||
inline bool operator==(const IndexMaskIterator &a, const IndexMaskIterator &b)
|
||||
{
|
||||
return a.data_ != b.data_;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name #IndexMask Inline Methods
|
||||
* \{ */
|
||||
|
||||
inline IndexMask::IndexMask()
|
||||
{
|
||||
static constexpr int64_t accumulated_sizes_for_empty[1] = {0};
|
||||
|
||||
data_.chunks_num = 0;
|
||||
data_.chunks = nullptr;
|
||||
data_.chunk_offsets = nullptr;
|
||||
data_.accumulated_sizes = accumulated_sizes_for_empty;
|
||||
data_.begin_it.segment_index = 0;
|
||||
data_.begin_it.index_in_segment = 0;
|
||||
data_.end_it.segment_index = 0;
|
||||
data_.end_it.index_in_segment = 0;
|
||||
}
|
||||
|
||||
inline IndexMaskIterator IndexMask::begin() const
|
||||
{
|
||||
IndexMaskIterator it;
|
||||
it.data_.chunk_index = 0;
|
||||
it.data_.chunk_it = data_.begin_it;
|
||||
it.mask_ = this;
|
||||
return it;
|
||||
}
|
||||
|
||||
inline IndexMaskIterator IndexMask::end() const
|
||||
{
|
||||
IndexMaskIterator it;
|
||||
it.data_.chunk_index = data_.chunks_num;
|
||||
it.data_.chunk_it.segment_index = 0;
|
||||
it.data_.chunk_it.index_in_segment = 0;
|
||||
it.mask_ = this;
|
||||
return it;
|
||||
}
|
||||
|
||||
inline const IndexMaskData &IndexMask::data() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
} // namespace index_mask
|
||||
|
||||
using index_mask::IndexMask;
|
||||
|
||||
} // namespace blender
|
||||
|
|
Loading…
Reference in New Issue