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

0001 /*
0002  *  SPDX-FileCopyrightText: 2021 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef KISMPL_H
0008 #define KISMPL_H
0009 
0010 #include <tuple>
0011 #include <utility>
0012 #include <optional>
0013 #include <functional>
0014 
0015 /**
0016  * 'kismpl' stands for kis-meta-program-library
0017  */
0018 namespace kismpl {
0019 
0020 namespace detail {
0021 
0022 template<std::size_t ...Idx>
0023 struct make_index_sequence_from_1_impl;
0024 
0025 template<std::size_t num, std::size_t ...Idx>
0026 struct make_index_sequence_from_1_impl<num, Idx...> {
0027     using type = typename make_index_sequence_from_1_impl<num - 1, num, Idx...>::type;
0028 };
0029 
0030 template<std::size_t ...Idx>
0031 struct make_index_sequence_from_1_impl<0, Idx...> {
0032     using type = std::index_sequence<Idx...>;
0033 };
0034 
0035 }  // namespace detail
0036 
0037 /**
0038  * Creates an index sequence in range 1, 2, 3, ..., Num
0039  *
0040  * Same as std::make_index_sequence, but starts counting
0041  * from 1 instead of 0.
0042  */
0043 template<std::size_t Num>
0044 using make_index_sequence_from_1 =
0045     typename detail::make_index_sequence_from_1_impl<Num>::type;
0046 
0047 namespace detail {
0048 
0049 template <typename F, typename Tuple, std::size_t... I>
0050 auto apply_to_tuple_impl(F f, Tuple &&t, std::index_sequence<I...>) {
0051     return std::make_tuple(f(std::get<I>(std::forward<Tuple>(t)))...);
0052 }
0053 }
0054 
0055 /**
0056  * Apply a given functor F to each element of the tuple and
0057  * return a tuple consisting of the resulting values.
0058  */
0059 template <typename F, typename Tuple>
0060 auto apply_to_tuple(F f, Tuple &&t) {
0061     return detail::apply_to_tuple_impl(std::forward<F>(f), std::forward<Tuple>(t),
0062                                        std::make_index_sequence<std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
0063 }
0064 
0065 /**
0066  * Convert a given functor f accepting multiple arguments into
0067  * a function that accepts a tuple with the same number of
0068  * elements
0069  */
0070 constexpr auto unzip_wrapper = [] (auto f) {
0071     return
0072         [=] (auto &&x) {
0073             return std::apply(f, std::forward<decltype(x)>(x));
0074         };
0075 };
0076 
0077 namespace detail {
0078 
0079 template <typename First, typename... Rest>
0080 struct first_type_impl
0081 {
0082     using type = First;
0083 };
0084 
0085 }
0086 
0087 /**
0088  * Return the first type of a parameter pack
0089  */
0090 template <typename... T>
0091 struct first_type
0092 {
0093     using type = typename detail::first_type_impl<T...>::type;
0094 };
0095 
0096 /**
0097  * A helper function to return the first type of a parameter
0098  * pack
0099  */
0100 template <typename... T>
0101 using first_type_t = typename first_type<T...>::type;
0102 
0103 namespace detail {
0104 template <typename Fun, typename T>
0105 struct fold_optional_impl {
0106     std::optional<T> fold(const std::optional<T> &first) {
0107         return first;
0108     }
0109 
0110     std::optional<T> fold(const std::optional<T> &first, const std::optional<T> &second) {
0111         if (first && second) {
0112             return m_fun(*first, *second);
0113         } else if (first) {
0114             return first;
0115         } else {
0116             return second;
0117         }
0118     }
0119 
0120     template <typename... Rest>
0121     std::optional<T> fold(const std::optional<T> &first, std::optional<T> const &second, const std::optional<Rest> &...rest) {
0122         return fold(fold(first, second), rest...);
0123     }
0124 
0125     const Fun m_fun;
0126 };
0127 
0128 } // namespace detail
0129 
0130 /**
0131  * Folds all the valid optional values using the binary function \p fun into one
0132  * optional value. When none optional values are present, an empty optional of the
0133  * specified type is returned.
0134  */
0135 template <typename Fun, typename... Args,
0136          typename T = typename first_type_t<std::remove_reference_t<Args>...>::value_type>
0137 std::optional<T> fold_optional(Fun &&fun, Args &&...args) {
0138     return detail::fold_optional_impl<Fun, T>{std::forward<Fun>(fun)}.fold(args...);
0139 }
0140 
0141 /**
0142  * A helper class for creation of a visitor for an std::visit
0143  */
0144 template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
0145 template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
0146 
0147 namespace detail {
0148 
0149 template<typename Op, typename Class, typename MemType, typename PtrType>
0150 struct mem_checker
0151 {
0152     template <typename Object>
0153     bool operator() (Object &&obj) const {
0154         Op op;
0155         return op(std::invoke(ptr, std::forward<Object>(obj)), value);
0156     }
0157 
0158     PtrType ptr;
0159     const MemType value;
0160 };
0161 
0162 template<typename Op, typename Class, typename MemType, typename PtrType>
0163 struct mem_compare
0164 {
0165     template <typename Object>
0166     bool operator() (Object &&lhs, Object &&rhs) const {
0167         Op op;
0168         return op(std::invoke(ptr, std::forward<Object>(lhs)),
0169                   std::invoke(ptr, std::forward<Object>(rhs)));
0170     }
0171 
0172     template <typename Object>
0173     bool operator() (Object &&lhs, const MemType &rhs) const {
0174         Op op;
0175         return op(std::invoke(ptr, std::forward<Object>(lhs)),
0176                   rhs);
0177     }
0178 
0179     template <typename Object>
0180     bool operator() (const MemType &lhs, Object &&rhs) const {
0181         Op op;
0182         return op(lhs,
0183                   std::invoke(ptr, std::forward<Object>(rhs)));
0184     }
0185 
0186     PtrType ptr;
0187 };
0188 
0189 } // detail
0190 
0191 /**
0192  * @brief mem_equal_to is an unary functor that compares a member of the object to
0193  *                     a given value
0194  *
0195  * The functor is supposed to be used in `std::find_if` and other standard algorithms.
0196  * It can automatically dereference a pointer-to-member or a pointer-to-method.
0197  *
0198  *  * Usage:
0199  *
0200  *        \code{.cpp}
0201  *
0202  *        struct Struct {
0203  *            Struct (int _id) : id(_id) {}
0204  *
0205  *            int id = -1;
0206  *            int idConstFunc() const {
0207  *                return id;
0208  *            }
0209  *        };
0210  *
0211  *        std::vector<Struct> vec({{0},{1},{2},{3}});
0212  *
0213  *        // find an element, which has member 'id' set to 1
0214  *        auto it1 = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::id, 1));
0215  *
0216  *        // find an element, whose member function 'idConstFunc()' returns 1
0217  *        auto it2 = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::idConstFunc, 1));
0218  *
0219  *        // the functor can automatically dereference pointers and shared pointers
0220  *        std::vector<std::shared_ptr<Struct>> vec({std::make_shared<Struct>(0),
0221  *                                                  std::make_shared<Struct>(1),
0222  *                                                  std::make_shared<Struct>(2),
0223  *                                                  std::make_shared<Struct>(3),
0224  *                                                  std::make_shared<Struct>(4)});
0225  *
0226  *        // the shared pointer is automatically lifted by the functor
0227  *        auto it3 = std::find_if(vec.begin(), vec.end(), kismpl::mem_equal_to(&Struct::id, 1));
0228  *
0229  *        \endcode
0230  */
0231 
0232 template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
0233 inline auto mem_equal_to(MemTypeNoRef Class::*ptr, MemType &&value) {
0234     return detail::mem_checker<std::equal_to<>, Class, MemTypeNoRef, decltype(ptr)>{ptr, std::forward<MemType>(value)};
0235 }
0236 
0237 template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
0238 inline auto mem_equal_to(MemTypeNoRef (Class::*ptr)() const, MemType &&value) {
0239     return detail::mem_checker<std::equal_to<>, Class, MemTypeNoRef, decltype(ptr)>{ptr, std::forward<MemType>(value)};
0240 }
0241 
0242 /**
0243  * @brief mem_less is an unary functor that compares a member of the object to
0244  *                 a given value
0245  *
0246  * @see mem_equal_to
0247  */
0248 
0249 template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
0250 inline auto mem_less(MemTypeNoRef Class::*ptr, MemType &&value) {
0251     return detail::mem_checker<std::less<>, Class, MemTypeNoRef, decltype(ptr)>{ptr, std::forward<MemType>(value)};
0252 }
0253 
0254 template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
0255 inline auto mem_less(MemTypeNoRef (Class::*ptr)() const, MemType &&value) {
0256     return detail::mem_checker<std::less<>, Class, MemTypeNoRef, decltype(ptr)>{ptr, std::forward<MemType>(value)};
0257 }
0258 
0259 /**
0260  * @brief mem_less_equal is an unary functor that compares a member of the object to
0261  *                       a given value
0262  *
0263  * @see mem_equal_to
0264  */
0265 
0266 template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
0267 inline auto mem_less_equal(MemTypeNoRef Class::*ptr, MemType &&value) {
0268     return detail::mem_checker<std::less_equal<>, Class, MemTypeNoRef, decltype(ptr)>{ptr, std::forward<MemType>(value)};
0269 }
0270 
0271 template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
0272 inline auto mem_less_equal(MemTypeNoRef (Class::*ptr)() const, MemType &&value) {
0273     return detail::mem_checker<std::less_equal<>, Class, MemTypeNoRef, decltype(ptr)>{ptr, std::forward<MemType>(value)};
0274 }
0275 
0276 /**
0277  * @brief mem_greater is an unary functor that compares a member of the object to
0278  *                    a given value
0279  *
0280  * @see mem_equal_to
0281  */
0282 
0283 template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
0284 inline auto mem_greater(MemTypeNoRef Class::*ptr, MemType &&value) {
0285     return detail::mem_checker<std::greater<>, Class, MemTypeNoRef, decltype(ptr)>{ptr, std::forward<MemType>(value)};
0286 }
0287 
0288 template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
0289 inline auto mem_greater(MemTypeNoRef (Class::*ptr)() const, MemType &&value) {
0290     return detail::mem_checker<std::greater<>, Class, MemTypeNoRef, decltype(ptr)>{ptr, std::forward<MemType>(value)};
0291 }
0292 
0293 /**
0294  * @brief mem_greater_equal is an unary functor that compares a member of the object to
0295  *                          a given value
0296  *
0297  * @see mem_equal_to
0298  */
0299 
0300 
0301 template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
0302 inline auto mem_greater_equal(MemTypeNoRef Class::*ptr, MemType &&value) {
0303     return detail::mem_checker<std::greater_equal<>, Class, MemTypeNoRef, decltype(ptr)>{ptr, std::forward<MemType>(value)};
0304 }
0305 
0306 template<typename Class, typename MemType, typename MemTypeNoRef = std::remove_reference_t<MemType>>
0307 inline auto mem_greater_equal(MemTypeNoRef (Class::*ptr)() const, MemType &&value) {
0308     return detail::mem_checker<std::greater_equal<>, Class, MemTypeNoRef, decltype(ptr)>{ptr, std::forward<MemType>(value)};
0309 }
0310 
0311 /**
0312  * @brief mem_less is a binary functor that compares a member of the object to a
0313  *                 given value or two objects based on the value of their members
0314  *
0315  * The functor is supposed to be used in `std::lower_bound` and other standard algorithms.
0316  * It can automatically dereference a pointer-to-member or a pointer-to-method.
0317  *
0318  *  * Usage:
0319  *
0320  *        \code{.cpp}
0321  *
0322  *        struct Struct {
0323  *            Struct (int _id) : id(_id) {}
0324  *
0325  *            int id = -1;
0326  *            int idConstFunc() const {
0327  *                return id;
0328  *            }
0329  *        };
0330  *
0331  *        std::vector<Struct> vec({{0},{1},{2},{3}});
0332  *
0333  *        // find the first element, whose 'id' is not less that 1
0334  *        auto it1 = std::lower_bound(vec.begin(), vec.end(), 1, kismpl::mem_less(&Struct::id));
0335  *
0336  *        // find the first element, whose 'id' retunred by 'idConstFunc()' is not less that 1
0337  *        auto it2 = std::lower_bound(vec.begin(), vec.end(), 1, kismpl::mem_less(&Struct::idConstFunc, 1));
0338  *
0339  *        // the functor can automatically dereference pointers and shared pointers
0340  *        std::vector<std::shared_ptr<Struct>> vec({std::make_shared<Struct>(0),
0341  *                                                  std::make_shared<Struct>(1),
0342  *                                                  std::make_shared<Struct>(2),
0343  *                                                  std::make_shared<Struct>(3),
0344  *                                                  std::make_shared<Struct>(4)});
0345  *
0346  *        // the shared pointer is automatically lifted by the functor
0347  *        auto it3 = std::lower_bound(vec.begin(), vec.end(), 1, kismpl::mem_less(&Struct::id));
0348  *
0349  *        \endcode
0350  */
0351 
0352 template<typename Class, typename MemType>
0353 inline auto mem_less(MemType Class::*ptr) {
0354     return detail::mem_compare<std::less<>, Class, MemType, decltype(ptr)>{ptr};
0355 }
0356 
0357 template<typename Class, typename MemType>
0358 inline auto mem_less(MemType (Class::*ptr)() const) {
0359     return detail::mem_compare<std::less<>, Class, MemType, decltype(ptr)>{ptr};
0360 }
0361 
0362 /**
0363  * @brief mem_less_equal is a binary functor that compares a member of the object to a
0364  *                       given value or two objects based on the value of their members
0365  *
0366  * @see mem_less
0367  */
0368 template<typename Class, typename MemType>
0369 inline auto mem_less_equal(MemType Class::*ptr) {
0370     return detail::mem_compare<std::less_equal<>, Class, MemType, decltype(ptr)>{ptr};
0371 }
0372 
0373 template<typename Class, typename MemType>
0374 inline auto mem_less_equal(MemType (Class::*ptr)() const) {
0375     return detail::mem_compare<std::less_equal<>, Class, MemType, decltype(ptr)>{ptr};
0376 }
0377 
0378 /**
0379  * @brief mem_greater is a binary functor that compares a member of the object to a
0380  *                    given value or two objects based on the value of their members
0381  *
0382  * @see mem_less
0383  */
0384 
0385 template<typename Class, typename MemType>
0386 inline auto mem_greater(MemType Class::*ptr) {
0387     return detail::mem_compare<std::greater<>, Class, MemType, decltype(ptr)>{ptr};
0388 }
0389 
0390 template<typename Class, typename MemType>
0391 inline auto mem_greater(MemType (Class::*ptr)() const) {
0392     return detail::mem_compare<std::greater<>, Class, MemType, decltype(ptr)>{ptr};
0393 }
0394 
0395 /**
0396  * @brief mem_greater_equal is a binary functor that compares a member of the object to a
0397  *                          given value or two objects based on the value of their members
0398  *
0399  * @see mem_less
0400  */
0401 
0402 template<typename Class, typename MemType>
0403 inline auto mem_greater_equal(MemType Class::*ptr) {
0404     return detail::mem_compare<std::greater_equal<>, Class, MemType, decltype(ptr)>{ptr};
0405 }
0406 
0407 template<typename Class, typename MemType>
0408 inline auto mem_greater_equal(MemType (Class::*ptr)() const) {
0409     return detail::mem_compare<std::greater_equal<>, Class, MemType, decltype(ptr)>{ptr};
0410 }
0411 
0412 /**
0413  * A simple wrapper class that executes a passed lambda
0414  * on destruction. It might be used for cleaning-up resources,
0415  * which are not a part of normal RAII relationships.
0416  */
0417 template <typename F>
0418 struct finally {
0419     finally(F &&f)
0420         : m_f(std::forward<F>(f))
0421     {
0422     }
0423 
0424     finally(const finally &) = delete;
0425     finally(finally &&) = delete;
0426 
0427     ~finally() {
0428         m_f();
0429     }
0430 private:
0431     F m_f;
0432 };
0433 
0434 
0435 } // namespace kismpl
0436 
0437 #endif // KISMPL_H