mirror of https://github.com/procxx/kepka.git
185 lines
5.7 KiB
C++
185 lines
5.7 KiB
C++
//
|
|
// This file is part of Kepka,
|
|
// an unofficial desktop version of Telegram messaging app,
|
|
// see https://github.com/procxx/kepka
|
|
//
|
|
// Kepka 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/procxx/kepka/blob/master/LICENSE
|
|
// Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|
// Copyright (c) 2017- Kepka Contributors, https://github.com/procxx
|
|
//
|
|
#pragma once
|
|
|
|
#include "base/variant.h"
|
|
#include <gsl/gsl_assert> // for Expects
|
|
|
|
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 optional_chain(const optional<Type> &value, Method &method, std::false_type)
|
|
-> optional_chain_result_t<decltype(method(*value))> {
|
|
return value ? make_optional(method(*value)) : none;
|
|
}
|
|
|
|
template <typename Type, typename Method>
|
|
inline auto optional_chain(const optional<Type> &value, Method &method, std::true_type)
|
|
-> optional_chain_result_t<decltype(method(*value))> {
|
|
return value ? (method(*value), true) : false;
|
|
}
|
|
|
|
template <typename Type, typename Method>
|
|
inline auto operator|(const optional<Type> &value, Method method) -> optional_chain_result_t<decltype(method(*value))> {
|
|
using is_void_return = std::is_same<decltype(method(*value)), void>;
|
|
return optional_chain(value, method, is_void_return{});
|
|
}
|
|
|
|
} // namespace base
|