File indexing completed on 2024-05-19 04:25:09

0001 /*
0002  *  SPDX-FileCopyrightText: 2023 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #ifndef KISLAGER_H
0007 #define KISLAGER_H
0008 
0009 #include <QtGlobal>
0010 #include <type_traits>
0011 #include "KisMpl.h"
0012 
0013 #include <lager/lenses.hpp>
0014 #include <lager/reader.hpp>
0015 
0016 
0017 namespace kislager {
0018 
0019 /**
0020  * Fold all valid optional cursors from a set into one by using \p func
0021  *
0022  * Example:
0023  *
0024  * std::optional<lager::reader<int>> brushSize1 = ...;
0025  * std::optional<lager::reader<int>> brushSize2 = ...;
0026  *
0027  * std::optional<lager::reader<int>> maxSize =
0028  *     fold_optional_cursors(&std::max, brushSize1, brushSize2);
0029  *
0030  * The resulting reader 'maxSize' will hold the maximum value of the two
0031  * brushes, or nothing if the source readers do not exist.
0032  */
0033 template <typename Func, typename... Cursors,
0034          typename FirstCursor = typename kismpl::first_type_t<std::remove_reference_t<Cursors>...>::value_type,
0035          typename T = typename FirstCursor::value_type>
0036 std::optional<lager::reader<T>> fold_optional_cursors(const Func &func, Cursors&& ...cursors) {
0037     auto fold_func = [func] (const auto &lhs, const auto &rhs) {
0038         return lager::with(lhs, rhs).map(func);
0039     };
0040 
0041     return kismpl::fold_optional(fold_func, cursors...);
0042 }
0043 
0044 namespace lenses {
0045 template <typename T>
0046 auto scale = [] (T multiplier) {
0047     return lager::lenses::getset(
0048         [multiplier] (T value) { return value * multiplier; },
0049         [multiplier] (T, T value) { return value / multiplier; }
0050         );
0051 };
0052 
0053 constexpr auto scale_int_to_real = [] (qreal multiplier) {
0054     return lager::lenses::getset(
0055         [multiplier] (int value) { return value * multiplier; },
0056         [multiplier] (int, qreal value) { return qRound(value / multiplier); }
0057         );
0058 };
0059 
0060 constexpr auto scale_real_to_int = [] (qreal multiplier) {
0061     return lager::lenses::getset(
0062         [multiplier] (qreal value) { return qRound(value * multiplier); },
0063         [multiplier] (qreal, int value) { return value / multiplier; }
0064         );
0065 };
0066 
0067 template <typename Src, typename Dst>
0068 auto do_static_cast = lager::lenses::getset(
0069     [] (Src value) { return static_cast<Dst>(value); },
0070     [] (Src, Dst value) { return static_cast<Src>(value); }
0071     );
0072 
0073 /**
0074  * A lens that accesses a base class \p Base of the derived
0075  * type \p Derived
0076  *
0077  * to_base2 variant accepts two types, Base and Derived,
0078  * which might be convenient for debugging.
0079  */
0080 template <typename Derived, typename Base,
0081          typename = std::enable_if_t<
0082              std::is_base_of_v<Base, Derived>>>
0083 auto to_base2 = lager::lenses::getset(
0084     [] (const Derived &value) -> Base { return static_cast<const Base&>(value); },
0085     [] (Derived src, const Base &value) { static_cast<Base&>(src) = value; return src; }
0086     );
0087 
0088 /**
0089  * A lens that accesses a base class \p Base of the derived
0090  * type \p Derived
0091  *
0092  * to_base variant accepts only one type \p Base, that is,
0093  * destination type into which we should convert the value
0094  * to
0095  */
0096 template <typename Base>
0097 auto to_base = lager::lenses::getset(
0098     [] (const auto &value) -> Base { return static_cast<const Base&>(value); },
0099     [] (auto src, const Base &value) { static_cast<Base&>(src) = value; return src; }
0100     );
0101 
0102 } // namespace lenses
0103 
0104 } // namespace kislager
0105 
0106 
0107 #endif // KISLAGER_H