diff options
author | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-03-31 13:16:02 +0900 |
---|---|---|
committer | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2018-03-31 14:23:55 +0900 |
commit | efeb50a46ad824aa258472f6ac8da74810f05a55 (patch) | |
tree | a89c6f35d56986c60e73f870530c9d6ee0527e6d /util.h | |
parent | 29093379b707bfe620234c2968b37aa86666542a (diff) | |
download | libquotient-efeb50a46ad824aa258472f6ac8da74810f05a55.tar.gz libquotient-efeb50a46ad824aa258472f6ac8da74810f05a55.zip |
Move source files to a separate folder
It's been long overdue to separate them from the rest of the stuff (docs etc.). Also, this allows installing to a directory within the checked out git tree (say, ./install/, similar to ./build/).
Diffstat (limited to 'util.h')
-rw-r--r-- | util.h | 205 |
1 files changed, 0 insertions, 205 deletions
diff --git a/util.h b/util.h deleted file mode 100644 index 65de0610..00000000 --- a/util.h +++ /dev/null @@ -1,205 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2016 Kitsune Ral <kitsune-ral@users.sf.net> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#pragma once - -#include <QtCore/QMetaEnum> -#include <QtCore/QDebug> - -#include <functional> - -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) -#else - // Thanks to Olivier for spelling it and for making Q_ENUM to replace it: - // https://woboq.com/blog/q_enum.html -#define REGISTER_ENUM(EnumName) \ - Q_ENUMS(EnumName) \ - friend QDebug operator<<(QDebug dbg, EnumName val) \ - { \ - static int enumIdx = staticMetaObject.indexOfEnumerator(#EnumName); \ - return dbg << Event::staticMetaObject.enumerator(enumIdx).valueToKey(int(val)); \ - } -#endif -} // namespace QMatrixClient - |