Skip to content

Instantly share code, notes, and snippets.

@amidvidy
Created August 6, 2014 22:18
Show Gist options
  • Save amidvidy/bab48f90480b215b0f51 to your computer and use it in GitHub Desktop.
Save amidvidy/bab48f90480b215b0f51 to your computer and use it in GitHub Desktop.
attempt at Either w/ c++ 11
// C++11 only
#if __cplusplus <= 201103L
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <functional>
#include <memory>
#include <type_traits>
namespace functional {
template<typename Left, typename Right>
struct Either {
static_assert(!std::is_same<Left, Right>::value, "Types must be different");
enum State {
UNSET, LEFT, RIGHT
};
Either() : _state(UNSET) { }
explicit Either(const Left& l) : _state(LEFT), _left(new Left(l)) {}
explicit Either(const Right& r) : _state(RIGHT), _right(new Right(r)) {}
Either(const Either& other) : _state(other._state) {
switch (_state) {
case LEFT: _left.reset(new Left(*other._left)); break;
case RIGHT: _right.reset(new Right(*other._right)); break;
case UNSET: break;
}
}
Either(Either&& other) : _state(other._state) {
switch (_state) {
case LEFT: _left.swap(other._left); break;
case RIGHT: _right.swap(other._right); break;
case UNSET: break;
}
}
// TODO: make exception safe
Either& operator=(const Either& other) {
this->~Either();
new (this) Either(other);
return *this;
}
bool isSet() const { return _state != UNSET; }
bool isLeft() const { return _state == LEFT; }
bool isRight() const { return _state == RIGHT; }
template<typename NewLeft, typename NewRight>
Either<NewLeft, NewRight> map(std::function<NewLeft(const Left&)> leftF,
std::function<NewRight(const Right&)> rightF) const {
switch (_state) { // no break needed since all paths return
case LEFT: return Either<NewLeft, NewRight>(leftF(*_left));
case RIGHT: return Either<NewLeft, NewRight>(rightF(*_right));
case UNSET: return Either<NewLeft, NewRight>();
}
}
template<typename NewLeft>
Either<NewLeft, Right> bind(std::function<Either<NewLeft, Right>(const Left&)> leftF) {
if (isLeft()) {
return leftF(*_left);
}
return Either<NewLeft, Right>(*_right);
}
const Either& get(std::function<void(const Left&)> leftF,
std::function<void(const Right&)> rightF) const {
switch (_state) {
case LEFT: leftF(*_left); break;
case RIGHT: rightF(*_right); break;
case UNSET: break;
}
return *this;
}
private:
std::unique_ptr<Left> _left;
std::unique_ptr<Right> _right;
const State _state;
};
} // functional {
int main() {
functional::Either<int, std::string> e1;
std::srand(std::time(0));
int rand = std::rand();
int toSet = rand % 3;
if (toSet == 0) {
e1 = functional::Either<int, std::string>(rand);
} else if (toSet == 1) {
e1 = functional::Either<int, std::string>(std::string("Random number is ") + std::to_string(rand));
} else {
/* leave unset */
}
e1.map<std::string, int>(
[](const int& i) -> std::string {
return std::string("My favorite number is ") + std::to_string(i);
},
[](const std::string& s) -> int {
return s.length();
})
.get(
[](const std::string& s) {
std::cout << s << std::endl;
},
[](const int& i) {
std::cout << "Length was: " << i << std::endl;
}
);
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment