/* 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 #include "base/variant.h" namespace base { template class optional_variant { public: optional_variant() : _impl(std::nullopt) { } 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 T &set(Args &&...args) { _impl.template set(std::forward(args)...); return get_unchecked(); } void clear() { _impl.template set(); } 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(); } template decltype(auto) match(Methods &&...methods) { return base::match(_impl, std::forward(methods)...); } template decltype(auto) match(Methods &&...methods) const { return base::match(_impl, std::forward(methods)...); } 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 inline decltype(auto) match( optional_variant &value, Methods &&...methods) { return value.match(std::forward(methods)...); } template inline decltype(auto) match( const optional_variant &value, Methods &&...methods) { return value.match(std::forward(methods)...); } template struct optional_wrap_once { using type = std::optional; }; template struct optional_wrap_once> { using type = std::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 optional_wrap_once_t make_optional(Type &&value) { return optional_wrap_once_t { std::forward(value) }; } } // namespace base template inline auto operator|(const std::optional &value, Method method) -> base::optional_chain_result_t { if constexpr (std::is_same_v) { return value ? (method(*value), true) : false; } else { return value ? base::optional_chain_result_t( method(*value)) : std::nullopt; } }