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