Skip to content

Instantly share code, notes, and snippets.

@erinacio
Created April 18, 2018 16:41
Show Gist options
  • Save erinacio/12ff7330fb5328793df813b0edb3bbe3 to your computer and use it in GitHub Desktop.
Save erinacio/12ff7330fb5328793df813b0edb3bbe3 to your computer and use it in GitHub Desktop.
// -std=c++14
#include <iostream>
#include <string>
#include <utility>
#include <unordered_map>
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>
// disclaimer: not tested
template <typename L, typename R>
class either
{
private:
either() {}
public:
explicit either(const L & left) : _left(left) {}
explicit either(const R & right) : _right(right) {}
explicit either(const either<L, R> & other) : _left(other._left), _right(other._right) {}
explicit either(L && left) : _left(left) {}
explicit either(R && right) : _right(right) {}
explicit either(either<L, R> && other) {
_left.swap(other._left);
_right.swap(other._right);
}
either<L, R> & operator = (const L & left) {
_left = left;
_right = boost::none;
return *this;
}
either<L, R> & operator = (const R & right) {
_left = boost::none;
_right = right;
return *this;
}
either<L, R> & operator = (const either<L, R> & other) {
_left = other._left;
_right = other._right;
return *this;
}
template <typename... T>
void emplace_left(T && ...args) {
_left.emplace(args...);
_right = boost::none;
}
template <typename... T>
void emplace_right(T && ...args) {
_left = boost::none;
_right.emplace(args...);
}
bool is_left() const {
return static_cast<bool>(_left);
}
bool is_right() const {
return static_cast<bool>(_right);
}
const L & left() const {
return _left.value();
}
L & left() {
return _left.value();
}
const R & right() const {
return _right.value();
}
R & right() {
return _right.value();
}
private:
boost::optional<L> _left;
boost::optional<R> _right;
};
template <typename L, typename R>
std::ostream & operator << (std::ostream & out, const either<L, R> &e) {
if (e.is_left()) {
out << e.left();
} else {
out << e.right();
}
return out;
}
template <typename T>
class recursive_map;
template <typename T>
class recursive_map : public std::unordered_map<std::string, either<recursive_map<T>, T>>
{
};
template <typename T>
std::ostream & operator << (std::ostream & out, const recursive_map<T> & map)
{
return out << "<recursive_map@" << &map << ">";
}
int main()
{
using mapped_type = recursive_map<int>::mapped_type;
recursive_map<int> map;
map.emplace("foobar", mapped_type(12));
map.emplace("foo", mapped_type(recursive_map<int>()));
map.at("foo").left().emplace("bar", mapped_type(42));
std::cout << map.at("foobar") << std::endl;
std::cout << map.at("foo").left().at("bar") << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment