diff options
author | Chanho Park <chanho61.park@samsung.com> | 2014-12-11 18:55:56 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-12-11 18:55:56 +0900 |
commit | 08c1e93fa36a49f49325a07fe91ff92c964c2b6c (patch) | |
tree | 7a7053ceb8874b28ec4b868d4c49b500008a102e /boost/lexical_cast/detail/converter_numeric.hpp | |
parent | bb4dd8289b351fae6b55e303f189127a394a1edd (diff) | |
download | boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.gz boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.bz2 boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.zip |
Imported Upstream version 1.57.0upstream/1.57.0
Diffstat (limited to 'boost/lexical_cast/detail/converter_numeric.hpp')
-rw-r--r-- | boost/lexical_cast/detail/converter_numeric.hpp | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/boost/lexical_cast/detail/converter_numeric.hpp b/boost/lexical_cast/detail/converter_numeric.hpp new file mode 100644 index 0000000000..83600f7e0b --- /dev/null +++ b/boost/lexical_cast/detail/converter_numeric.hpp @@ -0,0 +1,179 @@ +// Copyright Kevlin Henney, 2000-2005. +// Copyright Alexander Nasonov, 2006-2010. +// Copyright Antony Polukhin, 2011-2014. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// what: lexical_cast custom keyword cast +// who: contributed by Kevlin Henney, +// enhanced with contributions from Terje Slettebo, +// with additional fixes and suggestions from Gennaro Prota, +// Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov, +// Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann, +// Cheng Yang, Matthew Bradbury, David W. Birdsall, Pavel Korzh and other Boosters +// when: November 2000, March 2003, June 2005, June 2006, March 2011 - 2014 + +#ifndef BOOST_LEXICAL_CAST_DETAIL_CONVERTER_NUMERIC_HPP +#define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_NUMERIC_HPP + +#include <boost/config.hpp> +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + +#include <boost/limits.hpp> +#include <boost/mpl/if.hpp> +#include <boost/type_traits/ice.hpp> +#include <boost/type_traits/make_unsigned.hpp> +#include <boost/type_traits/is_signed.hpp> +#include <boost/type_traits/is_integral.hpp> +#include <boost/type_traits/is_arithmetic.hpp> +#include <boost/type_traits/is_base_of.hpp> + +#include <boost/numeric/conversion/cast.hpp> + +namespace boost { namespace detail { + +template <class Source > +struct detect_precision_loss +{ + typedef Source source_type; + typedef boost::numeric::Trunc<Source> Rounder; + typedef BOOST_DEDUCED_TYPENAME mpl::if_< + boost::is_arithmetic<Source>, Source, Source const& + >::type argument_type ; + + static inline source_type nearbyint(argument_type s, bool& is_ok) BOOST_NOEXCEPT { + const source_type near_int = Rounder::nearbyint(s); + if (near_int && is_ok) { + const source_type orig_div_round = s / near_int; + const source_type eps = std::numeric_limits<source_type>::epsilon(); + + is_ok = !((orig_div_round > 1 ? orig_div_round - 1 : 1 - orig_div_round) > eps); + } + + return s; + } + + typedef typename Rounder::round_style round_style; +}; + +template <typename Base, class Source> +struct fake_precision_loss: public Base +{ + typedef Source source_type ; + typedef BOOST_DEDUCED_TYPENAME mpl::if_< + boost::is_arithmetic<Source>, Source, Source const& + >::type argument_type ; + + static inline source_type nearbyint(argument_type s, bool& /*is_ok*/) BOOST_NOEXCEPT { + return s; + } +}; + +struct nothrow_overflow_handler +{ + inline bool operator() ( boost::numeric::range_check_result r ) const BOOST_NOEXCEPT { + return (r == boost::numeric::cInRange); + } +}; + +template <typename Target, typename Source> +inline bool noexcept_numeric_convert(const Source& arg, Target& result) BOOST_NOEXCEPT { + typedef boost::numeric::converter< + Target, + Source, + boost::numeric::conversion_traits<Target, Source >, + nothrow_overflow_handler, + detect_precision_loss<Source > + > converter_orig_t; + + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< + boost::is_base_of< detect_precision_loss<Source >, converter_orig_t >::value, + converter_orig_t, + fake_precision_loss<converter_orig_t, Source> + >::type converter_t; + + bool res = nothrow_overflow_handler()(converter_t::out_of_range(arg)); + result = converter_t::low_level_convert(converter_t::nearbyint(arg, res)); + return res; +} + +template <typename Target, typename Source> +struct lexical_cast_dynamic_num_not_ignoring_minus +{ + static inline bool try_convert(const Source &arg, Target& result) BOOST_NOEXCEPT { + return noexcept_numeric_convert<Target, Source >(arg, result); + } +}; + +template <typename Target, typename Source> +struct lexical_cast_dynamic_num_ignoring_minus +{ + static inline bool try_convert(const Source &arg, Target& result) BOOST_NOEXCEPT { + typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if_c< + boost::is_float<Source>::value, + boost::mpl::identity<Source>, + boost::make_unsigned<Source> + >::type usource_t; + + if (arg < 0) { + const bool res = noexcept_numeric_convert<Target, usource_t>(0u - arg, result); + result = static_cast<Target>(0u - result); + return res; + } else { + return noexcept_numeric_convert<Target, usource_t>(arg, result); + } + } +}; + +/* + * lexical_cast_dynamic_num follows the rules: + * 1) If Source can be converted to Target without precision loss and + * without overflows, then assign Source to Target and return + * + * 2) If Source is less than 0 and Target is an unsigned integer, + * then negate Source, check the requirements of rule 1) and if + * successful, assign static_casted Source to Target and return + * + * 3) Otherwise throw a bad_lexical_cast exception + * + * + * Rule 2) required because boost::lexical_cast has the behavior of + * stringstream, which uses the rules of scanf for conversions. And + * in the C99 standard for unsigned input value minus sign is + * optional, so if a negative number is read, no errors will arise + * and the result will be the two's complement. + */ +template <typename Target, typename Source> +struct dynamic_num_converter_impl +{ + static inline bool try_convert(const Source &arg, Target& result) BOOST_NOEXCEPT { + typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c< + boost::type_traits::ice_and< + boost::is_unsigned<Target>::value, + boost::type_traits::ice_or< + boost::is_signed<Source>::value, + boost::is_float<Source>::value + >::value, + boost::type_traits::ice_not< + boost::is_same<Source, bool>::value + >::value, + boost::type_traits::ice_not< + boost::is_same<Target, bool>::value + >::value + >::value, + lexical_cast_dynamic_num_ignoring_minus<Target, Source>, + lexical_cast_dynamic_num_not_ignoring_minus<Target, Source> + >::type caster_type; + + return caster_type::try_convert(arg, result); + } +}; + +}} // namespace boost::detail + +#endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_NUMERIC_HPP + |