diff --git a/CMakeLists.txt b/CMakeLists.txt index 59a7c6c..e445683 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,10 +43,12 @@ if(BUILD_TESTING AND ${KDALGORITHMS_BUILD_TEST}) add_executable(tst_kdalgorithms src/kdalgorithms.h - src/bits/copy_or_move_iterators.h + src/bits/read_iterator_wrapper.h src/bits/filter.h - src/bits/has_reserve_trait.h + src/bits/insert_wrapper.h src/bits/is_const_method.h + src/bits/is_detected.h + src/bits/method_tests.h src/bits/operators.h src/bits/return_type_trait.h src/bits/shared.h diff --git a/README.md b/README.md index 0a20664..821e51e 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,12 @@ Lots of Examples In this document you will find lots of examples. More, however, may be found in the unit tests. +Qt data types +------------- +A few of the functions (copy, filtered, and transform) need additional support for Qt +data types. Therefore, to us kdalgorithms together with Qt, you must include kdalgorithms_qt.h +rather than kdalgorithms.h + Algorithms ========== @@ -183,7 +189,7 @@ auto toString = [] (int i) { return QString::number(i); } QVector result = kdalgorithms::transformed(ints, toString); ``` -Finally ther is a version which does an inline transform: +Finally there is a version which does an inline transform: ``` std::vector ints{1,2,3}; @@ -192,6 +198,29 @@ kdalgorithms::transform(ints, square); // ints = {1,4,9} ``` +transformed on maps +------------------- +The transform methods can unfortunately not automatically deduce the +type of the result container - even when it is just the same type as the input container, +therefore two additional methods are provided: + +``` +std::map map{{1, "abc"}, {2, "def"}, {3, "hij"}, {4, "klm"}}; +auto doubleKeys = [](const auto& item) { + return std::make_pair(item.first * 2, item.second); +}; +auto result = kdalgorithms::transformed_to_same_container(map, doubleKeys); +// result = {2, "abc"}, {4, "def"}, {6, "hij"}, {8, "klm"} +``` + + +``` +std::map map{{1, "abc"}, {2, "def"}, {3, "hij"}, {4, "klm"}}; +auto result = kdalgorithms::transformed_with_new_return_type>( + map, [](auto item) { return std::make_pair(item.second, item.first); }); +// result = {{"abc", 1}, {"def", 2}, {"hij", 3}, {"klm", 4}}; +``` + See [std::transform](https://en.cppreference.com/w/cpp/algorithm/transform) for the algorithm from the standard. reverse / reversed diff --git a/src/bits/filter.h b/src/bits/filter.h index 05f166c..f260a24 100644 --- a/src/bits/filter.h +++ b/src/bits/filter.h @@ -1,6 +1,8 @@ #pragma once -#include "has_reserve_trait.h" +#include "insert_wrapper.h" +#include "method_tests.h" +#include "read_iterator_wrapper.h" #include "shared.h" #include "to_function_object.h" #include @@ -14,12 +16,12 @@ namespace detail { { ResultContainer result; #if __cplusplus >= 201703L - if constexpr (traits::has_reserve_method_v) { + if constexpr (detail::has_reserve_method_v) { result.reserve(input.size()); } #endif - auto range = copy_or_move_iterators(std::forward(input)); - std::copy_if(range.begin, range.end, std::back_inserter(result), + auto range = read_iterator_wrapper(std::forward(input)); + std::copy_if(range.begin, range.end, detail::insert_wrapper(result), std::forward(predicate)); return result; } diff --git a/src/bits/has_reserve_trait.h b/src/bits/has_reserve_trait.h deleted file mode 100644 index 5711036..0000000 --- a/src/bits/has_reserve_trait.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include - -namespace kdalgorithms { -namespace traits { - - template - struct make_void - { - typedef void type; - }; - - template - using void_t = typename make_void::type; - - template > - struct has_reserve_method : std::false_type - { - }; - - template - struct has_reserve_method().reserve(42))>> : std::true_type - { - }; - - template - constexpr bool has_reserve_method_v = has_reserve_method::value; - -} // namespace traits -} // namespace kdalgorithms diff --git a/src/bits/insert_wrapper.h b/src/bits/insert_wrapper.h new file mode 100644 index 0000000..cb8fc54 --- /dev/null +++ b/src/bits/insert_wrapper.h @@ -0,0 +1,88 @@ +#pragma once + +#include "method_tests.h" +#include +#include + +namespace kdalgorithms { +namespace detail { + // similar to std::inserter, but calls insert with just one argument - required for QSet in Qt5 + template + class single_arg_inserter + { + public: + using value_type = typename T::value_type; + single_arg_inserter(T &set) + : m_set(set) + { + } + + single_arg_inserter &operator++() { return *this; } + single_arg_inserter &operator*() { return *this; } + single_arg_inserter &operator=(const value_type &value) + { + m_set.insert(value); + return *this; + } + + private: + T &m_set; + }; + + template + using has_push_back = decltype(std::declval().push_back(std::declval())); + + template + using has_insert = decltype(std::declval().insert(std::declval())); + + template + auto insert_wrapper( + Container &c, + std::enable_if_t< + detail::is_detected_v, int> = + 0) + { + return std::back_inserter(c); + } + + template + auto insert_wrapper( + Container &c, + std::enable_if_t< + detail::is_detected_v, int> = 0) + { + return single_arg_inserter(c); + } + + // similar to std::inserter, but for QMap/QHash which usually accept a value in their operator= + template + class qmap_inserter + { + public: + qmap_inserter(T &map) + : m_map(map) + { + } + + qmap_inserter &operator++() { return *this; } + qmap_inserter &operator*() { return *this; } + qmap_inserter & + operator=(const std::pair &pair) + { + m_map.insert(pair.first, pair.second); + return *this; + } + + private: + T &m_map; + }; + + template + auto insert_wrapper(Container &c, + std::enable_if_t, int> = 0) + { + return qmap_inserter(c); + } + +} // namespace detail +} // namespace kdalgorithms diff --git a/src/bits/is_detected.h b/src/bits/is_detected.h new file mode 100644 index 0000000..611921d --- /dev/null +++ b/src/bits/is_detected.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +// Inspired from std::experimental::is_detected +// See https://en.cppreference.com/w/cpp/experimental/is_detected + +namespace kdalgorithms { +namespace detail { + template class, typename... Args> + struct detector : std::false_type + { + }; + + template