#pragma once #include #include #include #include namespace vcpkg { struct NullOpt { explicit constexpr NullOpt(int) {} }; const static constexpr NullOpt nullopt{0}; namespace details { template::value> struct OptionalStorage { VCPKG_MSVC_WARNING(suppress : 26495) constexpr OptionalStorage() noexcept : m_is_present(false), m_inactive() {} constexpr OptionalStorage(const T& t) : m_is_present(true), m_t(t) {} constexpr OptionalStorage(T&& t) : m_is_present(true), m_t(std::move(t)) {} ~OptionalStorage() noexcept { if (m_is_present) m_t.~T(); } VCPKG_MSVC_WARNING(suppress : 26495) OptionalStorage(const OptionalStorage& o) : m_is_present(o.m_is_present), m_inactive() { if (m_is_present) new (&m_t) T(o.m_t); } VCPKG_MSVC_WARNING(suppress : 26495) OptionalStorage(OptionalStorage&& o) noexcept : m_is_present(o.m_is_present), m_inactive() { if (m_is_present) { new (&m_t) T(std::move(o.m_t)); } } OptionalStorage& operator=(const OptionalStorage& o) { if (m_is_present && o.m_is_present) { m_t = o.m_t; } else if (!m_is_present && o.m_is_present) { m_is_present = true; new (&m_t) T(o.m_t); } else if (m_is_present && !o.m_is_present) { clear(); } return *this; } OptionalStorage& operator=(OptionalStorage&& o) noexcept { if (m_is_present && o.m_is_present) { m_t = std::move(o.m_t); } else if (!m_is_present && o.m_is_present) { m_is_present = true; new (&m_t) T(std::move(o.m_t)); } else if (m_is_present && !o.m_is_present) { clear(); } return *this; } constexpr bool has_value() const { return m_is_present; } const T& value() const { return this->m_t; } T& value() { return this->m_t; } private: void clear() { m_is_present = false; m_t.~T(); m_inactive = '\0'; } bool m_is_present; union { char m_inactive; T m_t; }; }; template struct OptionalStorage { VCPKG_MSVC_WARNING(suppress : 26495) constexpr OptionalStorage() noexcept : m_is_present(false), m_inactive() {} constexpr OptionalStorage(T&& t) : m_is_present(true), m_t(std::move(t)) {} ~OptionalStorage() noexcept { if (m_is_present) m_t.~T(); } VCPKG_MSVC_WARNING(suppress : 26495) OptionalStorage(OptionalStorage&& o) noexcept : m_is_present(o.m_is_present), m_inactive() { if (m_is_present) { new (&m_t) T(std::move(o.m_t)); } } OptionalStorage& operator=(OptionalStorage&& o) noexcept { if (m_is_present && o.m_is_present) { m_t = std::move(o.m_t); } else if (!m_is_present && o.m_is_present) { m_is_present = true; new (&m_t) T(std::move(o.m_t)); } else if (m_is_present && !o.m_is_present) { clear(); } return *this; } constexpr bool has_value() const { return m_is_present; } const T& value() const { return this->m_t; } T& value() { return this->m_t; } private: void clear() { m_is_present = false; m_t.~T(); m_inactive = '\0'; } bool m_is_present; union { char m_inactive; T m_t; }; }; template struct OptionalStorage { constexpr OptionalStorage() noexcept : m_t(nullptr) {} constexpr OptionalStorage(T& t) : m_t(&t) {} constexpr bool has_value() const { return m_t != nullptr; } T& value() const { return *this->m_t; } private: T* m_t; }; // Note: implemented in checks.cpp to cut the header dependency void exit_if_null(bool b, const LineInfo& line_info); } template struct Optional { constexpr Optional() noexcept {} // Constructors are intentionally implicit constexpr Optional(NullOpt) {} template, Optional>::value>> constexpr Optional(U&& t) : m_base(std::forward(t)) { } T&& value_or_exit(const LineInfo& line_info) && { details::exit_if_null(this->m_base.has_value(), line_info); return std::move(this->m_base.value()); } T& value_or_exit(const LineInfo& line_info) & { details::exit_if_null(this->m_base.has_value(), line_info); return this->m_base.value(); } const T& value_or_exit(const LineInfo& line_info) const& { details::exit_if_null(this->m_base.has_value(), line_info); return this->m_base.value(); } constexpr explicit operator bool() const { return this->m_base.has_value(); } constexpr bool has_value() const { return this->m_base.has_value(); } template T value_or(U&& default_value) const& { return this->m_base.has_value() ? this->m_base.value() : static_cast(std::forward(default_value)); } T value_or(T&& default_value) const& { return this->m_base.has_value() ? this->m_base.value() : static_cast(default_value); } template T value_or(U&& default_value) && { return this->m_base.has_value() ? std::move(this->m_base.value()) : static_cast(std::forward(default_value)); } T value_or(T&& default_value) && { return this->m_base.has_value() ? std::move(this->m_base.value()) : static_cast(default_value); } typename std::add_pointer::type get() const { return this->m_base.has_value() ? &this->m_base.value() : nullptr; } typename std::add_pointer::type get() { return this->m_base.has_value() ? &this->m_base.value() : nullptr; } template using map_t = decltype(std::declval()(std::declval())); template> U then(F f) const& { if (has_value()) { return f(this->m_base.value()); } else { return nullopt; } } template using move_map_t = decltype(std::declval()(std::declval())); template> U then(F f) && { if (has_value()) { return f(std::move(this->m_base.value())); } else { return nullopt; } } friend bool operator==(const Optional& lhs, const Optional& rhs) { if (lhs.m_base.has_value()) { if (rhs.m_base.has_value()) { return lhs.m_base.value() == rhs.m_base.value(); } return false; } return !rhs.m_base.has_value(); } private: details::OptionalStorage m_base; }; template Optional> make_optional(U&& u) { return Optional>(std::forward(u)); } template bool operator==(const Optional& o, const T& t) { if (auto p = o.get()) return *p == t; return false; } template bool operator==(const T& t, const Optional& o) { if (auto p = o.get()) return t == *p; return false; } template bool operator!=(const Optional& o, const T& t) { if (auto p = o.get()) return *p != t; return true; } template bool operator!=(const T& t, const Optional& o) { if (auto p = o.get()) return t != *p; return true; } template auto common_projection(const Container& input, Projection proj) -> Optional> { const auto last = input.end(); auto first = input.begin(); if (first == last) { return nullopt; } const auto& prototype = proj(*first); while (++first != last) { if (prototype != proj(*first)) { return nullopt; } } return prototype; } }