[graphics/krita] /: Implement member access functions for std::find_if and std::lower_bound

Dmitry Kazakov null at kde.org
Mon May 8 10:58:16 BST 2023


Git commit 9529c83bfce7c5257d7cc6867e5ae6a881706651 by Dmitry Kazakov.
Committed on 05/05/2023 at 11:23.
Pushed by dkazakov into branch 'master'.

Implement member access functions for std::find_if and std::lower_bound

Basically, the new functions in kismpl namespace allow us replace
weird lambdas of the form:

QList<KeyStroke>::const_iterator it =
         std::find_if(m_d->keyStrokes.constBegin(),
                      m_d->keyStrokes.constEnd(),
                     [color] (const KeyStroke &s) {
                         return s.color == color;
                     });

with much more readable code:

     QList<KeyStroke>::const_iterator it =
         std::find_if(m_d->keyStrokes.constBegin(),
                      m_d->keyStrokes.constEnd(),
                      kismpl::mem_equal_to(&KeyStroke::color, color));

The same is possible with binary predicates used in std::lower_bound
and std::upper_bound. This code with lambdas

auto it = std::lower_bound(m_stops.begin(), m_stops.end(),
                           KoGradientStop(t, KoColor(), COLORSTOP),
                           [](const KoGradientStop& a, const KoGradientStop& b) {
                               return a.position < b.position;
                           });

can be replaces with a readable function like this:

auto it = std::lower_bound(m_stops.begin(), m_stops.end(),
                           KoGradientStop(t, KoColor(), COLORSTOP),
                           kismpl::mem_less(&KoGradientStop::position));

This approach is inspired from the Lager library

CC:kimageshop at kde.org

M  +387  -0    libs/global/KisMpl.h
M  +5    -0    libs/global/kis_shared_ptr.h
M  +1    -4    libs/image/kis_stroke.cpp
M  +2    -6    libs/image/lazybrush/kis_colorize_mask.cpp
M  +283  -1    libs/image/tests/KisMplTest.cpp
M  +10   -1    libs/image/tests/KisMplTest.h
M  +5    -7    libs/pigment/resources/KoStopGradient.cpp
M  +1    -3    libs/ui/KisView.cpp
M  +1    -2    libs/ui/animation/VideoExportOptionsDialog.cpp
M  +1    -3    libs/ui/brushhud/kis_brush_hud_properties_config.cpp
M  +3    -3    libs/ui/input/kis_input_manager.cpp
M  +3    -3    libs/widgetutils/KisRecentFilesManager.cpp
M  +3    -3    plugins/dockers/layerdocker/NodeToolTip.cpp
M  +1    -3    plugins/paintops/defaultpaintops/brush/KisDabRenderingQueue.cpp
M  +2    -2    plugins/paintops/spray/KisSprayRandomDistributions.cpp

https://invent.kde.org/graphics/krita/commit/9529c83bfce7c5257d7cc6867e5ae6a881706651

diff --git a/libs/global/KisMpl.h b/libs/global/KisMpl.h
index b1d3ec62dc9..386136f63de 100644
--- a/libs/global/KisMpl.h
+++ b/libs/global/KisMpl.h
@@ -143,6 +143,393 @@ std::optional<T> fold_optional(Fun &&fun, Args &&...args) {
 template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
 template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
 
+namespace detail {
+
+template<typename Op, typename Class, typename MemType, typename PtrType>
+struct mem_checker;
+
+template<typename Op, typename Class, typename MemType>
+struct mem_checker<Op, Class, MemType, MemType Class::*>
+{
+    bool operator() (const Class &object) const {
+        Op op;
+        return op(object.*ptr, value);
+    }
+
+    bool operator() (Class *object) const {
+        Op op;
+        return op((*object).*ptr, value);
+    }
+
+    template <typename Ptr, typename = std::void_t<typename Ptr::element_type>>
+    bool operator() (const Ptr &object) const {
+        Op op;
+        return op((*object).*ptr, value);
+    }
+
+    MemType Class::* ptr;
+    const MemType value;
+};
+
+template<typename Op, typename Class, typename MemType>
+struct mem_checker<Op, Class, MemType, MemType (Class::*)() const>
+{
+    bool operator() (const Class &object) const {
+        Op op;
+        return op((object.*ptr)(), value);
+    }
+
+    bool operator() (Class *object) const {
+        Op op;
+        return op(((*object).*ptr)(), value);
+    }
+
+    template <typename Ptr, typename = std::void_t<typename Ptr::element_type>>
+    bool operator() (const Ptr &object) const {
+        Op op;
+        return op(((*object).*ptr)(), value);
+    }
+
+    MemType (Class::*ptr)() const;
+    const MemType value;
+};
+
+template<typename Op, typename Class, typename MemType, typename PtrType>
+struct mem_compare;
+
+template<typename Op, typename Class, typename MemType>
+struct mem_compare<Op, Class, MemType, MemType Class::*>
+{
+    bool operator() (const Class &lhs, const Class &rhs) const {
+        Op op;
+        return op(lhs.*ptr, rhs.*ptr);
+    }
+
+    bool operator() (const Class &lhs, const MemType &rhs) const {
+        Op op;
+        return op(lhs.*ptr, rhs);
+    }
+
+    bool operator() (const MemType &lhs, const Class &rhs) const {
+        Op op;
+        return op(lhs, rhs.*ptr);
+    }
+
+    bool operator() (Class *lhs, Class *rhs) const {
+        Op op;
+        return op((*lhs).*ptr, (*rhs).*ptr);
+    }
+
+    bool operator() (Class *lhs, const MemType &rhs) const {
+        Op op;
+        return op((*lhs).*ptr, rhs);
+    }
+
+    bool operator() (const MemType &lhs, Class *rhs) const {
+        Op op;
+        return op(lhs, (*rhs).*ptr);
+    }
+
+    template <typename Ptr, typename = std::void_t<typename Ptr::element_type>>
+    bool operator() (const Ptr &lhs, const Ptr &rhs) const {
+        Op op;
+        return op((*lhs).*ptr, (*rhs).*ptr);
+    }
+
+    template <typename Ptr, typename = std::void_t<typename Ptr::element_type>>
+    bool operator() (const Ptr &lhs, const MemType &rhs) const {
+        Op op;
+        return op((*lhs).*ptr, rhs);
+    }
+
+    template <typename Ptr, typename = std::void_t<typename Ptr::element_type>>
+    bool operator() (const MemType &lhs, const Ptr &rhs) const {
+        Op op;
+        return op(lhs, (*rhs).*ptr);
+    }
+
+    MemType Class::* ptr;
+};
+
+template<typename Op, typename Class, typename MemType>
+struct mem_compare<Op, Class, MemType, MemType (Class::*)() const>
+{
+    bool operator() (const Class &lhs, const Class &rhs) const {
+        Op op;
+        return op((lhs.*ptr)(), (rhs.*ptr)());
+    }
+
+    bool operator() (const Class &lhs, const MemType &rhs) const {
+        Op op;
+        return op((lhs.*ptr)(), rhs);
+    }
+
+    bool operator() (const MemType &lhs, const Class &rhs) const {
+        Op op;
+        return op(lhs, (rhs.*ptr)());
+    }
+
+    bool operator() (Class *lhs, Class *rhs) const {
+        Op op;
+        return op(((*lhs).*ptr)(), ((*rhs).*ptr)());
+    }
+
+    bool operator() (Class *lhs, const MemType &rhs) const {
+        Op op;
+        return op(((*lhs).*ptr)(), rhs);
+    }
+
+    bool operator() (const MemType &lhs, Class *rhs) const {
+        Op op;
+        return op(lhs, ((*rhs).*ptr)());
+    }
+
+    template <typename Ptr, typename = std::void_t<typename Ptr::element_type>>
+    bool operator() (const Ptr &lhs, const Ptr &rhs) const {
+        Op op;
+        return op(((*lhs).*ptr)(), ((*rhs).*ptr)());
+    }
+
+    template <typename Ptr, typename = std::void_t<typename Ptr::element_type>>
+    bool operator() (const Ptr &lhs, const MemType &rhs) const {
+        Op op;
+        return op(((*lhs).*ptr)(), rhs);
+    }
+
+    template <typename Ptr, typename = std::void_t<typename Ptr::element_type>>
+    bool operator() (const MemType &lhs, const Ptr &rhs) const {
+        Op op;
+        return op(lhs, ((*rhs).*ptr)());
+    }
+
+    MemType (Class::*ptr)() const;
+};
+
+
+} // detail
+
+/**
+ * @brief mem_equal_to is an unary functor that compares a member of the object to
+ *                     a given value
+ *
+ * The functor is supposed to be used in `std::find_if` and other standard algorithms.
+ * It can automatically dereference a pointer-to-member or a pointer-to-method.
+ *
+ *  * Usage:
+ *
+ *        \code{.cpp}
+ *
+ *        struct Struct {
+ *            Struct (int _id) : id(_id) {}
+ *
+ *            int id = -1;
+ *            int idConstFunc() const {
+ *                return id;
+ *            }
+ *        };
+ *
+ *        std::vector<Struct> vec({{0},{1},{2},{3}});
+ *
+ *        // find an element, which has member 'id' set to 1
+ *        auto it1 = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::id, 1));
+ *
+ *        // find an element, whose member function 'idConstFunc()' returns 1
+ *        auto it2 = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::idConstFunc, 1));
+ *
+ *        // the functor can automatically dereference pointers and shared pointers
+ *        std::vector<std::shared_ptr<Struct>> vec({std::make_shared<Struct>(0),
+ *                                                  std::make_shared<Struct>(1),
+ *                                                  std::make_shared<Struct>(2),
+ *                                                  std::make_shared<Struct>(3),
+ *                                                  std::make_shared<Struct>(4)});
+ *
+ *        // the shared pointer is automatically lifted by the functor
+ *        auto it3 = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::id, 1));
+ *
+ *        \endcode
+ */
+
+template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
+inline auto mem_equal_to(MemTypeNoRef Class::*ptr, MemType &&value) {
+    return detail::mem_checker<std::equal_to<>, Class, MemTypeNoRef, MemTypeNoRef Class::*>{ptr, std::forward<MemType>(value)};
+}
+
+template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
+inline auto mem_equal_to(MemTypeNoRef (Class::*ptr)() const, MemType &&value) {
+    return detail::mem_checker<std::equal_to<>, Class, MemTypeNoRef, MemTypeNoRef (Class::*)() const>{ptr, std::forward<MemType>(value)};
+}
+
+/**
+ * @brief mem_less is an unary functor that compares a member of the object to
+ *                 a given value
+ *
+ * @see mem_equal_to
+ */
+
+template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
+inline auto mem_less(MemTypeNoRef Class::*ptr, MemType &&value) {
+    return detail::mem_checker<std::less<>, Class, MemTypeNoRef, MemTypeNoRef Class::*>{ptr, std::forward<MemType>(value)};
+}
+
+template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
+inline auto mem_less(MemTypeNoRef (Class::*ptr)() const, MemType &&value) {
+    return detail::mem_checker<std::less<>, Class, MemTypeNoRef, MemTypeNoRef (Class::*)() const>{ptr, std::forward<MemType>(value)};
+}
+
+/**
+ * @brief mem_less_equal is an unary functor that compares a member of the object to
+ *                       a given value
+ *
+ * @see mem_equal_to
+ */
+
+template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
+inline auto mem_less_equal(MemTypeNoRef Class::*ptr, MemType &&value) {
+    return detail::mem_checker<std::less_equal<>, Class, MemTypeNoRef, MemTypeNoRef Class::*>{ptr, std::forward<MemType>(value)};
+}
+
+template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
+inline auto mem_less_equal(MemTypeNoRef (Class::*ptr)() const, MemType &&value) {
+    return detail::mem_checker<std::less_equal<>, Class, MemTypeNoRef, MemTypeNoRef (Class::*)() const>{ptr, std::forward<MemType>(value)};
+}
+
+/**
+ * @brief mem_greater is an unary functor that compares a member of the object to
+ *                    a given value
+ *
+ * @see mem_equal_to
+ */
+
+template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
+inline auto mem_greater(MemTypeNoRef Class::*ptr, MemType &&value) {
+    return detail::mem_checker<std::greater<>, Class, MemTypeNoRef, MemTypeNoRef Class::*>{ptr, std::forward<MemType>(value)};
+}
+
+template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
+inline auto mem_greater(MemTypeNoRef (Class::*ptr)() const, MemType &&value) {
+    return detail::mem_checker<std::greater<>, Class, MemTypeNoRef, MemTypeNoRef (Class::*)() const>{ptr, std::forward<MemType>(value)};
+}
+
+/**
+ * @brief mem_greater_equal is an unary functor that compares a member of the object to
+ *                          a given value
+ *
+ * @see mem_equal_to
+ */
+
+
+template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
+inline auto mem_greater_equal(MemTypeNoRef Class::*ptr, MemType &&value) {
+    return detail::mem_checker<std::greater_equal<>, Class, MemTypeNoRef, MemTypeNoRef Class::*>{ptr, std::forward<MemType>(value)};
+}
+
+template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
+inline auto mem_greater_equal(MemTypeNoRef (Class::*ptr)() const, MemType &&value) {
+    return detail::mem_checker<std::greater_equal<>, Class, MemTypeNoRef, MemTypeNoRef (Class::*)() const>{ptr, std::forward<MemType>(value)};
+}
+
+/**
+ * @brief mem_less is a binary functor that compares a member of the object to a
+ *                 given value or two objects based on the value of their members
+ *
+ * The functor is supposed to be used in `std::lower_bound` and other standard algorithms.
+ * It can automatically dereference a pointer-to-member or a pointer-to-method.
+ *
+ *  * Usage:
+ *
+ *        \code{.cpp}
+ *
+ *        struct Struct {
+ *            Struct (int _id) : id(_id) {}
+ *
+ *            int id = -1;
+ *            int idConstFunc() const {
+ *                return id;
+ *            }
+ *        };
+ *
+ *        std::vector<Struct> vec({{0},{1},{2},{3}});
+ *
+ *        // find the first element, whose 'id' is not less that 1
+ *        auto it1 = std::lower_bound(vec.begin(), vec.end(), 1, kismpl::mem_less(&Struct::id));
+ *
+ *        // find the first element, whose 'id' retunred by 'idConstFunc()' is not less that 1
+ *        auto it2 = std::lower_bound(vec.begin(), vec.end(), 1, kismpl::mem_less(&Struct::idConstFunc, 1));
+ *
+ *        // the functor can automatically dereference pointers and shared pointers
+ *        std::vector<std::shared_ptr<Struct>> vec({std::make_shared<Struct>(0),
+ *                                                  std::make_shared<Struct>(1),
+ *                                                  std::make_shared<Struct>(2),
+ *                                                  std::make_shared<Struct>(3),
+ *                                                  std::make_shared<Struct>(4)});
+ *
+ *        // the shared pointer is automatically lifted by the functor
+ *        auto it3 = std::lower_bound(vec.begin(), vec.end(), 1, kismpl::mem_less(&Struct::id));
+ *
+ *        \endcode
+ */
+
+template<typename Class, typename MemType>
+inline auto mem_less(MemType Class::*ptr) {
+    return detail::mem_compare<std::less<>, Class, MemType, MemType Class::*>{ptr};
+}
+
+template<typename Class, typename MemType>
+inline auto mem_less(MemType (Class::*ptr)() const) {
+    return detail::mem_compare<std::less<>, Class, MemType, MemType (Class::*)() const>{ptr};
+}
+
+/**
+ * @brief mem_less_equal is a binary functor that compares a member of the object to a
+ *                       given value or two objects based on the value of their members
+ *
+ * @see mem_less
+ */
+template<typename Class, typename MemType>
+inline auto mem_less_equal(MemType Class::*ptr) {
+    return detail::mem_compare<std::less_equal<>, Class, MemType, MemType Class::*>{ptr};
+}
+
+template<typename Class, typename MemType>
+inline auto mem_less_equal(MemType (Class::*ptr)() const) {
+    return detail::mem_compare<std::less_equal<>, Class, MemType, MemType (Class::*)() const>{ptr};
+}
+
+/**
+ * @brief mem_greater is a binary functor that compares a member of the object to a
+ *                    given value or two objects based on the value of their members
+ *
+ * @see mem_less
+ */
+
+template<typename Class, typename MemType>
+inline auto mem_greater(MemType Class::*ptr) {
+    return detail::mem_compare<std::greater<>, Class, MemType, MemType Class::*>{ptr};
+}
+
+template<typename Class, typename MemType>
+inline auto mem_greater(MemType (Class::*ptr)() const) {
+    return detail::mem_compare<std::greater<>, Class, MemType, MemType (Class::*)() const>{ptr};
+}
+
+/**
+ * @brief mem_greater_equal is a binary functor that compares a member of the object to a
+ *                          given value or two objects based on the value of their members
+ *
+ * @see mem_less
+ */
+
+template<typename Class, typename MemType>
+inline auto mem_greater_equal(MemType Class::*ptr) {
+    return detail::mem_compare<std::greater_equal<>, Class, MemType, MemType Class::*>{ptr};
+}
+
+template<typename Class, typename MemType>
+inline auto mem_greater_equal(MemType (Class::*ptr)() const) {
+    return detail::mem_compare<std::greater_equal<>, Class, MemType, MemType (Class::*)() const>{ptr};
+}
+
+
 } // namespace kismpl
 
 #endif // KISMPL_H
diff --git a/libs/global/kis_shared_ptr.h b/libs/global/kis_shared_ptr.h
index cc00f73a235..0d41a3c2eb7 100644
--- a/libs/global/kis_shared_ptr.h
+++ b/libs/global/kis_shared_ptr.h
@@ -57,6 +57,9 @@ class KisSharedPtr
 {
     friend class KisWeakSharedPtr<T>;
 public:
+    using element_type = T;
+    using weak_type = KisWeakSharedPtr<T>;
+
     /**
      * Creates a null pointer.
      */
@@ -235,6 +238,8 @@ class KisWeakSharedPtr
 {
     friend class KisSharedPtr<T>;
 public:
+    using element_type = T;
+
     /**
      * Creates a null pointer.
      */
diff --git a/libs/image/kis_stroke.cpp b/libs/image/kis_stroke.cpp
index 75c639c5525..012b2aa219f 100644
--- a/libs/image/kis_stroke.cpp
+++ b/libs/image/kis_stroke.cpp
@@ -89,10 +89,7 @@ void KisStroke::addMutatedJobs(const QVector<KisStrokeJobData *> list)
     // the stroke.
 
     auto it = std::find_if(m_jobsQueue.begin(), m_jobsQueue.end(),
-        [] (KisStrokeJob *job) {
-            return job->isOwnJob();
-        });
-
+                           std::mem_fn(&KisStrokeJob::isOwnJob));
 
     Q_FOREACH (KisStrokeJobData *data, list) {
         it = m_jobsQueue.insert(it, new KisStrokeJob(m_dabStrategy.data(), data, worksOnLevelOfDetail(), true));
diff --git a/libs/image/lazybrush/kis_colorize_mask.cpp b/libs/image/lazybrush/kis_colorize_mask.cpp
index a6b1a0deda9..5c335c969f4 100644
--- a/libs/image/lazybrush/kis_colorize_mask.cpp
+++ b/libs/image/lazybrush/kis_colorize_mask.cpp
@@ -684,9 +684,7 @@ void KisColorizeMask::setCurrentColor(const KoColor &_color)
     QList<KeyStroke>::const_iterator it =
         std::find_if(m_d->keyStrokes.constBegin(),
                      m_d->keyStrokes.constEnd(),
-                     [color] (const KeyStroke &s) {
-                         return s.color == color;
-                     });
+                     kismpl::mem_equal_to(&KeyStroke::color, color));
 
     KisPaintDeviceSP activeDevice;
     bool newKeyStroke = false;
@@ -958,9 +956,7 @@ void KisColorizeMask::removeKeyStroke(const KoColor &_color)
     QList<KeyStroke>::iterator it =
         std::find_if(m_d->keyStrokes.begin(),
                      m_d->keyStrokes.end(),
-                     [color] (const KeyStroke &s) {
-                         return s.color == color;
-                     });
+                     kismpl::mem_equal_to(&KeyStroke::color, color));
 
     KIS_SAFE_ASSERT_RECOVER_RETURN(it != m_d->keyStrokes.end());
 
diff --git a/libs/image/tests/KisMplTest.cpp b/libs/image/tests/KisMplTest.cpp
index c716f7f02ea..a8daf601a63 100644
--- a/libs/image/tests/KisMplTest.cpp
+++ b/libs/image/tests/KisMplTest.cpp
@@ -13,7 +13,7 @@
 #include <KisMpl.h>
 
 
-void KisMplTest::test()
+void KisMplTest::testFoldOptional()
 {
     std::optional<int> a(0x1);
     std::optional<int> b(0x2);
@@ -34,4 +34,286 @@ void KisMplTest::test()
 
 }
 
+namespace {
+struct Struct {
+    Struct(int _id) : id(_id) {}
+
+    int id = -1;
+    int idFunc() {
+        return id;
+    }
+    int idConstFunc() const {
+        return id;
+    }
+
+    int overloaded() const {
+        return id;
+    }
+
+    int overloaded() {
+        return id;
+    }
+
+};
+
+struct StructExplicit {
+    explicit StructExplicit (int _id) : id(_id) {}
+
+    int id = -1;
+    int idConstFunc() const {
+        return id;
+    }
+};
+}
+
+void KisMplTest::testMemberOperatorsEqualTo()
+{
+    int v = 1;
+    int &vref = v;
+    const int &vconstref = v;
+
+
+    std::vector<Struct> vec({{0},{1},{2},{3}});
+
+    ////////////////////////////////////////
+    // compare member variable against value
+
+    {
+        auto it = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::id, v));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 1);
+    }
+
+    // compare member variable against reference
+
+    {
+        auto it = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::id, vref));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 1);
+    }
+
+    // compare member variable against const reference
+
+    {
+        auto it = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::id, vconstref));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 1);
+    }
+
+    ////////////////////////////////////////
+    // compare member function against value
+
+    {
+        auto it = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::idConstFunc, v));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 1);
+    }
+
+    // compare member function against reference
+
+    {
+        auto it = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::id, vref));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 1);
+    }
+
+    // compare member function against const reference
+
+    {
+        auto it = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::id, vconstref));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 1);
+    }
+
+    ////////////////////////////////////////
+    // compare overloaded member function against value
+
+    {
+        auto it = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::overloaded, v));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 1);
+    }
+
+    // compare member function against reference
+
+    {
+        auto it = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::overloaded, vref));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 1);
+    }
+
+    // compare member function against const reference
+
+    {
+        auto it = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::overloaded, vconstref));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 1);
+    }
+}
+
+void KisMplTest::testMemberOperatorsEqualToPointer()
+{
+    std::vector<Struct> vec_base({{0},{1},{2},{3},{4}});
+    std::vector<Struct*> vec({&vec_base[0], &vec_base[1], &vec_base[2], &vec_base[3], &vec_base[3]});
+
+    {
+        auto it = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::id, 1));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 1);
+    }
+}
+
+void KisMplTest::testMemberOperatorsEqualToStdSharedPtr()
+{
+    std::vector<std::shared_ptr<Struct>> vec({std::make_shared<Struct>(0),
+                                              std::make_shared<Struct>(1),
+                                              std::make_shared<Struct>(2),
+                                              std::make_shared<Struct>(3),
+                                              std::make_shared<Struct>(4)});
+
+
+    {
+        auto it = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::id, 1));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 1);
+    }
+}
+
+void KisMplTest::testMemberOperatorsEqualToQSharedPointer()
+{
+    std::vector<QSharedPointer<Struct>> vec({QSharedPointer<Struct>::create(0),
+                                             QSharedPointer<Struct>::create(1),
+                                             QSharedPointer<Struct>::create(2),
+                                             QSharedPointer<Struct>::create(3),
+                                             QSharedPointer<Struct>::create(4)});
+
+    {
+        auto it = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::id, 1));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 1);
+    }
+}
+
+void KisMplTest::testMemberOperatorsLess()
+{
+    {
+        std::vector<StructExplicit> vec({StructExplicit(0),StructExplicit(1),StructExplicit(2),StructExplicit(3),StructExplicit(4)});
+
+        auto it = std::lower_bound(vec.begin(), vec.end(), 2, kismpl::mem_less(&StructExplicit::id));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 2);
+    }
+
+    {
+        std::vector<StructExplicit> vec({StructExplicit(0),StructExplicit(1),StructExplicit(2),StructExplicit(3),StructExplicit(4)});
+
+        auto it = std::lower_bound(vec.begin(), vec.end(), 2, kismpl::mem_less(&StructExplicit::idConstFunc));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 2);
+    }
+
+
+    {
+        std::vector<StructExplicit> vec_base({StructExplicit(0),StructExplicit(1),StructExplicit(2),StructExplicit(3),StructExplicit(4)});
+        std::vector<StructExplicit*> vec({&vec_base[0], &vec_base[1], &vec_base[2], &vec_base[3], &vec_base[3]});
+
+        auto it = std::lower_bound(vec.begin(), vec.end(), 2, kismpl::mem_less(&StructExplicit::id));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 2);
+    }
+
+    {
+        std::vector<StructExplicit> vec_base({StructExplicit(0),StructExplicit(1),StructExplicit(2),StructExplicit(3),StructExplicit(4)});
+        std::vector<StructExplicit*> vec({&vec_base[0], &vec_base[1], &vec_base[2], &vec_base[3], &vec_base[3]});
+
+        auto it = std::lower_bound(vec.begin(), vec.end(), 2, kismpl::mem_less(&StructExplicit::idConstFunc));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 2);
+    }
+
+    {
+        std::vector<std::shared_ptr<StructExplicit>> vec({std::make_shared<StructExplicit>(0),
+                                                          std::make_shared<StructExplicit>(1),
+                                                          std::make_shared<StructExplicit>(2),
+                                                          std::make_shared<StructExplicit>(3),
+                                                          std::make_shared<StructExplicit>(4)});
+
+
+        auto it = std::lower_bound(vec.begin(), vec.end(), 2, kismpl::mem_less(&StructExplicit::id));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 2);
+    }
+
+    {
+        std::vector<std::shared_ptr<StructExplicit>> vec({std::make_shared<StructExplicit>(0),
+                                                          std::make_shared<StructExplicit>(1),
+                                                          std::make_shared<StructExplicit>(2),
+                                                          std::make_shared<StructExplicit>(3),
+                                                          std::make_shared<StructExplicit>(4)});
+
+
+        auto it = std::lower_bound(vec.begin(), vec.end(), 2, kismpl::mem_less(&StructExplicit::idConstFunc));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 2);
+    }
+}
+
+void KisMplTest::testMemberOperatorsLessEqual()
+{
+    {
+        std::vector<StructExplicit> vec({StructExplicit(0),StructExplicit(1),StructExplicit(2),StructExplicit(3),StructExplicit(4)});
+
+        auto it = std::lower_bound(vec.begin(), vec.end(), 2, kismpl::mem_less_equal(&StructExplicit::id));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 3);
+    }
+
+    {
+        std::vector<StructExplicit> vec({StructExplicit(0),StructExplicit(1),StructExplicit(2),StructExplicit(3),StructExplicit(4)});
+
+        auto it = std::lower_bound(vec.begin(), vec.end(), 2, kismpl::mem_less_equal(&StructExplicit::idConstFunc));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 3);
+    }
+}
+
+void KisMplTest::testMemberOperatorsGreater()
+{
+    {
+        std::vector<StructExplicit> vec({StructExplicit(4),StructExplicit(3),StructExplicit(2),StructExplicit(1),StructExplicit(0)});
+
+        auto it = std::lower_bound(vec.begin(), vec.end(), 2, kismpl::mem_greater(&StructExplicit::id));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 2);
+    }
+
+    {
+        std::vector<StructExplicit> vec({StructExplicit(4),StructExplicit(3),StructExplicit(2),StructExplicit(1),StructExplicit(0)});
+
+        auto it = std::lower_bound(vec.begin(), vec.end(), 2, kismpl::mem_greater(&StructExplicit::idConstFunc));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 2);
+    }
+}
+
+void KisMplTest::testMemberOperatorsGreaterEqual()
+{
+    {
+        std::vector<StructExplicit> vec({StructExplicit(4),StructExplicit(3),StructExplicit(2),StructExplicit(1),StructExplicit(0)});
+
+        auto it = std::lower_bound(vec.begin(), vec.end(), 2, kismpl::mem_greater_equal(&StructExplicit::id));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 3);
+    }
+
+    {
+        std::vector<StructExplicit> vec({StructExplicit(4),StructExplicit(3),StructExplicit(2),StructExplicit(1),StructExplicit(0)});
+
+        auto it = std::lower_bound(vec.begin(), vec.end(), 2, kismpl::mem_greater_equal(&StructExplicit::idConstFunc));
+        QVERIFY(it != vec.end());
+        QCOMPARE(std::distance(vec.begin(), it), 3);
+    }
+}
+
+
 SIMPLE_TEST_MAIN(KisMplTest)
diff --git a/libs/image/tests/KisMplTest.h b/libs/image/tests/KisMplTest.h
index fc1acdef48c..e983682d7f2 100644
--- a/libs/image/tests/KisMplTest.h
+++ b/libs/image/tests/KisMplTest.h
@@ -12,7 +12,16 @@ class KisMplTest : public QObject
 {
     Q_OBJECT
 private Q_SLOTS:
-    void test();
+    void testFoldOptional();
+    void testMemberOperatorsEqualTo();
+    void testMemberOperatorsEqualToPointer();
+    void testMemberOperatorsEqualToStdSharedPtr();
+    void testMemberOperatorsEqualToQSharedPointer();
+
+    void testMemberOperatorsLess();
+    void testMemberOperatorsLessEqual();
+    void testMemberOperatorsGreater();
+    void testMemberOperatorsGreaterEqual();
 };
 
 #endif // KISMPLTEST_H
diff --git a/libs/pigment/resources/KoStopGradient.cpp b/libs/pigment/resources/KoStopGradient.cpp
index a671f673cd6..a72974bd05b 100644
--- a/libs/pigment/resources/KoStopGradient.cpp
+++ b/libs/pigment/resources/KoStopGradient.cpp
@@ -143,9 +143,8 @@ bool KoStopGradient::stopsAt(KoGradientStop& leftStop, KoGradientStop& rightStop
     } else {
         // we have at least two color stops
         // -> find the two stops which frame our t
-        auto it = std::lower_bound(m_stops.begin(), m_stops.end(), KoGradientStop(t, KoColor(), COLORSTOP), [](const KoGradientStop& a, const KoGradientStop& b) {
-            return a.position < b.position;
-            });
+        auto it = std::lower_bound(m_stops.begin(), m_stops.end(), KoGradientStop(t, KoColor(), COLORSTOP),
+                                   kismpl::mem_less(&KoGradientStop::position));
         leftStop = *(it - 1);
         rightStop = *(it);
         return true;
@@ -257,10 +256,9 @@ QList<int> KoStopGradient::requiredCanvasResources() const
 {
     QList<int> result;
 
-    if (std::find_if(m_stops.begin(), m_stops.end(),
-                     [] (const KoGradientStop &stop) {
-                         return stop.type != COLORSTOP;
-                     }) != m_stops.end()) {
+    if (std::find_if_not(m_stops.begin(), m_stops.end(),
+                         kismpl::mem_equal_to(&KoGradientStop::type, COLORSTOP))
+        != m_stops.end()) {
 
         result << KoCanvasResource::ForegroundColor << KoCanvasResource::BackgroundColor;
     }
diff --git a/libs/ui/KisView.cpp b/libs/ui/KisView.cpp
index af8c4144d46..67b3834b6e1 100644
--- a/libs/ui/KisView.cpp
+++ b/libs/ui/KisView.cpp
@@ -622,9 +622,7 @@ void KisView::dropEvent(QDropEvent *event)
                 if (reference) {
                     if (data->hasUrls()) {
                         const auto &urls = data->urls();
-                        const auto url = std::find_if(urls.constBegin(), urls.constEnd(), [&](const QUrl &url) {
-                            return url.isLocalFile();
-                        });
+                        const auto url = std::find_if(urls.constBegin(), urls.constEnd(), std::mem_fn(&QUrl::isLocalFile));
                         if (url != urls.constEnd()) {
                             reference->setFilename((*url).toLocalFile());
                         }
diff --git a/libs/ui/animation/VideoExportOptionsDialog.cpp b/libs/ui/animation/VideoExportOptionsDialog.cpp
index 2fbd86f4d69..3e3817b4a1d 100644
--- a/libs/ui/animation/VideoExportOptionsDialog.cpp
+++ b/libs/ui/animation/VideoExportOptionsDialog.cpp
@@ -417,8 +417,7 @@ void KisVideoExportOptionsDialog::setHDRConfiguration(bool value) {
 int findIndexById(const QString &id, const QVector<KoID> &ids)
 {
     int index = -1;
-    auto it = std::find_if(ids.begin(), ids.end(),
-                           [id] (const KoID &item) { return item.id() == id; });
+    auto it = std::find_if(ids.begin(), ids.end(), kismpl::mem_equal_to(&KoID::id, id));
     if (it != ids.end()) {
         index = std::distance(ids.begin(), it);
     }
diff --git a/libs/ui/brushhud/kis_brush_hud_properties_config.cpp b/libs/ui/brushhud/kis_brush_hud_properties_config.cpp
index acf61fb67a1..df487f29e96 100644
--- a/libs/ui/brushhud/kis_brush_hud_properties_config.cpp
+++ b/libs/ui/brushhud/kis_brush_hud_properties_config.cpp
@@ -109,9 +109,7 @@ void KisBrushHudPropertiesConfig::filterProperties(
     Q_FOREACH (const QString &id, selectedIds) {
         auto it = std::find_if(skippedProperties->begin(),
                                skippedProperties->end(),
-                               [id] (KisUniformPaintOpPropertySP prop) {
-                                   return prop->id() == id;
-                               });
+                               kismpl::mem_equal_to(&KisUniformPaintOpProperty::id, id));
 
         if (it != skippedProperties->end()) {
             *chosenProperties << *it;
diff --git a/libs/ui/input/kis_input_manager.cpp b/libs/ui/input/kis_input_manager.cpp
index b514d32b60f..5c77319bf15 100644
--- a/libs/ui/input/kis_input_manager.cpp
+++ b/libs/ui/input/kis_input_manager.cpp
@@ -132,12 +132,12 @@ void KisInputManager::attachPriorityEventFilter(QObject *filter, int priority)
     Private::PriorityList::iterator end = d->priorityEventFilter.end();
 
     it = std::find_if(begin, end,
-                      [filter] (const Private::PriorityPair &a) { return a.second == filter; });
+                      kismpl::mem_equal_to(&Private::PriorityPair::second, filter));
 
     if (it != end) return;
 
     it = std::find_if(begin, end,
-                      [priority] (const Private::PriorityPair &a) { return a.first > priority; });
+                      kismpl::mem_greater(&Private::PriorityPair::first, priority));
 
     d->priorityEventFilter.insert(it, qMakePair(priority, filter));
     d->priorityEventFilterSeqNo++;
@@ -149,7 +149,7 @@ void KisInputManager::detachPriorityEventFilter(QObject *filter)
     Private::PriorityList::iterator end = d->priorityEventFilter.end();
 
     it = std::find_if(it, end,
-                      [filter] (const Private::PriorityPair &a) { return a.second == filter; });
+                      kismpl::mem_equal_to(&Private::PriorityPair::second, filter));
 
     if (it != end) {
         d->priorityEventFilter.erase(it);
diff --git a/libs/widgetutils/KisRecentFilesManager.cpp b/libs/widgetutils/KisRecentFilesManager.cpp
index 493c26f3ffb..b0536adc4f6 100644
--- a/libs/widgetutils/KisRecentFilesManager.cpp
+++ b/libs/widgetutils/KisRecentFilesManager.cpp
@@ -16,6 +16,7 @@
 #include <kconfig.h>
 #include <kconfiggroup.h>
 #include <ksharedconfig.h>
+#include <KisMpl.h>
 
 class KisRecentFilesManager::Private
 {
@@ -54,9 +55,8 @@ bool KisRecentFilesManager::Private::containsUrl(const QUrl &url) const
 
 int KisRecentFilesManager::Private::indexOfUrl(const QUrl &url) const
 {
-    auto found = std::find_if(m_entries.constBegin(), m_entries.constEnd(), [url](const KisRecentFilesEntry &item) {
-        return item.m_url == url;
-    });
+    auto found = std::find_if(m_entries.constBegin(), m_entries.constEnd(),
+                              kismpl::mem_equal_to(&KisRecentFilesEntry::m_url, url));
     if (found == m_entries.constEnd()) {
         return -1;
     } else {
diff --git a/plugins/dockers/layerdocker/NodeToolTip.cpp b/plugins/dockers/layerdocker/NodeToolTip.cpp
index d2996a0eead..62ea6887cf9 100644
--- a/plugins/dockers/layerdocker/NodeToolTip.cpp
+++ b/plugins/dockers/layerdocker/NodeToolTip.cpp
@@ -59,9 +59,9 @@ QTextDocument *NodeToolTip::createDocument(const QModelIndex &index)
     QString errorMessage;
     {
         auto it = std::find_if(properties.begin(), properties.end(),
-        [] (const KisBaseNode::Property &prop) {
-            return prop.id == KisLayerPropertiesIcons::layerError.id();
-        });
+                               kismpl::mem_equal_to(&KisBaseNode::Property::id,
+                                                    KisLayerPropertiesIcons::layerError.id()));
+
         if (it != properties.end()) {
             doc->addResource(QTextDocument::ImageResource, QUrl("data:warn_symbol"), it->onIcon.pixmap(QSize(32,32)).toImage());
             errorMessage = QString("<table align=\"center\" border=\"0\"><tr valign=\"middle\"><td align=\"right\"><img src=\"data:warn_symbol\"></td><td align=\"left\"><b>%1</b></td></tr></table>").arg(it->state.toString());
diff --git a/plugins/paintops/defaultpaintops/brush/KisDabRenderingQueue.cpp b/plugins/paintops/defaultpaintops/brush/KisDabRenderingQueue.cpp
index e22ede016bf..7e6baed4228 100644
--- a/plugins/paintops/defaultpaintops/brush/KisDabRenderingQueue.cpp
+++ b/plugins/paintops/defaultpaintops/brush/KisDabRenderingQueue.cpp
@@ -202,9 +202,7 @@ QList<KisDabRenderingJobSP> KisDabRenderingQueue::notifyJobFinished(int seqNo, i
      */
     auto finishedJobIt =
         std::lower_bound(m_d->jobs.begin(), m_d->jobs.end(), seqNo,
-                         [] (KisDabRenderingJobSP job, int seqNo) {
-                             return job->seqNo < seqNo;
-                         });
+                         kismpl::mem_less(&KisDabRenderingJob::seqNo));
 
     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(finishedJobIt != m_d->jobs.end(), dependentJobs);
     KisDabRenderingJobSP finishedJob = *finishedJobIt;
diff --git a/plugins/paintops/spray/KisSprayRandomDistributions.cpp b/plugins/paintops/spray/KisSprayRandomDistributions.cpp
index 27c4d855267..5498e4a0056 100644
--- a/plugins/paintops/spray/KisSprayRandomDistributions.cpp
+++ b/plugins/paintops/spray/KisSprayRandomDistributions.cpp
@@ -7,6 +7,7 @@
 #include <cmath>
 
 #include <kis_assert.h>
+#include <KisMpl.h>
 
 #include "KisSprayRandomDistributions.h"
 
@@ -152,8 +153,7 @@ public:
         // Find the first sample that has cdf greater than the passed value
         auto sampleIterator =
             std::upper_bound(samples.begin(), samples.end(), SampleInfo{0.0, randomValue, 0.0},
-                [](const SampleInfo &a, const SampleInfo &b) -> bool {  return a.cdfAtX < b.cdfAtX; }
-            );
+                             kismpl::mem_less(&SampleInfo::cdfAtX));
         const double t = (randomValue - (sampleIterator - 1)->cdfAtX) * sampleIterator->oneOverCdfDy;
         return (sampleIterator - 1)->x + t * (sampleIterator->x - (sampleIterator - 1)->x);
     }



More information about the kimageshop mailing list