diff --git a/README.md b/README.md index 0c9062f34..ea0858166 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ Procedures for each standard are provided by the following R7RS-style libraries: cmake -B build -DCMAKE_BUILD_TYPE=Release cd build make package -sudo apt install build/meevax_0.5.84_amd64.deb +sudo apt install build/meevax_0.5.85_amd64.deb ``` or @@ -123,9 +123,9 @@ sudo rm -rf /usr/local/share/meevax | Target Name | Description |-------------|------------- -| `all` | Build shared-library `libmeevax.0.5.84.so` and executable `meevax` +| `all` | Build shared-library `libmeevax.0.5.85.so` and executable `meevax` | `test` | Test executable `meevax` -| `package` | Generate debian package `meevax_0.5.84_amd64.deb` +| `package` | Generate debian package `meevax_0.5.85_amd64.deb` | `install` | Copy files into `/usr/local` directly ## Usage diff --git a/VERSION b/VERSION index 05a42e401..ffccd09a9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.5.84 +0.5.85 diff --git a/include/meevax/bitset/simple_bitset.hpp b/include/meevax/bitset/simple_bitset.hpp index 99af260ec..b5f55e6aa 100644 --- a/include/meevax/bitset/simple_bitset.hpp +++ b/include/meevax/bitset/simple_bitset.hpp @@ -18,29 +18,32 @@ #define INCLUDED_MEEVAX_BITSET_SIMPLE_BITSET_HPP #include +#include namespace meevax { inline namespace bitset { template - struct simple_bitset + struct simple_bitset : public std::array { - std::array data {}; + constexpr simple_bitset() + : std::array {} + {} - auto test(std::size_t i) const noexcept -> bool + auto reset(std::size_t i) noexcept -> void { - return data[i]; + (*this)[i] = false; } auto set(std::size_t i) noexcept -> void { - data[i] = true; + (*this)[i] = true; } - auto reset(std::size_t i) noexcept -> void + auto test(std::size_t i) const noexcept -> bool { - data[i] = false; + return (*this)[i]; } }; } // namespace bitset diff --git a/include/meevax/iterator/naive_index_iterator.hpp b/include/meevax/iterator/naive_index_iterator.hpp new file mode 100644 index 000000000..3accfa8f0 --- /dev/null +++ b/include/meevax/iterator/naive_index_iterator.hpp @@ -0,0 +1,117 @@ +/* + Copyright 2018-2023 Tatsuya Yamasaki. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef INCLUDED_MEEVAX_ITERATOR_NAIVE_INDEX_ITERATOR_HPP +#define INCLUDED_MEEVAX_ITERATOR_NAIVE_INDEX_ITERATOR_HPP + +#include // reference_wrapper +#include +#include +#include +#include + +namespace meevax +{ +inline namespace iterator +{ + template + struct naive_index_iterator + { + using iterator_category = std::bidirectional_iterator_tag; + + using value_type = std::decay_t()[std::declval()])>; + + using reference = decltype(std::declval()[std::declval()]); + + using pointer = std::add_pointer_t; + + using difference_type = std::ptrdiff_t; + + std::reference_wrapper container; + + std::size_t index; + + explicit naive_index_iterator(Container const& container) + : container { std::cref(container) } + , index { container.size() } + {} + + explicit naive_index_iterator(Container const& container, std::size_t index) + : container { std::cref(container) } + , index { index } + { + if (container.size() < index) + { + index = container.size(); + } + } + + auto operator *() const -> decltype(auto) + { + assert(index < container.get().size()); + return container.get()[index]; + } + + auto operator ++() -> decltype(auto) + { + /* + NOTE: Incrementing the end iterator is undefined behavior, so there is + no need to consider that case. + */ + assert(index < container.get().size()); + + ++index; + + assert(index <= container.get().size()); + + return *this; + } + + auto operator --() -> decltype(auto) + { + /* + NOTE: Decrementing the begin iterator is undefined behavior, so there + is no need to consider that case. + */ + assert(index != 0); + + --index; + + assert(index < container.get().size()); + + return *this; + } + + friend auto operator ==(naive_index_iterator const& a, naive_index_iterator const& b) + { + /* + NOTE: Comparing iterators obtained from different containers is + undefined behavior. Therefore, here, it may be assumed that + a.container and b.container refer to the same container, meaning that + they have the same address. + */ + return a.index == b.index; + } + + friend auto operator !=(naive_index_iterator const& a, naive_index_iterator const& b) + { + return not (a == b); + } + }; +} // namespace iterator +} // namespace meevax + +#endif // INCLUDED_MEEVAX_ITERATOR_NAIVE_INDEX_ITERATOR_HPP diff --git a/include/meevax/memory/pointer_set.hpp b/include/meevax/memory/pointer_set.hpp index 0ef7d5cb2..d844d5e9b 100644 --- a/include/meevax/memory/pointer_set.hpp +++ b/include/meevax/memory/pointer_set.hpp @@ -23,11 +23,13 @@ #include #include #include +#include #include #include #include #include +#include namespace meevax { @@ -35,7 +37,7 @@ inline namespace memory { template typename Bitset = simple_bitset, - std::size_t N = 1024 * 1024> + std::size_t N = 4096 * 8> // getconf PAGE_SIZE class pointer_set { static_assert(std::is_pointer_v); @@ -79,6 +81,16 @@ inline namespace memory { Bitset::set(p.index()); } + + auto begin() const + { + return naive_index_iterator(*this, 0); + } + + auto end() const + { + return naive_index_iterator(*this); + } }; std::vector chunks; @@ -100,16 +112,16 @@ inline namespace memory std::size_t i; - std::size_t j; + std::optional> inner; explicit iterator(std::vector const& chunks, typename std::vector::const_iterator iter, std::size_t j) noexcept : chunks { chunks } , i { static_cast(std::distance(chunks.begin(), iter)) } - , j { j } + , inner { i < chunks.size() ? std::make_optional(naive_index_iterator(chunks[i], j)) : std::nullopt } { - if (not (i < chunks.size() and j < N and chunks[i].test(j))) + if (not dereferenceable() and incrementable()) { operator ++(); } @@ -118,32 +130,61 @@ inline namespace memory explicit iterator(std::vector const& chunks) noexcept : chunks { chunks } , i { chunks.size() } - , j { N } - {} + , inner { std::nullopt } + { + assert(not dereferenceable()); + } + + auto incrementable() const -> bool + { + return i < chunks.size() and inner; + } + + auto decrementable() const -> bool + { + return i != 0 or inner != chunks[i].begin(); + } + + auto dereferenceable() const -> bool + { + return incrementable() and **inner; + } auto operator *() const noexcept { - return compact_pointer::to_pointer(chunks[i].offset + j); + assert(dereferenceable()); + return compact_pointer::to_pointer(chunks[i].offset + inner->index); } auto operator ++() noexcept -> auto & { - ++j; + assert(incrementable()); + + /* + NOTE: Incrementing the end iterator is undefined behavior, so there + is no need to consider that case. + */ + if (++*inner == chunks[i].end()) + { + inner = chunks[++i].begin(); + } - for (; i < chunks.size(); ++i, j = 0) + assert(decrementable()); + + for (; i < chunks.size(); inner = chunks[++i].begin()) { - for (; j < N; ++j) + for (; inner != chunks[i].end(); ++*inner) { - if (chunks[i].test(j)) + if (**inner) { return *this; } } } - i = chunks.size(); + assert(i == chunks.size()); - j = N; + inner = std::nullopt; return *this; // end } @@ -157,29 +198,42 @@ inline namespace memory auto operator --() noexcept -> auto & { - i = std::min(chunks.size() - 1, i); + auto decrement_inner = [this]() + { + assert(decrementable()); - j = std::min(N - 1, j - 1); + if (i == chunks.size() or inner == chunks[i].begin()) + { + inner = std::prev(chunks[--i].end()); + } + else + { + --*inner; + } - /* - NOTE: N4659 6.9.1.4 + assert(incrementable()); + }; - Unsigned integers shall obey the laws of arithmetic modulo 2 n where - n is the number of bits in the value representation of that - particular size of integer. - */ - for (; i < chunks.size(); --i, j = N - 1) + decrement_inner(); + + for (; i < chunks.size(); inner = std::prev(chunks[--i].end())) { - for (; j < N; --j) + while (true) { - if (chunks[i].test(j)) + if (**inner) { return *this; } + + decrement_inner(); } } + #if defined(__GNUC__) or defined(__clang__) + __builtin_unreachable(); // Reaching here means decrementing the begin iterator. This is undefined behavior. + #else return *this; + #endif } auto operator --(int) noexcept @@ -191,7 +245,7 @@ inline namespace memory auto operator ==(iterator const& rhs) const noexcept { - return i == rhs.i and j == rhs.j; + return i == rhs.i and inner == rhs.inner; } auto operator !=(iterator const& rhs) const noexcept