/* Copyright (C) 2019 * * This file is part of the osdev components suite * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifndef OSDEV_COMPONENTS_MQTT_METAPROGRAMMINGDEFS_H #define OSDEV_COMPONENTS_MQTT_METAPROGRAMMINGDEFS_H #include // for std::size_t #include #include #include "utils.h" /** * @brief Create a type trait that checks for the existence of a member in a struct. * @param memberName The member name * * A call such as OSDEV_COMPONENTS_HASMEMBER_TRAIT(onSuccess) leads to a type trait has_onSuccess. */ #define OSDEV_COMPONENTS_HASMEMBER_TRAIT(memberName) \ template \ struct has_##memberName : public std::false_type \ { \ }; \ \ template \ struct has_##memberName().memberName)>> : public std::true_type \ { \ }; /** * @brief Create a type trait that checks for the existence of a member method with no parameters. * @param methodName The method name * @param postfix An extra postfix that is added to the type trait struct. * This makes it possible create type traits that check for * overloaded methods. * * A call such as OSDEV_COMPONENTS_HASMETHOD_TRAIT(capacity,1) leads to a type trait has_capacity1. */ #define OSDEV_COMPONENTS_HASMETHOD_TRAIT(methodName, postfix) \ template \ struct has_##methodName##postfix : public std::false_type \ { \ }; \ \ template \ struct has_##methodName##postfix().methodName())>> : public std::true_type \ { \ }; /** * @brief Create a type trait that checks for the existence of a member method with 1 or more parameters. * @param methodName The method name * @param postfix An extra postfix that is added to the type trait struct. * This makes it possible create type traits that check for * overloaded methods. * @param ... Variable number of arguments. These can be values, but also declval constructs such as std::declval(). * * A call such as OSDEV_COMPONENTS_HASMETHODWP_TRAIT(capacity,,"string") leads to a type trait has_capacity that * checks for the existence of a method capacity that accepts a const char pointer. */ #define OSDEV_COMPONENTS_HASMETHODWP_TRAIT(methodName, postfix, ...) \ template \ struct has_##methodName##postfix : public std::false_type \ { \ }; \ \ template \ struct has_##methodName##postfix().methodName(__VA_ARGS__))>> : public std::true_type \ { \ }; namespace osdev { namespace components { namespace mqtt { /** * @brief Used to detect ill formed types in a SFINAE context. * If the parameter pack Ts contains an invalid type, struct make_void cannot be expanded. */ template struct make_void { using type = void; }; /** * @brief Introduced in c++17 (but will also work in c++11) */ template using void_t = typename make_void::type; /// @brief Build an index list that can be used to traverse another list (f.i. a char array). /// Recursive definition. /// Start with an empty indices list. Build the indices list recursively. /// upper-1, indices... becomes the indices... in the next recursive call. template class meta_functor, std::size_t... Is> struct apply_bounded_range { typedef typename apply_bounded_range::result result; }; /// @brief Terminator of apply_bounded_range. /// Terminates when the upper bound (which runs) is equal to the lower bound. template class meta_functor, std::size_t... Is> struct apply_bounded_range { typedef typename meta_functor::result result; }; /** * @brief Helper method to perform static_assert on the expected count of a parameter pack. */ template void static_assert_count() { constexpr std::size_t actualCount = sizeof...(Args); static_assert(expectedCount == actualCount, "Unexpected parameter count."); } /** * @brief Helper method to convert a type to std::string. * @param d_first The output iterator to write the converted string to. * @param arg The argument to convert to std::string. */ template int apply_to_string_one(OutputIt d_first, const T& arg) { std::ostringstream ss; ss << arg; *d_first++ = ss.str(); return 0; } /** * @brief Converts all parameters to std::string. * @param d_first The output iterator to write the converted strings to. * @param args The arguments to convert to std::string. */ template void apply_to_string(OutputIt d_first, Args&&... args) { // d_first is not used when args parameter pack is empty. apply_unused_parameters(d_first); // We need to use the expand_type trick in order to be able to use an initializer list // so that we can call the method for every variadic argument using expand_type = int[]; // Array must be initialized with values. Add a single value so that the array can be initialized when the parameter pack is empty. expand_type et{ 0, apply_to_string_one(d_first, std::forward(args))... }; apply_unused_parameters(et); } /** * @brief Helper that removes const, volatile and reference from a type. * @note Defined in std C++20. */ template struct remove_cvref { using type = typename std::remove_cv::type>::type; }; } // End namespace mqtt } // End namespace components } // End namespace osdev #endif // OSDEV_COMPONENTS_MQTT_METAPROGRAMMINGDEFS_H