Skip to content

Commit

Permalink
Merge pull request #2751 from STEllAR-GROUP/throw_with_info
Browse files Browse the repository at this point in the history
Replace boost::exception with proposed exception_info
  • Loading branch information
hkaiser committed Jul 11, 2017
2 parents 11bce88 + 65cbc13 commit d2c401a
Show file tree
Hide file tree
Showing 9 changed files with 583 additions and 686 deletions.
347 changes: 181 additions & 166 deletions hpx/exception.hpp

Large diffs are not rendered by default.

272 changes: 272 additions & 0 deletions hpx/exception_info.hpp
@@ -0,0 +1,272 @@
// Copyright (c) 2017 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)

#ifndef HPX_EXCEPTION_INFO_HPP
#define HPX_EXCEPTION_INFO_HPP

#include <hpx/config.hpp>
#include <hpx/error_code.hpp>
#include <hpx/util/detail/pack.hpp>
#include <hpx/util/tuple.hpp>

#include <cstddef>
#include <exception>
#include <memory>
#include <type_traits>
#include <typeinfo>
#include <utility>

#if defined(HPX_WINDOWS)
# include <excpt.h>
# undef exception_info
#endif

namespace hpx
{
///////////////////////////////////////////////////////////////////////////
template <typename Tag, typename Type>
struct error_info
{
using tag = Tag;
using type = Type;

explicit error_info(Type const& value)
: _value(value)
{}

explicit error_info(Type&& value)
: _value(std::forward<Type>(value))
{}

Type _value;
};

#define HPX_DEFINE_ERROR_INFO(NAME, TYPE) \
struct NAME : ::hpx::error_info<NAME, TYPE> \
{ \
explicit NAME(TYPE const& value) \
: error_info(value) \
{} \
\
explicit NAME(TYPE&& value) \
: error_info(::std::forward<TYPE>(value)) \
{} \
} \
/**/

///////////////////////////////////////////////////////////////////////////
namespace detail
{
class exception_info_node_base
{
public:
virtual ~exception_info_node_base() = default;
virtual void const* lookup(std::type_info const& tag) const noexcept = 0;

std::shared_ptr<exception_info_node_base> next;
};

template <typename ...Ts>
class exception_info_node
: public exception_info_node_base
{
public:
template <typename ...Tags, typename ...Types>
explicit exception_info_node(
error_info<Tags, Types>&&... tagged_values)
: data(std::forward<Types>(tagged_values._value)...)
{}

template <std::size_t ...Is>
void const* _lookup(
util::detail::pack_c<std::size_t, Is...>,
std::type_info const& tag) const noexcept
{
using entry_type = std::pair<std::type_info const&, void const*>;
entry_type const entries[] = {
{typeid(typename Ts::tag), std::addressof(util::get<Is>(data))}...
};

for (auto const& entry : entries)
{
if (entry.first == tag)
return entry.second;
}
return nullptr;
}

void const* lookup(std::type_info const& tag) const noexcept override
{
using indices_pack =
typename util::detail::make_index_pack<sizeof...(Ts)>::type;
if (void const* value = _lookup(indices_pack(), tag))
return value;

return next ? next->lookup(tag) : nullptr;
}

using exception_info_node_base::next;
util::tuple<typename Ts::type...> data;
};
}

///////////////////////////////////////////////////////////////////////////
class exception_info
{
using node_ptr = std::shared_ptr<detail::exception_info_node_base>;

public:
exception_info() noexcept
: _file(nullptr), _line(0), _function(nullptr)
, _data(nullptr)
{}

exception_info(char const* file, int line) noexcept
: _file(file), _line(line), _function(nullptr)
, _data(nullptr)
{}

exception_info(char const* file, int line, char const* function) noexcept
: _file(file), _line(line), _function(function)
, _data(nullptr)
{}

exception_info(exception_info const& other) noexcept = default;
exception_info(exception_info&& other) noexcept = default;

exception_info& operator=(exception_info const& other) noexcept = default;
exception_info& operator=(exception_info&& other) noexcept = default;

virtual ~exception_info() = default;

char const* file_name() const noexcept
{
return _file;
}

int line() const noexcept
{
return _line;
}

char const* function_name() const noexcept
{
return _function;
}

template <typename ...Tags, typename ...Types>
exception_info& set(error_info<Tags, Types>&&... tagged_values)
{
using node_type = detail::exception_info_node<
error_info<Tags, Types>...>;

node_ptr node = std::make_shared<node_type>(std::move(tagged_values)...);
node->next = std::move(_data);
_data = std::move(node);
return *this;
}

template <typename Tag>
typename Tag::type const* get() const noexcept
{
auto const* data = _data.get();
return static_cast<typename Tag::type const*>(
data ? data->lookup(typeid(typename Tag::tag)) : nullptr);
}

private:
char const* _file;
unsigned int _line;
char const* _function;
node_ptr _data;
};

///////////////////////////////////////////////////////////////////////////
namespace detail
{
struct exception_with_info_base
: public exception_info
{
exception_with_info_base(std::type_info const& type, exception_info xi)
: exception_info(std::move(xi))
, type(type)
{}

std::type_info const& type;
};

template <typename E>
struct exception_with_info
: public E
, public exception_with_info_base
{
explicit exception_with_info(E const& e, exception_info xi)
: E(e)
, exception_with_info_base(typeid(E), std::move(xi))
{}

explicit exception_with_info(E&& e, exception_info xi)
: E(std::move(e))
, exception_with_info_base(typeid(E), std::move(xi))
{}
};
}

template <typename E> HPX_ATTRIBUTE_NORETURN
void throw_with_info(E&& e, exception_info&& xi = exception_info())
{
using ED = typename std::decay<E>::type;
static_assert(
#if defined(HPX_HAVE_CXX14_STD_IS_FINAL)
std::is_class<ED>::value && !std::is_final<ED>::value,
#else
std::is_class<ED>::value,
#endif
"E shall be a valid base class");
static_assert(
!std::is_base_of<exception_info, ED>::value,
"E shall not derive from exception_info");

throw detail::exception_with_info<ED>(std::forward<E>(e), std::move(xi));
}

template <typename E> HPX_ATTRIBUTE_NORETURN
void throw_with_info(E&& e, exception_info const& xi)
{
throw_with_info(std::forward<E>(e), exception_info(xi));
}

///////////////////////////////////////////////////////////////////////////
template <typename E>
exception_info const* get_exception_info(E const& e)
{
return dynamic_cast<exception_info const*>(std::addressof(e));
}

template <typename E>
exception_info* get_exception_info(E& e)
{
return dynamic_cast<exception_info*>(std::addressof(e));
}

inline exception_info const* get_exception_info(std::exception_ptr const& p)
{
try
{
if (p) std::rethrow_exception(p);
} catch (exception_info const& xi) {
return &xi;
} catch (...) {
}
return nullptr;
}

inline exception_info const* get_exception_info(hpx::error_code const& ec)
{
return get_exception_info(detail::access_exception(ec));
}
}

#endif /*HPX_EXCEPTION_INFO_HPP*/
3 changes: 2 additions & 1 deletion hpx/runtime/parcelset/decode_parcels.hpp
Expand Up @@ -9,6 +9,7 @@

#include <hpx/config.hpp>
#include <hpx/exception.hpp>
#include <hpx/exception_info.hpp>
#include <hpx/performance_counters/parcels/data_point.hpp>
#include <hpx/runtime/naming/name.hpp>
#include <hpx/runtime/naming/resolver_client.hpp>
Expand Down Expand Up @@ -253,7 +254,7 @@ namespace hpx { namespace parcelset
// We have to repackage all exceptions thrown by the
// serialization library as otherwise we will loose the
// e.what() description of the problem, due to slicing.
throw boost::enable_error_info(
hpx::throw_with_info(
hpx::exception(serialization_error, e.what()));
}
}
Expand Down
3 changes: 2 additions & 1 deletion hpx/runtime/parcelset/encode_parcels.hpp
Expand Up @@ -12,6 +12,7 @@

#include <hpx/config.hpp>
#include <hpx/exception.hpp>
#include <hpx/exception_info.hpp>
#include <hpx/runtime/actions/basic_action.hpp>
#include <hpx/runtime/parcelset/parcel.hpp>
#include <hpx/runtime/parcelset/parcel_buffer.hpp>
Expand Down Expand Up @@ -243,7 +244,7 @@ namespace hpx
// We have to repackage all exceptions thrown by the
// serialization library as otherwise we will loose the
// e.what() description of the problem, due to slicing.
throw boost::enable_error_info(
hpx::throw_with_info(
hpx::exception(serialization_error, e.what()));
return 0;
}
Expand Down
7 changes: 3 additions & 4 deletions src/error_code.cpp
Expand Up @@ -8,7 +8,6 @@
#include <hpx/error_code.hpp>
#include <hpx/exception.hpp>

#include <boost/exception/exception.hpp>
#include <boost/system/error_code.hpp>

#include <exception>
Expand Down Expand Up @@ -154,7 +153,7 @@ namespace hpx
error_code::error_code(int err, hpx::exception const& e)
{
this->boost::system::error_code::assign(err, get_hpx_category());
exception_ = get_exception_ptr(e);
exception_ = std::make_exception_ptr(e);
}

error_code::error_code(std::exception_ptr const& e)
Expand All @@ -169,8 +168,8 @@ namespace hpx
try {
std::rethrow_exception(exception_);
}
catch (boost::exception const& be) {
return dynamic_cast<std::exception const*>(&be)->what();
catch (std::exception const& be) {
return be.what();
}
}
return get_error_what(*this); // provide at least minimal error text
Expand Down

0 comments on commit d2c401a

Please sign in to comment.