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