diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a897cf..7ecd883 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,9 +27,9 @@ CPMAddPackage( # ---- Header target ---- -FILE(GLOB_RECURSE headers CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h") +file(GLOB_RECURSE headers CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h") add_library(EasyIterator-headers EXCLUDE_FROM_ALL ${headers}) -SET_TARGET_PROPERTIES(EasyIterator-headers PROPERTIES LINKER_LANGUAGE CXX) +set_target_properties(EasyIterator-headers PROPERTIES LINKER_LANGUAGE CXX) # ---- Create library ---- diff --git a/include/easy_iterator.h b/include/easy_iterator.h index 6f3a2c7..5612b88 100644 --- a/include/easy_iterator.h +++ b/include/easy_iterator.h @@ -123,8 +123,8 @@ namespace easy_iterator { /** * Base class for simple iterators. Takes several template parameters. * Implementations must define `operator++()` to update the value of `value`. - * @param `T` - The data type held by the iterator - * @param `D` - A functional that dereferences the data. Determines the value type of the + * @param `T` - The data type held by the iterator. + * @param `D` - A function that dereferences the data. Determines the value type of the * iterator. * @param `C` - A function that compares two values of type `T`. Used to determine if two * iterators are equal. @@ -155,21 +155,35 @@ namespace easy_iterator { value(std::forward(first)) {} DereferencedType operator*() { return dereferencer(value); } - auto *operator-> () const { return &**this; } - template bool operator==(const IteratorPrototype &other) const { - return compare(value, other.value); - } - template bool operator!=(const IteratorPrototype &other) const { - return !operator==(other); - } + auto *operator->() const { return &**this; } + + template + friend bool operator==(const IteratorPrototype &lhs, + const IteratorPrototype &rhs); + + // required for C++17 or earlier + template + friend bool operator!=(const IteratorPrototype &lhs, + const IteratorPrototype &rhs); }; - template IteratorPrototype(const T &)->IteratorPrototype; + template + bool operator==(const IteratorPrototype &lhs, const IteratorPrototype &rhs) { + return lhs.compare(lhs.value, rhs.value); + } + + // required for C++17 or earlier + template + bool operator!=(const IteratorPrototype &lhs, const IteratorPrototype &rhs) { + return !(lhs == rhs); + } + + template IteratorPrototype(const T &) -> IteratorPrototype; - template IteratorPrototype(const T &, const D &)->IteratorPrototype; + template IteratorPrototype(const T &, const D &) -> IteratorPrototype; template - IteratorPrototype(const T &, const D &, const C &)->IteratorPrototype; + IteratorPrototype(const T &, const D &, const C &) -> IteratorPrototype; namespace iterator_detail { struct WithState { @@ -185,7 +199,7 @@ namespace easy_iterator { } // namespace iterator_detail /** - * IteratorPrototype where advance is defined by the functional held by `F`. + * IteratorPrototype where advance is defined by the function held by `F`. */ template , typename D = dereference::ByValueReference, typename C = compare::ByValue> @@ -222,16 +236,13 @@ namespace easy_iterator { } return Base::dereferencer(Base::value); } - using Base::operator==; - using Base::operator!=; - bool operator==(const IterationEnd &other) const { return !operator!=(other); } - bool operator!=(const IterationEnd &) const { - if constexpr (Iterator::hasState) { - return Iterator::state; - } else { - return true; - } - } + + template + friend bool operator==(const Iterator &lhs, const IterationEnd &); + // required for C++17 or earlier + template + friend bool operator!=(const Iterator &lhs, const IterationEnd &); + explicit operator bool() const { if constexpr (Iterator::hasState) { return Iterator::state; @@ -241,15 +252,25 @@ namespace easy_iterator { } }; - template Iterator(const T &)->Iterator; + template bool operator==(const Iterator &lhs, const IterationEnd &) { + return !static_cast(lhs); + } + + // required for C++17 or earlier + template + bool operator!=(const Iterator &lhs, const IterationEnd &rhs) { + return !(lhs == rhs); + } + + template Iterator(const T &) -> Iterator; - template Iterator(const T &, const F &)->Iterator; + template Iterator(const T &, const F &) -> Iterator; template - Iterator(const T &, const F &, const D &)->Iterator; + Iterator(const T &, const F &, const D &) -> Iterator; template - Iterator(const T &, const F &, const D &, const C &)->Iterator; + Iterator(const T &, const F &, const D &, const C &) -> Iterator; template , typename D = dereference::ByValueReference, typename C = compare::ByValue> @@ -310,17 +331,17 @@ namespace easy_iterator { } /** - * Returns an iterator that increases it's value from `begin` to `end` by `1` for each step. + * Returns an iterator that increases its value from `begin` to `end` by `1` for each step. */ template auto range(T begin, T end) { return range(begin, end, 1); } /** - * Returns an iterator that increases it's value from `0` to `end` by `1` for each step. + * Returns an iterator that increases its value from `0` to `end` by `1` for each step. */ template auto range(T end) { return range(0, end); } /** - * Wrappes the `rbegin` and `rend` iterators. + * Wraps the `rbegin` and `rend` iterators. */ template auto reverse(T &v) { return wrap(v.rbegin(), v.rend()); } @@ -328,7 +349,7 @@ namespace easy_iterator { * Returns an iterable object where all argument iterators are traversed simultaneously. * Behaviour is undefined if the iterators do not have the same length. */ - template auto zip(Args &&... args) { + template auto zip(Args &&...args) { auto begin = Iterator(std::make_tuple(args.begin()...), increment::ByTupleIncrement(), dereference::ByTupleDereference(), compare::ByLastTupleElementMatch()); auto end = Iterator(std::make_tuple(args.end()...), increment::ByTupleIncrement(), @@ -344,7 +365,7 @@ namespace easy_iterator { } /** - * When used as a base class for a iterator type, `MakeIterable` will call the `bool init()` + * When used as a base class for an iterator type, `MakeIterable` will call the `bool init()` * member before iteration. If `init()` returns false, the iterator is empty. */ struct InitializedIterable {}; @@ -368,7 +389,7 @@ namespace easy_iterator { auto end() const { return IterationEnd(); } explicit MakeIterable(T &&value) : start(std::move(value)) {} - template explicit MakeIterable(Args &&... args) + template explicit MakeIterable(Args &&...args) : start(T(std::forward(args)...)) {} }; @@ -380,7 +401,7 @@ namespace easy_iterator { } /** - * copy-assigns the given value to every element in a container + * Copy-assigns the given value to every element in a container */ template void fill(A &arr, const T &value) { for (auto &v : arr) { @@ -389,7 +410,7 @@ namespace easy_iterator { } /** - * copies values from one container to another. + * Copies values from one container to another. * @param `a` - the container with values to be copies. * @param `b` - the target container. * @param `f` (optional) - a function to transform values before copying. diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1d229f1..19eaff8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -16,7 +16,7 @@ include(../cmake/CPM.cmake) CPMAddPackage( NAME doctest GITHUB_REPOSITORY onqtam/doctest - GIT_TAG 2.3.7 + GIT_TAG v2.4.11 ) if (TEST_INSTALLED_VERSION) @@ -53,11 +53,11 @@ endif() # ---- Add EasyIteratorTests ---- -ENABLE_TESTING() +enable_testing() # Note: doctest and similar testing frameworks can automatically configure CMake tests # For other testing frameworks add the tests target instead: -# ADD_TEST(EasyIteratorTests EasyIteratorTests) +# add_test(EasyIteratorTests EasyIteratorTests) include(${doctest_SOURCE_DIR}/scripts/cmake/doctest.cmake) doctest_discover_tests(EasyIteratorTests)