Skip to content

Instantly share code, notes, and snippets.

@nikhedonia
Created May 16, 2017 11:39
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save nikhedonia/db401285d9f3816e2a74d78c68dd4c6c to your computer and use it in GitHub Desktop.
Save nikhedonia/db401285d9f3816e2a74d78c68dd4c6c to your computer and use it in GitHub Desktop.
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