File indexing completed on 2024-06-23 04:27:51
0001 /* 0002 * SPDX-FileCopyrightText: 2022 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 #ifndef KISOPTIONTUPLE_H 0007 #define KISOPTIONTUPLE_H 0008 0009 #include <KisMpl.h> 0010 #include <boost/operators.hpp> 0011 #include <boost/tti/has_static_member_data.hpp> 0012 0013 namespace detail { 0014 0015 BOOST_TTI_HAS_STATIC_MEMBER_DATA(supports_prefix) 0016 0017 /** 0018 * A simple metafunction that detects the precence of 0019 * 'supports_prefix' and checks its value. 0020 */ 0021 template <typename T, bool has_member = has_static_member_data_supports_prefix<T, const bool>::value> 0022 struct supports_prefix; 0023 0024 template <typename T> 0025 struct supports_prefix<T, false> 0026 : std::bool_constant<false> 0027 { 0028 }; 0029 0030 template <typename T> 0031 struct supports_prefix<T, true> 0032 : std::bool_constant<T::supports_prefix> 0033 { 0034 }; 0035 0036 /** 0037 * Check if all the passed types define 'support_prefix = true' 0038 */ 0039 template <typename... T> 0040 struct all_support_prefix 0041 { 0042 static constexpr bool value = (supports_prefix<T>::value && ...); 0043 }; 0044 0045 /** 0046 * Check if none the passed types defines 'support_prefix = true' 0047 */ 0048 template <typename... T> 0049 struct none_support_prefix 0050 { 0051 static constexpr bool value = (!supports_prefix<T>::value && ...); 0052 }; 0053 0054 template <bool allSupportPrefix, bool noneSupportPrefix, typename... Data> 0055 struct KisOptionTupleImpl 0056 { 0057 static_assert (allSupportPrefix || noneSupportPrefix, 0058 "Either **all** or **none** arguments of KisOptionTuple should define 'supports_prefix'"); 0059 }; 0060 0061 /** 0062 * A prefix-supporting implementation of KisOptionTuple 0063 */ 0064 template <typename FirstData, typename... RestData> 0065 struct KisOptionTupleImpl<true, false, FirstData, RestData...> 0066 : public FirstData, 0067 public RestData..., 0068 public boost::equality_comparable<KisOptionTupleImpl<true, false, FirstData, RestData...>> 0069 { 0070 template <typename... T> 0071 KisOptionTupleImpl(const QString &prefix, T... args) 0072 : FirstData(prefix, std::forward<decltype(args)>(args)...), 0073 RestData(prefix)... 0074 { 0075 } 0076 0077 inline friend bool operator==(const KisOptionTupleImpl<true, false, FirstData, RestData...> &lhs, 0078 const KisOptionTupleImpl<true, false, FirstData, RestData...> &rhs) 0079 { 0080 0081 return ((static_cast<const FirstData&>(lhs) == static_cast<const FirstData&>(rhs)) && ... && 0082 (static_cast<const RestData&>(lhs) == static_cast<const RestData&>(rhs))); 0083 } 0084 0085 bool read(const KisPropertiesConfiguration *setting) 0086 { 0087 return (static_cast<FirstData&>(*this).read(setting) && ... && 0088 static_cast<RestData&>(*this).read(setting)); 0089 } 0090 0091 void write(KisPropertiesConfiguration *setting) const 0092 { 0093 (static_cast<const FirstData&>(*this).write(setting) , ... , 0094 static_cast<const RestData&>(*this).write(setting)); 0095 } 0096 0097 }; 0098 0099 /** 0100 * An implementation of KisOptionTuple without prefix support 0101 */ 0102 template <typename... Data> 0103 struct KisOptionTupleImpl<false, true, Data...> 0104 : public Data..., 0105 public boost::equality_comparable<KisOptionTupleImpl<false, true, Data...>> 0106 { 0107 template <typename... T> 0108 KisOptionTupleImpl(T... args) 0109 : kismpl::first_type_t<Data...>(std::forward<decltype(args)>(args)...) 0110 { 0111 } 0112 0113 inline friend bool operator==(const KisOptionTupleImpl<false, true, Data...> &lhs, 0114 const KisOptionTupleImpl<false, true, Data...> &rhs) 0115 { 0116 0117 return ((static_cast<const Data&>(lhs) == static_cast<const Data&>(rhs)) && ... ); 0118 } 0119 0120 bool read(const KisPropertiesConfiguration *setting) 0121 { 0122 return (static_cast<Data&>(*this).read(setting) && ... ); 0123 } 0124 0125 void write(KisPropertiesConfiguration *setting) const 0126 { 0127 (static_cast<const Data&>(*this).write(setting) , ... ); 0128 } 0129 }; 0130 0131 } // namespace detail 0132 0133 /** 0134 * KisOptionTuple is a class that merges multiple option 0135 * data structs into one by inheriting from all of them. 0136 * 0137 * KisOptionTuple automatically generates read, write and 0138 * operator== methods for the resulting class. 0139 * 0140 * You may later access the merged types via 0141 * kislager::lenses::to_base<BaseData> lens. 0142 * 0143 * Restrictions: 0144 * 0145 * 1) The merged structs must have **different** types 0146 * 2) The arguments passed to the constructor are passed 0147 * to constructor of the first base class of in the list. 0148 * 0149 * 0150 * Prefixed data structures 0151 * 0152 * If **all** the passed data types support 'prefixed' 0153 * read and write (that is, define 0154 * 'static constexpr bool T::supports_prefix = true'), 0155 * then the tuple switches into a "prefixed" mode: 0156 * 0157 * 1) KisOptionTuple's first constructor argument starts 0158 * accepting a prefix string 0159 * 0160 * 2) This prefix string is passed to all data objects' 0161 * constructors 0162 * 0163 * 3) The rest of the constructor's arguments are passed 0164 * to the first data object only 0165 * 0166 * Restrictions: 0167 * 0168 * 1) Either **all** or **none** data types must support 0169 * prefixed mode (and define 'supports_prefix). Otherwise 0170 * KisOptionTuple will fail to compile. 0171 */ 0172 0173 template <typename... Data> 0174 using KisOptionTuple = 0175 detail::KisOptionTupleImpl<detail::all_support_prefix<Data...>::value, 0176 detail::none_support_prefix<Data...>::value, 0177 Data...>; 0178 0179 #endif // KISOPTIONTUPLE_H