diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
commit | 6352e8e3196f78388b6c771073f9e03eaa612673 (patch) | |
tree | e23772f79a7fbc41bc9108951e9e136857484bf4 /source/core/StarMaybe.hpp | |
parent | 6741a057e5639280d85d0f88ba26f000baa58f61 (diff) |
everything everywhere
all at once
Diffstat (limited to 'source/core/StarMaybe.hpp')
-rw-r--r-- | source/core/StarMaybe.hpp | 400 |
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 |