/* **************************************************************************** * Copyright 2019 Open Systems Development BV * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * * DEALINGS IN THE SOFTWARE. * * ***************************************************************************/ #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