Chris@16: // Copyright Alexander Nasonov & Paul A. Bristow 2006. Chris@16: Chris@16: // Use, modification and distribution are subject to the Chris@16: // Boost Software License, Version 1.0. Chris@16: // (See accompanying file LICENSE_1_0.txt Chris@16: // or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED Chris@16: #define BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: #ifndef BOOST_NO_IS_ABSTRACT Chris@16: // Fix for SF:1358600 - lexical_cast & pure virtual functions & VC 8 STL Chris@16: #include Chris@16: #include Chris@16: #endif Chris@16: Chris@16: #if defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) || \ Chris@16: (defined(BOOST_MSVC) && (BOOST_MSVC<1310)) Chris@16: Chris@16: #define BOOST_LCAST_NO_COMPILE_TIME_PRECISION Chris@16: #endif Chris@16: Chris@16: #ifdef BOOST_LCAST_NO_COMPILE_TIME_PRECISION Chris@16: #include Chris@16: #else Chris@16: #include Chris@16: #endif Chris@16: Chris@16: namespace boost { namespace detail { Chris@16: Chris@16: class lcast_abstract_stub {}; Chris@16: Chris@16: #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION Chris@16: // Calculate an argument to pass to std::ios_base::precision from Chris@16: // lexical_cast. See alternative implementation for broken standard Chris@16: // libraries in lcast_get_precision below. Keep them in sync, please. Chris@16: template Chris@16: struct lcast_precision Chris@16: { Chris@16: #ifdef BOOST_NO_IS_ABSTRACT Chris@16: typedef std::numeric_limits limits; // No fix for SF:1358600. Chris@16: #else Chris@16: typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_< Chris@16: boost::is_abstract Chris@16: , std::numeric_limits Chris@16: , std::numeric_limits Chris@16: >::type limits; Chris@16: #endif Chris@16: Chris@16: BOOST_STATIC_CONSTANT(bool, use_default_precision = Chris@16: !limits::is_specialized || limits::is_exact Chris@16: ); Chris@16: Chris@16: BOOST_STATIC_CONSTANT(bool, is_specialized_bin = Chris@16: !use_default_precision && Chris@16: limits::radix == 2 && limits::digits > 0 Chris@16: ); Chris@16: Chris@16: BOOST_STATIC_CONSTANT(bool, is_specialized_dec = Chris@16: !use_default_precision && Chris@16: limits::radix == 10 && limits::digits10 > 0 Chris@16: ); Chris@16: Chris@16: BOOST_STATIC_CONSTANT(std::streamsize, streamsize_max = Chris@16: boost::integer_traits::const_max Chris@16: ); Chris@16: Chris@16: BOOST_STATIC_CONSTANT(unsigned int, precision_dec = limits::digits10 + 1U); Chris@16: Chris@16: BOOST_STATIC_ASSERT(!is_specialized_dec || Chris@16: precision_dec <= streamsize_max + 0UL Chris@16: ); Chris@16: Chris@16: BOOST_STATIC_CONSTANT(unsigned long, precision_bin = Chris@16: 2UL + limits::digits * 30103UL / 100000UL Chris@16: ); Chris@16: Chris@16: BOOST_STATIC_ASSERT(!is_specialized_bin || Chris@16: (limits::digits + 0UL < ULONG_MAX / 30103UL && Chris@16: precision_bin > limits::digits10 + 0UL && Chris@16: precision_bin <= streamsize_max + 0UL) Chris@16: ); Chris@16: Chris@16: BOOST_STATIC_CONSTANT(std::streamsize, value = Chris@16: is_specialized_bin ? precision_bin Chris@16: : is_specialized_dec ? precision_dec : 6 Chris@16: ); Chris@16: }; Chris@16: #endif Chris@16: Chris@16: template Chris@16: inline std::streamsize lcast_get_precision(T* = 0) Chris@16: { Chris@16: #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION Chris@16: return lcast_precision::value; Chris@16: #else // Follow lcast_precision algorithm at run-time: Chris@16: Chris@16: #ifdef BOOST_NO_IS_ABSTRACT Chris@16: typedef std::numeric_limits limits; // No fix for SF:1358600. Chris@16: #else Chris@16: typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_< Chris@16: boost::is_abstract Chris@16: , std::numeric_limits Chris@16: , std::numeric_limits Chris@16: >::type limits; Chris@16: #endif Chris@16: Chris@16: bool const use_default_precision = Chris@16: !limits::is_specialized || limits::is_exact; Chris@16: Chris@16: if(!use_default_precision) Chris@16: { // Includes all built-in floating-point types, float, double ... Chris@16: // and UDT types for which digits (significand bits) is defined (not zero) Chris@16: Chris@16: bool const is_specialized_bin = Chris@16: limits::radix == 2 && limits::digits > 0; Chris@16: bool const is_specialized_dec = Chris@16: limits::radix == 10 && limits::digits10 > 0; Chris@16: std::streamsize const streamsize_max = Chris@16: (boost::integer_traits::max)(); Chris@16: Chris@16: if(is_specialized_bin) Chris@16: { // Floating-point types with Chris@16: // limits::digits defined by the specialization. Chris@16: Chris@16: unsigned long const digits = limits::digits; Chris@16: unsigned long const precision = 2UL + digits * 30103UL / 100000UL; Chris@16: // unsigned long is selected because it is at least 32-bits Chris@16: // and thus ULONG_MAX / 30103UL is big enough for all types. Chris@16: BOOST_ASSERT( Chris@16: digits < ULONG_MAX / 30103UL && Chris@16: precision > limits::digits10 + 0UL && Chris@16: precision <= streamsize_max + 0UL Chris@16: ); Chris@16: return precision; Chris@16: } Chris@16: else if(is_specialized_dec) Chris@16: { // Decimal Floating-point type, most likely a User Defined Type Chris@16: // rather than a real floating-point hardware type. Chris@16: unsigned int const precision = limits::digits10 + 1U; Chris@16: BOOST_ASSERT(precision <= streamsize_max + 0UL); Chris@16: return precision; Chris@16: } Chris@16: } Chris@16: Chris@16: // Integral type (for which precision has no effect) Chris@16: // or type T for which limits is NOT specialized, Chris@16: // so assume stream precision remains the default 6 decimal digits. Chris@16: // Warning: if your User-defined Floating-point type T is NOT specialized, Chris@16: // then you may lose accuracy by only using 6 decimal digits. Chris@16: // To avoid this, you need to specialize T with either Chris@16: // radix == 2 and digits == the number of significand bits, Chris@16: // OR Chris@16: // radix = 10 and digits10 == the number of decimal digits. Chris@16: Chris@16: return 6; Chris@16: #endif Chris@16: } Chris@16: Chris@16: template Chris@16: inline void lcast_set_precision(std::ios_base& stream, T*) Chris@16: { Chris@16: stream.precision(lcast_get_precision()); Chris@16: } Chris@16: Chris@16: template Chris@16: inline void lcast_set_precision(std::ios_base& stream, Source*, Target*) Chris@16: { Chris@16: std::streamsize const s = lcast_get_precision(static_cast(0)); Chris@16: std::streamsize const t = lcast_get_precision(static_cast(0)); Chris@16: stream.precision(s > t ? s : t); Chris@16: } Chris@16: Chris@16: }} Chris@16: Chris@16: #endif // BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED Chris@16: