Skip to content

Instantly share code, notes, and snippets.

@Kludgy
Last active May 8, 2016 04:45
Show Gist options
  • Save Kludgy/cffbd475dc88322cf61e9c7016d1908c to your computer and use it in GitHub Desktop.
Save Kludgy/cffbd475dc88322cf61e9c7016d1908c to your computer and use it in GitHub Desktop.
Attempt at parity between cache and MySQL int-int casting semantics.
#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