From 689f70ce6d6b27ea2ccf7463e79dfefe5ce35899 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2019 11:21:29 -0700 Subject: Add a simple optional<> implementation --- common/aloptional.h | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 common/aloptional.h (limited to 'common/aloptional.h') diff --git a/common/aloptional.h b/common/aloptional.h new file mode 100644 index 00000000..75891329 --- /dev/null +++ b/common/aloptional.h @@ -0,0 +1,112 @@ +#ifndef AL_OPTIONAL_H +#define AL_OPTIONAL_H + +#include + +namespace al { + +#define REQUIRES(...) bool _rt=true, typename std::enable_if<_rt && (__VA_ARGS__),int>::type = 0 + +struct nullopt_t { }; +struct in_place_t { }; + +constexpr nullopt_t nullopt{}; +constexpr in_place_t in_place{}; + +template +class optional { +public: + using value_type = T; + + optional() noexcept = default; + optional(nullopt_t) noexcept { } + template::value)> + optional(const optional &rhs) : mHasValue{rhs.mHasValue} + { + if(mHasValue) + new (&mValue) T{*rhs}; + } + template::value)> + optional(optional&& rhs) : mHasValue{rhs.mHasValue} + { + if(mHasValue) + new (&mValue) T{std::move(*rhs)}; + } + template + explicit optional(in_place_t, Args&& ...args) + : mHasValue{true}, mValue{std::forward(args)...} + { } + template::value)> + optional(const optional&) noexcept = delete; + ~optional() { reset(); } + + optional& operator=(nullopt_t) noexcept { reset(); } + template::value && std::is_copy_assignable::value)> + optional& operator=(const optional &rhs) + { + if(!rhs) + reset(); + else + { + mValue = *rhs; + mHasValue = true; + } + return *this; + } + template::value && std::is_move_assignable::value)> + optional& operator=(optional&& rhs) + { + if(!rhs) + reset(); + else + { + mValue = std::move(*rhs); + mHasValue = true; + } + return *this; + } + template::value || !std::is_copy_assignable::value)> + optional& operator=(const optional&) = delete; + + const T* operator->() const { return &mValue; } + T* operator->() { return &mValue; } + const T& operator*() const& { return mValue; } + T& operator*() & { return mValue; } + const T&& operator*() const&& { return std::move(mValue); } + T&& operator*() && { return std::move(mValue); } + + operator bool() const noexcept { return mHasValue; } + bool has_value() const noexcept { return mHasValue; } + + T& value() & { return mValue; } + const T& value() const& { return mValue; } + T&& value() && { return std::move(mValue); } + const T&& value() const&& { return std::move(mValue); } + + template + T value_or(U&& defval) const& + { return bool{*this} ? **this : static_cast(std::forward(defval)); } + template + T value_or(U&& defval) && + { return bool{*this} ? std::move(**this) : static_cast(std::forward(defval)); } + + void reset() noexcept + { + if(mHasValue) + mValue.~T(); + mHasValue = false; + } + +private: + bool mHasValue{false}; + union { + char mDummy[sizeof(T)]{}; + T mValue; + }; +}; + +#undef REQUIRES + +} // namespace al + +#endif /* AL_SPAN_H */ -- cgit v1.2.3