aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKitsune Ral <Kitsune-Ral@users.sf.net>2018-04-02 14:13:11 +0900
committerKitsune Ral <Kitsune-Ral@users.sf.net>2018-04-02 14:13:11 +0900
commitd7725b45bfd33163840536f975853837aa8e4763 (patch)
treef97c12de84564de889ae976de57834e13d738127 /lib
parente003ffd274127a9f734f18c736d28be936a0dc89 (diff)
downloadlibquotient-d7725b45bfd33163840536f975853837aa8e4763.tar.gz
libquotient-d7725b45bfd33163840536f975853837aa8e4763.zip
lookup()/dispatch() removed; unique_ptr_cast() and qAsConst() introduced
qAsConst() is a copy-paste from Qt code and is only supplied by QMatrixClient if Qt is below 5.7. unique_ptr_cast<> is similar to static_cast<> of pointers but deals with unique_ptr's, passing ownership to the newly made pointer.
Diffstat (limited to 'lib')
-rw-r--r--lib/util.h178
1 files changed, 16 insertions, 162 deletions
diff --git a/lib/util.h b/lib/util.h
index 65de0610..92198b0b 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -22,171 +22,10 @@
#include <QtCore/QDebug>
#include <functional>
+#include <memory>
namespace QMatrixClient
{
- /**
- * @brief Lookup a value by a key in a varargs list
- *
- * This function template takes the value of its first argument (selector)
- * as a key and searches for it in the key-value map passed in
- * a parameter pack (every next pair of arguments forms a key-value pair).
- * If a match is found, the respective value is returned; if no pairs
- * matched, the last value (fallback) is returned.
- *
- * All options should be of the same type or implicitly castable to the
- * type of the first option. If you need some specific type to cast to
- * you can explicitly provide it as the ValueT template parameter
- * (e.g. <code>lookup<void*>(parameters...)</code>). Note that pointers
- * to methods of different classes and even to functions with different
- * signatures are of different types. If their return types are castable
- * to some common one, @see dispatch that deals with this by swallowing
- * the method invocation.
- *
- * Below is an example of usage to select a parser depending on contents of
- * a JSON object:
- * {@code
- * auto parser = lookup(obj.value["type"].toString(),
- * "type1", fn1,
- * "type2", fn2,
- * fallbackFn);
- * parser(obj);
- * }
- *
- * The implementation is based on tail recursion; every recursion step
- * removes 2 arguments (match and value). There's no selector value for the
- * fallback option (the last one); therefore, the total number of lookup()
- * arguments should be even: selector + n key-value pairs + fallback
- *
- * @note Beware of calling lookup() with a <code>const char*</code> selector
- * (the first parameter) - most likely it won't do what you expect because
- * of shallow comparison.
- */
- template <typename ValueT, typename SelectorT>
- ValueT lookup(SelectorT/*unused*/, ValueT&& fallback)
- {
- return std::forward<ValueT>(fallback);
- }
-
- template <typename ValueT, typename SelectorT, typename KeyT, typename... Ts>
- ValueT lookup(SelectorT&& selector, KeyT&& key, ValueT&& value, Ts&&... remainder)
- {
- if( selector == key )
- return std::forward<ValueT>(value);
-
- // Drop the failed key-value pair and recurse with 2 arguments less.
- return lookup<ValueT>(std::forward<SelectorT>(selector),
- std::forward<Ts>(remainder)...);
- }
-
- /**
- * A wrapper around lookup() for functions of different types castable
- * to a common std::function<> form
- *
- * This class uses std::function<> magic to first capture arguments of
- * a yet-unknown function or function object, and then to coerce types of
- * all functions/function objects passed for lookup to the type
- * std::function<ResultT(ArgTs...). Without Dispatch<>, you would have
- * to pass the specific function type to lookup, since your functions have
- * different signatures. The type is not always obvious, and the resulting
- * construct in client code would almost always be rather cumbersome.
- * Dispatch<> deduces the necessary function type (well, almost - you still
- * have to specify the result type) and hides the clumsiness. For more
- * information on what std::function<> can wrap around, see
- * https://cpptruths.blogspot.jp/2015/11/covariance-and-contravariance-in-c.html
- *
- * The function arguments are captured by value (i.e. copied) to avoid
- * hard-to-find issues with dangling references in cases when a Dispatch<>
- * object is passed across different contexts (e.g. returned from another
- * function).
- *
- * \tparam ResultT - the desired type of a picked function invocation (mandatory)
- * \tparam ArgTs - function argument types (deduced)
- */
-#if __GNUC__ < 5 && __GNUC_MINOR__ < 9
- // GCC 4.8 cannot cope with parameter packs inside lambdas; so provide a single
- // argument version of Dispatch<> that we only need so far.
- template <typename ResultT, typename ArgT>
-#else
- template <typename ResultT, typename... ArgTs>
-#endif
- class Dispatch
- {
- // The implementation takes a chapter from functional programming:
- // Dispatch<> uses a function that in turn accepts a function as its
- // argument. The sole purpose of the outer function (initialized by
- // a lambda-expression in the constructor) is to store the arguments
- // to any of the functions later looked up. The inner function (its
- // type is defined by fn_t alias) is the one returned by lookup()
- // invocation inside to().
- //
- // It's a bit counterintuitive to specify function parameters before
- // the list of functions but otherwise it would take several overloads
- // here to match all the ways a function-like behaviour can be done:
- // reference-to-function, pointer-to-function, function object. This
- // probably could be done as well but I preferred a more compact
- // solution: you show what you have and if it's possible to bring all
- // your functions to the same std::function<> based on what you have
- // as parameters, the code will compile. If it's not possible, modern
- // compilers are already good enough at pinpointing a specific place
- // where types don't match.
- public:
-#if __GNUC__ < 5 && __GNUC_MINOR__ < 9
- using fn_t = std::function<ResultT(ArgT)>;
- explicit Dispatch(ArgT&& arg)
- : boundArgs([=](fn_t &&f) { return f(std::move(arg)); })
- { }
-#else
- using fn_t = std::function<ResultT(ArgTs...)>;
- explicit Dispatch(ArgTs&&... args)
- : boundArgs([=](fn_t &&f) { return f(std::move(args)...); })
- { }
-#endif
-
- template <typename... LookupParamTs>
- ResultT to(LookupParamTs&&... lookupParams)
- {
- // Here's the magic, two pieces of it:
- // 1. Specifying fn_t in lookup() wraps all functions in
- // \p lookupParams into the same std::function<> type. This
- // includes conversion of return types from more specific to more
- // generic (because std::function is covariant by return types and
- // contravariant by argument types (see the link in the Doxygen
- // part of the comments).
- auto fn = lookup<fn_t>(std::forward<LookupParamTs>(lookupParams)...);
- // 2. Passing the result of lookup() to boundArgs() invokes the
- // lambda-expression mentioned in the constructor, which simply
- // invokes this passed function with a set of arguments captured
- // by lambda.
- if (fn)
- return boundArgs(std::move(fn));
-
- // A shortcut to allow passing nullptr for a function;
- // a default-constructed ResultT will be returned
- // (for pointers, it will be nullptr)
- return {};
- }
-
- private:
- std::function<ResultT(fn_t&&)> boundArgs;
- };
-
- /**
- * Dispatch a set of parameters to one of a set of functions, depending on
- * a selector value
- *
- * Use <code>dispatch<CommonType>(parameters).to(lookup parameters)</code>
- * instead of lookup() if you need to pick one of several functions returning
- * types castable to the same CommonType. See event.cpp for a typical use case.
- *
- * \see Dispatch
- */
- template <typename ResultT, typename... ArgTs>
- Dispatch<ResultT, ArgTs...> dispatch(ArgTs&& ... args)
- {
- return Dispatch<ResultT, ArgTs...>(std::forward<ArgTs>(args)...);
- }
-
// The below enables pretty-printing of enums in logs
#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
#define REGISTER_ENUM(EnumName) Q_ENUM(EnumName)
@@ -201,5 +40,20 @@ namespace QMatrixClient
return dbg << Event::staticMetaObject.enumerator(enumIdx).valueToKey(int(val)); \
}
#endif
+
+ template <typename T1, typename PtrT2>
+ inline auto unique_ptr_cast(PtrT2&& p)
+ {
+ return std::unique_ptr<T1>(static_cast<T1*>(p.release()));
+ }
+
+#if QT_VERSION < QT_VERSION_CHECK(5, 7, 0)
+ // Copy-pasted from Qt 5.10
+ template <typename T>
+ Q_DECL_CONSTEXPR typename std::add_const<T>::type &qAsConst(T &t) Q_DECL_NOTHROW { return t; }
+ // prevent rvalue arguments:
+ template <typename T>
+ static void qAsConst(const T &&) Q_DECL_EQ_DELETE;
+#endif
} // namespace QMatrixClient