analysing Assembly generated by Eithers
#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