Apply patch for [CVE-2012-2677][boost] ordered_malloc() overflow
[external/boost.git] / libs / utility / numeric_traits_test.cpp
1 //  (C) Copyright David Abrahams 2001.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5
6 //  See http://www.boost.org for most recent version including documentation.
7
8 //  Revision History
9 //  1  Apr 2001 Fixes for ICL; use BOOST_STATIC_CONSTANT
10 //  11 Feb 2001 Fixes for Borland (David Abrahams)
11 //  23 Jan 2001 Added test for wchar_t (David Abrahams)
12 //  23 Jan 2001 Now statically selecting a test for signed numbers to avoid
13 //              warnings with fancy compilers. Added commentary and
14 //              additional dumping of traits data for tested types (David
15 //              Abrahams).
16 //  21 Jan 2001 Initial version (David Abrahams)
17
18 #include <boost/detail/numeric_traits.hpp>
19 #include <cassert>
20 #include <boost/type_traits.hpp>
21 #include <boost/static_assert.hpp>
22 #include <boost/cstdint.hpp>
23 #include <boost/utility.hpp>
24 #include <boost/lexical_cast.hpp>
25 #include <climits>
26 #include <typeinfo>
27 #include <iostream>
28 #include <string>
29 #ifndef BOOST_NO_LIMITS
30 # include <limits>
31 #endif
32
33 // =================================================================================
34 // template class complement_traits<Number> --
35 //
36 //    statically computes the max and min for 1s and 2s-complement binary
37 //    numbers. This helps on platforms without <limits> support. It also shows
38 //    an example of a recursive template that works with MSVC!
39 //
40
41 template <unsigned size> struct complement; // forward
42
43 // The template complement, below, does all the real work, using "poor man's
44 // partial specialization". We need complement_traits_aux<> so that MSVC doesn't
45 // complain about undefined min/max as we're trying to recursively define them. 
46 template <class Number, unsigned size>
47 struct complement_traits_aux
48 {
49     BOOST_STATIC_CONSTANT(Number, max = complement<size>::template traits<Number>::max);
50     BOOST_STATIC_CONSTANT(Number, min = complement<size>::template traits<Number>::min);
51 };
52
53 template <unsigned size>
54 struct complement
55 {
56     template <class Number>
57     struct traits
58     {
59      private:
60         // indirection through complement_traits_aux necessary to keep MSVC happy
61         typedef complement_traits_aux<Number, size - 1> prev;
62      public:
63 #if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && __GNUC_PATCHLEVEL__ == 2
64       // GCC 4.0.2 ICEs on these C-style casts
65         BOOST_STATIC_CONSTANT(Number, max =
66                             Number((prev::max) << CHAR_BIT)
67                             + Number(UCHAR_MAX));
68         BOOST_STATIC_CONSTANT(Number, min = Number((prev::min) << CHAR_BIT));
69 #else
70         BOOST_STATIC_CONSTANT(Number, max =
71                             Number(Number(prev::max) << CHAR_BIT)
72                             + Number(UCHAR_MAX));
73         BOOST_STATIC_CONSTANT(Number, min = Number(Number(prev::min) << CHAR_BIT));
74 #endif
75    
76     };
77 };
78
79 // Template class complement_base<> -- defines values for min and max for
80 // complement<1>, at the deepest level of recursion. Uses "poor man's partial
81 // specialization" again.
82 template <bool is_signed> struct complement_base;
83
84 template <> struct complement_base<false>
85 {
86     template <class Number>
87     struct values
88     {
89         BOOST_STATIC_CONSTANT(Number, min = 0);
90         BOOST_STATIC_CONSTANT(Number, max = UCHAR_MAX);
91     };
92 };
93
94 template <> struct complement_base<true>
95 {
96     template <class Number>
97     struct values
98     {
99         BOOST_STATIC_CONSTANT(Number, min = SCHAR_MIN);
100         BOOST_STATIC_CONSTANT(Number, max = SCHAR_MAX);
101     };
102 };
103
104 // Base specialization of complement, puts an end to the recursion.
105 template <>
106 struct complement<1>
107 {
108     template <class Number>
109     struct traits
110     {
111         BOOST_STATIC_CONSTANT(bool, is_signed = boost::detail::is_signed<Number>::value);
112         BOOST_STATIC_CONSTANT(Number, min =
113                             complement_base<is_signed>::template values<Number>::min);
114         BOOST_STATIC_CONSTANT(Number, max =
115                             complement_base<is_signed>::template values<Number>::max);
116     };
117 };
118
119 // Now here's the "pretty" template you're intended to actually use.
120 //   complement_traits<Number>::min, complement_traits<Number>::max are the
121 //   minimum and maximum values of Number if Number is a built-in integer type.
122 template <class Number>
123 struct complement_traits
124 {
125     BOOST_STATIC_CONSTANT(Number, max = (complement_traits_aux<Number, sizeof(Number)>::max));
126     BOOST_STATIC_CONSTANT(Number, min = (complement_traits_aux<Number, sizeof(Number)>::min));
127 };
128
129 // =================================================================================
130
131 // Support for streaming various numeric types in exactly the format I want. I
132 // needed this in addition to all the assertions so that I could see exactly
133 // what was going on.
134 //
135 // Numbers go through a 2-stage conversion process (by default, though, no real
136 // conversion).
137 //
138 template <class T> struct stream_as {
139     typedef T t1;
140     typedef T t2;
141 };
142
143 // char types first get converted to unsigned char, then to unsigned.
144 template <> struct stream_as<char> {
145     typedef unsigned char t1;
146     typedef unsigned t2;
147 };
148 template <> struct stream_as<unsigned char> {
149     typedef unsigned char t1; typedef unsigned t2;
150 };
151 template <> struct stream_as<signed char>  {
152     typedef unsigned char t1; typedef unsigned t2;
153 };
154
155 #if defined(BOOST_MSVC_STD_ITERATOR) // No intmax streaming built-in
156
157 // With this library implementation, __int64 and __uint64 get streamed as strings
158 template <> struct stream_as<boost::uintmax_t> {
159     typedef std::string t1;
160     typedef std::string t2;
161 };
162
163 template <> struct stream_as<boost::intmax_t>  {
164     typedef std::string t1;
165     typedef std::string t2;
166 };
167 #endif
168
169 // Standard promotion process for streaming
170 template <class T> struct promote
171 {
172     static typename stream_as<T>::t1 from(T x) {
173         typedef typename stream_as<T>::t1 t1;
174         return t1(x);
175     }
176 };
177
178 #if defined(BOOST_MSVC_STD_ITERATOR) // No intmax streaming built-in
179
180 // On this platform, stream them as long/unsigned long if they fit.
181 // Otherwise, write a string.
182 template <> struct promote<boost::uintmax_t> {
183     std::string static from(const boost::uintmax_t x) {
184         if (x > ULONG_MAX)
185             return std::string("large unsigned value");
186         else
187             return boost::lexical_cast<std::string>((unsigned long)x);
188     }
189 };
190 template <> struct promote<boost::intmax_t> {
191     std::string static from(const boost::intmax_t x) {
192         if (x > boost::intmax_t(ULONG_MAX))
193             return std::string("large positive signed value");
194         else if (x >= 0)
195             return boost::lexical_cast<std::string>((unsigned long)x);
196         
197         if (x < boost::intmax_t(LONG_MIN))
198             return std::string("large negative signed value");
199         else
200             return boost::lexical_cast<std::string>((long)x);
201     }
202 };
203 #endif
204
205 // This is the function which converts types to the form I want to stream them in.
206 template <class T>
207 typename stream_as<T>::t2 stream_number(T x)
208 {
209     return promote<T>::from(x);
210 }
211 // =================================================================================
212
213 //
214 // Tests for built-in signed and unsigned types
215 //
216
217 // Tag types for selecting tests
218 struct unsigned_tag {};
219 struct signed_tag {};
220
221 // Tests for unsigned numbers. The extra default Number parameter works around
222 // an MSVC bug.
223 template <class Number>
224 void test_aux(unsigned_tag, Number*)
225 {
226     typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
227     BOOST_STATIC_ASSERT(!boost::detail::is_signed<Number>::value);
228     BOOST_STATIC_ASSERT(
229         (sizeof(Number) < sizeof(boost::intmax_t))
230         | (boost::is_same<difference_type, boost::intmax_t>::value));
231
232 #if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && __GNUC_PATCHLEVEL__ == 2
233     // GCC 4.0.2 ICEs on this C-style cases
234     BOOST_STATIC_ASSERT((complement_traits<Number>::max) > Number(0));
235     BOOST_STATIC_ASSERT((complement_traits<Number>::min) == Number(0));
236 #else
237     // Force casting to Number here to work around the fact that it's an enum on MSVC
238     BOOST_STATIC_ASSERT(Number(complement_traits<Number>::max) > Number(0));
239     BOOST_STATIC_ASSERT(Number(complement_traits<Number>::min) == Number(0));
240 #endif
241
242     const Number max = complement_traits<Number>::max;
243     const Number min = complement_traits<Number>::min;
244     
245     const Number test_max = (sizeof(Number) < sizeof(boost::intmax_t))
246         ? max
247         : max / 2 - 1;
248
249     std::cout << std::hex << "(unsigned) min = " << stream_number(min) << ", max = "
250               << stream_number(max) << "..." << std::flush;
251     std::cout << "difference_type = " << typeid(difference_type).name() << "..."
252               << std::flush;
253     
254     difference_type d1 = boost::detail::numeric_distance(Number(0), test_max);
255     difference_type d2 = boost::detail::numeric_distance(test_max, Number(0));
256     
257     std::cout << "0->" << stream_number(test_max) << "==" << std::dec << stream_number(d1) << "; "
258               << std::hex << stream_number(test_max) << "->0==" << std::dec << stream_number(d2) << "..." << std::flush;
259
260     assert(d1 == difference_type(test_max));
261     assert(d2 == -difference_type(test_max));
262 }
263
264 // Tests for signed numbers. The extra default Number parameter works around an
265 // MSVC bug.
266 struct out_of_range_tag {};
267 struct in_range_tag {};
268
269 // This test morsel gets executed for numbers whose difference will always be
270 // representable in intmax_t
271 template <class Number>
272 void signed_test(in_range_tag, Number*)
273 {
274     BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
275     typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
276     const Number max = complement_traits<Number>::max;
277     const Number min = complement_traits<Number>::min;
278     
279     difference_type d1 = boost::detail::numeric_distance(min, max);
280     difference_type d2 = boost::detail::numeric_distance(max, min);
281
282     std::cout << stream_number(min) << "->" << stream_number(max) << "==";
283     std::cout << std::dec << stream_number(d1) << "; ";
284     std::cout << std::hex << stream_number(max) << "->" << stream_number(min)
285               << "==" << std::dec << stream_number(d2) << "..." << std::flush;
286     assert(d1 == difference_type(max) - difference_type(min));
287     assert(d2 == difference_type(min) - difference_type(max));
288 }
289
290 // This test morsel gets executed for numbers whose difference may exceed the
291 // capacity of intmax_t.
292 template <class Number>
293 void signed_test(out_of_range_tag, Number*)
294 {
295     BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
296     typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
297     const Number max = complement_traits<Number>::max;
298     const Number min = complement_traits<Number>::min;
299
300     difference_type min_distance = complement_traits<difference_type>::min;
301     difference_type max_distance = complement_traits<difference_type>::max;
302
303     const Number n1 = Number(min + max_distance);
304     const Number n2 = Number(max + min_distance);
305     difference_type d1 = boost::detail::numeric_distance(min, n1);
306     difference_type d2 = boost::detail::numeric_distance(max, n2);
307
308     std::cout << stream_number(min) << "->" << stream_number(n1) << "==";
309     std::cout << std::dec << stream_number(d1) << "; ";
310     std::cout << std::hex << stream_number(max) << "->" << stream_number(n2)
311               << "==" << std::dec << stream_number(d2) << "..." << std::flush;
312     assert(d1 == max_distance);
313     assert(d2 == min_distance);
314 }
315
316 template <class Number>
317 void test_aux(signed_tag, Number*)
318 {
319     typedef typename boost::detail::numeric_traits<Number>::difference_type difference_type;
320     BOOST_STATIC_ASSERT(boost::detail::is_signed<Number>::value);
321     BOOST_STATIC_ASSERT(
322         (sizeof(Number) < sizeof(boost::intmax_t))
323         | (boost::is_same<difference_type, Number>::value));
324
325 #if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && __GNUC_PATCHLEVEL__ == 2
326     // GCC 4.0.2 ICEs on this cast
327     BOOST_STATIC_ASSERT((complement_traits<Number>::max) > Number(0));
328     BOOST_STATIC_ASSERT((complement_traits<Number>::min) < Number(0));
329 #else
330     // Force casting to Number here to work around the fact that it's an enum on MSVC
331     BOOST_STATIC_ASSERT(Number(complement_traits<Number>::max) > Number(0));
332     BOOST_STATIC_ASSERT(Number(complement_traits<Number>::min) < Number(0));
333 #endif    
334     const Number max = complement_traits<Number>::max;
335     const Number min = complement_traits<Number>::min;
336     
337     std::cout << std::hex << "min = " << stream_number(min) << ", max = "
338               << stream_number(max) << "..." << std::flush;
339     std::cout << "difference_type = " << typeid(difference_type).name() << "..."
340               << std::flush;
341
342     typedef typename boost::detail::if_true<
343                           (sizeof(Number) < sizeof(boost::intmax_t))>
344                         ::template then<
345                           in_range_tag,
346                           out_of_range_tag
347                         >::type
348         range_tag;
349     signed_test<Number>(range_tag(), 0);
350 }
351
352
353 // Test for all numbers. The extra default Number parameter works around an MSVC
354 // bug.
355 template <class Number>
356 void test(Number* = 0)
357 {
358     std::cout << "testing " << typeid(Number).name() << ":\n"
359 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
360               << "is_signed: " << (std::numeric_limits<Number>::is_signed ? "true\n" : "false\n")
361               << "is_bounded: " << (std::numeric_limits<Number>::is_bounded ? "true\n" : "false\n")
362               << "digits: " << std::numeric_limits<Number>::digits << "\n"
363 #endif
364               << "..." << std::flush;
365
366     // factoring out difference_type for the assert below confused Borland :(
367     typedef boost::detail::is_signed<
368 #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300
369         typename
370 #endif
371         boost::detail::numeric_traits<Number>::difference_type
372         > is_signed;
373     BOOST_STATIC_ASSERT(is_signed::value);
374
375     typedef typename boost::detail::if_true<
376         boost::detail::is_signed<Number>::value
377         >::template then<signed_tag, unsigned_tag>::type signedness;
378     
379     test_aux<Number>(signedness(), 0);
380     std::cout << "passed" << std::endl;
381 }
382
383 int main()
384 {
385     test<char>();
386     test<unsigned char>();
387     test<signed char>();
388     test<wchar_t>();
389     test<short>();
390     test<unsigned short>();
391     test<int>();
392     test<unsigned int>();
393     test<long>();
394     test<unsigned long>();
395 #if defined(BOOST_HAS_LONG_LONG) && !defined(BOOST_NO_INTEGRAL_INT64_T)
396     test< ::boost::long_long_type>();
397     test< ::boost::ulong_long_type>();
398 #elif defined(BOOST_MSVC)
399     // The problem of not having compile-time static class constants other than
400     // enums prevents this from working, since values get truncated.
401     // test<boost::uintmax_t>();
402     // test<boost::intmax_t>();
403 #endif
404     return 0;
405 }