diff --git a/CMakeLists.txt b/CMakeLists.txt index 9da53f2..d0ebaf1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.20) include(cmake/color.cmake) -set(BLT_VERSION 1.1.2) +set(BLT_VERSION 1.1.3) set(BLT_TARGET BLT) @@ -140,7 +140,7 @@ install(FILES ${CMAKE_BINARY_DIR}/config/blt/config.h DESTINATION ${CMAKE_INSTAL set_target_properties(${BLT_TARGET} PROPERTIES VERSION ${BLT_VERSION}) set_target_properties(${BLT_TARGET} PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR}) if (NOT ${MOLD} STREQUAL MOLD-NOTFOUND) - target_compile_options(${BLT_TARGET} PUBLIC -fuse-ld=mold) + target_link_options(${BLT_TARGET} PUBLIC -fuse-ld=mold) endif () install(TARGETS ${BLT_TARGET} @@ -154,16 +154,16 @@ macro(blt_add_project name source type) add_executable(${name}-${type} ${source}) + if (NOT ${MOLD} STREQUAL MOLD-NOTFOUND) + add_link_options(-fuse-ld=mold) + endif () + target_link_libraries(${name}-${type} PRIVATE BLT) target_compile_options(${name}-${type} PRIVATE -Wall -Wextra -Wpedantic -Wno-comment) target_link_options(${name}-${type} PRIVATE -Wall -Wextra -Wpedantic -Wno-comment) target_compile_definitions(${name}-${type} PRIVATE BLT_DEBUG_LEVEL=${DEBUG_LEVEL}) - if (NOT ${MOLD} STREQUAL MOLD-NOTFOUND) - target_compile_options(${name}-${type} PUBLIC -fuse-ld=mold) - endif () - if (${TRACK_ALLOCATIONS}) target_compile_definitions(${name}-${type} PRIVATE BLT_TRACK_ALLOCATIONS=1) endif () diff --git a/include/blt/iterator/common.h b/include/blt/iterator/common.h index 746af3c..12389dc 100644 --- a/include/blt/iterator/common.h +++ b/include/blt/iterator/common.h @@ -21,6 +21,7 @@ #include #include +#include namespace blt::iterator { @@ -37,7 +38,8 @@ namespace blt::iterator base_wrapper operator--(int) { static_assert(std::is_same_v || - std::is_same_v, + std::is_same_v, "Iterator must allow random access"); auto tmp = *this; --*this; @@ -86,27 +88,22 @@ namespace blt::iterator friend bool operator==(const base_wrapper& a, const base_wrapper& b) { - return a.base() == b.base(); + return static_cast(a).base() == static_cast(b).base(); } friend bool operator!=(const base_wrapper& a, const base_wrapper& b) { - return !(a.base() == b.base()); // NOLINT + return !(static_cast(a).base() == static_cast(b).base()); // NOLINT } }; - template + template struct passthrough_wrapper : public base_wrapper { public: explicit passthrough_wrapper(Iter iter): iter(std::move(iter)) {} - meta::deref_return_t operator*() const - { - return *iter; - } - auto base() const { return iter; @@ -118,8 +115,189 @@ namespace blt::iterator } protected: - Iter iter; + mutable Iter iter; }; + + template + struct passthrough_wrapper : public passthrough_wrapper + { + using passthrough_wrapper::passthrough_wrapper; + + meta::deref_return_t operator*() const + { + return *this->iter; + } + }; + + namespace impls + { + template + struct skip_wrapper : public passthrough_wrapper> + { + public: + using iterator_category = typename std::iterator_traits::iterator_category; + using value_type = typename std::iterator_traits::value_type; + using difference_type = typename std::iterator_traits::difference_type; + using pointer = typename std::iterator_traits::pointer; + using reference = typename std::iterator_traits::reference; + + explicit skip_wrapper(Iter iter, blt::size_t n): passthrough_wrapper>(std::move(iter)), skip(n) + {} + + meta::deref_return_t operator*() const + { + BLT_TRACE("Dereference Skip"); + forward_skip(); + return *this->iter; + } + + skip_wrapper& operator++() + { + BLT_TRACE("Forward Skip"); + forward_skip(); + ++this->iter; + return *this; + } + + skip_wrapper& operator--() + { + BLT_TRACE("Backward Skip"); + forward_skip(); + --this->iter; + return *this; + } + + friend skip_wrapper operator+(const skip_wrapper& a, blt::ptrdiff_t n) + { + static_assert(std::is_same_v, + "Iterator must allow random access"); + return {a.base() + static_cast(a.skip) + n, 0}; + } + + friend skip_wrapper operator-(const skip_wrapper& a, blt::ptrdiff_t n) + { + static_assert(std::is_same_v, + "Iterator must allow random access"); + return {a.base() - static_cast(a.skip) - n, 0}; + } + + private: + void forward_skip() const + { + if constexpr (std::is_same_v) + { + if (skip > 0) + { + this->iter = this->iter + skip; + skip = 0; + } + } else + { + while (skip > 0) + { + ++this->iter; + --skip; + } + } + } + + mutable blt::size_t skip; + }; + + template + class take_t + { + private: + template + auto take_base(blt::size_t n) + { + static_assert(!std::is_same_v, + "Cannot .take() on an input iterator!"); + auto* d = static_cast(this); + auto begin = d->begin(); + auto end = d->end(); + + // take variant for forward and bidirectional iterators + if constexpr (std::is_same_v || + std::is_same_v) + { + // with these guys we have to loop forward to move the iterators. an unfortunate inefficiency + auto new_end = begin; + for (blt::size_t i = 0; i < n; i++) + { + if constexpr (check) + { + if (new_end == end) + break; + } + ++new_end; + } + return Derived{std::move(begin), std::move(new_end)}; + } else if constexpr (std::is_same_v) + { + // random access iterators can have math directly applied to them. + if constexpr (check) + { + return Derived{begin, begin + std::min(static_cast(n), std::distance(begin, end))}; + } else + { + return Derived{begin, begin + n}; + } + } + } + + public: + auto take(blt::size_t n) + { return take_base(n); } + + auto take_or(blt::size_t n) + { return take_base(n); } + }; + } + + template + class iterator_container : public impls::take_t> + { + public: + using iterator_category = typename IterBase::iterator_category; + + iterator_container(IterBase begin, IterBase end): m_begin(std::move(begin)), m_end(std::move(end)) + {} + + template + iterator_container(Iter&& begin, Iter&& end): m_begin(std::forward(begin)), m_end(std::forward(end)) + {} + + auto rev() + { + static_assert((std::is_same_v || + std::is_same_v), + ".rev() must be used with bidirectional (or better) iterators!"); + return iterator_container>{std::reverse_iterator{end()}, + std::reverse_iterator{begin()}}; + } + + auto skip(blt::size_t n) + { + return iterator_container>{impls::skip_wrapper{begin(), n}, + impls::skip_wrapper{end(), n}}; + } + + auto begin() const + { + return m_begin; + } + + auto end() const + { + return m_end; + } + + protected: + IterBase m_begin; + IterBase m_end; + }; + } #endif //BLT_ITERATOR_ITER_COMMON diff --git a/include/blt/iterator/zip.h b/include/blt/iterator/zip.h index 4efb86a..4a04d41 100644 --- a/include/blt/iterator/zip.h +++ b/include/blt/iterator/zip.h @@ -38,6 +38,9 @@ namespace blt using pointer = value_type; using reference = value_type; + explicit zip_wrapper(std::tuple iter): iter(std::move(iter)) + {} + explicit zip_wrapper(Iter... iter): iter(std::make_tuple(iter...)) {} @@ -77,7 +80,7 @@ namespace blt return sub(a, b, std::index_sequence_for()); } - auto base() + auto base() const { return iter; } @@ -94,80 +97,6 @@ namespace blt return min; } }; - - template - struct skip_wrapper : public passthrough_wrapper> - { - public: - using iterator_category = typename std::iterator_traits::iterator_category; - using value_type = typename std::iterator_traits::value_type; - using difference_type = typename std::iterator_traits::difference_type; - using pointer = typename std::iterator_traits::pointer; - using reference = typename std::iterator_traits::reference; - - explicit skip_wrapper(Iter iter, blt::size_t n): passthrough_wrapper>(std::move(iter)), skip(n) - {} - - skip_wrapper& operator++() - { - if constexpr (std::is_same_v) - { - if (skip > 0) - { - this->base() += skip; - skip = 0; - } - } else - { - while (skip > 0) - { - ++this->base(); - --skip; - } - } - - ++this->base(); - return *this; - } - - skip_wrapper& operator--() - { - if constexpr (std::is_same_v) - { - if (skip > 0) - { - this->base() -= skip; - skip = 0; - } - } else - { - while (skip > 0) - { - --this->base(); - --skip; - } - } - --this->base(); - return *this; - } - - friend skip_wrapper operator+(const skip_wrapper& a, blt::ptrdiff_t n) - { - static_assert(std::is_same_v, - "Iterator must allow random access"); - return {a.base() + static_cast(a.skip) + n, 0}; - } - - friend skip_wrapper operator-(const skip_wrapper& a, blt::ptrdiff_t n) - { - static_assert(std::is_same_v, - "Iterator must allow random access"); - return {a.base() - static_cast(a.skip) - n, 0}; - } - - private: - blt::size_t skip; - }; } template @@ -183,92 +112,15 @@ namespace blt }; template - class zip_iterator_storage; - - template - class zip_iterator_storage_rev; - - template - class zip_iterator_storage + class zip_iterator_storage : public iterator::iterator_container> { public: - using iterator_category = meta::lowest_iterator_category_t; - public: - zip_iterator_storage(iterator_pair... iterator_pairs): - m_begins(std::move(iterator_pairs.begin)...), m_ends(std::move(iterator_pairs.end)...) + using iterator::iterator_container>::iterator_container; + + explicit zip_iterator_storage(iterator_pair... iterator_pairs): + iterator::iterator_container>(iterator::zip_wrapper{std::move(iterator_pairs.begin)...}, + iterator::zip_wrapper{std::move(iterator_pairs.end)...}) {} - - zip_iterator_storage(iterator::zip_wrapper begins, iterator::zip_wrapper ends): - m_begins(std::move(begins)), m_ends(std::move(ends)) - {} - - auto rev() - { - static_assert((std::is_same_v || - std::is_same_v), - ".rev() must be used with bidirectional (or better) iterators!"); - return zip_iterator_storage_rev{m_ends, m_begins}; - } - - auto skip(blt::size_t n) - { - - } - - auto begin() const - { - return m_begins; - } - - auto end() const - { - return m_ends; - } - - private: - iterator::zip_wrapper m_begins; - iterator::zip_wrapper m_ends; - }; - - template - class zip_iterator_storage_rev - { - public: - using iterator_category = meta::lowest_iterator_category_t; - public: - zip_iterator_storage_rev(iterator_pair... iterator_pairs): m_begins(iterator_pairs.begin...), m_ends(iterator_pairs.end...) - { - static_assert((std::is_same_v || - std::is_same_v), - "reverse iteration is only supported on bidirectional or better iterators!"); - } - - zip_iterator_storage_rev(iterator::zip_wrapper begins, - iterator::zip_wrapper ends): m_begins(std::move(begins)), m_ends(std::move(ends)) - { - static_assert((std::is_same_v || - std::is_same_v), - "reverse iteration is only supported on bidirectional or better iterators!"); - } - - auto rev() - { - return zip_iterator_storage{m_ends.base(), m_begins.base()}; - } - - auto begin() const - { - return m_begins; - } - - auto end() const - { - return m_ends; - } - - private: - std::reverse_iterator> m_begins; - std::reverse_iterator> m_ends; }; /* @@ -281,11 +133,6 @@ namespace blt template zip_iterator_storage(std::initializer_list...) -> zip_iterator_storage; - template - zip_iterator_storage_rev(iterator_pair...) -> zip_iterator_storage_rev; - - template - zip_iterator_storage_rev(std::initializer_list...) -> zip_iterator_storage_rev; /* * Helper functions for creating zip containers diff --git a/libraries/parallel-hashmap b/libraries/parallel-hashmap index 93201da..7ef2e73 160000 --- a/libraries/parallel-hashmap +++ b/libraries/parallel-hashmap @@ -1 +1 @@ -Subproject commit 93201da2ba5a6aba0a6e57ada64973555629b3e3 +Subproject commit 7ef2e733416953b222851f9a360d7fc72d068ee5 diff --git a/tests/iterator_tests.cpp b/tests/iterator_tests.cpp index 0ee82fc..0fb5198 100644 --- a/tests/iterator_tests.cpp +++ b/tests/iterator_tests.cpp @@ -136,7 +136,7 @@ void test_zip() BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n"; } BLT_TRACE("================================"); - for (auto [a1, a2, a3] : blt::zip(array_1, array_2, list_1).take(3).rev()) + for (auto [a1, a2, a3] : blt::zip(array_1, array_2, array_3).take(3).rev()) { BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n"; } @@ -150,6 +150,11 @@ void test_zip() { BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n"; } + BLT_TRACE("================================"); + for (auto [a1, a2, a3] : blt::zip(array_1, array_2, array_3).skip(2).rev()) + { + BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n"; + } } int main()