/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include #include "base/variant.h" namespace base { struct none_type { bool operator==(none_type other) const { return true; } bool operator!=(none_type other) const { return false; } bool operator<(none_type other) const { return false; } bool operator<=(none_type other) const { return true; } bool operator>(none_type other) const { return false; } bool operator>=(none_type other) const { return true; } }; constexpr none_type none = {}; template class optional_variant { public: optional_variant() : _impl(none) { } optional_variant(const optional_variant &other) : _impl(other._impl) { } optional_variant(optional_variant &&other) : _impl(std::move(other._impl)) { } template >::value>> optional_variant(T &&value) : _impl(std::forward(value)) { } optional_variant &operator=(const optional_variant &other) { _impl = other._impl; return *this; } optional_variant &operator=(optional_variant &&other) { _impl = std::move(other._impl); return *this; } template >::value>> optional_variant &operator=(T &&value) { _impl = std::forward(value); return *this; } bool has_value() const { return !is(); } explicit operator bool() const { return has_value(); } bool operator==(const optional_variant &other) const { return _impl == other._impl; } bool operator!=(const optional_variant &other) const { return _impl != other._impl; } bool operator<(const optional_variant &other) const { return _impl < other._impl; } bool operator<=(const optional_variant &other) const { return _impl <= other._impl; } bool operator>(const optional_variant &other) const { return _impl > other._impl; } bool operator>=(const optional_variant &other) const { return _impl >= other._impl; } template decltype(auto) is() const { return _impl.template is(); } template decltype(auto) get_unchecked() { return _impl.template get_unchecked(); } template decltype(auto) get_unchecked() const { return _impl.template get_unchecked(); } private: variant _impl; }; template inline T *get_if(optional_variant *v) { return (v && v->template is()) ? &v->template get_unchecked() : nullptr; } template inline const T *get_if(const optional_variant *v) { return (v && v->template is()) ? &v->template get_unchecked() : nullptr; } template class optional; template struct optional_wrap_once { using type = optional; }; template struct optional_wrap_once> { using type = optional; }; template using optional_wrap_once_t = typename optional_wrap_once>::type; template struct optional_chain_result { using type = optional_wrap_once_t; }; template <> struct optional_chain_result { using type = bool; }; template using optional_chain_result_t = typename optional_chain_result::type; template class optional : public optional_variant { public: using optional_variant::optional_variant; Type &operator*() { auto result = get_if(this); Expects(result != nullptr); return *result; } const Type &operator*() const { auto result = get_if(this); Expects(result != nullptr); return *result; } Type *operator->() { auto result = get_if(this); Expects(result != nullptr); return result; } const Type *operator->() const { auto result = get_if(this); Expects(result != nullptr); return result; } }; template optional_wrap_once_t make_optional(Type &&value) { return optional_wrap_once_t { std::forward(value) }; } template inline auto operator|(const optional &value, Method method) -> optional_chain_result_t { if constexpr (std::is_same_v) { return value ? (method(*value), true) : false; } else { return value ? make_optional(method(*value)) : none; } } } // namespace base