diff --git a/include/melon/container/static_filter_map.hpp b/include/melon/container/static_filter_map.hpp index 08706fa..7ac3a4f 100644 --- a/include/melon/container/static_filter_map.hpp +++ b/include/melon/container/static_filter_map.hpp @@ -110,7 +110,7 @@ class static_filter_map { protected: constexpr void _bump_up() noexcept { - if(_local_index++ == N - 1) { + if(++_local_index == N) { ++_p; _local_index = 0; } @@ -227,7 +227,7 @@ class static_filter_map { constexpr const_reference operator*() const noexcept { return (*iterator_base::_p >> iterator_base::_local_index) & - 1; + static_cast(1); } constexpr const_reference operator[](difference_type i) const { return *(*this + i); @@ -308,18 +308,22 @@ class static_filter_map { K begin_index = std::max(static_cast(0), *std::ranges::begin(r)); K end_index = std::min(static_cast(_size), *std::ranges::end(r)); + //* const_iterator begin_it(_data.get() + begin_index / N, begin_index & span_index_mask); const const_iterator end_it(_data.get() + end_index / N, end_index & span_index_mask); auto next_it = [end_it](const_iterator cursor) { - ++cursor; - span_type shifted = (*cursor._p) >> cursor._local_index; + span_type shifted; + if(++cursor._local_index == N) goto find_next_span; + shifted = (*cursor._p) >> cursor._local_index; if(shifted == span_type{0}) { + find_next_span: cursor._local_index = 0; do { - if(++cursor._p > end_it._p) return cursor; + if(++cursor._p > end_it._p) [[unlikely]] + return cursor; } while(*cursor._p == span_type{0}); shifted = *cursor._p; } @@ -342,6 +346,25 @@ class static_filter_map { [end_it](const const_iterator & cursor) -> bool { return cursor < end_it; }); + /*/ + auto next_index = [this, end_index](K i) { + for(;;) { + const size_type offset = i & span_index_mask; + i += static_cast(std::countr_zero( + _data[i / N] & + ((~static_cast(1)) << offset))) - + offset; + if((i >= end_index || at(i))) [[likely]] + return i; + } + }; + + if(!at(begin_index)) begin_index = next_index(begin_index); + + return intrusive_view( + begin_index, std::identity{}, std::move(next_index), + [end_index](const K & i) -> bool { return i < end_index; }); + //*/ } else { return std::views::filter( std::views::transform( diff --git a/include/melon/container/wip_static_map_atomic_bool.hpp b/include/melon/container/wip_static_map_atomic_bool.hpp deleted file mode 100644 index 6842398..0000000 --- a/include/melon/container/wip_static_map_atomic_bool.hpp +++ /dev/null @@ -1,260 +0,0 @@ -#ifndef MELON_STATIC_MAP_ATOMIC_BOOL_HPP -#define MELON_STATIC_MAP_ATOMIC_BOOL_HPP - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "melon/container/static_map.hpp" - -namespace fhamonic { -namespace melon { - -template - requires std::integral -class static_map> { -public: - using value_type = bool; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; - -private: - using span_type = std::size_t; - static_assert(std::is_unsigned_v); - static constexpr size_type N = sizeof(span_type) << 3; - static constexpr size_type span_index_mask = N - 1; - static constexpr size_type nb_spans(std::size_t n) { - return (n + N - 1) / N; - } - -public: - struct reference { - std::atomic * _p; - span_type _mask; - - reference(std::atomic * x, size_type y) - : _p(x), _mask(span_type(1) << y) {} - reference() noexcept : _p(0), _mask(0) {} - reference(const reference &) = default; - - operator bool() const noexcept { return !!(_p->load() & _mask); } - reference & operator=(bool x) noexcept { - if(x) - _p->fetch_or(_mask); - else - _p->fetch_and(~_mask); - return *this; - } - reference & operator=(const reference & x) noexcept { - return *this = bool(x); - } - bool operator==(const reference & x) const { - return bool(*this) == bool(x); - } - bool operator<(const reference & x) const { - return !bool(*this) && bool(x); - } - }; - using const_reference = bool; - - template - class iterator_base { - public: - using iterator_category = std::random_access_iterator_tag; - using difference_type = static_map>::difference_type; - using value_type = bool; - using pointer = void; - - protected: - std::atomic * _p; - size_type _local_index; - - public: - iterator_base(std::atomic * p, size_type index) - : _p(p), _local_index(index) {} - - iterator_base() = default; - iterator_base(const iterator_base &) = default; - iterator_base(iterator_base &&) = default; - - iterator_base & operator=(const iterator_base &) = default; - iterator_base & operator=(iterator_base &&) = default; - - protected: - constexpr void _incr() noexcept { - if(_local_index++ == N - 1) { - ++_p; - _local_index = 0; - } - } - constexpr void _decr() noexcept { - if(_local_index++ == 0) { - --_p; - _local_index = N - 1; - } - } - constexpr void _incr(difference_type i) noexcept { - difference_type n = static_cast(_local_index) + i; - _p += n / difference_type(N); - n = n % difference_type(N); - if(n < 0) { - n += difference_type(N); - --_p; - } - _local_index = static_cast(n); - } - - public: - friend bool operator==(const iterator_base & x, - const iterator_base & y) noexcept { - return x._p == y._p && x._local_index == y._local_index; - } - friend constexpr std::strong_ordering operator<=>( - const iterator_base & x, const iterator_base & y) noexcept { - if(const auto cmp = x._p <=> y._p; cmp != 0) return cmp; - return x._local_index <=> y._local_index; - } - difference_type operator-(const iterator_base & other) const noexcept { - return (difference_type(N) * (_p - other._p) + - static_cast(_local_index) - - static_cast(other._local_index)); - } - - I & operator++() noexcept { - _incr(); - return *static_cast(this); - } - I operator++(int) noexcept { - I tmp = *static_cast(this); - _incr(); - return tmp; - } - I & operator--() noexcept { - _decr(); - return *static_cast(this); - } - I operator--(int) noexcept { - I tmp = *static_cast(this); - _decr(); - return tmp; - } - I & operator+=(difference_type i) noexcept { - _incr(i); - return *static_cast(this); - } - I & operator-=(difference_type i) noexcept { - _incr(-i); - return *static_cast(this); - } - - friend I operator+(const I & x, difference_type n) { - I tmp = x; - tmp += n; - return tmp; - } - friend I operator+(difference_type n, const I & x) { return x + n; } - friend I operator-(const I & x, difference_type n) { - I tmp = x; - tmp -= n; - return tmp; - } - }; - - class iterator : public iterator_base { - public: - using iterator_base::iterator_base; - using reference = static_map>::reference; - - reference operator*() const noexcept { - return reference(_p, _local_index); - } - reference operator[](difference_type i) const { return *(*this + i); } - }; - - class const_iterator : public iterator_base { - public: - using iterator_base::iterator_base; - using reference = const_reference; - - const_reference operator*() const noexcept { - return (_p->load() >> _local_index) & 1; - } - const_reference operator[](difference_type i) const noexcept { - return *(*this + i); - } - }; - -private: - std::unique_ptr[]> _data; - size_type _size; - -public: - static_map() : _data(nullptr), _size(0){}; - static_map(size_type size) - : _data(std::make_unique[]>(nb_spans(size))) - , _size(size){}; - - static_map(size_type size, bool init_value) : static_map(size) { - fill(init_value); - }; - - static_map(const static_map & other) : static_map(other._size) { - const size_type length = nb_spans(_size); - for(size_type i = 0; i < length; ++i) - _data[i].store(other._data[i].load()); - }; - static_map(static_map &&) = default; - - static_map & operator=(const static_map & other) { - resize(other.size()); - const size_type length = nb_spans(_size); - for(size_type i = 0; i < length; ++i) - _data[i].store(other._data[i].load()); - return *this; - }; - static_map & operator=(static_map &&) = default; - - iterator begin() noexcept { return iterator(_data.get(), 0); } - iterator end() noexcept { - return iterator(_data.get() + _size / N, _size & span_index_mask); - } - const_iterator begin() const noexcept { - return const_iterator(_data.get(), 0); - } - const_iterator end() const noexcept { - return const_iterator(_data.get() + _size / N, _size & span_index_mask); - } - - size_type size() const noexcept { return _size; } - void resize(size_type n) { - if(n == _size) return; - _data = std::make_unique[]>(nb_spans(n)); - _size = n; - } - - reference operator[](size_type i) noexcept { - assert(i < size()); - return reference(_data.get() + i / N, i & span_index_mask); - } - const_reference operator[](size_type i) const noexcept { - assert(i < size()); - return reference(_data.get() + i / N, i & span_index_mask); - } - - void fill(bool b) noexcept { - const span_type value = b ? ~span_type(0) : span_type(0); - std::for_each(_data.get(), _data.get() + nb_spans(_size), - [value](auto & span) { span.store(value); }); - } -}; - -} // namespace melon -} // namespace fhamonic - -#endif // MELON_STATIC_MAP_ATOMIC_BOOL_HPP \ No newline at end of file diff --git a/include/melon/views/dual.hpp b/include/melon/experimental/dual.hpp similarity index 100% rename from include/melon/views/dual.hpp rename to include/melon/experimental/dual.hpp diff --git a/test/static_filter_map_test.cpp b/test/static_filter_map_test.cpp index 5d55d10..fa8b7ec 100755 --- a/test/static_filter_map_test.cpp +++ b/test/static_filter_map_test.cpp @@ -138,7 +138,7 @@ GTEST_TEST(static_map_bool, iterator_extensive_read) { } GTEST_TEST(static_map_bool, filter) { - const std::size_t nb_bools = 8971; + const std::size_t nb_bools = 153; static_filter_map map(nb_bools, false); std::vector indices; @@ -164,51 +164,64 @@ GTEST_TEST(static_map_bool, filter) { } GTEST_TEST(static_map_bool, filter_bench) { - const double density = 0.9; - const std::size_t nb_bools = 153546; - static_filter_map map(nb_bools, false); - std::vector indices; + std::cout << "density,map_filter,manual_filter\n"; auto gen = std::bind(std::uniform_real_distribution<>(0, 1), std::default_random_engine()); - for(std::size_t i = 0; i < nb_bools; ++i) { - if(gen() > density) continue; - indices.emplace_back(i); - map[i] = true; - } - - static_assert(std::random_access_iterator::iterator>); - static_assert( - std::random_access_iterator::iterator>); + for(double hole_density : std::initializer_list{ + 1.0, 0.99, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.01, 0}) { + std::cout << hole_density << ','; + const std::size_t nb_bools = 13451; + static_filter_map map(nb_bools, false); + std::vector indices; - { - auto start = std::chrono::high_resolution_clock::now(); + std::size_t hole_size = 3; - std::size_t cpt = 0; - for(auto && i : - map.filter(std::views::iota(std::size_t{0}, nb_bools))) { - ++cpt; + for(std::size_t i = 0; i < nb_bools - hole_size; ++i) { + if(gen() > hole_density) continue; + for(std::size_t j = 0; j < hole_size; ++j) map[i + j] = true; + } + for(std::size_t i = 0; i < nb_bools; ++i) { + if(map[i]) indices.emplace_back(i); } - ASSERT_EQ(cpt, indices.size()); - auto stop = std::chrono::high_resolution_clock::now(); - auto duration = duration_cast(stop - start); - std::cout << "map filter : " << duration.count() << " us" << std::endl; - } + static_assert(std::random_access_iterator::iterator>); + static_assert(std::random_access_iterator< + static_map::iterator>); - { - auto start = std::chrono::high_resolution_clock::now(); + { + auto start = std::chrono::high_resolution_clock::now(); - std::size_t cpt = 0; - for(std::size_t i = 0; i < nb_bools; ++i) { - if(!map[i]) continue; - ++cpt; + std::vector ids; + for(auto && i : + map.filter(std::views::iota(std::size_t{0}, nb_bools))) { + ids.emplace_back(i); + } + ASSERT_TRUE(EQ_MULTISETS(ids, indices)); + + auto stop = std::chrono::high_resolution_clock::now(); + auto duration = + duration_cast(stop - start); + + std::cout << duration.count() << ','; } - ASSERT_EQ(cpt, indices.size()); - auto stop = std::chrono::high_resolution_clock::now(); - auto duration = duration_cast(stop - start); - std::cout << "manual filter : " << duration.count() << " us" << std::endl; + { + auto start = std::chrono::high_resolution_clock::now(); + + std::vector ids; + for(std::size_t i = 0; i < nb_bools; ++i) { + if(!map[i]) continue; + ids.emplace_back(i); + } + ASSERT_TRUE(EQ_MULTISETS(ids, indices)); + + auto stop = std::chrono::high_resolution_clock::now(); + auto duration = + duration_cast(stop - start); + + std::cout << duration.count() << std::endl; + } } } \ No newline at end of file