/* Copyright (C) 2009 - 2018 by Mark de Wever Part of the Battle for Wesnoth Project https://www.wesnoth.org/ 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 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. See the COPYING file for more details. */ /** * @file * New lexcical_cast header. * * For debugging you can include this header _in_ a namespace (to honor ODR) * and have a set of functions that throws exceptions instead of doing the * real job. This is done for the unit tests but should normally not be done. */ #ifdef LEXICAL_CAST_DEBUG #undef LEXICAL_CAST_HPP_INCLUDED #endif #ifndef LEXICAL_CAST_HPP_INCLUDED #define LEXICAL_CAST_HPP_INCLUDED #ifdef LEXICAL_CAST_DEBUG #undef DEBUG_THROW /** * Throws an exception for debugging. * * @param id The unique name to identify the function. * @note this name is a user defined string and * should not be modified once used! */ #define DEBUG_THROW(id) throw id; #else #ifdef __FreeBSD__ #define __LONG_LONG_SUPPORTED #endif #include "global.hpp" #include #include #include #include #include #include #include #define DEBUG_THROW(id) #endif /** * @namespace implementation * Contains the implementation details for lexical_cast and shouldn't be used * directly. */ namespace implementation { template< typename To , typename From , typename ToEnable = void , typename FromEnable = void > struct lexical_caster; } // namespace implementation /** * Lexical cast converts one type to another. * * @tparam To The type to convert to. * @tparam From The type to convert from. * * @param value The value to convert. * * @returns The converted value. * * @throw bad_lexical_cast if the cast was unsuccessful. */ template inline To lexical_cast(From value) { return implementation::lexical_caster().operator()(value, boost::none); } /** * Lexical cast converts one type to another with a fallback. * * @tparam To The type to convert to. * @tparam From The type to convert from. * * @param value The value to convert. * @param fallback The fallback value to return if the cast fails. * * @returns The converted value. */ template inline To lexical_cast_default(From value, To fallback = To()) { return implementation::lexical_caster().operator()(value, fallback); } /** Thrown when a lexical_cast fails. */ struct bad_lexical_cast : std::exception { const char* what() const noexcept { return "bad_lexical_cast"; } }; namespace implementation { /** * Base class for the conversion. * * Since functions can't be partially specialized we use a class, which can be * partially specialized for the conversion. * * @tparam To The type to convert to. * @tparam From The type to convert from. * @tparam ToEnable Filter to enable the To type. * @tparam FromEnable Filter to enable the From type. */ template< typename To , typename From , typename ToEnable , typename FromEnable > struct lexical_caster { To operator()(From value, boost::optional fallback) const { DEBUG_THROW("generic"); To result = To(); std::stringstream sstr; if(!(sstr << value && sstr >> result)) { if(fallback) { return fallback.get(); } throw bad_lexical_cast(); } else { return result; } } }; /** * Specialized conversion class. * * Specialized for returning strings from an integral type or a pointer to an * integral type. */ template struct lexical_caster< std::string , From , void , std::enable_if_t>::value> > { std::string operator()(From value, boost::optional) const { DEBUG_THROW("specialized - To std::string - From integral (pointer)"); std::stringstream sstr; sstr << value; return sstr.str(); } }; /** * Specialized conversion class. * * Specialized for returning a long long from a (const) char*. * @note is separate from the other signed types since a long long has a * performance penalty at 32 bit systems. */ template struct lexical_caster< long long , From , void , std::enable_if_t , From>::value> > { long long operator()(From value, boost::optional fallback) const { DEBUG_THROW("specialized - To long long - From (const) char*"); if(fallback) { return lexical_cast_default(std::string(value), fallback.get()); } else { return lexical_cast(std::string(value)); } } }; /** * Specialized conversion class. * * Specialized for returning a long long from a std::string. * @note is separate from the other signed types since a long long has a * performance penalty at 32 bit systems. */ template <> struct lexical_caster< long long , std::string > { long long operator()(const std::string& value, boost::optional fallback) const { DEBUG_THROW("specialized - To long long - From std::string"); try { return std::stoll(value); } catch(const std::invalid_argument&) { } catch(const std::out_of_range&) { } if(fallback) { return fallback.get(); } else { throw bad_lexical_cast(); } } }; /** * Specialized conversion class. * * Specialized for returning a signed type from a (const) char*. */ template struct lexical_caster< To , From , std::enable_if_t::value && std::is_signed::value && !std::is_same::value> , std::enable_if_t , From>::value> > { To operator()(From value, boost::optional fallback) const { DEBUG_THROW("specialized - To signed - From (const) char*"); if(fallback) { return lexical_cast_default(std::string(value), fallback.get()); } else { return lexical_cast(std::string(value)); } } }; /** * Specialized conversion class. * * Specialized for returning a signed type from a std::string. */ template struct lexical_caster< To , std::string , std::enable_if_t::value && std::is_signed::value && !std::is_same::value> > { To operator()(const std::string& value, boost::optional fallback) const { DEBUG_THROW("specialized - To signed - From std::string"); try { long res = std::stol(value); if(std::numeric_limits::lowest() <= res && std::numeric_limits::max() >= res) { return static_cast(res); } } catch(const std::invalid_argument&) { } catch(const std::out_of_range&) { } if(fallback) { return fallback.get(); } else { throw bad_lexical_cast(); } } }; /** * Specialized conversion class. * * Specialized for returning a floating point type from a (const) char*. */ template struct lexical_caster< To , From , std::enable_if_t::value> , std::enable_if_t , From>::value> > { To operator()(From value, boost::optional fallback) const { DEBUG_THROW("specialized - To floating point - From (const) char*"); if(fallback) { return lexical_cast_default(std::string(value), fallback.get()); } else { return lexical_cast(std::string(value)); } } }; /** * Specialized conversion class. * * Specialized for returning a floating point type from a std::string. */ template struct lexical_caster< To , std::string , std::enable_if_t::value> > { To operator()(const std::string& value, boost::optional fallback) const { DEBUG_THROW("specialized - To floating point - From std::string"); // Explicitly reject hexadecimal values. Unit tests of the config class require that. if(value.find_first_of("Xx") != std::string::npos) { if(fallback) { return fallback.get(); } else { throw bad_lexical_cast(); } } try { long double res = std::stold(value); if((static_cast(std::numeric_limits::lowest()) <= res) && (static_cast(std::numeric_limits::max()) >= res)) { return static_cast(res); } } catch(const std::invalid_argument&) { } catch(const std::out_of_range&) { } if(fallback) { return fallback.get(); } else { throw bad_lexical_cast(); } } }; /** * Specialized conversion class. * * Specialized for returning a unsigned long long from a (const) char*. * @note is separate from the other unsigned types since a unsigned long long * has a performance penalty at 32 bit systems. */ template struct lexical_caster< unsigned long long , From , void , std::enable_if_t , From>::value> > { unsigned long long operator()(From value, boost::optional fallback) const { DEBUG_THROW( "specialized - To unsigned long long - From (const) char*"); if(fallback) { return lexical_cast_default(std::string(value), fallback.get()); } else { return lexical_cast(std::string(value)); } } }; /** * Specialized conversion class. * * Specialized for returning a unsigned long long from a std::string. * @note is separate from the other unsigned types since a unsigned long long * has a performance penalty at 32 bit systems. */ template <> struct lexical_caster< unsigned long long , std::string > { unsigned long long operator()(const std::string& value, boost::optional fallback) const { DEBUG_THROW("specialized - To unsigned long long - From std::string"); try { return std::stoull(value); } catch(const std::invalid_argument&) { } catch(const std::out_of_range&) { } if(fallback) { return fallback.get(); } else { throw bad_lexical_cast(); } } }; /** * Specialized conversion class. * * Specialized for returning a unsigned type from a (const) char*. */ template struct lexical_caster< To , From , std::enable_if_t::value && !std::is_same::value> , std::enable_if_t , From>::value> > { To operator()(From value, boost::optional fallback) const { DEBUG_THROW("specialized - To unsigned - From (const) char*"); if(fallback) { return lexical_cast_default(std::string(value), fallback.get()); } else { return lexical_cast(std::string(value)); } } }; /** * Specialized conversion class. * * Specialized for returning a unsigned type from a std::string. */ template struct lexical_caster< To , std::string , std::enable_if_t::value> > { To operator()(const std::string& value, boost::optional fallback) const { DEBUG_THROW("specialized - To unsigned - From std::string"); try { unsigned long res = std::stoul(value); // No need to check the lower bound, it's zero for all unsigned types. if(std::numeric_limits::max() >= res) { return static_cast(res); } } catch(const std::invalid_argument&) { } catch(const std::out_of_range&) { } if(fallback) { return fallback.get(); } else { throw bad_lexical_cast(); } } }; } // namespace implementation #endif