/* 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 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 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 { using parent = optional_variant; public: using parent::parent; Type &operator*() & { Expects(parent::template is()); return parent::template get_unchecked(); } Type &&operator*() && { Expects(parent::template is()); return std::move(parent::template get_unchecked()); } const Type &operator*() const & { Expects(parent::template is()); return parent::template get_unchecked(); } Type *operator->() { Expects(parent::template is()); return std::addressof(parent::template get_unchecked()); } const Type *operator->() const { Expects(parent::template is()); return std::addressof(parent::template get_unchecked()); } template Type &emplace(Args &&...args) { return parent::template set(std::forward(args)...); } }; 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