CodeMover prototype
[dyninst.git] / external / boost / detail / lcast_precision.hpp
1 // Copyright Alexander Nasonov & Paul A. Bristow 2006.\r
2 \r
3 // Use, modification and distribution are subject to the\r
4 // Boost Software License, Version 1.0.\r
5 // (See accompanying file LICENSE_1_0.txt\r
6 // or copy at http://www.boost.org/LICENSE_1_0.txt)\r
7 \r
8 #ifndef BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED\r
9 #define BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED\r
10 \r
11 #include <climits>\r
12 #include <ios>\r
13 #include <limits>\r
14 \r
15 #include <boost/config.hpp>\r
16 #include <boost/integer_traits.hpp>\r
17 \r
18 #ifndef BOOST_NO_IS_ABSTRACT\r
19 // Fix for SF:1358600 - lexical_cast & pure virtual functions & VC 8 STL\r
20 #include <boost/mpl/if.hpp>\r
21 #include <boost/type_traits/is_abstract.hpp>\r
22 #endif\r
23 \r
24 #if defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) || \\r
25   (defined(BOOST_MSVC) && (BOOST_MSVC<1310))\r
26 \r
27 #define BOOST_LCAST_NO_COMPILE_TIME_PRECISION\r
28 #endif\r
29 \r
30 #ifdef BOOST_LCAST_NO_COMPILE_TIME_PRECISION\r
31 #include <boost/assert.hpp>\r
32 #else\r
33 #include <boost/static_assert.hpp>\r
34 #endif\r
35 \r
36 namespace boost { namespace detail {\r
37 \r
38 class lcast_abstract_stub {};\r
39 \r
40 #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION\r
41 // Calculate an argument to pass to std::ios_base::precision from\r
42 // lexical_cast. See alternative implementation for broken standard\r
43 // libraries in lcast_get_precision below. Keep them in sync, please.\r
44 template<class T>\r
45 struct lcast_precision\r
46 {\r
47 #ifdef BOOST_NO_IS_ABSTRACT\r
48     typedef std::numeric_limits<T> limits; // No fix for SF:1358600.\r
49 #else\r
50     typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_<\r
51         boost::is_abstract<T>\r
52       , std::numeric_limits<lcast_abstract_stub>\r
53       , std::numeric_limits<T>\r
54       >::type limits;\r
55 #endif\r
56 \r
57     BOOST_STATIC_CONSTANT(bool, use_default_precision =\r
58             !limits::is_specialized || limits::is_exact\r
59         );\r
60 \r
61     BOOST_STATIC_CONSTANT(bool, is_specialized_bin =\r
62             !use_default_precision &&\r
63             limits::radix == 2 && limits::digits > 0\r
64         );\r
65 \r
66     BOOST_STATIC_CONSTANT(bool, is_specialized_dec =\r
67             !use_default_precision &&\r
68             limits::radix == 10 && limits::digits10 > 0\r
69         );\r
70 \r
71     BOOST_STATIC_CONSTANT(std::streamsize, streamsize_max =\r
72             boost::integer_traits<std::streamsize>::const_max\r
73         );\r
74 \r
75     BOOST_STATIC_CONSTANT(unsigned int, precision_dec = limits::digits10 + 1U);\r
76 \r
77     BOOST_STATIC_ASSERT(!is_specialized_dec ||\r
78             precision_dec <= streamsize_max + 0UL\r
79         );\r
80 \r
81     BOOST_STATIC_CONSTANT(unsigned long, precision_bin =\r
82             2UL + limits::digits * 30103UL / 100000UL\r
83         );\r
84 \r
85     BOOST_STATIC_ASSERT(!is_specialized_bin ||\r
86             (limits::digits + 0UL < ULONG_MAX / 30103UL &&\r
87             precision_bin > limits::digits10 + 0UL &&\r
88             precision_bin <= streamsize_max + 0UL)\r
89         );\r
90 \r
91     BOOST_STATIC_CONSTANT(std::streamsize, value =\r
92             is_specialized_bin ? precision_bin\r
93                                : is_specialized_dec ? precision_dec : 6\r
94         );\r
95 };\r
96 #endif\r
97 \r
98 template<class T>\r
99 inline std::streamsize lcast_get_precision(T* = 0)\r
100 {\r
101 #ifndef BOOST_LCAST_NO_COMPILE_TIME_PRECISION\r
102     return lcast_precision<T>::value;\r
103 #else // Follow lcast_precision algorithm at run-time:\r
104 \r
105 #ifdef BOOST_NO_IS_ABSTRACT\r
106     typedef std::numeric_limits<T> limits; // No fix for SF:1358600.\r
107 #else\r
108     typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_<\r
109         boost::is_abstract<T>\r
110       , std::numeric_limits<lcast_abstract_stub>\r
111       , std::numeric_limits<T>\r
112       >::type limits;\r
113 #endif\r
114 \r
115     bool const use_default_precision =\r
116         !limits::is_specialized || limits::is_exact;\r
117 \r
118     if(!use_default_precision)\r
119     { // Includes all built-in floating-point types, float, double ...\r
120       // and UDT types for which digits (significand bits) is defined (not zero)\r
121 \r
122         bool const is_specialized_bin =\r
123             limits::radix == 2 && limits::digits > 0;\r
124         bool const is_specialized_dec =\r
125             limits::radix == 10 && limits::digits10 > 0;\r
126         std::streamsize const streamsize_max =\r
127             (boost::integer_traits<std::streamsize>::max)();\r
128 \r
129         if(is_specialized_bin)\r
130         { // Floating-point types with\r
131           // limits::digits defined by the specialization.\r
132 \r
133             unsigned long const digits = limits::digits;\r
134             unsigned long const precision = 2UL + digits * 30103UL / 100000UL;\r
135             // unsigned long is selected because it is at least 32-bits\r
136             // and thus ULONG_MAX / 30103UL is big enough for all types.\r
137             BOOST_ASSERT(\r
138                     digits < ULONG_MAX / 30103UL &&\r
139                     precision > limits::digits10 + 0UL &&\r
140                     precision <= streamsize_max + 0UL\r
141                 );\r
142             return precision;\r
143         }\r
144         else if(is_specialized_dec)\r
145         {   // Decimal Floating-point type, most likely a User Defined Type\r
146             // rather than a real floating-point hardware type.\r
147             unsigned int const precision = limits::digits10 + 1U;\r
148             BOOST_ASSERT(precision <= streamsize_max + 0UL);\r
149             return precision;\r
150         }\r
151     }\r
152 \r
153     // Integral type (for which precision has no effect)\r
154     // or type T for which limits is NOT specialized,\r
155     // so assume stream precision remains the default 6 decimal digits.\r
156     // Warning: if your User-defined Floating-point type T is NOT specialized,\r
157     // then you may lose accuracy by only using 6 decimal digits.\r
158     // To avoid this, you need to specialize T with either\r
159     // radix == 2 and digits == the number of significand bits,\r
160     // OR\r
161     // radix = 10 and digits10 == the number of decimal digits.\r
162 \r
163     return 6;\r
164 #endif\r
165 }\r
166 \r
167 template<class T>\r
168 inline void lcast_set_precision(std::ios_base& stream, T*)\r
169 {\r
170     stream.precision(lcast_get_precision<T>());\r
171 }\r
172 \r
173 template<class Source, class Target>\r
174 inline void lcast_set_precision(std::ios_base& stream, Source*, Target*)\r
175 {\r
176     std::streamsize const s = lcast_get_precision((Source*)0);\r
177     std::streamsize const t = lcast_get_precision((Target*)0);\r
178     stream.precision(s > t ? s : t);\r
179 }\r
180 \r
181 }}\r
182 \r
183 #endif //  BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED\r
184 \r