summaryrefslogtreecommitdiff
path: root/boost/lexical_cast/detail/converter_numeric.hpp
diff options
context:
space:
mode:
authorChanho Park <chanho61.park@samsung.com>2014-12-11 18:55:56 +0900
committerChanho Park <chanho61.park@samsung.com>2014-12-11 18:55:56 +0900
commit08c1e93fa36a49f49325a07fe91ff92c964c2b6c (patch)
tree7a7053ceb8874b28ec4b868d4c49b500008a102e /boost/lexical_cast/detail/converter_numeric.hpp
parentbb4dd8289b351fae6b55e303f189127a394a1edd (diff)
downloadboost-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.hpp179
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
+