| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- #ifndef AL_OPTIONAL_H
- #define AL_OPTIONAL_H
- #include <initializer_list>
- #include <type_traits>
- #include <utility>
- #include "almalloc.h"
- namespace al {
- #define REQUIRES(...) bool rt_=true, typename std::enable_if<rt_ && (__VA_ARGS__),bool>::type = true
- struct nullopt_t { };
- struct in_place_t { };
- constexpr nullopt_t nullopt{};
- constexpr in_place_t in_place{};
- template<typename T>
- class optional {
- bool mHasValue{false};
- union {
- char mDummy[sizeof(T)]{};
- T mValue;
- };
- template<typename... Args>
- void DoConstruct(Args&& ...args)
- {
- ::new (std::addressof(mValue)) T{std::forward<Args>(args)...};
- mHasValue = true;
- }
- public:
- using value_type = T;
- optional() noexcept = default;
- optional(nullopt_t) noexcept { }
- template<REQUIRES(std::is_copy_constructible<T>::value)>
- optional(const optional &rhs) { if(rhs) DoConstruct(*rhs); }
- template<REQUIRES(std::is_move_constructible<T>::value)>
- optional(optional&& rhs) { if(rhs) DoConstruct(std::move(*rhs)); }
- template<typename... Args, REQUIRES(std::is_constructible<T, Args...>::value)>
- explicit optional(in_place_t, Args&& ...args) : mHasValue{true}
- , mValue{std::forward<Args>(args)...}
- { }
- template<typename U, typename... Args, REQUIRES(std::is_constructible<T, std::initializer_list<U>&, Args...>::value)>
- explicit optional(in_place_t, std::initializer_list<U> il, Args&& ...args)
- : mHasValue{true}, mValue{il, std::forward<Args>(args)...}
- { }
- template<typename U=value_type, REQUIRES(std::is_constructible<T, U&&>::value &&
- !std::is_same<typename std::decay<U>::type, in_place_t>::value &&
- !std::is_same<typename std::decay<U>::type, optional<T>>::value &&
- std::is_constructible<U&&, T>::value)>
- constexpr explicit optional(U&& value) : mHasValue{true}, mValue{std::forward<U>(value)}
- { }
- template<typename U=value_type, REQUIRES(std::is_constructible<T, U&&>::value &&
- !std::is_same<typename std::decay<U>::type, in_place_t>::value &&
- !std::is_same<typename std::decay<U>::type, optional<T>>::value &&
- !std::is_constructible<U&&, T>::value)>
- constexpr optional(U&& value) : mHasValue{true}, mValue{std::forward<U>(value)}
- { }
- ~optional() { if(mHasValue) al::destroy_at(std::addressof(mValue)); }
- optional& operator=(nullopt_t) noexcept { reset(); return *this; }
- template<REQUIRES(std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value)>
- optional& operator=(const optional &rhs)
- {
- if(!rhs)
- reset();
- else if(*this)
- mValue = *rhs;
- else
- DoConstruct(*rhs);
- return *this;
- }
- template<REQUIRES(std::is_move_constructible<T>::value && std::is_move_assignable<T>::value)>
- optional& operator=(optional&& rhs)
- {
- if(!rhs)
- reset();
- else if(*this)
- mValue = std::move(*rhs);
- else
- DoConstruct(std::move(*rhs));
- return *this;
- }
- template<typename U=T, REQUIRES(std::is_constructible<T, U>::value &&
- std::is_assignable<T&, U>::value &&
- !std::is_same<typename std::decay<U>::type, optional<T>>::value &&
- (!std::is_same<typename std::decay<U>::type, T>::value ||
- !std::is_scalar<U>::value))>
- optional& operator=(U&& rhs)
- {
- if(*this)
- mValue = std::forward<U>(rhs);
- else
- DoConstruct(std::forward<U>(rhs));
- return *this;
- }
- const T* operator->() const { return std::addressof(mValue); }
- T* operator->() { return std::addressof(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<typename U>
- T value_or(U&& defval) const&
- { return bool{*this} ? **this : static_cast<T>(std::forward<U>(defval)); }
- template<typename U>
- T value_or(U&& defval) &&
- { return bool{*this} ? std::move(**this) : static_cast<T>(std::forward<U>(defval)); }
- void reset() noexcept
- {
- if(mHasValue)
- al::destroy_at(std::addressof(mValue));
- mHasValue = false;
- }
- };
- template<typename T>
- inline optional<typename std::decay<T>::type> make_optional(T&& arg)
- { return optional<typename std::decay<T>::type>{in_place, std::forward<T>(arg)}; }
- template<typename T, typename... Args>
- inline optional<T> make_optional(Args&& ...args)
- { return optional<T>{in_place, std::forward<Args>(args)...}; }
- template<typename T, typename U, typename... Args>
- inline optional<T> make_optional(std::initializer_list<U> il, Args&& ...args)
- { return optional<T>{in_place, il, std::forward<Args>(args)...}; }
- #undef REQUIRES
- } // namespace al
- #endif /* AL_SPAN_H */
|