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

summaryrefslogtreecommitdiff
path: root/source/core/StarMaybe.hpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
commit6352e8e3196f78388b6c771073f9e03eaa612673 (patch)
treee23772f79a7fbc41bc9108951e9e136857484bf4 /source/core/StarMaybe.hpp
parent6741a057e5639280d85d0f88ba26f000baa58f61 (diff)
everything everywhere
all at once
Diffstat (limited to 'source/core/StarMaybe.hpp')
-rw-r--r--source/core/StarMaybe.hpp400
1 files changed, 400 insertions, 0 deletions
diff --git a/source/core/StarMaybe.hpp b/source/core/StarMaybe.hpp
new file mode 100644
index 0000000..f0e7904
--- /dev/null
+++ b/source/core/StarMaybe.hpp
@@ -0,0 +1,400 @@
+#ifndef STAR_MAYBE_HPP
+#define STAR_MAYBE_HPP
+
+#include "StarException.hpp"
+#include "StarHash.hpp"
+
+namespace Star {
+
+STAR_EXCEPTION(InvalidMaybeAccessException, StarException);
+
+template <typename T>
+class Maybe {
+public:
+ typedef T* PointerType;
+ typedef T const* PointerConstType;
+ typedef T& RefType;
+ typedef T const& RefConstType;
+
+ Maybe();
+
+ Maybe(T const& t);
+ Maybe(T&& t);
+
+ Maybe(Maybe const& rhs);
+ Maybe(Maybe&& rhs);
+ template <typename T2>
+ Maybe(Maybe<T2> const& rhs);
+
+ ~Maybe();
+
+ Maybe& operator=(Maybe const& rhs);
+ Maybe& operator=(Maybe&& rhs);
+ template <typename T2>
+ Maybe& operator=(Maybe<T2> const& rhs);
+
+ bool isValid() const;
+ bool isNothing() const;
+ explicit operator bool() const;
+
+ PointerConstType ptr() const;
+ PointerType ptr();
+
+ PointerConstType operator->() const;
+ PointerType operator->();
+
+ RefConstType operator*() const;
+ RefType operator*();
+
+ bool operator==(Maybe const& rhs) const;
+ bool operator!=(Maybe const& rhs) const;
+ bool operator<(Maybe const& rhs) const;
+
+ RefConstType get() const;
+ RefType get();
+
+ // Get either the contents of this Maybe or the given default.
+ T value(T def = T()) const;
+
+ // Get either this value, or if this value is none the given value.
+ Maybe orMaybe(Maybe const& other) const;
+
+ // Takes the value out of this Maybe, leaving it Nothing.
+ T take();
+
+ // If this Maybe is set, assigns it to t and leaves this Maybe as Nothing.
+ bool put(T& t);
+
+ void set(T const& t);
+ void set(T&& t);
+
+ template <typename... Args>
+ void emplace(Args&&... t);
+
+ void reset();
+
+ // Apply a function to the contained value if it is not Nothing.
+ template <typename Function>
+ void exec(Function&& function);
+
+ // Functor map operator. If this maybe is not Nothing, then applies the
+ // given function to it and returns the result, otherwise returns Nothing (of
+ // the type the function would normally return).
+ template <typename Function>
+ auto apply(Function&& function) const -> Maybe<typename std::decay<decltype(function(std::declval<T>()))>::type>;
+
+ // Monadic bind operator. Given function should return another Maybe.
+ template <typename Function>
+ auto sequence(Function function) const -> decltype(function(std::declval<T>()));
+
+private:
+ union {
+ T m_data;
+ };
+
+ bool m_initialized;
+};
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, Maybe<T> const& v);
+
+template <typename T>
+struct hash<Maybe<T>> {
+ size_t operator()(Maybe<T> const& m) const;
+ hash<T> hasher;
+};
+
+template <typename T>
+Maybe<T>::Maybe()
+ : m_initialized(false) {}
+
+template <typename T>
+Maybe<T>::Maybe(T const& t)
+ : Maybe() {
+ new (&m_data) T(t);
+ m_initialized = true;
+}
+
+template <typename T>
+Maybe<T>::Maybe(T&& t)
+ : Maybe() {
+ new (&m_data) T(forward<T>(t));
+ m_initialized = true;
+}
+
+template <typename T>
+Maybe<T>::Maybe(Maybe const& rhs)
+ : Maybe() {
+ if (rhs.m_initialized) {
+ new (&m_data) T(rhs.m_data);
+ m_initialized = true;
+ }
+}
+
+template <typename T>
+Maybe<T>::Maybe(Maybe&& rhs)
+ : Maybe() {
+ if (rhs.m_initialized) {
+ new (&m_data) T(move(rhs.m_data));
+ m_initialized = true;
+ rhs.reset();
+ }
+}
+
+template <typename T>
+template <typename T2>
+Maybe<T>::Maybe(Maybe<T2> const& rhs)
+ : Maybe() {
+ if (rhs) {
+ new (&m_data) T(*rhs);
+ m_initialized = true;
+ }
+}
+
+template <typename T>
+Maybe<T>::~Maybe() {
+ reset();
+}
+
+template <typename T>
+Maybe<T>& Maybe<T>::operator=(Maybe const& rhs) {
+ if (&rhs == this)
+ return *this;
+
+ if (rhs)
+ emplace(*rhs);
+ else
+ reset();
+
+ return *this;
+}
+
+template <typename T>
+template <typename T2>
+Maybe<T>& Maybe<T>::operator=(Maybe<T2> const& rhs) {
+ if (rhs)
+ emplace(*rhs);
+ else
+ reset();
+
+ return *this;
+}
+
+template <typename T>
+Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) {
+ if (&rhs == this)
+ return *this;
+
+ if (rhs)
+ emplace(rhs.take());
+ else
+ reset();
+
+ return *this;
+}
+
+template <typename T>
+bool Maybe<T>::isValid() const {
+ return m_initialized;
+}
+
+template <typename T>
+bool Maybe<T>::isNothing() const {
+ return !m_initialized;
+}
+
+template <typename T>
+Maybe<T>::operator bool() const {
+ return m_initialized;
+}
+
+template <typename T>
+auto Maybe<T>::ptr() const -> PointerConstType {
+ if (m_initialized)
+ return &m_data;
+ return nullptr;
+}
+
+template <typename T>
+auto Maybe<T>::ptr() -> PointerType {
+ if (m_initialized)
+ return &m_data;
+ return nullptr;
+}
+
+template <typename T>
+auto Maybe<T>::operator-> () const -> PointerConstType {
+ if (!m_initialized)
+ throw InvalidMaybeAccessException();
+
+ return &m_data;
+}
+
+template <typename T>
+auto Maybe<T>::operator->() -> PointerType {
+ if (!m_initialized)
+ throw InvalidMaybeAccessException();
+
+ return &m_data;
+}
+
+template <typename T>
+auto Maybe<T>::operator*() const -> RefConstType {
+ return get();
+}
+
+template <typename T>
+auto Maybe<T>::operator*() -> RefType {
+ return get();
+}
+
+template <typename T>
+bool Maybe<T>::operator==(Maybe const& rhs) const {
+ if (!m_initialized && !rhs.m_initialized)
+ return true;
+ if (m_initialized && rhs.m_initialized)
+ return get() == rhs.get();
+ return false;
+}
+
+template <typename T>
+bool Maybe<T>::operator!=(Maybe const& rhs) const {
+ return !operator==(rhs);
+}
+
+template <typename T>
+bool Maybe<T>::operator<(Maybe const& rhs) const {
+ if (m_initialized && rhs.m_initialized)
+ return get() < rhs.get();
+ if (!m_initialized && rhs.m_initialized)
+ return true;
+ return false;
+}
+
+template <typename T>
+auto Maybe<T>::get() const -> RefConstType {
+ if (!m_initialized)
+ throw InvalidMaybeAccessException();
+
+ return m_data;
+}
+
+template <typename T>
+auto Maybe<T>::get() -> RefType {
+ if (!m_initialized)
+ throw InvalidMaybeAccessException();
+
+ return m_data;
+}
+
+template <typename T>
+T Maybe<T>::value(T def) const {
+ if (m_initialized)
+ return m_data;
+ else
+ return def;
+}
+
+template <typename T>
+Maybe<T> Maybe<T>::orMaybe(Maybe const& other) const {
+ if (m_initialized)
+ return *this;
+ else
+ return other;
+}
+
+template <typename T>
+T Maybe<T>::take() {
+ if (!m_initialized)
+ throw InvalidMaybeAccessException();
+
+ T val(move(m_data));
+
+ reset();
+
+ return val;
+}
+
+template <typename T>
+bool Maybe<T>::put(T& t) {
+ if (m_initialized) {
+ t = move(m_data);
+
+ reset();
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+template <typename T>
+void Maybe<T>::set(T const& t) {
+ emplace(t);
+}
+
+template <typename T>
+void Maybe<T>::set(T&& t) {
+ emplace(forward<T>(t));
+}
+
+template <typename T>
+template <typename... Args>
+void Maybe<T>::emplace(Args&&... t) {
+ reset();
+
+ new (&m_data) T(forward<Args>(t)...);
+ m_initialized = true;
+}
+
+template <typename T>
+void Maybe<T>::reset() {
+ if (m_initialized) {
+ m_initialized = false;
+ m_data.~T();
+ }
+}
+
+template <typename T>
+template <typename Function>
+auto Maybe<T>::apply(Function&& function) const
+ -> Maybe<typename std::decay<decltype(function(std::declval<T>()))>::type> {
+ if (!isValid())
+ return {};
+ return function(get());
+}
+
+template <typename T>
+template <typename Function>
+void Maybe<T>::exec(Function&& function) {
+ if (isValid())
+ function(get());
+}
+
+template <typename T>
+template <typename Function>
+auto Maybe<T>::sequence(Function function) const -> decltype(function(std::declval<T>())) {
+ if (!isValid())
+ return {};
+ return function(get());
+}
+
+template <typename T>
+std::ostream& operator<<(std::ostream& os, Maybe<T> const& v) {
+ if (v)
+ return os << "Just (" << *v << ")";
+ else
+ return os << "Nothing";
+}
+
+template <typename T>
+size_t hash<Maybe<T>>::operator()(Maybe<T> const& m) const {
+ if (!m)
+ return 0;
+ else
+ return hasher(*m);
+}
+
+}
+
+#endif