/* 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 #ifndef Unexpected #define Unexpected(message) std::abort() #define UniqueFunctionUnexpected #endif // Unexpected namespace base { namespace details { template class moveable_callable_wrap { public: static_assert( std::is_move_constructible_v, "Should be at least moveable."); moveable_callable_wrap(Callable &&other) : _value(std::move(other)) { } moveable_callable_wrap &operator=(Callable &&other) { _value = std::move(other); return *this; } moveable_callable_wrap(moveable_callable_wrap &&other) : _value(std::move(other._value)) { } moveable_callable_wrap( const moveable_callable_wrap &other) : _value(fail_construct()) { } moveable_callable_wrap &operator=( moveable_callable_wrap &&other) { _value = std::move(other._value); return *this; } moveable_callable_wrap &operator=( const moveable_callable_wrap &other) { return fail_assign(); } template decltype(auto) operator()(Args &&...args) const { return _value(std::forward(args)...); } private: [[noreturn]] Callable fail_construct() { Unexpected("Attempt to copy-construct a move-only type."); } [[noreturn]] moveable_callable_wrap &fail_assign() { Unexpected("Attempt to copy-assign a move-only type."); } mutable Callable _value; }; } // namespace details template class unique_function; template class unique_function final { public: unique_function(std::nullptr_t = nullptr) noexcept { } unique_function(const unique_function &other) = delete; unique_function &operator=(const unique_function &other) = delete; // Move construct / assign from the same type. unique_function(unique_function &&other) : _impl(std::move(other._impl)) { } unique_function &operator=(unique_function &&other) { _impl = std::move(other._impl); return *this; } template < typename Callable, typename = std::enable_if_t< std::is_convertible_v< decltype(std::declval()( std::declval()...)), Return>>> unique_function(Callable &&other) : unique_function( std::forward(other), std::is_copy_constructible>{}) { } template < typename Callable, typename = std::enable_if_t< std::is_convertible_v< decltype(std::declval()( std::declval()...)), Return>>> unique_function &operator=(Callable &&other) { using Decayed = std::decay_t; if constexpr (std::is_copy_constructible_v) { _impl = std::forward(other); } else if constexpr (std::is_move_constructible_v) { _impl = details::moveable_callable_wrap( std::forward(other)); } else { static_assert(false_t(other), "Should be moveable."); } return *this; } void swap(unique_function &other) { _impl.swap(other._impl); } template Return operator()(OtherArgs &&...args) { return _impl(std::forward(args)...); } explicit operator bool() const { return _impl.operator bool(); } friend inline bool operator==( const unique_function &value, std::nullptr_t) noexcept { return value._impl == nullptr; } friend inline bool operator==( std::nullptr_t, const unique_function &value) noexcept { return value._impl == nullptr; } friend inline bool operator!=( const unique_function &value, std::nullptr_t) noexcept { return value._impl != nullptr; } friend inline bool operator!=( std::nullptr_t, const unique_function &value) noexcept { return value._impl != nullptr; } private: template unique_function(Callable &&other, std::true_type) : _impl(std::forward(other)) { } template unique_function(Callable &&other, std::false_type) : _impl(details::moveable_callable_wrap>( std::forward(other))) { } std::function _impl; }; } // namespace base #ifdef UniqueFunctionUnexpected #undef UniqueFunctionUnexpected #undef Unexpected #endif // UniqueFunctionUnexpectedb