Last active
December 27, 2015 00:29
-
-
Save benstiglitz/7237894 to your computer and use it in GitHub Desktop.
Safe bounded casting between types.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if __has_extension(c_generic_selections) && __has_extension(c_static_assert) | |
#import "EvilCastImpl.h" | |
// Returns the value of s, clamping it to the bounds of type t. s and d must either both be integers | |
// or both be floating-point values. | |
#define EvilBoundedCheckedCast(t, s) __EvilChecked(t, s, Cast) | |
// Tries to assign the value of s to d, returning 1 if s is within the bounds of s and 0 if not. | |
// s and d must either both be integers or both be floating-point values. | |
#define EvilCheckedAssign(d, s) __EvilChecked(d, s, Assign) | |
#else | |
#error Compiler features necessary for implementing EvilBoundedCheckedCast and EvilCheckedCast are not present. | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define __EvilMinOfCastableType(T) _Generic(T, \ | |
char: CHAR_MIN, \ | |
unsigned char: 0, \ | |
short: SHRT_MIN, \ | |
unsigned short: 0, \ | |
int: INT_MIN, \ | |
unsigned int: 0, \ | |
long: LONG_MIN, \ | |
unsigned long: 0, \ | |
float: -FLT_MAX, \ | |
double: -DBL_MAX \ | |
) | |
#define __EvilMaxOfCastableType(T) _Generic(T, \ | |
char: CHAR_MAX, \ | |
unsigned char: UCHAR_MAX, \ | |
short: SHRT_MAX, \ | |
unsigned short: USHRT_MAX, \ | |
int: INT_MAX, \ | |
unsigned int: UINT_MAX, \ | |
long: LONG_MAX, \ | |
unsigned long: ULONG_MAX, \ | |
float: FLT_MAX, \ | |
double: DBL_MAX \ | |
) | |
#define __EvilIsCastableFloatType(T) _Generic(T, \ | |
float: 1, \ | |
double: 1, \ | |
const float: 1, \ | |
const double: 1, \ | |
default: 0 \ | |
) | |
#define __EvilIsCastableIntType(T) _Generic(T, \ | |
char: 1, \ | |
unsigned char: 1, \ | |
short: 1, \ | |
unsigned short: 1, \ | |
int: 1, \ | |
unsigned int: 1, \ | |
long: 1, \ | |
unsigned long: 1, \ | |
const char: 1, \ | |
const unsigned char: 1, \ | |
const short: 1, \ | |
const unsigned short: 1, \ | |
const int: 1, \ | |
const unsigned int: 1, \ | |
const long: 1, \ | |
const unsigned long: 1, \ | |
default: 0 \ | |
) | |
#define __EvilCheckedAssignWithBoundType(d, s, bt) \ | |
((__builtin_expect((bt)s > (bt)__EvilMaxOfCastableType(d) || (bt)s < (bt)__EvilMinOfCastableType(d), 0)) \ | |
? ({NSCAssert(NO, @"Out-of-bounds type assignment failed"); 0;}) \ | |
: ({d = (__typeof(d))s; 1;}) \ | |
) | |
#define __EvilCheckedCastWithBoundType(t, s, bt) \ | |
({t __tt; \ | |
__builtin_expect((bt)s > (bt)__EvilMaxOfCastableType(__tt), 0) \ | |
? ({NSCAssert(NO, @"Out-of-bounds type assignment was clamped to max"); (t)__EvilMaxOfCastableType(__tt);}) \ | |
: ( \ | |
__builtin_expect((bt)s < (bt)__EvilMinOfCastableType(__tt), 0) \ | |
? ({NSCAssert(NO, @"Out-of-bounds type assignment was clamped to min"); (t)__EvilMinOfCastableType(__tt);}) \ | |
: ({(t)s;}) \ | |
); \ | |
}) | |
#define __EvilCheckedIntAssign(d, s) __EvilCheckedAssignWithBoundType(d, s, long long) | |
#define __EvilCheckedFloatAssign(d, s) __EvilCheckedAssignWithBoundType(d, s, long double) | |
#define __EvilCheckedIntCast(t, s) __EvilCheckedCastWithBoundType(t, s, long long) | |
#define __EvilCheckedFloatCast(t, s) __EvilCheckedCastWithBoundType(t, s, long double) | |
#define __EvilChecked(a, b, s) \ | |
({__typeof(a) __t; __typeof(b) __u = b; _Static_assert((__EvilIsCastableIntType(__t) && __EvilIsCastableIntType(__u)) \ | |
|| (__EvilIsCastableFloatType(__t) && __EvilIsCastableFloatType(__u)), "Invalid types for EvilChecked" #s "."); \ | |
__EvilIsCastableIntType(__t) && __EvilIsCastableIntType(__u) \ | |
? __EvilCheckedInt##s(a, __u) \ | |
: (__EvilIsCastableFloatType(__t) && __EvilIsCastableFloatType(__u) \ | |
? __EvilCheckedFloat##s(a, __u) \ | |
: (__typeof(a))({__builtin_unreachable(); 0;}) \ | |
); \ | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment