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