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
5 *
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/
10 *
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.
15 *
16 * The Original Code is Mozilla code.
17 *
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.
21 *
22 * Contributor(s):
23 *  Benoit Jacob <bjacob@mozilla.com>
24 *  Jeff Muizelaar <jmuizelaar@mozilla.com>
25 *
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.
37 *
38 * ***** END LICENSE BLOCK ***** */
39
40// Necessary modifications are made to the original CheckedInt.h file to remove
41// dependencies on prtypes.
42// Also, change define Mozilla_CheckedInt_h to CheckedInt_h, change namespace
43// from mozilla to WebCore for easier usage.
44
45#ifndef CheckedInt_h
46#define CheckedInt_h
47
48#include <climits>
49
50namespace WebCore {
51
52namespace CheckedInt_internal {
53
54/* we don't want to use std::numeric_limits here because int... types may not support it,
55 * depending on the platform, e.g. on certain platform they use nonstandard built-in types
56 */
57
58/*** Step 1: manually record information for all the types that we want to support
59 ***/
60
61struct unsupported_type {};
62
63template<typename T> struct integer_type_manually_recorded_info;
64
65
66#define CHECKEDINT_REGISTER_SUPPORTED_TYPE(T,_twice_bigger_type,_unsigned_type) \
67template<> struct integer_type_manually_recorded_info<T>       \
68{                                                              \
69    enum { is_supported = 1 };                                 \
70    typedef _twice_bigger_type twice_bigger_type;              \
71    typedef _unsigned_type unsigned_type;                      \
72};
73
74//                                 Type      Twice Bigger Type   Unsigned Type
75CHECKEDINT_REGISTER_SUPPORTED_TYPE(int8_t,   int16_t,             uint8_t)
76CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint8_t,  uint16_t,            uint8_t)
77CHECKEDINT_REGISTER_SUPPORTED_TYPE(int16_t,  int32_t,             uint16_t)
78CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint16_t, uint32_t,            uint16_t)
79CHECKEDINT_REGISTER_SUPPORTED_TYPE(int32_t,  int64_t,             uint32_t)
80CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint32_t, uint64_t,            uint32_t)
81CHECKEDINT_REGISTER_SUPPORTED_TYPE(int64_t,  unsupported_type,    uint64_t)
82CHECKEDINT_REGISTER_SUPPORTED_TYPE(uint64_t, unsupported_type,    uint64_t)
83
84// now implement the fallback for standard types like int, long, ...
85// the difficulty is that they may or may not be equal to one of the above types, and/or
86// to each other. This is why any attempt to handle at once PRInt8... types and standard types
87// is bound to fail.
88template<typename T>
89struct is_standard_integer_type { enum { value = 0 }; };
90
91template<>
92struct is_standard_integer_type<char> { enum { value = 1 }; };
93template<>
94struct is_standard_integer_type<unsigned char> { enum { value = 1 }; };
95template<>
96struct is_standard_integer_type<short> { enum { value = 1 }; };
97template<>
98struct is_standard_integer_type<unsigned short> { enum { value = 1 }; };
99template<>
100struct is_standard_integer_type<int> { enum { value = 1 }; };
101template<>
102struct is_standard_integer_type<unsigned int> { enum { value = 1 }; };
103template<>
104struct is_standard_integer_type<long> { enum { value = 1 }; };
105template<>
106struct is_standard_integer_type<unsigned long> { enum { value = 1 }; };
107template<>
108struct is_standard_integer_type<long long> { enum { value = 1 }; };
109template<>
110struct is_standard_integer_type<unsigned long long> { enum { value = 1 }; };
111
112template<int size, bool is_signed>
113struct explicitly_sized_integer_type {};
114
115template<>
116struct explicitly_sized_integer_type<1, true> { typedef int8_t type; };
117template<>
118struct explicitly_sized_integer_type<1, false> { typedef uint8_t type; };
119template<>
120struct explicitly_sized_integer_type<2, true> { typedef int16_t type; };
121template<>
122struct explicitly_sized_integer_type<2, false> { typedef uint16_t type; };
123template<>
124struct explicitly_sized_integer_type<4, true> { typedef int32_t type; };
125template<>
126struct explicitly_sized_integer_type<4, false> { typedef uint32_t type; };
127template<>
128struct explicitly_sized_integer_type<8, true> { typedef int64_t type; };
129template<>
130struct explicitly_sized_integer_type<8, false> { typedef uint64_t type; };
131
132template<typename T> struct integer_type_manually_recorded_info
133{
134    enum {
135      is_supported = is_standard_integer_type<T>::value,
136      size = sizeof(T),
137      is_signed = (T(-1) > T(0)) ? 0 : 1
138    };
139    typedef typename explicitly_sized_integer_type<size, is_signed>::type explicit_sized_type;
140    typedef integer_type_manually_recorded_info<explicit_sized_type> base;
141    typedef typename base::twice_bigger_type twice_bigger_type;
142    typedef typename base::unsigned_type unsigned_type;
143};
144
145template<typename T, bool is_supported = integer_type_manually_recorded_info<T>::is_supported>
146struct TYPE_NOT_SUPPORTED_BY_CheckedInt {};
147
148template<typename T>
149struct TYPE_NOT_SUPPORTED_BY_CheckedInt<T, true> { static void run() {} };
150
151
152/*** Step 2: record some info about a given integer type,
153 ***         including whether it is supported, whether a twice bigger integer type
154 ***         is supported, what that twice bigger type is, and some stuff as found
155 ***         in std::numeric_limits (which we don't use because int.. types may
156 ***         not support it, if they are defined directly from compiler built-in types).
157 ***/
158
159template<typename T> struct is_unsupported_type { enum { answer = 0 }; };
160template<> struct is_unsupported_type<unsupported_type> { enum { answer = 1 }; };
161
162template<typename T> struct integer_traits
163{
164    typedef typename integer_type_manually_recorded_info<T>::twice_bigger_type twice_bigger_type;
165
166    enum {
167        is_supported = integer_type_manually_recorded_info<T>::is_supported,
168        twice_bigger_type_is_supported
169            = is_unsupported_type<
170                  typename integer_type_manually_recorded_info<T>::twice_bigger_type
171              >::answer ? 0 : 1,
172        size = sizeof(T),
173        position_of_sign_bit = CHAR_BIT * size - 1,
174        is_signed = (T(-1) > T(0)) ? 0 : 1
175    };
176
177    static T min()
178    {
179        // bitwise ops may return a larger type, that's why we cast explicitly to T
180        return is_signed ? T(T(1) << position_of_sign_bit) : T(0);
181    }
182
183    static T max()
184    {
185        return ~min();
186    }
187};
188
189/*** Step 3: Implement the actual validity checks --- ideas taken from IntegerLib, code different.
190 ***/
191
192// bitwise ops may return a larger type, so it's good to use these inline helpers guaranteeing that
193// the result is really of type T
194
195template<typename T> inline T has_sign_bit(T x)
196{
197    return x >> integer_traits<T>::position_of_sign_bit;
198}
199
200template<typename T> inline T binary_complement(T x)
201{
202    return ~x;
203}
204
205template<typename T, typename U,
206         bool is_T_signed = integer_traits<T>::is_signed,
207         bool is_U_signed = integer_traits<U>::is_signed>
208struct is_in_range_impl {};
209
210template<typename T, typename U>
211struct is_in_range_impl<T, U, true, true>
212{
213    static T run(U x)
214    {
215        return (x <= integer_traits<T>::max()) &
216               (x >= integer_traits<T>::min());
217    }
218};
219
220template<typename T, typename U>
221struct is_in_range_impl<T, U, false, false>
222{
223    static T run(U x)
224    {
225        return x <= integer_traits<T>::max();
226    }
227};
228
229template<typename T, typename U>
230struct is_in_range_impl<T, U, true, false>
231{
232    static T run(U x)
233    {
234        if (sizeof(T) > sizeof(U))
235            return 1;
236        else
237            return x <= U(integer_traits<T>::max());
238    }
239};
240
241template<typename T, typename U>
242struct is_in_range_impl<T, U, false, true>
243{
244    static T run(U x)
245    {
246        if (sizeof(T) >= sizeof(U))
247            return x >= 0;
248        else
249            return x >= 0 && x <= U(integer_traits<T>::max());
250    }
251};
252
253template<typename T, typename U> inline T is_in_range(U x)
254{
255    return is_in_range_impl<T, U>::run(x);
256}
257
258template<typename T> inline T is_add_valid(T x, T y, T result)
259{
260    return integer_traits<T>::is_signed ?
261                        // addition is valid if the sign of x+y is equal to either that of x or that of y.
262                        // Beware! These bitwise operations can return a larger integer type, if T was a
263                        // small type like int8, so we explicitly cast to T.
264                        has_sign_bit(binary_complement(T((result^x) & (result^y))))
265                    :
266                        binary_complement(x) >= y;
267}
268
269template<typename T> inline T is_sub_valid(T x, T y, T result)
270{
271    return integer_traits<T>::is_signed ?
272                        // substraction is valid if either x and y have same sign, or x-y and x have same sign
273                        has_sign_bit(binary_complement(T((result^x) & (x^y))))
274                    :
275                        x >= y;
276}
277
278template<typename T,
279         bool is_signed =  integer_traits<T>::is_signed,
280         bool twice_bigger_type_is_supported = integer_traits<T>::twice_bigger_type_is_supported>
281struct is_mul_valid_impl {};
282
283template<typename T>
284struct is_mul_valid_impl<T, true, true>
285{
286    static T run(T x, T y)
287    {
288        typedef typename integer_traits<T>::twice_bigger_type twice_bigger_type;
289        twice_bigger_type product = twice_bigger_type(x) * twice_bigger_type(y);
290        return is_in_range<T>(product);
291    }
292};
293
294template<typename T>
295struct is_mul_valid_impl<T, false, true>
296{
297    static T run(T x, T y)
298    {
299        typedef typename integer_traits<T>::twice_bigger_type twice_bigger_type;
300        twice_bigger_type product = twice_bigger_type(x) * twice_bigger_type(y);
301        return is_in_range<T>(product);
302    }
303};
304
305template<typename T>
306struct is_mul_valid_impl<T, true, false>
307{
308    static T run(T x, T y)
309    {
310        const T max_value = integer_traits<T>::max();
311        const T min_value = integer_traits<T>::min();
312
313        if (x == 0 || y == 0) return true;
314
315        if (x > 0) {
316            if (y > 0)
317                return x <= max_value / y;
318            else
319                return y >= min_value / x;
320        } else {
321            if (y > 0)
322                return x >= min_value / y;
323            else
324                return y >= max_value / x;
325        }
326    }
327};
328
329template<typename T>
330struct is_mul_valid_impl<T, false, false>
331{
332    static T run(T x, T y)
333    {
334        const T max_value = integer_traits<T>::max();
335        if (x == 0 || y == 0) return true;
336        return x <= max_value / y;
337    }
338};
339
340template<typename T> inline T is_mul_valid(T x, T y, T /*result not used*/)
341{
342    return is_mul_valid_impl<T>::run(x, y);
343}
344
345template<typename T> inline T is_div_valid(T x, T y)
346{
347    return integer_traits<T>::is_signed ?
348                        // keep in mind that min/-1 is invalid because abs(min)>max
349                        y != 0 && (x != integer_traits<T>::min() || y != T(-1))
350                    :
351                        y != 0;
352}
353
354} // end namespace CheckedInt_internal
355
356
357/*** Step 4: Now define the CheckedInt class.
358 ***/
359
360/** \class CheckedInt
361  * \brief Integer wrapper class checking for integer overflow and other errors
362  * \param T the integer type to wrap. Can be any of int8_t, uint8_t, int16_t, uint16_t,
363  *          int32_t, uint32_t, int64_t, uint64_t.
364  *
365  * This class implements guarded integer arithmetic. Do a computation, then check that
366  * valid() returns true, you then have a guarantee that no problem, such as integer overflow,
367  * happened during this computation.
368  *
369  * The arithmetic operators in this class are guaranteed not to crash your app
370  * in case of a division by zero.
371  *
372  * For example, suppose that you want to implement a function that computes (x+y)/z,
373  * that doesn't crash if z==0, and that reports on error (divide by zero or integer overflow).
374  * You could code it as follows:
375    \code
376    bool compute_x_plus_y_over_z(int32_t x, int32_t y, int32_t z, int32_t *result)
377    {
378        CheckedInt<int32_t> checked_result = (CheckedInt<int32_t>(x) + y) / z;
379        *result = checked_result.value();
380        return checked_result.valid();
381    }
382    \endcode
383  *
384  * Implicit conversion from plain integers to checked integers is allowed. The plain integer
385  * is checked to be in range before being casted to the destination type. This means that the following
386  * lines all compile, and the resulting CheckedInts are correctly detected as valid or invalid:
387  * \code
388    CheckedInt<uint8_t> x(1);   // 1 is of type int, is found to be in range for uint8_t, x is valid
389    CheckedInt<uint8_t> x(-1);  // -1 is of type int, is found not to be in range for uint8_t, x is invalid
390    CheckedInt<int8_t> x(-1);   // -1 is of type int, is found to be in range for int8_t, x is valid
391    CheckedInt<int8_t> x(int16_t(1000)); // 1000 is of type int16_t, is found not to be in range for int8_t, x is invalid
392    CheckedInt<int32_t> x(uint32_t(123456789)); // 3123456789 is of type uint32_t, is found not to be in range
393                                             // for int32_t, x is invalid
394  * \endcode
395  * Implicit conversion from
396  * checked integers to plain integers is not allowed. As shown in the
397  * above example, to get the value of a checked integer as a normal integer, call value().
398  *
399  * Arithmetic operations between checked and plain integers is allowed; the result type
400  * is the type of the checked integer.
401  *
402  * Safe integers of different types cannot be used in the same arithmetic expression.
403  */
404template<typename T>
405class CheckedInt
406{
407protected:
408    T mValue;
409    T mIsValid; // stored as a T to limit the number of integer conversions when
410                // evaluating nested arithmetic expressions.
411
412    template<typename U>
413    CheckedInt(const U& value, bool isValid) : mValue(value), mIsValid(isValid)
414    {
415        CheckedInt_internal::TYPE_NOT_SUPPORTED_BY_CheckedInt<T>::run();
416    }
417
418public:
419    /** Constructs a checked integer with given \a value. The checked integer is initialized as valid or invalid
420      * depending on whether the \a value is in range.
421      *
422      * This constructor is not explicit. Instead, the type of its argument is a separate template parameter,
423      * ensuring that no conversion is performed before this constructor is actually called.
424      * As explained in the above documentation for class CheckedInt, this constructor checks that its argument is
425      * valid.
426      */
427    template<typename U>
428    CheckedInt(const U& value)
429        : mValue(value),
430          mIsValid(CheckedInt_internal::is_in_range<T>(value))
431    {
432        CheckedInt_internal::TYPE_NOT_SUPPORTED_BY_CheckedInt<T>::run();
433    }
434
435    /** Constructs a valid checked integer with uninitialized value */
436    CheckedInt() : mIsValid(1)
437    {
438        CheckedInt_internal::TYPE_NOT_SUPPORTED_BY_CheckedInt<T>::run();
439    }
440
441    /** \returns the actual value */
442    T value() const { return mValue; }
443
444    /** \returns true if the checked integer is valid, i.e. is not the result
445      * of an invalid operation or of an operation involving an invalid checked integer
446      */
447    bool valid() const { return mIsValid; }
448
449    /** \returns the sum. Checks for overflow. */
450    template<typename U> friend CheckedInt<U> operator +(const CheckedInt<U>& lhs, const CheckedInt<U>& rhs);
451    /** Adds. Checks for overflow. \returns self reference */
452    template<typename U> CheckedInt& operator +=(const U &rhs);
453    /** \returns the difference. Checks for overflow. */
454    template<typename U> friend CheckedInt<U> operator -(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
455    /** Substracts. Checks for overflow. \returns self reference */
456    template<typename U> CheckedInt& operator -=(const U &rhs);
457    /** \returns the product. Checks for overflow. */
458    template<typename U> friend CheckedInt<U> operator *(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
459    /** Multiplies. Checks for overflow. \returns self reference */
460    template<typename U> CheckedInt& operator *=(const U &rhs);
461    /** \returns the quotient. Checks for overflow and for divide-by-zero. */
462    template<typename U> friend CheckedInt<U> operator /(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
463    /** Divides. Checks for overflow and for divide-by-zero. \returns self reference */
464    template<typename U> CheckedInt& operator /=(const U &rhs);
465
466    /** \returns the opposite value. Checks for overflow. */
467    CheckedInt operator -() const
468    {
469        T result = -value();
470        /* give the compiler a good chance to perform RVO */
471        return CheckedInt(result,
472                       mIsValid & CheckedInt_internal::is_sub_valid(T(0), value(), result));
473    }
474
475    /** \returns true if the left and right hand sides are valid and have the same value. */
476    bool operator ==(const CheckedInt& other) const
477    {
478        return bool(mIsValid & other.mIsValid & T(value() == other.value()));
479    }
480
481private:
482    /** operator!= is disabled. Indeed: (a!=b) should be the same as !(a==b) but that
483      * would mean that if a or b is invalid, (a!=b) is always true, which is very tricky.
484      */
485    template<typename U>
486    bool operator !=(const U& other) const { return !(*this == other); }
487};
488
489#define CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP)               \
490template<typename T>                                          \
491inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs) \
492{                                                             \
493    T x = lhs.value();                                        \
494    T y = rhs.value();                                        \
495    T result = x OP y;                                        \
496    T is_op_valid                                             \
497        = CheckedInt_internal::is_##NAME##_valid(x, y, result);  \
498    /* give the compiler a good chance to perform RVO */      \
499    return CheckedInt<T>(result,                                 \
500                      lhs.mIsValid &                          \
501                      rhs.mIsValid &                          \
502                      is_op_valid);                           \
503}
504
505CHECKEDINT_BASIC_BINARY_OPERATOR(add, +)
506CHECKEDINT_BASIC_BINARY_OPERATOR(sub, -)
507CHECKEDINT_BASIC_BINARY_OPERATOR(mul, *)
508
509// division can't be implemented by CHECKEDINT_BASIC_BINARY_OPERATOR
510// because if rhs == 0, we are not allowed to even try to compute the quotient.
511template<typename T>
512inline CheckedInt<T> operator /(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs)
513{
514    T x = lhs.value();
515    T y = rhs.value();
516    T is_op_valid = CheckedInt_internal::is_div_valid(x, y);
517    T result = is_op_valid ? (x / y) : 0;
518    /* give the compiler a good chance to perform RVO */
519    return CheckedInt<T>(result,
520                      lhs.mIsValid &
521                      rhs.mIsValid &
522                      is_op_valid);
523}
524
525// implement cast_to_CheckedInt<T>(x), making sure that
526//  - it allows x to be either a CheckedInt<T> or any integer type that can be casted to T
527//  - if x is already a CheckedInt<T>, we just return a reference to it, instead of copying it (optimization)
528
529template<typename T, typename U>
530struct cast_to_CheckedInt_impl
531{
532    typedef CheckedInt<T> return_type;
533    static CheckedInt<T> run(const U& u) { return u; }
534};
535
536template<typename T>
537struct cast_to_CheckedInt_impl<T, CheckedInt<T> >
538{
539    typedef const CheckedInt<T>& return_type;
540    static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
541};
542
543template<typename T, typename U>
544inline typename cast_to_CheckedInt_impl<T, U>::return_type
545cast_to_CheckedInt(const U& u)
546{
547    return cast_to_CheckedInt_impl<T, U>::run(u);
548}
549
550#define CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
551template<typename T>                                          \
552template<typename U>                                          \
553CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(const U &rhs)    \
554{                                                             \
555    *this = *this OP cast_to_CheckedInt<T>(rhs);                 \
556    return *this;                                             \
557}                                                             \
558template<typename T, typename U>                              \
559inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, const U &rhs) \
560{                                                             \
561    return lhs OP cast_to_CheckedInt<T>(rhs);                    \
562}                                                             \
563template<typename T, typename U>                              \
564inline CheckedInt<T> operator OP(const U & lhs, const CheckedInt<T> &rhs) \
565{                                                             \
566    return cast_to_CheckedInt<T>(lhs) OP rhs;                    \
567}
568
569CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
570CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
571CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
572CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
573
574template<typename T, typename U>
575inline bool operator ==(const CheckedInt<T> &lhs, const U &rhs)
576{
577    return lhs == cast_to_CheckedInt<T>(rhs);
578}
579
580template<typename T, typename U>
581inline bool operator ==(const U & lhs, const CheckedInt<T> &rhs)
582{
583    return cast_to_CheckedInt<T>(lhs) == rhs;
584}
585
586} // end namespace WebCore
587
588#endif /* CheckedInt_h */
589