// // cast.h // string-utils // // Created by Sam Jaffe on 2/13/21. // Copyright © 2021 Sam Jaffe. All rights reserved. // #pragma once #include #include #include #include #include #include #include #include "any_of.h" #define CAST_NUMBER_IMPL(type, func, ...) \ inline bool cast(std::string const & str, type & to) { \ char * rval; \ to = func(str.c_str(), &rval, ##__VA_ARGS__); \ return rval == str.c_str() + str.length(); \ } namespace string_utils { namespace traits { template struct is_stringy : std::false_type {}; template struct is_variant : std::false_type {}; template struct is_variant> : std::true_type {}; template struct is_stringy< T, std::enable_if_t{} && !is_variant{}>> : std::true_type {}; }} namespace string_utils { template std::pair cast(std::string const & str); template bool cast(std::string const & str, std::optional & to); template bool cast(std::string const & str, std::variant & to); template bool cast(std::vector const & str, std::tuple & to); template bool cast(std::vector const & str, std::pair & to); } namespace string_utils { template {}>> bool cast(std::string const & str, T & to) { to = T(str); return true; } CAST_NUMBER_IMPL(long, std::strtol, 10); CAST_NUMBER_IMPL(long long, std::strtoll, 10); CAST_NUMBER_IMPL(float, std::strtof); CAST_NUMBER_IMPL(double, std::strtod); CAST_NUMBER_IMPL(long double, std::strtold); inline bool cast(std::string const & str, int & to) { long tmp; bool rval = cast(str, tmp); to = static_cast(tmp); return rval && tmp == static_cast(to); } inline bool cast(std::string const & str, bool & to) { if (any_of(str, "true", "TRUE", "YES", "1")) { to = true; return true; } else if (any_of(str, "false", "FALSE", "NO", "0")) { to = false; return true; } return false; } } namespace string_utils::detail { template bool cast_alternative(std::string const & str, std::variant & to) { auto [rval, found] = cast(str); if (found) { to = std::move(rval); } return found; } template bool cast_tuple(std::vector const & str, Tuple & to, std::index_sequence) { return ((cast(str[Is], std::get(to))) && ...); } template bool cast_tuple(std::vector const & str, Tuple & to) { constexpr size_t N = std::tuple_size_v; return str.size() == N && cast_tuple(str, to, std::make_index_sequence{}); } } namespace string_utils { template bool cast(std::string const & str, std::variant & to) { return (detail::cast_alternative(str, to) || ...); } template bool cast(std::string const & str, std::optional & to) { auto [value, success] = cast(str); if (success) { to = std::move(value); } return true; } template bool cast(std::vector const & str, std::tuple & to) { return detail::cast_tuple(str, to); } template bool cast(std::vector const & str, std::pair & to) { return detail::cast_tuple(str, to); } } // This should be placed last in the file namespace string_utils { template std::pair cast(std::string const & str) { using string_utils::cast; std::pair rval; rval.second = cast(str, rval.first); return rval; } } #undef CAST_NUMBER_IMPL