/******************************************************************************* * * MIT License * * Copyright (c) 2017 Advanced Micro Devices, Inc. * * 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 GUARD_MIOPEN_TEST_ARGS_HPP #define GUARD_MIOPEN_TEST_ARGS_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace args { using string_map = std::unordered_map>; template string_map parse(std::vector as, IsKeyword is_keyword) { string_map result; std::string flag; for(auto&& x : as) { if(is_keyword(x)) { flag = x; result[flag]; // Ensure the flag exists } else { result[flag].push_back(x); } } return result; } namespace detail { template auto is_container(miopen::rank<1>, T&& x) -> decltype(x.insert(x.end(), *x.begin()), std::true_type{}); template std::false_type is_container(miopen::rank<0>, T&&); template auto is_input_streamable(miopen::rank<1>, T&& x, U&& y) -> decltype((x >> y), std::true_type{}); template std::false_type is_input_streamable(miopen::rank<0>, T&&, U&&); template auto is_output_streamable(miopen::rank<1>, T&& x, U&& y) -> decltype((x << y), std::true_type{}); template std::false_type is_output_streamable(miopen::rank<0>, T&&, U&&); template struct requires_bool { static const bool value = B; }; template struct requires_unwrap : T { }; } // namespace detail template struct is_container : decltype(detail::is_container(miopen::rank<1>{}, std::declval())){}; template struct is_input_streamable : decltype(detail::is_input_streamable( miopen::rank<1>{}, std::declval(), std::declval::type>())){}; template struct is_output_streamable : decltype(detail::is_output_streamable( miopen::rank<1>{}, std::declval(), std::declval::type>())){}; #ifdef _MSC_VER #define ARGS_REQUIRES_BOOL(...) \ args::detail::requires_unwrap{}), \ __LINE__>::value #else #define ARGS_REQUIRES_BOOL(...) (__VA_ARGS__) #endif #define ARGS_REQUIRES(...) \ bool MIOPEN_PP_CAT( \ RequiresBool, \ __LINE__) = true, \ typename std::enable_if::type = 0 template struct value_parser { template {} and not std::is_pointer{} and not std::is_enum{})> static T apply(const std::string& x) { T result; std::stringstream ss; ss.str(x); ss >> result; if(ss.fail()) throw std::runtime_error("Failed to parse: " + x); return result; } template {})> static T apply(const std::string& x) { std::ptrdiff_t i; std::stringstream ss; ss.str(x); ss >> i; if(ss.fail()) throw std::runtime_error("Failed to parse: " + x); return static_cast(i); } }; struct any_value { std::string s; template ::apply(std::string{})), ARGS_REQUIRES(not std::is_enum{})> operator T() const { return value_parser::apply(s); } }; template auto any_construct_impl(miopen::rank<1>, std::index_sequence, const Data& d) -> decltype(T(any_value{d[Ns]}...)) { return T(any_value{d[Ns]}...); } template [[noreturn]] T any_construct_impl(miopen::rank<0>, std::index_sequence, const Data&) { throw std::runtime_error("Cannot construct: " + miopen::get_type_name()); } template T any_construct(const Data& d) { return any_construct_impl(miopen::rank<1>{}, std::make_index_sequence(), d); } struct write_value { template using is_multi_value = std::integral_constant{} and not std::is_convertible{})>; template {})> void operator()(Container& result, std::vector params) const { using value_type = typename Container::value_type; for(auto&& s : params) { result.insert(result.end(), value_parser::apply(s)); } } template {} and is_input_streamable{})> void operator()(T& result, std::vector params) const { if(params.empty()) throw std::runtime_error("Missing argument"); result = value_parser::apply(params.back()); } template {} and not is_input_streamable{})> void operator()(T& result, std::vector params) const { switch(params.size()) { case 0: { result = any_construct(params); break; } case 1: { result = any_construct(params); break; } case 2: { result = any_construct(params); break; } case 3: { result = any_construct(params); break; } case 4: { result = any_construct(params); break; } case 5: { result = any_construct(params); break; } case 6: { result = any_construct(params); break; } case 7: { result = any_construct(params); break; } default: throw std::runtime_error("Cannot construct: " + miopen::get_type_name()); } } }; struct read_value { template {} and not is_output_streamable{})> std::string operator()(Container& xs) const { if(xs.begin() == xs.end()) return ""; return std::accumulate(xs.begin() + 1, xs.end(), (*this)(*xs.begin()), [&](auto x, auto y) { return x + " " + (*this)(y); }); } template {})> std::string operator()(T& x) const { std::stringstream ss; ss << x; return ss.str(); } }; } // namespace args #endif // GUARD_MIOPEN_TEST_ARGS_HPP