Skip to content

Instantly share code, notes, and snippets.

@benstiglitz
Last active December 27, 2015 00:29
Show Gist options
  • Save benstiglitz/7237894 to your computer and use it in GitHub Desktop.
Save benstiglitz/7237894 to your computer and use it in GitHub Desktop.
Safe bounded casting between types.
#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
#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