Skip to content

Commit

Permalink
recovered make_shared_context/capture and marked them [[deprecated]]
Browse files Browse the repository at this point in the history
  • Loading branch information
zajo committed Jan 2, 2024
1 parent 9f4e637 commit fcd845f
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 0 deletions.
121 changes: 121 additions & 0 deletions include/boost/leaf/capture.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#ifndef BOOST_LEAF_CAPTURE_HPP_INCLUDED
#define BOOST_LEAF_CAPTURE_HPP_INCLUDED

// Copyright 2018-2023 Emil Dotchevski and Reverge Studios, Inc.

// 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 <boost/leaf/config.hpp>
#include <boost/leaf/handle_errors.hpp>

#if BOOST_LEAF_CFG_CAPTURE

namespace boost { namespace leaf {

namespace leaf_detail
{
template <class R, bool IsResult = is_result_type<R>::value>
struct is_result_tag;

template <class R>
struct is_result_tag<R, false>
{
};

template <class R>
struct is_result_tag<R, true>
{
};
}

#ifdef BOOST_LEAF_NO_EXCEPTIONS

namespace leaf_detail
{
template <class R, class F, class... A>
inline
decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...))
capture_impl(is_result_tag<R, false>, F && f, A... a) noexcept
{
return std::forward<F>(f)(std::forward<A>(a)...);
}

template <class R, class Future>
inline
decltype(std::declval<Future>().get())
future_get_impl(is_result_tag<R, false>, Future & fut) noexcept
{
return fut.get();
}
}

#else

namespace leaf_detail
{
// Not defined, no longer supported. Please use try_capture_all instead of make_shared_context/capture.
template <class R, class F, class... A>
decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...))
capture_impl(is_result_tag<R, false>, F && f, A... a);

// Not defined, no longer supported. Please use try_capture_all instead of make_shared_context/capture.
template <class R, class Future>
decltype(std::declval<Future>().get())
future_get_impl(is_result_tag<R, false>, Future & fut );
}

#endif

namespace leaf_detail
{
template <class R, class F, class... A>
inline
decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...))
capture_impl(is_result_tag<R, true>, F && f, A... a) noexcept
{
return try_capture_all(
[&]
{
return std::forward<F>(f)(std::forward<A>(a)...);
} );
}

template <class R, class Future>
inline
decltype(std::declval<Future>().get())
future_get_impl(is_result_tag<R, true>, Future & fut) noexcept
{
if( auto r = fut.get() )
return r;
else
{
r.unload();
return r;
}
}
}

template <class F, class... A>
inline
decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...))
capture(context_ptr &&, F && f, A... a)
{
using namespace leaf_detail;
return capture_impl(is_result_tag<decltype(std::declval<F>()(std::forward<A>(std::declval<A>())...))>(), std::forward<F>(f), std::forward<A>(a)...);
}

template <class Future>
inline
decltype(std::declval<Future>().get())
future_get( Future & fut )
{
using namespace leaf_detail;
return future_get_impl(is_result_tag<decltype(std::declval<Future>().get())>(), fut);
}

} }

#endif

#endif
10 changes: 10 additions & 0 deletions include/boost/leaf/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,16 @@

////////////////////////////////////////

#ifndef BOOST_LEAF_DEPRECATED
# if __cplusplus > 201402L
# define BOOST_LEAF_DEPRECATED(msg) [[deprecated(msg)]]
# else
# define BOOST_LEAF_DEPRECATED(msg)
# endif
#endif

////////////////////////////////////////

#ifndef BOOST_LEAF_NO_EXCEPTIONS
# include <exception>
# if (defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L) || (defined(_MSC_VER) && _MSC_VER >= 1900)
Expand Down
20 changes: 20 additions & 0 deletions include/boost/leaf/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,26 @@ BOOST_LEAF_CONSTEXPR inline context_type_from_handlers<H...> make_context( H &&
return { };
}

////////////////////////////////////////////

#if BOOST_LEAF_CFG_CAPTURE

template <class...>
BOOST_LEAF_DEPRECATED("Please use try_capture_all instead of make_shared_context/capture.")
inline context_ptr make_shared_context() noexcept
{
return std::make_shared<polymorphic_context>();
}

template <class... H>
BOOST_LEAF_DEPRECATED("Please use try_capture_all instead of make_shared_context/capture.")
inline context_ptr make_shared_context( H && ... ) noexcept
{
return std::make_shared<polymorphic_context>();
}

#endif

} }

#endif
2 changes: 2 additions & 0 deletions include/boost/leaf/detail/all.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/leaf/config.hpp>
#include <boost/leaf/capture.hpp>
#include <boost/leaf/common.hpp>
#include <boost/leaf/context.hpp>
#include <boost/leaf/error.hpp>
#include <boost/leaf/exception.hpp>
#include <boost/leaf/handle_errors.hpp>
Expand Down
12 changes: 12 additions & 0 deletions include/boost/leaf/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,18 @@ inline error_id current_error() noexcept
return leaf_detail::make_error_id(leaf_detail::current_id());
}

////////////////////////////////////////////

class polymorphic_context
{
};

#if BOOST_LEAF_CFG_CAPTURE
using context_ptr = std::shared_ptr<polymorphic_context>;
#endif

////////////////////////////////////////////

template <class Ctx>
class context_activator
{
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ if option_enable_unit_tests
'capture_exception_result_unload_test',
'capture_exception_state_test',
'capture_exception_unload_test',
'capture_result_async_test_',
'capture_result_async_test',
'capture_result_state_test',
'context_activator_test',
Expand Down
1 change: 1 addition & 0 deletions test/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ run capture_exception_result_async_test.cpp ;
run capture_exception_result_unload_test.cpp ;
run capture_exception_state_test.cpp ;
run capture_exception_unload_test.cpp ;
run capture_result_async_test_.cpp ;
run capture_result_async_test.cpp ;
run capture_result_state_test.cpp ;
run context_activator_test.cpp ;
Expand Down
162 changes: 162 additions & 0 deletions test/capture_result_async_test_.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
// Copyright 2018-2023 Emil Dotchevski and Reverge Studios, Inc.

// 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 <boost/leaf/config.hpp>

#if defined(BOOST_LEAF_NO_THREADS) || !BOOST_LEAF_CFG_CAPTURE

#include <iostream>

int main()
{
std::cout << "Unit test not applicable." << std::endl;
return 0;
}

#else

#ifdef BOOST_LEAF_TEST_SINGLE_HEADER
# include "leaf.hpp"
#else
# include <boost/leaf/capture.hpp>
# include <boost/leaf/result.hpp>
# include <boost/leaf/handle_errors.hpp>
# include <boost/leaf/on_error.hpp>
#endif

#include "lightweight_test.hpp"
#include <vector>
#include <future>
#include <iterator>
#include <algorithm>

namespace leaf = boost::leaf;

template <int> struct info { int value; };

struct fut_info
{
int a;
int b;
int result;
std::future<leaf::result<int>> fut;
};

template <class ErrorHandlers, class F>
std::vector<fut_info> launch_tasks( int task_count, F f )
{
BOOST_LEAF_ASSERT(task_count>0);
std::vector<fut_info> fut;
std::generate_n( std::back_inserter(fut), task_count,
[=]
{
int const a = rand();
int const b = rand();
int const res = (rand()%10) - 5;
return fut_info { a, b, res, std::async( std::launch::async,
[=]
{
return leaf::capture(leaf::make_shared_context<ErrorHandlers>(), f, a, b, res);
} ) };
} );
return fut;
}

int main()
{
int received_a, received_b;
auto error_handlers = std::make_tuple(
[&received_a, &received_b]( info<1> const & x1, info<2> const & x2, info<4> const & )
{
received_a = x1.value;
received_b = x2.value;
return -1;
},
[]
{
return -2;
} );

{
std::vector<fut_info> fut = launch_tasks<decltype(error_handlers)>(
100,
[]( int a, int b, int res ) -> leaf::result<int>
{
if( res >= 0 )
return res;
else
return leaf::new_error( info<1>{a}, info<2>{b}, info<3>{} );
} );

for( auto & f : fut )
{
f.fut.wait();
int r = leaf::try_handle_all(
[&]
{
auto load = leaf::on_error( info<4>{} );

// Calling future_get is required in order to make the on_error (above) work.
return leaf::future_get(f.fut);
},
error_handlers );
if( f.result>=0 )
BOOST_TEST_EQ(r, f.result);
else
{
BOOST_TEST_EQ(r, -1);
BOOST_TEST_EQ(f.a, received_a);
BOOST_TEST_EQ(f.b, received_b);
}
}
}

{
std::vector<fut_info> fut = launch_tasks<decltype(error_handlers)>(
100,
[]( int a, int b, int res ) -> leaf::result<int>
{
if( res >= 0 )
return res;
else
return leaf::new_error( info<1>{a}, info<2>{b}, info<3>{} );
} );

for( auto & f : fut )
{
f.fut.wait();
int r = leaf::try_handle_all(
[&]
{
auto load = leaf::on_error( info<4>{} );

return leaf::try_handle_some(
[&]
{
// Not calling future_get, a on_error in this scope won't work correctly.
// This is to verify that the on_error in the outer scope (above) works.
return f.fut.get();
},
[]( leaf::error_info const & err )
{
return err.error();
} );
},
error_handlers );
if( f.result>=0 )
BOOST_TEST_EQ(r, f.result);
else
{
BOOST_TEST_EQ(r, -1);
BOOST_TEST_EQ(f.a, received_a);
BOOST_TEST_EQ(f.b, received_b);
}
}
}

return boost::report_errors();
}

#endif

0 comments on commit fcd845f

Please sign in to comment.