HelenOS sources
This source file includes following definitions.
- invoke_callable
- copy_callable
- destroy_callable
- swap
- assign
- target_type
- target
- target
- clear_
- swap
#ifndef LIBCPP_BITS_FUNCTIONAL_FUNCTION
#define LIBCPP_BITS_FUNCTIONAL_FUNCTION
#include <__bits/functional/conditional_function_typedefs.hpp>
#include <__bits/functional/reference_wrapper.hpp>
#include <__bits/memory/allocator_arg.hpp>
#include <__bits/memory/allocator_traits.hpp>
#include <typeinfo>
#include <type_traits>
#include <utility>
namespace std
{
namespace aux
{
template<class Callable, class R, class... Args>
R invoke_callable(Callable* clbl, Args&&... args)
{
return (*clbl)(forward<Args>(args)...);
}
template<class Callable>
void copy_callable(Callable* to, Callable* from)
{
new(to) Callable{*from};
}
template<class Callable>
void destroy_callable(Callable* clbl)
{
if (clbl)
clbl->~Callable();
}
}
class bad_function_call;
template<class>
class function;
template<class R, class... Args>
class function<R(Args...)>
: public aux::conditional_function_typedefs<Args...>
{
public:
using result_type = R;
function() noexcept
: callable_{}, callable_size_{}, call_{},
copy_{}, dest_{}
{ }
function(nullptr_t) noexcept
: function{}
{ }
function(const function& other)
: callable_{}, callable_size_{other.callable_size_},
call_{other.call_}, copy_{other.copy_}, dest_{other.dest_}
{
callable_ = new uint8_t[callable_size_];
(*copy_)(callable_, other.callable_);
}
function(function&& other)
: callable_{other.callable_}, callable_size_{other.callable_size_},
call_{other.call_}, copy_{other.copy_}, dest_{other.dest_}
{
other.callable_ = nullptr;
other.callable_size_ = size_t{};
other.call_ = nullptr;
other.copy_ = nullptr;
other.dest_ = nullptr;
}
template<class F>
function(F f)
: callable_{}, callable_size_{sizeof(F)},
call_{(call_t)aux::invoke_callable<F, R, Args...>},
copy_{(copy_t)aux::copy_callable<F>},
dest_{(dest_t)aux::destroy_callable<F>}
{
callable_ = new uint8_t[callable_size_];
(*copy_)(callable_, (uint8_t*)&f);
}
template<class A>
function(allocator_arg_t, const A& a) noexcept
: function{}
{ }
template<class A>
function(allocator_arg_t, const A& a, nullptr_t) noexcept
: function{}
{ }
template<class A>
function(allocator_arg_t, const A& a, const function& other)
: function{other}
{ }
template<class A>
function(allocator_arg_t, const A& a, function&& other)
: function{move(other)}
{ }
template<class F, class A>
function(allocator_arg_t, const A& a, F f)
: function{f}
{ }
function& operator=(const function& rhs)
{
function{rhs}.swap(*this);
return *this;
}
function& operator=(function&& rhs)
{
clear_();
callable_ = rhs.callable_;
callable_size_ = rhs.callable_size_;
call_ = rhs.call_;
copy_ = rhs.copy_;
dest_ = rhs.dest_;
rhs.callable_ = nullptr;
rhs.callable_size_ = size_t{};
rhs.call_ = nullptr;
rhs.copy_ = nullptr;
rhs.dest_ = nullptr;
return *this;
}
function& operator=(nullptr_t) noexcept
{
clear_();
return *this;
}
template<class F>
function& operator=(F&& f)
{
callable_size_ = sizeof(F);
callable_ = new uint8_t[callable_size_];
call_ = aux::invoke_callable<F, R, Args...>;
copy_ = aux::copy_callable<F>;
dest_ = aux::destroy_callable<F>;
(*copy_)(callable_, (uint8_t*)&f);
}
template<class F>
function& operator=(reference_wrapper<F> ref) noexcept
{
return (*this) = ref.get();
}
~function()
{
if (callable_)
{
(*dest_)(callable_);
delete[] callable_;
}
}
void swap(function& other) noexcept
{
std::swap(callable_, other.callable_);
std::swap(callable_size_, other.callable_size_);
std::swap(call_, other.call_);
std::swap(copy_, other.copy_);
std::swap(dest_, other.dest_);
}
template<class F, class A>
void assign(F&& f, const A& a)
{
function{allocator_arg, a, forward<F>(f)}.swap(*this);
}
explicit operator bool() const noexcept
{
return callable_ != nullptr;
}
result_type operator()(Args... args) const
{
if constexpr (is_same_v<R, void>)
(*call_)(callable_, forward<Args>(args)...);
else
return (*call_)(callable_, forward<Args>(args)...);
}
const type_info& target_type() const noexcept
{
return typeid(*callable_);
}
template<class T>
T* target() noexcept
{
if (target_type() == typeid(T))
return (T*)callable_;
else
return nullptr;
}
template<class T>
const T* target() const noexcept
{
if (target_type() == typeid(T))
return (T*)callable_;
else
return nullptr;
}
private:
using call_t = R(*)(uint8_t*, Args&&...);
using copy_t = void (*)(uint8_t*, uint8_t*);
using dest_t = void (*)(uint8_t*);
uint8_t* callable_;
size_t callable_size_;
call_t call_;
copy_t copy_;
dest_t dest_;
void clear_()
{
if (callable_)
{
(*dest_)(callable_);
delete[] callable_;
callable_ = nullptr;
}
}
};
template<class R, class... Args>
bool operator==(const function<R(Args...)>& f, nullptr_t) noexcept
{
return !f;
}
template<class R, class... Args>
bool operator==(nullptr_t, const function<R(Args...)>& f) noexcept
{
return !f;
}
template<class R, class... Args>
bool operator!=(const function<R(Args...)>& f, nullptr_t) noexcept
{
return (bool)f;
}
template<class R, class... Args>
bool operator!=(nullptr_t, const function<R(Args...)>& f) noexcept
{
return (bool)f;
}
template<class R, class... Args>
void swap(function<R(Args...)>& f1, function<R(Args...)>& f2)
{
f1.swap(f2);
}
template<class R, class... Args, class Alloc>
struct uses_allocator<function<R(Args...)>, Alloc>
: true_type
{ };
}
#endif
HelenOS homepage, sources at GitHub