200 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			200 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
| This file is part of Telegram Desktop,
 | |
| the official desktop version of Telegram messaging app, see https://telegram.org
 | |
| 
 | |
| Telegram Desktop is free software: you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation, either version 3 of the License, or
 | |
| (at your option) any later version.
 | |
| 
 | |
| It is distributed in the hope that it will be useful,
 | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | |
| GNU General Public License for more details.
 | |
| 
 | |
| In addition, as a special exception, the copyright holders give permission
 | |
| to link the code of portions of this program with the OpenSSL library.
 | |
| 
 | |
| Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
 | |
| Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
 | |
| */
 | |
| #pragma once
 | |
| 
 | |
| #include <gsl/gsl_assert>
 | |
| #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 <typename... Types>
 | |
| 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 <typename T, typename = std::enable_if_t<!std::is_base_of<optional_variant, std::decay_t<T>>::value>>
 | |
| 	optional_variant(T &&value) : _impl(std::forward<T>(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 <typename T, typename = std::enable_if_t<!std::is_base_of<optional_variant, std::decay_t<T>>::value>>
 | |
| 	optional_variant &operator=(T &&value) {
 | |
| 		_impl = std::forward<T>(value);
 | |
| 		return *this;
 | |
| 	}
 | |
| 
 | |
| 	explicit operator bool() const {
 | |
| 		return (get_if<none_type>(&_impl) == nullptr);
 | |
| 	}
 | |
| 	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 <typename T>
 | |
| 	decltype(auto) is() const {
 | |
| 		return _impl.template is<T>();
 | |
| 	}
 | |
| 	template <typename T>
 | |
| 	decltype(auto) get_unchecked() {
 | |
| 		return _impl.template get_unchecked<T>();
 | |
| 	}
 | |
| 	template <typename T>
 | |
| 	decltype(auto) get_unchecked() const {
 | |
| 		return _impl.template get_unchecked<T>();
 | |
| 	}
 | |
| 
 | |
| private:
 | |
| 	variant<none_type, Types...> _impl;
 | |
| 
 | |
| };
 | |
| 
 | |
| template <typename T, typename... Types>
 | |
| inline T *get_if(optional_variant<Types...> *v) {
 | |
| 	return (v && v->template is<T>()) ? &v->template get_unchecked<T>() : nullptr;
 | |
| }
 | |
| 
 | |
| template <typename T, typename... Types>
 | |
| inline const T *get_if(const optional_variant<Types...> *v) {
 | |
| 	return (v && v->template is<T>()) ? &v->template get_unchecked<T>() : nullptr;
 | |
| }
 | |
| 
 | |
| template <typename Type>
 | |
| class optional;
 | |
| 
 | |
| template <typename Type>
 | |
| struct optional_wrap_once {
 | |
| 	using type = optional<Type>;
 | |
| };
 | |
| 
 | |
| template <typename Type>
 | |
| struct optional_wrap_once<optional<Type>> {
 | |
| 	using type = optional<Type>;
 | |
| };
 | |
| 
 | |
| template <typename Type>
 | |
| using optional_wrap_once_t = typename optional_wrap_once<std::decay_t<Type>>::type;
 | |
| 
 | |
| template <typename Type>
 | |
| struct optional_chain_result {
 | |
| 	using type = optional_wrap_once_t<Type>;
 | |
| };
 | |
| 
 | |
| template <>
 | |
| struct optional_chain_result<void> {
 | |
| 	using type = bool;
 | |
| };
 | |
| 
 | |
| template <typename Type>
 | |
| using optional_chain_result_t = typename optional_chain_result<Type>::type;
 | |
| 
 | |
| template <typename Type>
 | |
| class optional : public optional_variant<Type> {
 | |
| public:
 | |
| 	using optional_variant<Type>::optional_variant;
 | |
| 
 | |
| 	Type &operator*() {
 | |
| 		auto result = get_if<Type>(this);
 | |
| 		Expects(result != nullptr);
 | |
| 		return *result;
 | |
| 	}
 | |
| 	const Type &operator*() const {
 | |
| 		auto result = get_if<Type>(this);
 | |
| 		Expects(result != nullptr);
 | |
| 		return *result;
 | |
| 	}
 | |
| 	Type *operator->() {
 | |
| 		auto result = get_if<Type>(this);
 | |
| 		Expects(result != nullptr);
 | |
| 		return result;
 | |
| 	}
 | |
| 	const Type *operator->() const {
 | |
| 		auto result = get_if<Type>(this);
 | |
| 		Expects(result != nullptr);
 | |
| 		return result;
 | |
| 	}
 | |
| 
 | |
| };
 | |
| 
 | |
| template <typename Type>
 | |
| optional_wrap_once_t<Type> make_optional(Type &&value) {
 | |
| 	return optional_wrap_once_t<Type> { std::forward<Type>(value) };
 | |
| }
 | |
| 
 | |
| template <typename Type, typename Method>
 | |
| inline auto operator|(const optional<Type> &value, Method method)
 | |
| -> optional_chain_result_t<decltype(method(*value))> {
 | |
| 	if constexpr (std::is_same_v<decltype(method(*value)), void>) {
 | |
| 		return value ? (method(*value), true) : false;
 | |
| 	} else {
 | |
| 		return value ? make_optional(method(*value)) : none;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| } // namespace base
 | 
