diff --git a/include/fiction/algorithms/iter/bdl_input_iterator.hpp b/include/fiction/algorithms/iter/bdl_input_iterator.hpp index 16aff0a9d..3ac04a6eb 100644 --- a/include/fiction/algorithms/iter/bdl_input_iterator.hpp +++ b/include/fiction/algorithms/iter/bdl_input_iterator.hpp @@ -23,7 +23,8 @@ namespace fiction * set. To this end, the iterator alters the given layout. The state enumeration wraps around, i.e. after the last * possible input state, the first input state is set again. * - * The iterator is bidirectional and can be used in iterator-based `for` loops. + * The iterator satisfies the requirements of `LegacyRandomAccessIterator` and can be used in iterator-based `for` + * loops. * * @tparam Lyt SiDB cell-level layout type. */ @@ -49,6 +50,15 @@ class bdl_input_iterator set_all_inputs(); } + /** + * Dereference operator. Returns a reference to the layout with the current input state. + * + * @return Reference to the current layout. + */ + [[nodiscard]] Lyt& operator*() const noexcept + { + return layout; + } /** * Prefix increment operator. Sets the next input state. * @@ -75,6 +85,20 @@ class bdl_input_iterator return result; } + /** + * Addition assignment operator. Sets a next input state. + * + * @param m The amount of input states to skip. + * @return Reference to `this`. + */ + bdl_input_iterator& operator+=(const uint64_t m) noexcept + { + current_input_index += m; + + set_all_inputs(); + + return *this; + } /** * Prefix decrement operator. Sets the previous input state. * @@ -102,13 +126,42 @@ class bdl_input_iterator return result; } /** - * Dereference operator. Returns a reference to the layout with the current input state. + * Subtraction assignment operator. Sets a previous input state. * - * @return Reference to the current layout. + * @param m The amount of input states to skip. + * @return Reference to `this`. */ - [[nodiscard]] Lyt& operator*() const noexcept + bdl_input_iterator& operator-=(const uint64_t m) noexcept { - return layout; + current_input_index -= m; + + set_all_inputs(); + + return *this; + } + /** + * Subscript operator. Sets the input state to the current one plus the given subscript. + * + * @param m The amount of input states to skip. + * @return Reference to `this`. + */ + bdl_input_iterator& operator[](const uint64_t m) noexcept + { + current_input_index += m; + + set_all_inputs(); + + return *this; + } + /** + * Subtraction operator. Computes the difference between the current input index and the given iterator ones. + * + * @param other Iterator to compute the difference with. + * @return The difference between the current input index and the given iterator ones. + */ + [[nodiscard]] std::size_t operator-(const bdl_input_iterator& other) const noexcept + { + return current_input_index - other.current_input_index; } /** * Equality operator. Compares the current input index with the given integer. @@ -225,7 +278,8 @@ namespace std template struct iterator_traits> { - using iterator_category = std::bidirectional_iterator_tag; + using iterator_category = std::random_access_iterator_tag; + using difference_type = std::size_t; using value_type = Lyt; }; } // namespace std diff --git a/test/algorithms/iter/aspect_ratio_iterator.cpp b/test/algorithms/iter/aspect_ratio_iterator.cpp index 2e3f85003..fb2140c96 100644 --- a/test/algorithms/iter/aspect_ratio_iterator.cpp +++ b/test/algorithms/iter/aspect_ratio_iterator.cpp @@ -7,8 +7,19 @@ #include #include +#include +#include + using namespace fiction; +TEST_CASE("Traits", "[bdl-input-iterator]") +{ + CHECK(std::is_same_v>::iterator_category, + std::forward_iterator_tag>); + + CHECK(std::is_same_v>::value_type, offset::ucoord_t>); +} + TEST_CASE("Aspect ratio iteration", "[aspect-ratio-iterator]") { aspect_ratio_iterator ari{1}; diff --git a/test/algorithms/iter/bdl_input_iterator.cpp b/test/algorithms/iter/bdl_input_iterator.cpp index 825e23ef3..43202f80d 100644 --- a/test/algorithms/iter/bdl_input_iterator.cpp +++ b/test/algorithms/iter/bdl_input_iterator.cpp @@ -8,8 +8,100 @@ #include #include +#include +#include +#include + using namespace fiction; +TEST_CASE("Traits", "[bdl-input-iterator]") +{ + using layout = sidb_cell_clk_lyt_siqad; + + CHECK(std::is_same_v>::iterator_category, + std::random_access_iterator_tag>); + + CHECK(std::is_same_v>::value_type, layout>); + + CHECK(std::is_same_v>::difference_type, std::size_t>); +} + +TEST_CASE("Operators", "[bdl-input-iterators]") +{ + using layout = sidb_cell_clk_lyt_siqad; + + layout lyt{}; + + bdl_input_iterator bii{lyt}; + + CHECK(bii == 0ull); + CHECK(bii != 1ull); + + CHECK(bii < 1ull); + CHECK(bii <= 1ull); + + CHECK(bii >= 0ull); + + // increment + ++bii; + + CHECK(bii == 1ull); + CHECK(bii != 0ull); + + CHECK(bii < 2ull); + CHECK(bii <= 2ull); + + CHECK(bii > 0ull); + CHECK(bii >= 0ull); + + // decrement + --bii; + + CHECK(bii == 0ull); + CHECK(bii != 1ull); + + CHECK(bii < 1ull); + CHECK(bii <= 1ull); + + CHECK(bii >= 0ull); + + // increment assignment + bii += 2ull; + + CHECK(bii == 2ull); + CHECK(bii != 1ull); + + CHECK(bii < 3ull); + CHECK(bii <= 3ull); + + CHECK(bii > 1ull); + CHECK(bii >= 1ull); + + const auto bii_cp = bii; + + // decrement assignment + bii -= 2ull; + + CHECK(bii == 0ull); + CHECK(bii != 1ull); + + CHECK(bii < 1ull); + CHECK(bii <= 1ull); + + CHECK(bii >= 0ull); + + // difference + CHECK(bii_cp - bii == 2ull); + + // subscript + CHECK(bii[0] == 0ull); + CHECK(bii[1] == 1ull); + CHECK(bii[2] == 3ull); + CHECK(bii[3] == 6ull); + CHECK(bii[4] == 10ull); + +} + TEST_CASE("Empty layout iteration", "[bdl-input-iterator]") { using layout = sidb_cell_clk_lyt_siqad; @@ -20,6 +112,8 @@ TEST_CASE("Empty layout iteration", "[bdl-input-iterator]") CHECK((*bii).num_cells() == 0); + // increment + ++bii; CHECK((*bii).num_cells() == 0); @@ -28,6 +122,18 @@ TEST_CASE("Empty layout iteration", "[bdl-input-iterator]") CHECK((*bii).num_cells() == 0); CHECK((*bii_cp).num_cells() == 0); + + // decrement + + --bii; + + CHECK((*bii).num_cells() == 0); + + auto bii_cm = bii--; + + CHECK((*bii).num_cells() == 0); + + CHECK((*bii_cm).num_cells() == 0); } TEST_CASE("BDL wire iteration", "[bdl-input-iterator]") @@ -49,6 +155,9 @@ TEST_CASE("BDL wire iteration", "[bdl-input-iterator]") lyt.assign_cell_type({20, 0, 0}, sidb_technology::cell_type::OUTPUT); bdl_input_iterator bii{lyt}; + CHECK(bii == 0ull); + + // start by incrementing over all input states // layout at input state 0 const auto& lyt_0 = *bii; @@ -58,6 +167,7 @@ TEST_CASE("BDL wire iteration", "[bdl-input-iterator]") CHECK(lyt_0.get_cell_type({2, 0, 0}) == sidb_technology::cell_type::EMPTY); ++bii; + CHECK(bii == 1ull); // layout at input state 1 const auto& lyt_1 = *bii; @@ -68,11 +178,30 @@ TEST_CASE("BDL wire iteration", "[bdl-input-iterator]") // doing another iteration should overflow and set it back to 0 ++bii; + CHECK(bii == 2ull); const auto& lyt_2 = *bii; CHECK(lyt_2.get_cell_type({0, 0, 0}) == sidb_technology::cell_type::INPUT); CHECK(lyt_2.get_cell_type({2, 0, 0}) == sidb_technology::cell_type::EMPTY); + + // finally, decrement back to the initial state, doing another wrap-around + + --bii; + CHECK(bii == 1ull); + + const auto& lyt_1_1 = *bii; + + CHECK(lyt_1_1.get_cell_type({0, 0, 0}) == sidb_technology::cell_type::EMPTY); + CHECK(lyt_1_1.get_cell_type({2, 0, 0}) == sidb_technology::cell_type::INPUT); + + --bii; + CHECK(bii == 0ull); + + const auto& lyt_0_1 = *bii; + + CHECK(lyt_0_1.get_cell_type({0, 0, 0}) == sidb_technology::cell_type::INPUT); + CHECK(lyt_0_1.get_cell_type({2, 0, 0}) == sidb_technology::cell_type::EMPTY); } TEST_CASE("SiQAD's AND gate iteration", "[bdl-input-iterator]")