Last active
May 8, 2016 04:45
-
-
Save Kludgy/cffbd475dc88322cf61e9c7016d1908c to your computer and use it in GitHub Desktop.
Attempt at parity between cache and MySQL int-int casting semantics.
This file contains hidden or 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
#include <iostream> | |
#include <limits> | |
#include <algorithm> | |
using std::numeric_limits; | |
using std::min; | |
using std::max; | |
using std::cout; | |
using std::endl; | |
namespace detail | |
{ | |
// Note that both A and B must be integral to permit a cast. | |
// No warranty about the correctness of this code! | |
enum { EQ, LT, GT }; | |
template <class A, class B> static constexpr int evalAordB() | |
{ | |
return | |
sizeof(A) == sizeof(B) ? EQ : | |
sizeof(A) < sizeof(B) ? LT : GT; | |
} | |
template<class A, class B, bool aIntegral, bool bIntegral, bool aSigned, bool bSigned, int aOrdB> struct SqlCastIntegral; | |
// Width A = B | |
template <class A, class B> struct SqlCastIntegral< A, B, true, true, false, false, EQ > { static constexpr B eval(A x) { return B(x); } }; // <== min,max(A) = min,max(B) | |
template <class A, class B> struct SqlCastIntegral< A, B, true, true, false, true , EQ > { static constexpr B eval(A x) { return B(min<A>(x, numeric_limits<B>::max())); } }; // <== min,max(A) > min,max(B), min(A) = 0 | |
template <class A, class B> struct SqlCastIntegral< A, B, true, true, true , false, EQ > { static constexpr B eval(A x) { return B(max<A>(x, 0)); } }; // <== min,max(A) < min,max(B), min(B) = 0 | |
template <class A, class B> struct SqlCastIntegral< A, B, true, true, true , true , EQ > { static constexpr B eval(A x) { return B(x); } }; // <== min,max(A) = min,max(B) | |
// Width A < B | |
template <class A, class B> struct SqlCastIntegral< A, B, true, true, false, false, LT > { static constexpr B eval(A x) { return B(x); } }; // <== min(A,B) = 0, max(A) < max(B) | |
template <class A, class B> struct SqlCastIntegral< A, B, true, true, false, true , LT > { static constexpr B eval(A x) { return B(x); } }; // <== min(A) > min(B), max(A) <= max(B), min(A) = 0 | |
template <class A, class B> struct SqlCastIntegral< A, B, true, true, true , false, LT > { static constexpr B eval(A x) { return B(max<A>(x, 0)); } }; // <== min(A) < min(B), max(A) < max(B), min(B) = 0 | |
template <class A, class B> struct SqlCastIntegral< A, B, true, true, true , true , LT > { static constexpr B eval(A x) { return B(x); } }; // <== min(A) > min(B), max(A) < max(B) | |
// Width A > B | |
template <class A, class B> struct SqlCastIntegral< A, B, true, true, false, false, GT > { static constexpr B eval(A x) { return B(min<A>(x, (A)numeric_limits<B>::max())); } }; // <== min(A,B) = 0, max(A) > max(B) | |
template <class A, class B> struct SqlCastIntegral< A, B, true, true, false, true , GT > { static constexpr B eval(A x) { return B(min<A>(x, (A)numeric_limits<B>::max())); } }; // <== min(A) > min(B), max(A) > max(B), min(A) = 0 | |
template <class A, class B> struct SqlCastIntegral< A, B, true, true, true , false, GT > { static constexpr B eval(A x) { return B(max<A>(min<A>(x, (A)numeric_limits<B>::max()), 0)); } }; // <== min(A) < min(B), max(A) >= max(B), min(B) = 0 | |
template <class A, class B> struct SqlCastIntegral< A, B, true, true, true , true , GT > { static constexpr B eval(A x) { return B(max<A>(min<A>(x, (A)numeric_limits<B>::max()), numeric_limits<B>::min())); } }; // <== min(A) < min(B), max(A) > max(B) | |
} | |
template <class B, class A> constexpr B SqlCastIntegral(A x) | |
{ | |
return detail::SqlCastIntegral | |
<A, B, | |
numeric_limits<A>::is_integer, numeric_limits<B>::is_integer, | |
numeric_limits<A>::is_signed, numeric_limits<B>::is_signed, | |
detail::evalAordB<A, B>() >:: | |
eval(x); | |
} | |
int main() | |
{ | |
cout << "Clamping integers to the intersections of their respective ranges." << endl; | |
cout << endl; | |
cout << "sign change:" << endl; | |
cout << " max(uint16_t) -> int16_t = " << SqlCastIntegral< int16_t >( numeric_limits< uint16_t >::max() ) << endl; | |
cout << " max( int16_t) -> uint16_t = " << SqlCastIntegral< uint16_t >( numeric_limits< int16_t >::max() ) << endl; | |
cout << " min(uint16_t) -> int16_t = " << SqlCastIntegral< int16_t >( numeric_limits< uint16_t >::min() ) << endl; | |
cout << " min( int16_t) -> uint16_t = " << SqlCastIntegral< uint16_t >( numeric_limits< int16_t >::min() ) << endl; | |
cout << endl; | |
cout << "widening:" << endl; | |
cout << " max(uint16_t) -> uint32_t = " << SqlCastIntegral< uint32_t >( numeric_limits< uint16_t >::max() ) << endl; | |
cout << " max(uint16_t) -> int32_t = " << SqlCastIntegral< int32_t >( numeric_limits< uint16_t >::max() ) << endl; | |
cout << " max( int16_t) -> uint32_t = " << SqlCastIntegral< uint32_t >( numeric_limits< int16_t >::max() ) << endl; | |
cout << " max( int16_t) -> int32_t = " << SqlCastIntegral< int32_t >( numeric_limits< int16_t >::max() ) << endl; | |
cout << " min(uint16_t) -> uint32_t = " << SqlCastIntegral< uint32_t >( numeric_limits< uint16_t >::min() ) << endl; | |
cout << " min(uint16_t) -> int32_t = " << SqlCastIntegral< int32_t >( numeric_limits< uint16_t >::min() ) << endl; | |
cout << " min( int16_t) -> uint32_t = " << SqlCastIntegral< uint32_t >( numeric_limits< int16_t >::min() ) << endl; | |
cout << " min( int16_t) -> int32_t = " << SqlCastIntegral< int32_t >( numeric_limits< int16_t >::min() ) << endl; | |
cout << endl; | |
cout << "narrowing:" << endl; | |
cout << " max(uint32_t) -> uint16_t = " << SqlCastIntegral< uint16_t >( numeric_limits< uint32_t >::max() ) << endl; | |
cout << " max(uint32_t) -> int16_t = " << SqlCastIntegral< int16_t >( numeric_limits< uint32_t >::max() ) << endl; | |
cout << " max( int32_t) -> uint16_t = " << SqlCastIntegral< uint16_t >( numeric_limits< int32_t >::max() ) << endl; | |
cout << " max( int32_t) -> int16_t = " << SqlCastIntegral< int16_t >( numeric_limits< int32_t >::max() ) << endl; | |
cout << " min(uint32_t) -> uint16_t = " << SqlCastIntegral< uint16_t >( numeric_limits< uint32_t >::min() ) << endl; | |
cout << " min(uint32_t) -> int16_t = " << SqlCastIntegral< int16_t >( numeric_limits< uint32_t >::min() ) << endl; | |
cout << " min( int32_t) -> uint16_t = " << SqlCastIntegral< uint16_t >( numeric_limits< int32_t >::min() ) << endl; | |
cout << " min( int32_t) -> int16_t = " << SqlCastIntegral< int16_t >( numeric_limits< int32_t >::min() ) << endl; | |
cout << endl; | |
return 0; | |
} | |
/* | |
With G++ 4.9.2, C++14 (but should work fine with C++11 and maybe even 0x.) | |
Clamping integers to the intersections of their respective ranges. | |
sign change: | |
max(uint16_t) -> int16_t = 32767 | |
max( int16_t) -> uint16_t = 32767 | |
min(uint16_t) -> int16_t = 0 | |
min( int16_t) -> uint16_t = 0 | |
widening: | |
max(uint16_t) -> uint32_t = 65535 | |
max(uint16_t) -> int32_t = 65535 | |
max( int16_t) -> uint32_t = 32767 | |
max( int16_t) -> int32_t = 32767 | |
min(uint16_t) -> uint32_t = 0 | |
min(uint16_t) -> int32_t = 0 | |
min( int16_t) -> uint32_t = 0 | |
min( int16_t) -> int32_t = -32768 | |
narrowing: | |
max(uint32_t) -> uint16_t = 65535 | |
max(uint32_t) -> int16_t = 32767 | |
max( int32_t) -> uint16_t = 65535 | |
max( int32_t) -> int16_t = 32767 | |
min(uint32_t) -> uint16_t = 0 | |
min(uint32_t) -> int16_t = 0 | |
min( int32_t) -> uint16_t = 0 | |
min( int32_t) -> int16_t = -32768 | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment