Permalink
Browse files

Merge pull request #3571 from STEllAR-GROUP/function-empty

 Make empty [unique_]function vtable non-dependent
  • Loading branch information...
hkaiser committed Dec 2, 2018
2 parents 255e90f + eb83d9d commit e5120d77a235aa34c2aed253ff57361e533e8d5a
@@ -57,30 +57,21 @@ namespace hpx { namespace util { namespace detail
template <typename VTable, typename R, typename ...Ts>
class function_base<VTable, R(Ts...)>
{
// make sure the empty table instance is initialized in time, even
// during early startup
static VTable const* get_empty_table()
{
static VTable const empty_table =
detail::construct_vtable<detail::empty_function<R(Ts...)> >();
return &empty_table;
}

public:
function_base() noexcept
: vptr(get_empty_table())
: vptr(detail::get_empty_function_vtable<VTable>())
{
std::memset(object, 0, vtable::function_storage_size);
vtable::default_construct<empty_function<R(Ts...)> >(object);
vtable::default_construct<empty_function>(object);
}

function_base(function_base&& other) noexcept
: vptr(other.vptr)
{
// move-construct
std::memcpy(object, other.object, vtable::function_storage_size);
other.vptr = get_empty_table();
vtable::default_construct<empty_function<R(Ts...)> >(other.object);
other.vptr = detail::get_empty_function_vtable<VTable>();
vtable::default_construct<empty_function>(other.object);
}

~function_base()
@@ -116,7 +107,7 @@ namespace hpx { namespace util { namespace detail
vtable::reconstruct<target_type>(object, std::forward<F>(f));
} else {
reset();
vtable::_delete<empty_function<R(Ts...)> >(object);
vtable::_delete<empty_function>(object);

vptr = f_vptr;
vtable::construct<target_type>(object, std::forward<F>(f));
@@ -128,12 +119,12 @@ namespace hpx { namespace util { namespace detail

void reset() noexcept
{
if (!vptr->empty)
if (!empty())
{
vptr->delete_(object);

vptr = get_empty_table();
vtable::default_construct<empty_function<R(Ts...)> >(object);
vptr = detail::get_empty_function_vtable<VTable>();
vtable::default_construct<empty_function>(object);
}
}

@@ -145,7 +136,7 @@ namespace hpx { namespace util { namespace detail

bool empty() const noexcept
{
return vptr->empty;
return vptr == detail::get_empty_function_vtable<VTable>();
}

explicit operator bool() const noexcept
@@ -8,42 +8,40 @@
#ifndef HPX_UTIL_DETAIL_EMPTY_FUNCTION_HPP
#define HPX_UTIL_DETAIL_EMPTY_FUNCTION_HPP

#include <hpx/throw_exception.hpp>
#include <hpx/config.hpp>
#include <hpx/util/detail/function_registration.hpp>
#include <hpx/util/detail/vtable/vtable.hpp>

namespace hpx { namespace util { namespace detail
{
///////////////////////////////////////////////////////////////////////////
template <typename Sig>
struct empty_function; // must be trivial and empty
struct empty_function {}; // must be trivial and empty

template <typename R, typename ...Ts>
struct empty_function<R(Ts...)>
{
R operator()(Ts...) const
{
hpx::throw_exception(bad_function_call,
"empty function object should not be used",
"empty_function::operator()");
}
};
HPX_NORETURN HPX_EXPORT void throw_bad_function_call();

// Pseudo registration for empty functions.
// We don't want to serialize empty functions.
template <typename VTable, typename Sig>
template <typename VTable>
struct get_function_name_impl<
VTable
, hpx::util::detail::empty_function<Sig>
, hpx::util::detail::empty_function
>
{
static char const* call()
HPX_NORETURN static char const* call()
{
hpx::throw_exception(bad_function_call,
"empty function object should not be used",
"get_function_name<empty_function>");
return "";
throw_bad_function_call();
}
};

///////////////////////////////////////////////////////////////////////////
// make sure the empty table instance is initialized in time, even
// during early startup
template <typename VTable>
VTable const* get_empty_function_vtable()
{
static VTable const empty_vtable = construct_vtable<empty_function>();
return &empty_vtable;
}
}}}

#endif
@@ -11,6 +11,7 @@
#include <hpx/config.hpp>
#include <hpx/traits/get_function_address.hpp>
#include <hpx/traits/get_function_annotation.hpp>
#include <hpx/util/detail/empty_function.hpp>
#include <hpx/util/detail/vtable/vtable.hpp>
#include <hpx/util/invoke.hpp>

@@ -81,6 +82,16 @@ namespace hpx { namespace util { namespace detail
: callable_vtable_base(construct_vtable<T>())
, invoke(&callable_vtable::template _invoke<T>)
{}

HPX_NORETURN static R _empty_invoke(void**, Ts&&...)
{
throw_bad_function_call();
}

HPX_CONSTEXPR callable_vtable(construct_vtable<empty_function>) noexcept
: callable_vtable_base(construct_vtable<empty_function>())
, invoke(&callable_vtable::_empty_invoke)
{}
};
}}}

@@ -11,6 +11,7 @@
#include <hpx/config.hpp>
#include <hpx/runtime/serialization/detail/polymorphic_intrusive_factory.hpp>
#include <hpx/util/detail/function_registration.hpp>
#include <hpx/util/detail/empty_function.hpp>
#include <hpx/util/detail/vtable/serializable_vtable.hpp>
#include <hpx/util/detail/vtable/vtable.hpp>

@@ -30,12 +31,18 @@ namespace hpx { namespace util { namespace detail
serializable_function_vtable(construct_vtable<T>) noexcept
: VTable(construct_vtable<T>())
, serializable_vtable(construct_vtable<T>())
, name(this->empty ? "empty" : get_function_name<VTable, T>())
, name(get_function_name<VTable, T>())
{
hpx::serialization::detail::polymorphic_intrusive_factory::instance().
register_class(name, &serializable_function_vtable::get_vtable<T>);
}

serializable_function_vtable(construct_vtable<empty_function>) noexcept
: VTable(construct_vtable<empty_function>())
, serializable_vtable(construct_vtable<empty_function>())
, name("empty")
{}

template <typename T>
static void* get_vtable()
{
@@ -24,13 +24,10 @@ namespace hpx { namespace util { namespace detail
struct unique_function_vtable
: vtable, callable_vtable<Sig>
{
bool empty;

template <typename T>
HPX_CONSTEXPR unique_function_vtable(construct_vtable<T>) noexcept
: vtable(construct_vtable<T>())
, callable_vtable<Sig>(construct_vtable<T>())
, empty(std::is_same<T, empty_function<Sig> >::value)
{}
};
}}}
@@ -14,6 +14,7 @@
#include <hpx/traits/get_function_annotation.hpp>
#include <hpx/traits/is_callable.hpp>
#include <hpx/util/detail/basic_function.hpp>
#include <hpx/util/detail/empty_function.hpp>
#include <hpx/util/detail/function_registration.hpp>
#include <hpx/util/detail/vtable/function_vtable.hpp>
#include <hpx/util/detail/vtable/vtable.hpp>
@@ -53,15 +54,10 @@ namespace hpx { namespace util
function(function const& other)
: base_type()
{
detail::vtable::_delete<
detail::empty_function<R(Ts...)>
>(this->object);
detail::vtable::_delete<detail::empty_function>(this->object);

this->vptr = other.vptr;
if (!this->vptr->empty)
{
this->vptr->copy(this->object, other.object);
}
this->vptr->copy(this->object, other.object);
}

function(function&& other) noexcept
@@ -87,15 +83,10 @@ namespace hpx { namespace util
if (this != &other)
{
reset();
detail::vtable::_delete<
detail::empty_function<R(Ts...)>
>(this->object);
detail::vtable::_delete<detail::empty_function>(this->object);

this->vptr = other.vptr;
if (!this->vptr->empty)
{
this->vptr->copy(this->object, other.object);
}
this->vptr->copy(this->object, other.object);
}
return *this;
}
@@ -36,6 +36,9 @@ add_hpx_library_sources(hpx
GLOB_RECURSE GLOBS "${PROJECT_SOURCE_DIR}/src/util/*.cpp"
EXCLUDE ".*lightweight_test.cpp"
APPEND)
add_hpx_library_sources(hpx
GLOB_RECURSE GLOBS "${PROJECT_SOURCE_DIR}/src/util/detail/*.cpp"
APPEND)
add_hpx_library_sources(hpx
GLOB_RECURSE GLOBS "${PROJECT_SOURCE_DIR}/src/lcos/*.cpp"
APPEND)
@@ -0,0 +1,20 @@
// Copyright (c) 2011 Thomas Heller
// Copyright (c) 2013 Hartmut Kaiser
// Copyright (c) 2014 Agustin Berge
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <hpx/util/detail/empty_function.hpp>

#include <hpx/throw_exception.hpp>

namespace hpx { namespace util { namespace detail
{
HPX_NORETURN void throw_bad_function_call()
{
hpx::throw_exception(bad_function_call,
"empty function object should not be used",
"empty_function::operator()");
}
}}}

0 comments on commit e5120d7

Please sign in to comment.