Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/core/StarEither.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/core/StarEither.hpp')
-rw-r--r--source/core/StarEither.hpp243
1 files changed, 243 insertions, 0 deletions
diff --git a/source/core/StarEither.hpp b/source/core/StarEither.hpp
new file mode 100644
index 0000000..287e4bc
--- /dev/null
+++ b/source/core/StarEither.hpp
@@ -0,0 +1,243 @@
+#ifndef STAR_EITHER_HPP
+#define STAR_EITHER_HPP
+
+#include "StarVariant.hpp"
+
+namespace Star {
+
+STAR_EXCEPTION(EitherException, StarException);
+
+template <typename Value>
+struct EitherLeftValue {
+ Value value;
+};
+
+template <typename Value>
+struct EitherRightValue {
+ Value value;
+};
+
+template <typename Value>
+EitherLeftValue<Value> makeLeft(Value value);
+
+template <typename Value>
+EitherRightValue<Value> makeRight(Value value);
+
+// Container that contains exactly one of either Left or Right.
+template <typename Left, typename Right>
+class Either {
+public:
+ // Constructs Either that contains a default constructed Left value
+ Either();
+
+ Either(EitherLeftValue<Left> left);
+ Either(EitherRightValue<Right> right);
+
+ template <typename T>
+ Either(EitherLeftValue<T> left);
+
+ template <typename T>
+ Either(EitherRightValue<T> right);
+
+ Either(Either const& rhs);
+ Either(Either&& rhs);
+
+ Either& operator=(Either const& rhs);
+ Either& operator=(Either&& rhs);
+
+ template <typename T>
+ Either& operator=(EitherLeftValue<T> left);
+
+ template <typename T>
+ Either& operator=(EitherRightValue<T> right);
+
+ bool isLeft() const;
+ bool isRight() const;
+
+ void setLeft(Left left);
+ void setRight(Right left);
+
+ // left() and right() throw EitherException on invalid access
+
+ Left const& left() const;
+ Right const& right() const;
+
+ Left& left();
+ Right& right();
+
+ Maybe<Left> maybeLeft() const;
+ Maybe<Right> maybeRight() const;
+
+ // leftPtr() and rightPtr() do not throw on invalid access
+
+ Left const* leftPtr() const;
+ Right const* rightPtr() const;
+
+ Left* leftPtr();
+ Right* rightPtr();
+
+private:
+ typedef EitherLeftValue<Left> LeftType;
+ typedef EitherRightValue<Right> RightType;
+
+ Variant<LeftType, RightType> m_value;
+};
+
+template <typename Value>
+EitherLeftValue<Value> makeLeft(Value value) {
+ return {move(value)};
+}
+
+template <typename Value>
+EitherRightValue<Value> makeRight(Value value) {
+ return {move(value)};
+}
+
+template <typename Left, typename Right>
+Either<Left, Right>::Either() {}
+
+template <typename Left, typename Right>
+Either<Left, Right>::Either(EitherLeftValue<Left> left)
+ : m_value(move(left)) {}
+
+template <typename Left, typename Right>
+Either<Left, Right>::Either(EitherRightValue<Right> right)
+ : m_value(move(right)) {}
+
+template <typename Left, typename Right>
+template <typename T>
+Either<Left, Right>::Either(EitherLeftValue<T> left)
+ : Either(LeftType{move(left.value)}) {}
+
+template <typename Left, typename Right>
+template <typename T>
+Either<Left, Right>::Either(EitherRightValue<T> right)
+ : Either(RightType{move(right.value)}) {}
+
+template <typename Left, typename Right>
+Either<Left, Right>::Either(Either const& rhs)
+ : m_value(rhs.m_value) {}
+
+template <typename Left, typename Right>
+Either<Left, Right>::Either(Either&& rhs)
+ : m_value(move(rhs.m_value)) {}
+
+template <typename Left, typename Right>
+Either<Left, Right>& Either<Left, Right>::operator=(Either const& rhs) {
+ m_value = rhs.m_value;
+ return *this;
+}
+
+template <typename Left, typename Right>
+Either<Left, Right>& Either<Left, Right>::operator=(Either&& rhs) {
+ m_value = move(rhs.m_value);
+ return *this;
+}
+
+template <typename Left, typename Right>
+template <typename T>
+Either<Left, Right>& Either<Left, Right>::operator=(EitherLeftValue<T> left) {
+ m_value = LeftType{move(left.value)};
+ return *this;
+}
+
+template <typename Left, typename Right>
+template <typename T>
+Either<Left, Right>& Either<Left, Right>::operator=(EitherRightValue<T> right) {
+ m_value = RightType{move(right.value)};
+ return *this;
+}
+
+template <typename Left, typename Right>
+bool Either<Left, Right>::isLeft() const {
+ return m_value.template is<LeftType>();
+}
+
+template <typename Left, typename Right>
+bool Either<Left, Right>::isRight() const {
+ return m_value.template is<RightType>();
+}
+
+template <typename Left, typename Right>
+void Either<Left, Right>::setLeft(Left left) {
+ m_value = LeftType{move(left)};
+}
+
+template <typename Left, typename Right>
+void Either<Left, Right>::setRight(Right right) {
+ m_value = RightType{move(right)};
+}
+
+template <typename Left, typename Right>
+Left const& Either<Left, Right>::left() const {
+ if (auto l = leftPtr())
+ return *l;
+ throw EitherException("Improper access of left side of Either");
+}
+
+template <typename Left, typename Right>
+Right const& Either<Left, Right>::right() const {
+ if (auto r = rightPtr())
+ return *r;
+ throw EitherException("Improper access of right side of Either");
+}
+
+template <typename Left, typename Right>
+Left& Either<Left, Right>::left() {
+ if (auto l = leftPtr())
+ return *l;
+ throw EitherException("Improper access of left side of Either");
+}
+
+template <typename Left, typename Right>
+Right& Either<Left, Right>::right() {
+ if (auto r = rightPtr())
+ return *r;
+ throw EitherException("Improper access of right side of Either");
+}
+
+template <typename Left, typename Right>
+Maybe<Left> Either<Left, Right>::maybeLeft() const {
+ if (auto l = leftPtr())
+ return *l;
+ return {};
+}
+
+template <typename Left, typename Right>
+Maybe<Right> Either<Left, Right>::maybeRight() const {
+ if (auto r = rightPtr())
+ return *r;
+ return {};
+}
+
+template <typename Left, typename Right>
+Left const* Either<Left, Right>::leftPtr() const {
+ if (auto l = m_value.template ptr<LeftType>())
+ return &l->value;
+ return nullptr;
+}
+
+template <typename Left, typename Right>
+Right const* Either<Left, Right>::rightPtr() const {
+ if (auto r = m_value.template ptr<RightType>())
+ return &r->value;
+ return nullptr;
+}
+
+template <typename Left, typename Right>
+Left* Either<Left, Right>::leftPtr() {
+ if (auto l = m_value.template ptr<LeftType>())
+ return &l->value;
+ return nullptr;
+}
+
+template <typename Left, typename Right>
+Right* Either<Left, Right>::rightPtr() {
+ if (auto r = m_value.template ptr<RightType>())
+ return &r->value;
+ return nullptr;
+}
+
+}
+
+#endif