-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathSafeInt3.hpp
7484 lines (6551 loc) · 235 KB
/
SafeInt3.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*-----------------------------------------------------------------------------------------------------------
SafeInt.hpp
Version 3.0.18p
This software is licensed under the Microsoft Public License (Ms-PL).
For more information about Microsoft open source licenses, refer to
http://www.microsoft.com/opensource/licenses.mspx
This license governs use of the accompanying software. If you use the software, you accept this license.
If you do not accept the license, do not use the software.
Definitions
The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here
as under U.S. copyright law. A "contribution" is the original software, or any additions or changes to
the software. A "contributor" is any person that distributes its contribution under this license.
"Licensed patents" are a contributor's patent claims that read directly on its contribution.
Grant of Rights
(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations
in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to
reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution
or any derivative works that you create.
(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in
section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed
patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution
in the software or derivative works of the contribution in the software.
Conditions and Limitations
(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo,
or trademarks.
(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the
software, your patent license from such contributor to the software ends automatically.
(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and
attribution notices that are present in the software.
(D) If you distribute any portion of the software in source code form, you may do so only under this license
by including a complete copy of this license with your distribution. If you distribute any portion of the
software in compiled or object code form, you may only do so under a license that complies with this license.
(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties,
guarantees, or conditions. You may have additional consumer rights under your local laws which this license
cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties
of merchantability, fitness for a particular purpose and non-infringement.
Copyright (c) Microsoft Corporation. All rights reserved.
This header implements an integer handling class designed to catch
unsafe integer operations
This header compiles properly at Wall on Visual Studio, -Wall on gcc, and -Weverything on clang.
Please read the leading comments before using the class.
---------------------------------------------------------------*/
#pragma once
// It is a bit tricky to sort out what compiler we are actually using,
// do this once here, and avoid cluttering the code
#define VISUAL_STUDIO_COMPILER 0
#define CLANG_COMPILER 1
#define GCC_COMPILER 2
#define UNKNOWN_COMPILER -1
// Clang will sometimes pretend to be Visual Studio
// and does pretend to be gcc. Check it first, as nothing else pretends to be clang
#if defined __clang__
#define SAFEINT_COMPILER CLANG_COMPILER
#elif defined __GNUC__
#define SAFEINT_COMPILER GCC_COMPILER
#elif defined _MSC_VER
#define SAFEINT_COMPILER VISUAL_STUDIO_COMPILER
#else
#define SAFEINT_COMPILER UNKNOWN_COMPILER
#endif
// Enable compiling with /Wall under VC
#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER
#pragma warning(push)
// Disable warnings coming from headers
#pragma warning(disable : 4987 4820 4987 4820)
#endif
// Need this for ptrdiff_t on some compilers
#include <cstddef>
#include <cstdlib>
#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER && defined _M_AMD64
#include <intrin.h>
#define SAFEINT_USE_INTRINSICS 1
#else
#define SAFEINT_USE_INTRINSICS 0
#endif
#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER
#pragma warning(pop)
#endif
// Various things needed for GCC
#if SAFEINT_COMPILER == GCC_COMPILER || SAFEINT_COMPILER == CLANG_COMPILER
#define NEEDS_INT_DEFINED
#if !defined NULL
#define NULL 0
#endif
// GCC warning suppression
#if SAFEINT_COMPILER == GCC_COMPILER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
#include <stdint.h>
// clang only
#if SAFEINT_COMPILER == CLANG_COMPILER
#if __has_feature(cxx_nullptr)
#define NEEDS_NULLPTR_DEFINED 0
#endif
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wc++11-long-long"
#pragma clang diagnostic ignored "-Wold-style-cast"
#pragma clang diagnostic ignored "-Wunused-local-typedef"
#endif
#endif
// If the user made a choice, respect it #if !defined
#if !defined NEEDS_NULLPTR_DEFINED
// Visual Studio 2010 and higher support this
#if SAFEINT_COMPILER == VISUAL_STUDIO_COMPILER
#if (_MSC_VER < 1600)
#define NEEDS_NULLPTR_DEFINED 1
#else
#define NEEDS_NULLPTR_DEFINED 0
#endif
#else
// Let everything else trigger based on whether we use c++11 or above
#if __cplusplus >= 201103L
#define NEEDS_NULLPTR_DEFINED 0
#else
#define NEEDS_NULLPTR_DEFINED 1
#endif
#endif
#endif
#if NEEDS_NULLPTR_DEFINED
#define nullptr NULL
#endif
#ifndef C_ASSERT
#define C_ASSERT_DEFINED_SAFEINT
#define C_ASSERT(e) typedef char __C_ASSERT__[(e) ? 1 : -1]
#endif
// Let's test some assumptions
// We're assuming two's complement negative numbers
C_ASSERT(-1 == static_cast<int>(0xffffffff));
/************* Compiler Options
*****************************************************************************************************
SafeInt supports several compile-time options that can change the behavior of the class.
Compiler options:
SAFEINT_WARN_64BIT_PORTABILITY - this re-enables various warnings that happen when /Wp64 is used. Enabling this
option is not recommended. NEEDS_INT_DEFINED - if your compiler does not support __int8, __int16,
__int32 and __int64, you can enable this. SAFEINT_ASSERT_ON_EXCEPTION - it is often easier to stop on an assert
and figure out a problem than to try and figure out how you landed in the catch block. SafeIntDefaultExceptionHandler -
if you'd like to replace the exception handlers SafeInt provides, define your replacement and define this. Note - two
built in (Windows-specific) options exist:
- SAFEINT_FAILFAST - bypasses all exception handlers, exits the app with an
exception
- SAFEINT_RAISE_EXCEPTION - throws Win32 exceptions, which can be caught
SAFEINT_DISALLOW_UNSIGNED_NEGATION - Invoking the unary negation operator creates warnings, but if you'd like it to
completely fail to compile, define this. ANSI_CONVERSIONS - This changes the class to use default
comparison behavior, which may be unsafe. Enabling this option is not recommended. SAFEINT_DISABLE_BINARY_ASSERT -
binary AND, OR or XOR operations on mixed size types can produce unexpected results. If you do this, the default is to
assert. Set this if you prefer not to assert under these conditions. SIZE_T_CAST_NEEDED - some compilers
complain if there is not a cast to size_t, others complain if there is one. This lets you not have your compiler
complain. SAFEINT_DISABLE_SHIFT_ASSERT - Set this option if you don't want to assert when shifting more bits than
the type has. Enabling this option is not recommended.
************************************************************************************************************************************/
/*
* The SafeInt class is designed to have as low an overhead as possible
* while still ensuring that all integer operations are conducted safely.
* Nearly every operator has been overloaded, with a very few exceptions.
*
* A usability-safety trade-off has been made to help ensure safety. This
* requires that every operation return either a SafeInt or a bool. If we
* allowed an operator to return a base integer type T, then the following
* can happen:
*
* char i = SafeInt<char>(32) * 2 + SafeInt<char>(16) * 4;
*
* The * operators take precedence, get overloaded, return a char, and then
* you have:
*
* char i = (char)64 + (char)64; //overflow!
*
* This situation would mean that safety would depend on usage, which isn't
* acceptable.
*
* One key operator that is missing is an implicit cast to type T. The reason for
* this is that if there is an implicit cast operator, then we end up with
* an ambiguous compile-time precedence. Because of this ambiguity, there
* are two methods that are provided:
*
* Casting operators for every native integer type
* Version 3 note - it now compiles correctly for size_t without warnings
*
* SafeInt::Ptr() - returns the address of the internal integer
* Note - the '&' (address of) operator has been overloaded and returns
* the address of the internal integer.
*
* The SafeInt class should be used in any circumstances where ensuring
* integrity of the calculations is more important than performance. See Performance
* Notes below for additional information.
*
* Many of the conditionals will optimize out or be inlined for a release
* build (especially with /Ox), but it does have significantly more overhead,
* especially for signed numbers. If you do not _require_ negative numbers, use
* unsigned integer types - certain types of problems cannot occur, and this class
* performs most efficiently.
*
* Here's an example of when the class should ideally be used -
*
* void* AllocateMemForStructs(int StructSize, int HowMany)
* {
* SafeInt<unsigned long> s(StructSize);
*
* s *= HowMany;
*
* return malloc(s);
*
* }
*
* Here's when it should NOT be used:
*
* void foo()
* {
* int i;
*
* for(i = 0; i < 0xffff; i++)
* ....
* }
*
* Error handling - a SafeInt class will throw exceptions if something
* objectionable happens. The exceptions are SafeIntException classes,
* which contain an enum as a code.
*
* Typical usage might be:
*
* bool foo()
* {
* SafeInt<unsigned long> s; //note that s == 0 unless set
*
* try{
* s *= 23;
* ....
* }
* catch(SafeIntException err)
* {
* //handle errors here
* }
* }
*
* Update for 3.0 - the exception class is now a template parameter.
* You can replace the exception class with any exception class you like. This is accomplished by:
* 1) Create a class that has the following interface:
*
template <> class YourSafeIntExceptionHandler < YourException >
{
public:
static __declspec(noreturn) void __stdcall SafeIntOnOverflow()
{
throw YourException( YourSafeIntArithmeticOverflowError );
}
static __declspec(noreturn) void __stdcall SafeIntOnDivZero()
{
throw YourException( YourSafeIntDivideByZeroError );
}
};
*
* Note that you don't have to throw C++ exceptions, you can throw Win32 exceptions, or do
* anything you like, just don't return from the call back into the code.
*
* 2) Either explicitly declare SafeInts like so:
* SafeInt< int, YourSafeIntExceptionHandler > si;
* or
* #define SafeIntDefaultExceptionHandler YourSafeIntExceptionHandler
*
* Performance:
*
* Due to the highly nested nature of this class, you can expect relatively poor
* performance in unoptimized code. In tests of optimized code vs. correct inline checks
* in native code, this class has been found to take approximately 8% more CPU time (this varies),
* most of which is due to exception handling. Solutions:
*
* 1) Compile optimized code - /Ox is best, /O2 also performs well. Interestingly, /O1
* (optimize for size) does not work as well.
* 2) If that 8% hit is really a serious problem, walk through the code and inline the
* exact same checks as the class uses.
* 3) Some operations are more difficult than others - avoid using signed integers, and if
* possible keep them all the same size. 64-bit integers are also expensive. Mixing
* different integer sizes and types may prove expensive. Be aware that literals are
* actually ints. For best performance, cast literals to the type desired.
*
*
* Performance update
* The current version of SafeInt uses template specialization to force the compiler to invoke only the
* operator implementation needed for any given pair of types. This will dramatically improve the perf
* of debug builds.
*
* 3.0 update - not only have we maintained the specialization, there were some cases that were overly complex,
* and using some additional cases (e.g. signed __int64 and unsigned __int64) resulted in some simplification.
* Additionally, there was a lot of work done to better optimize the 64-bit multiplication.
*
* Binary Operators
*
* All of the binary operators have certain assumptions built into the class design.
* This is to ensure correctness. Notes on each class of operator follow:
*
* Arithmetic Operators (*,/,+,-,%)
* There are three possible variants:
* SafeInt< T, E > op SafeInt< T, E >
* SafeInt< T, E > op U
* U op SafeInt< T, E >
*
* The SafeInt< T, E > op SafeInt< U, E > variant is explicitly not supported, and if you try to do
* this the compiler with throw the following error:
*
* error C2593: 'operator *' is ambiguous
*
* This is because the arithmetic operators are required to return a SafeInt of some type.
* The compiler cannot know whether you'd prefer to get a type T or a type U returned. If
* you need to do this, you need to extract the value contained within one of the two using
* the casting operator. For example:
*
* SafeInt< T, E > t, result;
* SafeInt< U, E > u;
*
* result = t * (U)u;
*
* Comparison Operators
* Because each of these operators return type bool, mixing SafeInts of differing types is
* allowed.
*
* Shift Operators
* Shift operators always return the type on the left hand side of the operator. Mixed type
* operations are allowed because the return type is always known.
*
* Boolean Operators
* Like comparison operators, these overloads always return type bool, and mixed-type SafeInts
* are allowed. Additionally, specific overloads exist for type bool on both sides of the
* operator.
*
* Binary Operators
* Mixed-type operations are discouraged, however some provision has been made in order to
* enable things like:
*
* SafeInt<char> c = 2;
*
* if(c & 0x02)
* ...
*
* The "0x02" is actually an int, and it needs to work.
* In the case of binary operations on integers smaller than 32-bit, or of mixed type, corner
* cases do exist where you could get unexpected results. In any case where SafeInt returns a different
* result than the underlying operator, it will call assert(). You should examine your code and cast things
* properly so that you are not programming with side effects.
*
* Documented issues:
*
* This header compiles correctly at /W4 using VC++ 8 (Version 14.00.50727.42) and later.
* As of this writing, I believe it will also work for VC 7.1, but not for VC 7.0 or below.
* If you need a version that will work with lower level compilers, try version 1.0.7. None
* of them work with Visual C++ 6, and gcc didn't work very well, either, though this hasn't
* been tried recently.
*
* It is strongly recommended that any code doing integer manipulation be compiled at /W4
* - there are a number of warnings which pertain to integer manipulation enabled that are
* not enabled at /W3 (default for VC++)
*
* Perf note - postfix operators are slightly more costly than prefix operators.
* Unless you're actually assigning it to something, ++SafeInt is less expensive than SafeInt++
*
* The comparison operator behavior in this class varies from the ANSI definition, which is
* arguably broken. As an example, consider the following:
*
* unsigned int l = 0xffffffff;
* char c = -1;
*
* if(c == l)
* printf("Why is -1 equal to 4 billion???\n");
*
* The problem here is that c gets cast to an int, now has a value of 0xffffffff, and then gets
* cast again to an unsigned int, losing the true value. This behavior is despite the fact that
* an __int64 exists, and the following code will yield a different (and intuitively correct)
* answer:
*
* if((__int64)c == (__int64)l))
* printf("Why is -1 equal to 4 billion???\n");
* else
* printf("Why doesn't the compiler upcast to 64-bits when needed?\n");
*
* Note that combinations with smaller integers won't display the problem - if you
* changed "unsigned int" above to "unsigned short", you'd get the right answer.
*
* If you prefer to retain the ANSI standard behavior insert
* #define ANSI_CONVERSIONS
* into your source. Behavior differences occur in the following cases:
* 8, 16, and 32-bit signed int, unsigned 32-bit int
* any signed int, unsigned 64-bit int
* Note - the signed int must be negative to show the problem
*
*
* Revision history:
*
* Oct 12, 2003 - Created
* Author - David LeBlanc - [email protected]
*
* Oct 27, 2003 - fixed numerous items pointed out by michmarc and bdawson
* Dec 28, 2003 - 1.0
* added support for mixed-type operations
* thanks to vikramh
* also fixed broken __int64 multiplication section
* added extended support for mixed-type operations where possible
* Jan 28, 2004 - 1.0.1
* changed WCHAR to wchar_t
* fixed a construct in two mixed-type assignment overloads that was
* not compiling on some compilers
* Also changed name of private method to comply with standards on
* reserved names
* Thanks to Niels Dekker for the input
* Feb 12, 2004 - 1.0.2
* Minor changes to remove dependency on Windows headers
* Consistently used __int16, __int32 and __int64 to ensure
* portability
* May 10, 2004 - 1.0.3
* Corrected bug in one case of GreaterThan
* July 22, 2004 - 1.0.4
* Tightened logic in addition check (saving 2 instructions)
* Pulled error handler out into function to enable user-defined replacement
* Made internal type of SafeIntException an enum (as per Niels' suggestion)
* Added casts for base integer types (as per Scott Meyers' suggestion)
* Updated usage information - see important new perf notes.
* Cleaned up several const issues (more thanks to Niels)
*
* Oct 1, 2004 - 1.0.5
* Added support for SEH exceptions instead of C++ exceptions - Win32 only
* Made handlers for DIV0 and overflows individually overridable
* Commented out the destructor - major perf gains here
* Added cast operator for type long, since long != __int32
* Corrected a couple of missing const modifiers
* Fixed broken >= and <= operators for type U op SafeInt< T, E >
* Nov 5, 2004 - 1.0.6
* Implemented new logic in binary operators to resolve issues with
* implicit casts
* Fixed casting operator because char != signed char
* Defined __int32 as int instead of long
* Removed unsafe SafeInt::Value method
* Re-implemented casting operator as a result of removing Value method
* Dec 1, 2004 - 1.0.7
* Implemented specialized operators for pointer arithmetic
* Created overloads for cases of U op= SafeInt. What you do with U
* after that may be dangerous.
* Fixed bug in corner case of MixedSizeModulus
* Fixed bug in MixedSizeMultiply and MixedSizeDivision with input of 0
* Added throw() decorations
*
* Apr 12, 2005 - 2.0
* Extensive revisions to leverage template specialization.
* April, 2007 Extensive revisions for version 3.0
* Nov 22, 2009 Forked from MS internal code
* Changes needed to support gcc compiler - many thanks to Niels Dekker
* for determining not just the issues, but also suggesting fixes.
* Also updating some of the header internals to be the same as the upcoming Visual Studio version.
*
* Jan 16, 2010 64-bit gcc has long == __int64, which means that many of the existing 64-bit
* templates are over-specialized. This forces a redefinition of all the 64-bit
* multiplication routines to use pointers instead of references for return
* values. Also, let's use some intrinsics for x64 Microsoft compiler to
* reduce code size, and hopefully improve efficiency.
*
* June 21, 2014 Better support for clang, higher warning levels supported for all 3 primary supported
compilers (Visual Studio, clang, gcc).
Also started to converge the code base such that the public CodePlex version will
be a drop-in replacement for the Visual Studio version.
* Note about code style - throughout this class, casts will be written using C-style (T),
* not C++ style static_cast< T >. This is because the class is nearly always dealing with integer
* types, and in this case static_cast and a C cast are equivalent. Given the large number of casts,
* the code is a little more readable this way. In the event a cast is needed where static_cast couldn't
* be substituted, we'll use the new templatized cast to make it explicit what the operation is doing.
*
************************************************************************************************************
* Version 3.0 changes:
*
* 1) The exception type thrown is now replacable, and you can throw your own exception types. This should help
* those using well-developed exception classes.
* 2) The 64-bit multiplication code has had a lot of perf work done, and should be faster than 2.0.
* 3) There is now limited floating point support. You can initialize a SafeInt with a floating point type,
* and you can cast it out (or assign) to a float as well.
* 4) There is now an Align method. I noticed people use this a lot, and rarely check errors, so now you have one.
*
* Another major improvement is the addition of external functions - if you just want to check an operation, this can now
happen:
* All of the following can be invoked without dealing with creating a class, or managing exceptions. This is especially
handy
* for 64-bit porting, since SafeCast compiles away for a 32-bit cast from size_t to unsigned long, but checks it for
64-bit.
*
* inline bool SafeCast( const T From, U& To ) throw()
* inline bool SafeEquals( const T t, const U u ) throw()
* inline bool SafeNotEquals( const T t, const U u ) throw()
* inline bool SafeGreaterThan( const T t, const U u ) throw()
* inline bool SafeGreaterThanEquals( const T t, const U u ) throw()
* inline bool SafeLessThan( const T t, const U u ) throw()
* inline bool SafeLessThanEquals( const T t, const U u ) throw()
* inline bool SafeModulus( const T& t, const U& u, T& result ) throw()
* inline bool SafeMultiply( T t, U u, T& result ) throw()
* inline bool SafeDivide( T t, U u, T& result ) throw()
* inline bool SafeAdd( T t, U u, T& result ) throw()
* inline bool SafeSubtract( T t, U u, T& result ) throw()
*
*/
// use these if the compiler does not support _intXX
#ifdef NEEDS_INT_DEFINED
#define __int8 char
#define __int16 short
#define __int32 int
#define __int64 long long
#endif
namespace msl
{
namespace safeint3
{
// catch these to handle errors
// Currently implemented code values:
// ERROR_ARITHMETIC_OVERFLOW
// EXCEPTION_INT_DIVIDE_BY_ZERO
enum SafeIntError
{
SafeIntNoError = 0,
SafeIntArithmeticOverflow,
SafeIntDivideByZero
};
} // namespace safeint3
} // namespace msl
/*
* Error handler classes
* Using classes to deal with exceptions is going to allow the most
* flexibility, and we can mix different error handlers in the same project
* or even the same file. It isn't advisable to do this in the same function
* because a SafeInt< int, MyExceptionHandler > isn't the same thing as
* SafeInt< int, YourExceptionHander >.
* If for some reason you have to translate between the two, cast one of them back to its
* native type.
*
* To use your own exception class with SafeInt, first create your exception class,
* which may look something like the SafeIntException class below. The second step is to
* create a template specialization that implements SafeIntOnOverflow and SafeIntOnDivZero.
* For example:
*
* template <> class SafeIntExceptionHandler < YourExceptionClass >
* {
* static __declspec(noreturn) void __stdcall SafeIntOnOverflow()
* {
* throw YourExceptionClass( EXCEPTION_INT_OVERFLOW );
* }
*
* static __declspec(noreturn) void __stdcall SafeIntOnDivZero()
* {
* throw YourExceptionClass( EXCEPTION_INT_DIVIDE_BY_ZERO );
* }
* };
*
* typedef SafeIntExceptionHandler < YourExceptionClass > YourSafeIntExceptionHandler
* You'd then declare your SafeInt objects like this:
* SafeInt< int, YourSafeIntExceptionHandler >
*
* Unfortunately, there is no such thing as partial template specialization in typedef
* statements, so you have three options if you find this cumbersome:
*
* 1) Create a holder class:
*
* template < typename T >
* class MySafeInt
* {
* public:
* SafeInt< T, MyExceptionClass> si;
* };
*
* You'd then declare an instance like so:
* MySafeInt< int > i;
*
* You'd lose handy things like initialization - it would have to be initialized as:
*
* i.si = 0;
*
* 2) You could create a typedef for every int type you deal with:
*
* typedef SafeInt< int, MyExceptionClass > MySafeInt;
* typedef SafeInt< char, MyExceptionClass > MySafeChar;
*
* and so on. The second approach is probably more usable, and will just drop into code
* better, which is the original intent of the SafeInt class.
*
* 3) If you're going to consistently use a different class to handle your exceptions,
* you can override the default typedef like so:
*
* #define SafeIntDefaultExceptionHandler YourSafeIntExceptionHandler
*
* Overall, this is probably the best approach.
* */
// On the Microsoft compiler, violating a throw() annotation is a silent error.
// Other compilers might turn these into exceptions, and some users may want to not have throw() enabled.
// In addition, some error handlers may not throw C++ exceptions, which makes everything no throw.
#if defined SAFEINT_REMOVE_NOTHROW
#define SAFEINT_NOTHROW
#else
#define SAFEINT_NOTHROW throw()
#endif
namespace msl
{
namespace safeint3
{
// If you would like to use your own custom assert
// Define SAFEINT_ASSERT
#if !defined SAFEINT_ASSERT
#include <assert.h>
#define SAFEINT_ASSERT(x) assert(x)
#endif
#if defined SAFEINT_ASSERT_ON_EXCEPTION
inline void SafeIntExceptionAssert() SAFEINT_NOTHROW { SAFEINT_ASSERT(false); }
#else
inline void SafeIntExceptionAssert() SAFEINT_NOTHROW {}
#endif
#if SAFEINT_COMPILER == GCC_COMPILER || SAFEINT_COMPILER == CLANG_COMPILER
#define SAFEINT_NORETURN __attribute__((noreturn))
#define SAFEINT_STDCALL
#define SAFEINT_VISIBLE __attribute__((__visibility__("default")))
#define SAFEINT_WEAK __attribute__((weak))
#else
#define SAFEINT_NORETURN __declspec(noreturn)
#define SAFEINT_STDCALL __stdcall
#define SAFEINT_VISIBLE
#define SAFEINT_WEAK
#endif
class SAFEINT_VISIBLE SafeIntException
{
public:
SafeIntException() SAFEINT_NOTHROW { m_code = SafeIntNoError; }
SafeIntException(SafeIntError code) SAFEINT_NOTHROW { m_code = code; }
SafeIntError m_code;
};
namespace SafeIntInternal
{
// Visual Studio version of SafeInt provides for two possible error
// handlers:
// SafeIntErrorPolicy_SafeIntException - C++ exception, default if not otherwise defined
// SafeIntErrorPolicy_InvalidParameter - Calls fail fast (Windows-specific), bypasses any exception handlers,
// exits the app with a crash
template<typename E>
class SafeIntExceptionHandler;
template<>
class SafeIntExceptionHandler<SafeIntException>
{
public:
static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow()
{
SafeIntExceptionAssert();
throw SafeIntException(SafeIntArithmeticOverflow);
}
static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero()
{
SafeIntExceptionAssert();
throw SafeIntException(SafeIntDivideByZero);
}
};
#if !defined _CRT_SECURE_INVALID_PARAMETER
// Calling fail fast is somewhat more robust than calling abort,
// but abort is the closest we can manage without Visual Studio support
// Need the header for abort()
#include <stdlib.h>
#define _CRT_SECURE_INVALID_PARAMETER(msg) abort()
#endif
class SafeInt_InvalidParameter
{
public:
static SAFEINT_NORETURN void SafeIntOnOverflow() SAFEINT_NOTHROW
{
SafeIntExceptionAssert();
_CRT_SECURE_INVALID_PARAMETER("SafeInt Arithmetic Overflow");
}
static SAFEINT_NORETURN void SafeIntOnDivZero() SAFEINT_NOTHROW
{
SafeIntExceptionAssert();
_CRT_SECURE_INVALID_PARAMETER("SafeInt Divide By Zero");
}
};
#if defined _WINDOWS_
class SafeIntWin32ExceptionHandler
{
public:
static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnOverflow() SAFEINT_NOTHROW
{
SafeIntExceptionAssert();
RaiseException(static_cast<DWORD>(EXCEPTION_INT_OVERFLOW), EXCEPTION_NONCONTINUABLE, 0, 0);
}
static SAFEINT_NORETURN void SAFEINT_STDCALL SafeIntOnDivZero() SAFEINT_NOTHROW
{
SafeIntExceptionAssert();
RaiseException(static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), EXCEPTION_NONCONTINUABLE, 0, 0);
}
};
#endif
} // namespace SafeIntInternal
// both of these have cross-platform support
typedef SafeIntInternal::SafeIntExceptionHandler<SafeIntException> CPlusPlusExceptionHandler;
typedef SafeIntInternal::SafeInt_InvalidParameter InvalidParameterExceptionHandler;
// This exception handler is no longer recommended, but is left here in order not to break existing users
#if defined _WINDOWS_
typedef SafeIntInternal::SafeIntWin32ExceptionHandler Win32ExceptionHandler;
#endif
// For Visual Studio compatibility
#if defined VISUAL_STUDIO_SAFEINT_COMPAT
typedef CPlusPlusExceptionHandler SafeIntErrorPolicy_SafeIntException;
typedef InvalidParameterExceptionHandler SafeIntErrorPolicy_InvalidParameter;
#endif
// If the user hasn't defined a default exception handler,
// define one now, depending on whether they would like Win32 or C++ exceptions
// This library will use conditional noexcept soon, but not in this release
// Some users might mix exception handlers, which is not advised, but is supported
#if !defined SafeIntDefaultExceptionHandler
#if defined SAFEINT_RAISE_EXCEPTION
#if !defined _WINDOWS_
#error Include windows.h in order to use Win32 exceptions
#endif
#define SafeIntDefaultExceptionHandler Win32ExceptionHandler
#elif defined SAFEINT_FAILFAST
#define SafeIntDefaultExceptionHandler InvalidParameterExceptionHandler
#else
#define SafeIntDefaultExceptionHandler CPlusPlusExceptionHandler
#if !defined SAFEINT_EXCEPTION_HANDLER_CPP
#define SAFEINT_EXCEPTION_HANDLER_CPP 1
#endif
#endif
#endif
#if !defined SAFEINT_EXCEPTION_HANDLER_CPP
#define SAFEINT_EXCEPTION_HANDLER_CPP 0
#endif
// If an error handler is chosen other than C++ exceptions, such as Win32 exceptions, fail fast,
// or abort, then all methods become no throw. Some teams track throw() annotations closely,
// and the following option provides for this.
#if SAFEINT_EXCEPTION_HANDLER_CPP
#define SAFEINT_CPP_THROW
#else
#define SAFEINT_CPP_THROW SAFEINT_NOTHROW
#endif
// Turns out we can fool the compiler into not seeing compile-time constants with
// a simple template specialization
template<int method>
class CompileConst;
template<>
class CompileConst<true>
{
public:
static bool Value() SAFEINT_NOTHROW { return true; }
};
template<>
class CompileConst<false>
{
public:
static bool Value() SAFEINT_NOTHROW { return false; }
};
// The following template magic is because we're now not allowed
// to cast a float to an enum. This means that if we happen to assign
// an enum to a SafeInt of some type, it won't compile, unless we prevent
// isFloat = ( (T)( (float)1.1 ) > (T)1 )
// from compiling in the case of an enum, which is the point of the specialization
// that follows.
// If we have support for std<typetraits>, then we can do this easily, and detect enums as well
template<typename T>
class NumericType;
#if defined _LIBCPP_TYPE_TRAITS || defined _TYPE_TRAITS_
// Continue to special case bool
template<>
class NumericType<bool>
{
public:
enum
{
isBool = true,
isFloat = false,
isInt = false
};
};
template<typename T>
class NumericType
{
public:
enum
{
isBool = false, // We specialized out a bool
isFloat = std::is_floating_point<T>::value,
// If it is an enum, then consider it an int type
// This does allow someone to make a SafeInt from an enum type, which is not recommended,
// but it also allows someone to add an enum value to a SafeInt, which is handy.
isInt = std::is_integral<T>::value || std::is_enum<T>::value
};
};
#else
template<>
class NumericType<bool>
{
public:
enum
{
isBool = true,
isFloat = false,
isInt = false
};
};
template<>
class NumericType<char>
{
public:
enum
{
isBool = false,
isFloat = false,
isInt = true
};
};
template<>
class NumericType<unsigned char>
{
public:
enum
{
isBool = false,
isFloat = false,
isInt = true
};
};
template<>
class NumericType<signed char>
{
public:
enum
{
isBool = false,
isFloat = false,
isInt = true
};
};
template<>
class NumericType<short>
{
public:
enum
{
isBool = false,
isFloat = false,
isInt = true
};
};
template<>
class NumericType<unsigned short>
{
public:
enum
{
isBool = false,
isFloat = false,
isInt = true
};
};
#if defined SAFEINT_USE_WCHAR_T || defined _NATIVE_WCHAR_T_DEFINED
template<>
class NumericType<wchar_t>
{
public:
enum
{
isBool = false,
isFloat = false,
isInt = true
};
};
#endif
template<>
class NumericType<int>
{
public:
enum
{
isBool = false,
isFloat = false,
isInt = true
};
};
template<>
class NumericType<unsigned int>
{
public:
enum
{
isBool = false,
isFloat = false,
isInt = true
};
};
template<>
class NumericType<long>
{
public:
enum
{
isBool = false,
isFloat = false,
isInt = true
};
};
template<>
class NumericType<unsigned long>
{
public:
enum
{
isBool = false,
isFloat = false,
isInt = true
};
};
template<>
class NumericType<__int64>
{
public:
enum
{
isBool = false,
isFloat = false,
isInt = true
};
};
template<>
class NumericType<unsigned __int64>
{
public:
enum
{
isBool = false,
isFloat = false,
isInt = true
};
};
template<>
class NumericType<float>