Created
May 16, 2017 11:39
-
-
Save nikhedonia/db401285d9f3816e2a74d78c68dd4c6c to your computer and use it in GitHub Desktop.
analysing Assembly generated by Eithers
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
#include <type_traits> | |
template<class L> | |
struct Left { | |
L const value; | |
}; | |
template<class R> | |
struct Right { | |
R const value; | |
}; | |
template<class T> | |
constexpr Left<T> left(T const& value) { | |
return {value}; | |
} | |
template<class T> | |
constexpr Right<T> right(T const& value) { | |
return {value}; | |
} | |
template<class L, class R> | |
struct Either { | |
union { | |
L mutable leftValue; | |
R mutable rightValue; | |
}; | |
bool const isLeft; | |
constexpr Either(Either<L, R> const& e) | |
: isLeft{e.isLeft} { | |
if(isLeft) { | |
leftValue = e.leftValue; | |
} else { | |
rightValue = e.rightValue; | |
} | |
} | |
constexpr Either(Left<L> const& left) | |
: leftValue{left.value} | |
, isLeft{true} | |
{} | |
constexpr Either(Right<R> const& right) | |
: rightValue{right.value} | |
, isLeft{false} | |
{} | |
~Either() { | |
if(isLeft) { | |
leftValue.~L(); | |
} else { | |
rightValue.~R(); | |
} | |
} | |
template<class F> | |
constexpr auto leftMap(F const& f)const | |
-> Either<decltype(f(leftValue)), R> { | |
if (isLeft) return {left(f(leftValue))}; | |
return {right(rightValue)}; | |
} | |
template<class F> | |
constexpr auto rightMap(F const& f)const | |
-> Either<L, decltype(f(rightValue))> { | |
if (isLeft) return {left(leftValue)}; | |
return {right(f(rightValue))}; | |
} | |
template<class LL=L, class RR=R> | |
constexpr auto join()const | |
-> typename std::common_type<LL, RR> | |
::type { | |
if (isLeft) return leftValue; | |
return rightValue; | |
} | |
}; | |
using namespace std; | |
static constexpr int ERROR_CODE = 42; | |
static constexpr int m1=10; | |
static constexpr int m2=13; | |
auto eitherError(int const& num) { | |
using E = Either<int, float>; | |
return (num<0) ? | |
(E)left(ERROR_CODE) : | |
(E)right((float)num) ; | |
} | |
auto eitherCompute(int const& num) { | |
return eitherError(num) | |
.leftMap([](auto){ return 0;}) | |
.rightMap([](auto const& f){ return f*m1;}) | |
.rightMap([](auto const& f){ return f*m2;}) | |
.join(); | |
} | |
int codeError(int const& num, float& out ) { | |
if(num<0) { | |
return ERROR_CODE; | |
} else { | |
out = num; | |
return 0; | |
} | |
} | |
int errorCompute(int const& num) { | |
float out; | |
if(codeError(num, out)) { | |
return 0; | |
} | |
return out*m1*m2; | |
} | |
float throwError(int const& num) { | |
if(num<0) throw ERROR_CODE; | |
return num; | |
} | |
float throwCompute(int const& num) { | |
try { | |
return throwError(num)*m1*m2; | |
} catch(int) { | |
return 0; | |
} | |
} | |
/* assembly time: https://godbolt.org/g/5f6mT9 | |
.LCPI1_0: | |
.long 1124204544 # float 130 | |
eitherCompute(int const&): # @eitherCompute(int const&) | |
mov eax, dword ptr [rdi] | |
test eax, eax | |
jns .LBB1_1 | |
xorps xmm0, xmm0 | |
ret | |
.LBB1_1: | |
cvtsi2ss xmm0, eax | |
mulss xmm0, dword ptr [rip + .LCPI1_0] | |
ret | |
#END##eitherCompute | |
codeError(int const&, float&): # @codeError(int const&, float&) | |
mov eax, dword ptr [rdi] | |
test eax, eax | |
js .LBB2_1 | |
cvtsi2ss xmm0, eax | |
movss dword ptr [rsi], xmm0 | |
xor eax, eax | |
ret | |
.LBB2_1: | |
mov eax, 42 | |
ret | |
#END##codeError | |
throwCompute(int const&): # @throwCompute(int const&) | |
push rax | |
mov eax, dword ptr [rdi] | |
test eax, eax | |
js .LBB5_1 | |
cvtsi2ss xmm0, eax | |
mulss xmm0, dword ptr [rip + .LCPI5_0] | |
pop rax | |
ret | |
.LBB5_1: | |
mov edi, 4 | |
call __cxa_allocate_exception | |
mov dword ptr [rax], 42 | |
mov esi, typeinfo for int | |
xor edx, edx | |
mov rdi, rax | |
call __cxa_throw | |
mov rdi, rax | |
call __cxa_begin_catch | |
call __cxa_end_catch | |
xorps xmm0, xmm0 | |
pop rax | |
ret | |
GCC_except_table5: | |
.byte 255 # @LPStart Encoding = omit | |
.byte 3 # @TType Encoding = udata4 | |
.asciz "\257\200" # @TType base offset | |
.byte 3 # Call site Encoding = udata4 | |
.byte 39 # Call site table length | |
.long .Lfunc_begin5-.Lfunc_begin5 # >> Call Site 1 << | |
.long .Ltmp19-.Lfunc_begin5 # Call between .Lfunc_begin5 and .Ltmp19 | |
.long 0 # has no landing pad | |
.byte 0 # On action: cleanup | |
.long .Ltmp19-.Lfunc_begin5 # >> Call Site 2 << | |
.long .Ltmp20-.Ltmp19 # Call between .Ltmp19 and .Ltmp20 | |
.long .Ltmp21-.Lfunc_begin5 # jumps to .Ltmp21 | |
.byte 1 # On action: 1 | |
.long .Ltmp20-.Lfunc_begin5 # >> Call Site 3 << | |
.long .Lfunc_end5-.Ltmp20 # Call between .Ltmp20 and .Lfunc_end5 | |
.long 0 # has no landing pad | |
.byte 0 # On action: cleanup | |
.byte 1 # >> Action Record 1 << | |
.byte 0 # No further actions | |
.long typeinfo for int # TypeInfo 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment