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