Back out due to mochiserver breakage. (no_r=me)
[mozilla-central.git] / xpcom / ds / CheckedInt.h
bloba8b65c80dfb0c160d9b5617424015162a21c2d0f
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is Mozilla code.
18 * The Initial Developer of the Original Code is the Mozilla Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2009
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Benoit Jacob <bjacob@mozilla.com>
24 * Jeff Muizelaar <jmuizelaar@mozilla.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #ifndef mozilla_CheckedInt_h
41 #define mozilla_CheckedInt_h
43 #include "prtypes.h"
45 #include <climits>
47 namespace mozilla {
49 namespace CheckedInt_internal {
51 /* we don't want to use std::numeric_limits here because PRInt... types may not support it,
52 * depending on the platform, e.g. on certain platforms they use nonstandard built-in types
55 /*** Step 1: manually record information for all the types that we want to support
56 ***/
58 struct unsupported_type {};
60 template<typename T> struct integer_type_manually_recorded_info
62 enum { is_supported = 0 };
63 typedef unsupported_type twice_bigger_type;
64 typedef unsupported_type unsigned_type;
68 #define CHECKEDINT_REGISTER_SUPPORTED_TYPE(T,_twice_bigger_type,_unsigned_type) \
69 template<> struct integer_type_manually_recorded_info<T> \
70 { \
71 enum { is_supported = 1 }; \
72 typedef _twice_bigger_type twice_bigger_type; \
73 typedef _unsigned_type unsigned_type; \
74 static void TYPE_NOT_SUPPORTED_BY_CheckedInt() {} \
77 // Type Twice Bigger Type Unsigned Type
78 CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt8, PRInt16, PRUint8)
79 CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint8, PRUint16, PRUint8)
80 CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt16, PRInt32, PRUint16)
81 CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint16, PRUint32, PRUint16)
82 CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt32, PRInt64, PRUint32)
83 CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint32, PRUint64, PRUint32)
84 CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt64, unsupported_type, PRUint64)
85 CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint64, unsupported_type, PRUint64)
88 /*** Step 2: record some info about a given integer type,
89 *** including whether it is supported, whether a twice bigger integer type
90 *** is supported, what that twice bigger type is, and some stuff as found
91 *** in std::numeric_limits (which we don't use because PRInt.. types may
92 *** not support it, if they are defined directly from compiler built-in types).
93 *** We use function names min_value() and max_value() instead of min() and max()
94 *** because of stupid min/max macros in Windows headers.
95 ***/
97 template<typename T> struct is_unsupported_type { enum { answer = 0 }; };
98 template<> struct is_unsupported_type<unsupported_type> { enum { answer = 1 }; };
100 template<typename T> struct integer_traits
102 typedef typename integer_type_manually_recorded_info<T>::twice_bigger_type twice_bigger_type;
103 typedef typename integer_type_manually_recorded_info<T>::unsigned_type unsigned_type;
105 enum {
106 is_supported = integer_type_manually_recorded_info<T>::is_supported,
107 twice_bigger_type_is_supported
108 = is_unsupported_type<
109 typename integer_type_manually_recorded_info<T>::twice_bigger_type
110 >::answer ? 0 : 1,
111 size = sizeof(T),
112 position_of_sign_bit = CHAR_BIT * size - 1,
113 is_signed = (T(-1) > T(0)) ? 0 : 1
116 static T min_value()
118 // bitwise ops may return a larger type, that's why we cast explicitly to T
119 // in C++, left bit shifts on signed values is undefined by the standard unless the shifted value is representable.
120 // notice that signed-to-unsigned conversions are always well-defined in the standard,
121 // as the value congruent to 2^n as expected. By contrast, unsigned-to-signed is only well-defined if the value is
122 // representable.
123 return is_signed ? T(unsigned_type(1) << position_of_sign_bit) : T(0);
126 static T max_value()
128 return ~min_value();
132 /*** Step 3: Implement the actual validity checks --- ideas taken from IntegerLib, code different.
133 ***/
135 // bitwise ops may return a larger type, so it's good to use these inline helpers guaranteeing that
136 // the result is really of type T
138 template<typename T> inline T has_sign_bit(T x)
140 // in C++, right bit shifts on negative values is undefined by the standard.
141 // notice that signed-to-unsigned conversions are always well-defined in the standard,
142 // as the value congruent modulo 2^n as expected. By contrast, unsigned-to-signed is only well-defined if the value is
143 // representable. Here the unsigned-to-signed conversion is OK because the value (the result of the shift) is 0 or 1.
144 typedef typename integer_traits<T>::unsigned_type unsigned_T;
145 return T(unsigned_T(x) >> integer_traits<T>::position_of_sign_bit);
148 template<typename T> inline T binary_complement(T x)
150 return ~x;
153 template<typename T, typename U,
154 bool is_T_signed = integer_traits<T>::is_signed,
155 bool is_U_signed = integer_traits<U>::is_signed>
156 struct is_in_range_impl {};
158 template<typename T, typename U>
159 struct is_in_range_impl<T, U, true, true>
161 static T run(U x)
163 return (x <= integer_traits<T>::max_value()) &
164 (x >= integer_traits<T>::min_value());
168 template<typename T, typename U>
169 struct is_in_range_impl<T, U, false, false>
171 static T run(U x)
173 return x <= integer_traits<T>::max_value();
177 template<typename T, typename U>
178 struct is_in_range_impl<T, U, true, false>
180 static T run(U x)
182 if (sizeof(T) > sizeof(U))
183 return 1;
184 else
185 return x <= U(integer_traits<T>::max_value());
189 template<typename T, typename U>
190 struct is_in_range_impl<T, U, false, true>
192 static T run(U x)
194 if (sizeof(T) >= sizeof(U))
195 return x >= 0;
196 else
197 return x >= 0 && x <= U(integer_traits<T>::max_value());
201 template<typename T, typename U> inline T is_in_range(U x)
203 return is_in_range_impl<T, U>::run(x);
206 template<typename T> inline T is_add_valid(T x, T y, T result)
208 return integer_traits<T>::is_signed ?
209 // addition is valid if the sign of x+y is equal to either that of x or that of y.
210 // Beware! These bitwise operations can return a larger integer type, if T was a
211 // small type like int8, so we explicitly cast to T.
212 has_sign_bit(binary_complement(T((result^x) & (result^y))))
214 binary_complement(x) >= y;
217 template<typename T> inline T is_sub_valid(T x, T y, T result)
219 return integer_traits<T>::is_signed ?
220 // substraction is valid if either x and y have same sign, or x-y and x have same sign
221 has_sign_bit(binary_complement(T((result^x) & (x^y))))
223 x >= y;
226 template<typename T,
227 bool is_signed = integer_traits<T>::is_signed,
228 bool twice_bigger_type_is_supported = integer_traits<T>::twice_bigger_type_is_supported>
229 struct is_mul_valid_impl {};
231 template<typename T, bool is_signed>
232 struct is_mul_valid_impl<T, is_signed, true>
234 static T run(T x, T y)
236 typedef typename integer_traits<T>::twice_bigger_type twice_bigger_type;
237 twice_bigger_type product = twice_bigger_type(x) * twice_bigger_type(y);
238 return is_in_range<T>(product);
242 template<typename T>
243 struct is_mul_valid_impl<T, true, false>
245 static T run(T x, T y)
247 const T max_value = integer_traits<T>::max_value();
248 const T min_value = integer_traits<T>::min_value();
250 if (x == 0 || y == 0) return true;
252 if (x > 0) {
253 if (y > 0)
254 return x <= max_value / y;
255 else
256 return y >= min_value / x;
257 } else {
258 if (y > 0)
259 return x >= min_value / y;
260 else
261 return y >= max_value / x;
266 template<typename T>
267 struct is_mul_valid_impl<T, false, false>
269 static T run(T x, T y)
271 const T max_value = integer_traits<T>::max_value();
272 if (x == 0 || y == 0) return true;
273 return x <= max_value / y;
277 template<typename T> inline T is_mul_valid(T x, T y, T /*result not used*/)
279 return is_mul_valid_impl<T>::run(x, y);
282 template<typename T> inline T is_div_valid(T x, T y)
284 return integer_traits<T>::is_signed ?
285 // keep in mind that min/-1 is invalid because abs(min)>max
286 y != 0 && (x != integer_traits<T>::min_value() || y != T(-1))
288 y != 0;
291 } // end namespace CheckedInt_internal
294 /*** Step 4: Now define the CheckedInt class.
295 ***/
297 /** \class CheckedInt
298 * \brief Integer wrapper class checking for integer overflow and other errors
299 * \param T the integer type to wrap. Can be any of PRInt8, PRUint8, PRInt16, PRUint16,
300 * PRInt32, PRUint32, PRInt64, PRUint64.
302 * This class implements guarded integer arithmetic. Do a computation, check that
303 * valid() returns true, you then have a guarantee that no problem, such as integer overflow,
304 * happened during this computation.
306 * The arithmetic operators in this class are guaranteed not to crash your app
307 * in case of a division by zero.
309 * For example, suppose that you want to implement a function that computes (x+y)/z,
310 * that doesn't crash if z==0, and that reports on error (divide by zero or integer overflow).
311 * You could code it as follows:
312 \code
313 PRBool compute_x_plus_y_over_z(PRInt32 x, PRInt32 y, PRInt32 z, PRInt32 *result)
315 CheckedInt<PRInt32> checked_result = (CheckedInt<PRInt32>(x) + y) / z;
316 *result = checked_result.value();
317 return checked_result.valid();
319 \endcode
321 * Implicit conversion from plain integers to checked integers is allowed. The plain integer
322 * is checked to be in range before being casted to the destination type. This means that the following
323 * lines all compile, and the resulting CheckedInts are correctly detected as valid or invalid:
324 * \code
325 CheckedInt<PRUint8> x(1); // 1 is of type int, is found to be in range for PRUint8, x is valid
326 CheckedInt<PRUint8> x(-1); // -1 is of type int, is found not to be in range for PRUint8, x is invalid
327 CheckedInt<PRInt8> x(-1); // -1 is of type int, is found to be in range for PRInt8, x is valid
328 CheckedInt<PRInt8> x(PRInt16(1000)); // 1000 is of type PRInt16, is found not to be in range for PRInt8, x is invalid
329 CheckedInt<PRInt32> x(PRUint32(3123456789)); // 3123456789 is of type PRUint32, is found not to be in range
330 // for PRInt32, x is invalid
331 * \endcode
332 * Implicit conversion from
333 * checked integers to plain integers is not allowed. As shown in the
334 * above example, to get the value of a checked integer as a normal integer, call value().
336 * Arithmetic operations between checked and plain integers is allowed; the result type
337 * is the type of the checked integer.
339 * Checked integers of different types cannot be used in the same arithmetic expression.
341 * There are convenience typedefs for all PR integer types, of the following form (these are just 2 examples):
342 \code
343 typedef CheckedInt<PRInt32> CheckedInt32;
344 typedef CheckedInt<PRUint16> CheckedUint16;
345 \endcode
347 template<typename T>
348 class CheckedInt
350 protected:
351 T mValue;
352 T mIsValid; // stored as a T to limit the number of integer conversions when
353 // evaluating nested arithmetic expressions.
355 template<typename U>
356 CheckedInt(const U& value, PRBool isValid) : mValue(value), mIsValid(isValid)
358 CheckedInt_internal::integer_type_manually_recorded_info<T>
359 ::TYPE_NOT_SUPPORTED_BY_CheckedInt();
362 public:
363 /** Constructs a checked integer with given \a value. The checked integer is initialized as valid or invalid
364 * depending on whether the \a value is in range.
366 * This constructor is not explicit. Instead, the type of its argument is a separate template parameter,
367 * ensuring that no conversion is performed before this constructor is actually called.
368 * As explained in the above documentation for class CheckedInt, this constructor checks that its argument is
369 * valid.
371 template<typename U>
372 CheckedInt(const U& value)
373 : mValue(value),
374 mIsValid(CheckedInt_internal::is_in_range<T>(value))
376 CheckedInt_internal::integer_type_manually_recorded_info<T>
377 ::TYPE_NOT_SUPPORTED_BY_CheckedInt();
380 /** Constructs a valid checked integer with uninitialized value */
381 CheckedInt() : mIsValid(1)
383 CheckedInt_internal::integer_type_manually_recorded_info<T>
384 ::TYPE_NOT_SUPPORTED_BY_CheckedInt();
387 /** \returns the actual value */
388 T value() const { return mValue; }
390 /** \returns PR_TRUE if the checked integer is valid, i.e. is not the result
391 * of an invalid operation or of an operation involving an invalid checked integer
393 PRBool valid() const
395 return mIsValid;
398 /** \returns the sum. Checks for overflow. */
399 template<typename U> friend CheckedInt<U> operator +(const CheckedInt<U>& lhs, const CheckedInt<U>& rhs);
400 /** Adds. Checks for overflow. \returns self reference */
401 template<typename U> CheckedInt& operator +=(const U &rhs);
402 /** \returns the difference. Checks for overflow. */
403 template<typename U> friend CheckedInt<U> operator -(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
404 /** Substracts. Checks for overflow. \returns self reference */
405 template<typename U> CheckedInt& operator -=(const U &rhs);
406 /** \returns the product. Checks for overflow. */
407 template<typename U> friend CheckedInt<U> operator *(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
408 /** Multiplies. Checks for overflow. \returns self reference */
409 template<typename U> CheckedInt& operator *=(const U &rhs);
410 /** \returns the quotient. Checks for overflow and for divide-by-zero. */
411 template<typename U> friend CheckedInt<U> operator /(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
412 /** Divides. Checks for overflow and for divide-by-zero. \returns self reference */
413 template<typename U> CheckedInt& operator /=(const U &rhs);
415 /** \returns the opposite value. Checks for overflow. */
416 CheckedInt operator -() const
418 T result = -value();
419 /* give the compiler a good chance to perform RVO */
420 return CheckedInt(result,
421 mIsValid & CheckedInt_internal::is_sub_valid(T(0), value(), result));
424 /** \returns true if the left and right hand sides are valid and have the same value. */
425 PRBool operator ==(const CheckedInt& other) const
427 return PRBool(mIsValid & other.mIsValid & T(value() == other.value()));
430 /** prefix ++ */
431 CheckedInt& operator++()
433 *this = *this + 1;
434 return *this;
437 /** postfix ++ */
438 CheckedInt operator++(int)
440 CheckedInt tmp = *this;
441 *this = *this + 1;
442 return tmp;
445 /** prefix -- */
446 CheckedInt& operator--()
448 *this = *this - 1;
449 return *this;
452 /** postfix -- */
453 CheckedInt operator--(int)
455 CheckedInt tmp = *this;
456 *this = *this - 1;
457 return tmp;
460 private:
461 /** operator!= is disabled. Indeed, (a!=b) should be the same as !(a==b) but that
462 * would mean that if a or b is invalid, (a!=b) is always true, which is very tricky.
464 template<typename U>
465 PRBool operator !=(const U& other) const { return !(*this == other); }
468 #define CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP) \
469 template<typename T> \
470 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs) \
472 T x = lhs.value(); \
473 T y = rhs.value(); \
474 T result = x OP y; \
475 T is_op_valid \
476 = CheckedInt_internal::is_##NAME##_valid(x, y, result); \
477 /* give the compiler a good chance to perform RVO */ \
478 return CheckedInt<T>(result, \
479 lhs.mIsValid & rhs.mIsValid & is_op_valid); \
482 CHECKEDINT_BASIC_BINARY_OPERATOR(add, +)
483 CHECKEDINT_BASIC_BINARY_OPERATOR(sub, -)
484 CHECKEDINT_BASIC_BINARY_OPERATOR(mul, *)
486 // division can't be implemented by CHECKEDINT_BASIC_BINARY_OPERATOR
487 // because if rhs == 0, we are not allowed to even try to compute the quotient.
488 template<typename T>
489 inline CheckedInt<T> operator /(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs)
491 T x = lhs.value();
492 T y = rhs.value();
493 T is_op_valid = CheckedInt_internal::is_div_valid(x, y);
494 T result = is_op_valid ? (x / y) : 0;
495 /* give the compiler a good chance to perform RVO */
496 return CheckedInt<T>(result,
497 lhs.mIsValid & rhs.mIsValid & is_op_valid);
500 // implement cast_to_CheckedInt<T>(x), making sure that
501 // - it allows x to be either a CheckedInt<T> or any integer type that can be casted to T
502 // - if x is already a CheckedInt<T>, we just return a reference to it, instead of copying it (optimization)
504 template<typename T, typename U>
505 struct cast_to_CheckedInt_impl
507 typedef CheckedInt<T> return_type;
508 static CheckedInt<T> run(const U& u) { return u; }
511 template<typename T>
512 struct cast_to_CheckedInt_impl<T, CheckedInt<T> >
514 typedef const CheckedInt<T>& return_type;
515 static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
518 template<typename T, typename U>
519 inline typename cast_to_CheckedInt_impl<T, U>::return_type
520 cast_to_CheckedInt(const U& u)
522 return cast_to_CheckedInt_impl<T, U>::run(u);
525 #define CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
526 template<typename T> \
527 template<typename U> \
528 CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(const U &rhs) \
530 *this = *this OP cast_to_CheckedInt<T>(rhs); \
531 return *this; \
533 template<typename T, typename U> \
534 inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, const U &rhs) \
536 return lhs OP cast_to_CheckedInt<T>(rhs); \
538 template<typename T, typename U> \
539 inline CheckedInt<T> operator OP(const U & lhs, const CheckedInt<T> &rhs) \
541 return cast_to_CheckedInt<T>(lhs) OP rhs; \
544 CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
545 CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
546 CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
547 CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
549 template<typename T, typename U>
550 inline PRBool operator ==(const CheckedInt<T> &lhs, const U &rhs)
552 return lhs == cast_to_CheckedInt<T>(rhs);
555 template<typename T, typename U>
556 inline PRBool operator ==(const U & lhs, const CheckedInt<T> &rhs)
558 return cast_to_CheckedInt<T>(lhs) == rhs;
561 // convenience typedefs.
562 // the use of a macro here helps make sure that we don't let a typo slip into some of these.
563 #define CHECKEDINT_MAKE_TYPEDEF(Type) \
564 typedef CheckedInt<PR##Type> Checked##Type;
566 CHECKEDINT_MAKE_TYPEDEF(Int8)
567 CHECKEDINT_MAKE_TYPEDEF(Uint8)
568 CHECKEDINT_MAKE_TYPEDEF(Int16)
569 CHECKEDINT_MAKE_TYPEDEF(Uint16)
570 CHECKEDINT_MAKE_TYPEDEF(Int32)
571 CHECKEDINT_MAKE_TYPEDEF(Uint32)
572 CHECKEDINT_MAKE_TYPEDEF(Int64)
573 CHECKEDINT_MAKE_TYPEDEF(Uint64)
575 } // end namespace mozilla
577 #endif /* mozilla_CheckedInt_h */