8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 16:03:03 +01:00

Update boost to version 1.86.0.

This commit is contained in:
Adriano dos Santos Fernandes 2024-10-16 23:22:31 -03:00
parent dc5fb8f082
commit 46d8f5f4a9
1542 changed files with 278788 additions and 19610 deletions

31
extern/boost/boost/algorithm/string.hpp vendored Normal file
View File

@ -0,0 +1,31 @@
// Boost string_algo library string_algo.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2004.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_ALGO_HPP
#define BOOST_STRING_ALGO_HPP
/*! \file
Cumulative include for string_algo library
*/
#include <boost/algorithm/string/std_containers_traits.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/find.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/erase.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/find_iterator.hpp>
#endif // BOOST_STRING_ALGO_HPP

View File

@ -0,0 +1,176 @@
// Boost string_algo library case_conv.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_CASE_CONV_HPP
#define BOOST_STRING_CASE_CONV_HPP
#include <boost/algorithm/string/config.hpp>
#include <algorithm>
#include <locale>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/range/as_literal.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/value_type.hpp>
#include <boost/algorithm/string/detail/case_conv.hpp>
/*! \file
Defines sequence case-conversion algorithms.
Algorithms convert each element in the input sequence to the
desired case using provided locales.
*/
namespace boost {
namespace algorithm {
// to_lower -----------------------------------------------//
//! Convert to lower case
/*!
Each element of the input sequence is converted to lower
case. The result is a copy of the input converted to lower case.
It is returned as a sequence or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input range
\param Loc A locale used for conversion
\return
An output iterator pointing just after the last inserted character or
a copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<typename OutputIteratorT, typename RangeT>
inline OutputIteratorT
to_lower_copy(
OutputIteratorT Output,
const RangeT& Input,
const std::locale& Loc=std::locale())
{
return ::boost::algorithm::detail::transform_range_copy(
Output,
::boost::as_literal(Input),
::boost::algorithm::detail::to_lowerF<
typename range_value<RangeT>::type >(Loc));
}
//! Convert to lower case
/*!
\overload
*/
template<typename SequenceT>
inline SequenceT to_lower_copy(
const SequenceT& Input,
const std::locale& Loc=std::locale())
{
return ::boost::algorithm::detail::transform_range_copy<SequenceT>(
Input,
::boost::algorithm::detail::to_lowerF<
typename range_value<SequenceT>::type >(Loc));
}
//! Convert to lower case
/*!
Each element of the input sequence is converted to lower
case. The input sequence is modified in-place.
\param Input A range
\param Loc a locale used for conversion
*/
template<typename WritableRangeT>
inline void to_lower(
WritableRangeT& Input,
const std::locale& Loc=std::locale())
{
::boost::algorithm::detail::transform_range(
::boost::as_literal(Input),
::boost::algorithm::detail::to_lowerF<
typename range_value<WritableRangeT>::type >(Loc));
}
// to_upper -----------------------------------------------//
//! Convert to upper case
/*!
Each element of the input sequence is converted to upper
case. The result is a copy of the input converted to upper case.
It is returned as a sequence or copied to the output iterator
\param Output An output iterator to which the result will be copied
\param Input An input range
\param Loc A locale used for conversion
\return
An output iterator pointing just after the last inserted character or
a copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<typename OutputIteratorT, typename RangeT>
inline OutputIteratorT
to_upper_copy(
OutputIteratorT Output,
const RangeT& Input,
const std::locale& Loc=std::locale())
{
return ::boost::algorithm::detail::transform_range_copy(
Output,
::boost::as_literal(Input),
::boost::algorithm::detail::to_upperF<
typename range_value<RangeT>::type >(Loc));
}
//! Convert to upper case
/*!
\overload
*/
template<typename SequenceT>
inline SequenceT to_upper_copy(
const SequenceT& Input,
const std::locale& Loc=std::locale())
{
return ::boost::algorithm::detail::transform_range_copy<SequenceT>(
Input,
::boost::algorithm::detail::to_upperF<
typename range_value<SequenceT>::type >(Loc));
}
//! Convert to upper case
/*!
Each element of the input sequence is converted to upper
case. The input sequence is modified in-place.
\param Input An input range
\param Loc a locale used for conversion
*/
template<typename WritableRangeT>
inline void to_upper(
WritableRangeT& Input,
const std::locale& Loc=std::locale())
{
::boost::algorithm::detail::transform_range(
::boost::as_literal(Input),
::boost::algorithm::detail::to_upperF<
typename range_value<WritableRangeT>::type >(Loc));
}
} // namespace algorithm
// pull names to the boost namespace
using algorithm::to_lower;
using algorithm::to_lower_copy;
using algorithm::to_upper;
using algorithm::to_upper_copy;
} // namespace boost
#endif // BOOST_STRING_CASE_CONV_HPP

View File

@ -0,0 +1,130 @@
// Boost string_algo library string_funct.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_CASE_CONV_DETAIL_HPP
#define BOOST_STRING_CASE_CONV_DETAIL_HPP
#include <boost/algorithm/string/config.hpp>
#include <locale>
#include <functional>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/type_traits/make_unsigned.hpp>
namespace boost {
namespace algorithm {
namespace detail {
// case conversion functors -----------------------------------------------//
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(push)
#pragma warning(disable:4512) //assignment operator could not be generated
#endif
// a tolower functor
template<typename CharT>
struct to_lowerF
{
typedef CharT argument_type;
typedef CharT result_type;
// Constructor
to_lowerF( const std::locale& Loc ) : m_Loc( &Loc ) {}
// Operation
CharT operator ()( CharT Ch ) const
{
#if defined(BOOST_BORLANDC) && (BOOST_BORLANDC >= 0x560) && (BOOST_BORLANDC <= 0x564) && !defined(_USE_OLD_RW_STL)
return std::tolower( static_cast<typename boost::make_unsigned <CharT>::type> ( Ch ));
#else
return std::tolower<CharT>( Ch, *m_Loc );
#endif
}
private:
const std::locale* m_Loc;
};
// a toupper functor
template<typename CharT>
struct to_upperF
{
typedef CharT argument_type;
typedef CharT result_type;
// Constructor
to_upperF( const std::locale& Loc ) : m_Loc( &Loc ) {}
// Operation
CharT operator ()( CharT Ch ) const
{
#if defined(BOOST_BORLANDC) && (BOOST_BORLANDC >= 0x560) && (BOOST_BORLANDC <= 0x564) && !defined(_USE_OLD_RW_STL)
return std::toupper( static_cast<typename boost::make_unsigned <CharT>::type> ( Ch ));
#else
return std::toupper<CharT>( Ch, *m_Loc );
#endif
}
private:
const std::locale* m_Loc;
};
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(pop)
#endif
// algorithm implementation -------------------------------------------------------------------------
// Transform a range
template<typename OutputIteratorT, typename RangeT, typename FunctorT>
OutputIteratorT transform_range_copy(
OutputIteratorT Output,
const RangeT& Input,
FunctorT Functor)
{
return std::transform(
::boost::begin(Input),
::boost::end(Input),
Output,
Functor);
}
// Transform a range (in-place)
template<typename RangeT, typename FunctorT>
void transform_range(
const RangeT& Input,
FunctorT Functor)
{
std::transform(
::boost::begin(Input),
::boost::end(Input),
::boost::begin(Input),
Functor);
}
template<typename SequenceT, typename RangeT, typename FunctorT>
inline SequenceT transform_range_copy(
const RangeT& Input,
FunctorT Functor)
{
return SequenceT(
::boost::make_transform_iterator(
::boost::begin(Input),
Functor),
::boost::make_transform_iterator(
::boost::end(Input),
Functor));
}
} // namespace detail
} // namespace algorithm
} // namespace boost
#endif // BOOST_STRING_CASE_CONV_DETAIL_HPP

View File

@ -0,0 +1,204 @@
// Boost string_algo library find_format.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_FIND_FORMAT_DETAIL_HPP
#define BOOST_STRING_FIND_FORMAT_DETAIL_HPP
#include <boost/algorithm/string/config.hpp>
#include <boost/range/iterator_range_core.hpp>
#include <boost/range/const_iterator.hpp>
#include <boost/range/iterator.hpp>
#include <boost/algorithm/string/detail/find_format_store.hpp>
#include <boost/algorithm/string/detail/replace_storage.hpp>
namespace boost {
namespace algorithm {
namespace detail {
// find_format_copy (iterator variant) implementation -------------------------------//
template<
typename OutputIteratorT,
typename InputT,
typename FormatterT,
typename FindResultT,
typename FormatResultT >
inline OutputIteratorT find_format_copy_impl2(
OutputIteratorT Output,
const InputT& Input,
FormatterT Formatter,
const FindResultT& FindResult,
const FormatResultT& FormatResult )
{
typedef find_format_store<
BOOST_STRING_TYPENAME
range_const_iterator<InputT>::type,
FormatterT,
FormatResultT > store_type;
// Create store for the find result
store_type M( FindResult, FormatResult, Formatter );
if ( !M )
{
// Match not found - return original sequence
Output = std::copy( ::boost::begin(Input), ::boost::end(Input), Output );
return Output;
}
// Copy the beginning of the sequence
Output = std::copy( ::boost::begin(Input), ::boost::begin(M), Output );
// Format find result
// Copy formatted result
Output = std::copy( ::boost::begin(M.format_result()), ::boost::end(M.format_result()), Output );
// Copy the rest of the sequence
Output = std::copy( M.end(), ::boost::end(Input), Output );
return Output;
}
template<
typename OutputIteratorT,
typename InputT,
typename FormatterT,
typename FindResultT >
inline OutputIteratorT find_format_copy_impl(
OutputIteratorT Output,
const InputT& Input,
FormatterT Formatter,
const FindResultT& FindResult )
{
if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) {
return ::boost::algorithm::detail::find_format_copy_impl2(
Output,
Input,
Formatter,
FindResult,
Formatter(FindResult) );
} else {
return std::copy( ::boost::begin(Input), ::boost::end(Input), Output );
}
}
// find_format_copy implementation --------------------------------------------------//
template<
typename InputT,
typename FormatterT,
typename FindResultT,
typename FormatResultT >
inline InputT find_format_copy_impl2(
const InputT& Input,
FormatterT Formatter,
const FindResultT& FindResult,
const FormatResultT& FormatResult)
{
typedef find_format_store<
BOOST_STRING_TYPENAME
range_const_iterator<InputT>::type,
FormatterT,
FormatResultT > store_type;
// Create store for the find result
store_type M( FindResult, FormatResult, Formatter );
if ( !M )
{
// Match not found - return original sequence
return InputT( Input );
}
InputT Output;
// Copy the beginning of the sequence
boost::algorithm::detail::insert( Output, ::boost::end(Output), ::boost::begin(Input), M.begin() );
// Copy formatted result
boost::algorithm::detail::insert( Output, ::boost::end(Output), M.format_result() );
// Copy the rest of the sequence
boost::algorithm::detail::insert( Output, ::boost::end(Output), M.end(), ::boost::end(Input) );
return Output;
}
template<
typename InputT,
typename FormatterT,
typename FindResultT >
inline InputT find_format_copy_impl(
const InputT& Input,
FormatterT Formatter,
const FindResultT& FindResult)
{
if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) {
return ::boost::algorithm::detail::find_format_copy_impl2(
Input,
Formatter,
FindResult,
Formatter(FindResult) );
} else {
return Input;
}
}
// replace implementation ----------------------------------------------------//
template<
typename InputT,
typename FormatterT,
typename FindResultT,
typename FormatResultT >
inline void find_format_impl2(
InputT& Input,
FormatterT Formatter,
const FindResultT& FindResult,
const FormatResultT& FormatResult)
{
typedef find_format_store<
BOOST_STRING_TYPENAME
range_iterator<InputT>::type,
FormatterT,
FormatResultT > store_type;
// Create store for the find result
store_type M( FindResult, FormatResult, Formatter );
if ( !M )
{
// Search not found - return original sequence
return;
}
// Replace match
::boost::algorithm::detail::replace( Input, M.begin(), M.end(), M.format_result() );
}
template<
typename InputT,
typename FormatterT,
typename FindResultT >
inline void find_format_impl(
InputT& Input,
FormatterT Formatter,
const FindResultT& FindResult)
{
if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) {
::boost::algorithm::detail::find_format_impl2(
Input,
Formatter,
FindResult,
Formatter(FindResult) );
}
}
} // namespace detail
} // namespace algorithm
} // namespace boost
#endif // BOOST_STRING_FIND_FORMAT_DETAIL_HPP

View File

@ -0,0 +1,275 @@
// Boost string_algo library find_format_all.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_FIND_FORMAT_ALL_DETAIL_HPP
#define BOOST_STRING_FIND_FORMAT_ALL_DETAIL_HPP
#include <boost/algorithm/string/config.hpp>
#include <boost/range/iterator_range_core.hpp>
#include <boost/range/const_iterator.hpp>
#include <boost/range/value_type.hpp>
#include <boost/algorithm/string/detail/find_format_store.hpp>
#include <boost/algorithm/string/detail/replace_storage.hpp>
#include <deque>
namespace boost {
namespace algorithm {
namespace detail {
// find_format_all_copy (iterator variant) implementation ---------------------------//
template<
typename OutputIteratorT,
typename InputT,
typename FinderT,
typename FormatterT,
typename FindResultT,
typename FormatResultT >
inline OutputIteratorT find_format_all_copy_impl2(
OutputIteratorT Output,
const InputT& Input,
FinderT Finder,
FormatterT Formatter,
const FindResultT& FindResult,
const FormatResultT& FormatResult )
{
typedef BOOST_STRING_TYPENAME
range_const_iterator<InputT>::type input_iterator_type;
typedef find_format_store<
input_iterator_type,
FormatterT,
FormatResultT > store_type;
// Create store for the find result
store_type M( FindResult, FormatResult, Formatter );
// Initialize last match
input_iterator_type LastMatch=::boost::begin(Input);
// Iterate through all matches
while( M )
{
// Copy the beginning of the sequence
Output = std::copy( LastMatch, M.begin(), Output );
// Copy formatted result
Output = std::copy( ::boost::begin(M.format_result()), ::boost::end(M.format_result()), Output );
// Proceed to the next match
LastMatch=M.end();
M=Finder( LastMatch, ::boost::end(Input) );
}
// Copy the rest of the sequence
Output = std::copy( LastMatch, ::boost::end(Input), Output );
return Output;
}
template<
typename OutputIteratorT,
typename InputT,
typename FinderT,
typename FormatterT,
typename FindResultT >
inline OutputIteratorT find_format_all_copy_impl(
OutputIteratorT Output,
const InputT& Input,
FinderT Finder,
FormatterT Formatter,
const FindResultT& FindResult )
{
if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) {
return ::boost::algorithm::detail::find_format_all_copy_impl2(
Output,
Input,
Finder,
Formatter,
FindResult,
Formatter(FindResult) );
} else {
return std::copy( ::boost::begin(Input), ::boost::end(Input), Output );
}
}
// find_format_all_copy implementation ----------------------------------------------//
template<
typename InputT,
typename FinderT,
typename FormatterT,
typename FindResultT,
typename FormatResultT >
inline InputT find_format_all_copy_impl2(
const InputT& Input,
FinderT Finder,
FormatterT Formatter,
const FindResultT& FindResult,
const FormatResultT& FormatResult)
{
typedef BOOST_STRING_TYPENAME
range_const_iterator<InputT>::type input_iterator_type;
typedef find_format_store<
input_iterator_type,
FormatterT,
FormatResultT > store_type;
// Create store for the find result
store_type M( FindResult, FormatResult, Formatter );
// Initialize last match
input_iterator_type LastMatch=::boost::begin(Input);
// Output temporary
InputT Output;
// Iterate through all matches
while( M )
{
// Copy the beginning of the sequence
boost::algorithm::detail::insert( Output, ::boost::end(Output), LastMatch, M.begin() );
// Copy formatted result
boost::algorithm::detail::insert( Output, ::boost::end(Output), M.format_result() );
// Proceed to the next match
LastMatch=M.end();
M=Finder( LastMatch, ::boost::end(Input) );
}
// Copy the rest of the sequence
::boost::algorithm::detail::insert( Output, ::boost::end(Output), LastMatch, ::boost::end(Input) );
return Output;
}
template<
typename InputT,
typename FinderT,
typename FormatterT,
typename FindResultT >
inline InputT find_format_all_copy_impl(
const InputT& Input,
FinderT Finder,
FormatterT Formatter,
const FindResultT& FindResult)
{
if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) {
return ::boost::algorithm::detail::find_format_all_copy_impl2(
Input,
Finder,
Formatter,
FindResult,
Formatter(FindResult) );
} else {
return Input;
}
}
// find_format_all implementation ------------------------------------------------//
template<
typename InputT,
typename FinderT,
typename FormatterT,
typename FindResultT,
typename FormatResultT >
inline void find_format_all_impl2(
InputT& Input,
FinderT Finder,
FormatterT Formatter,
FindResultT FindResult,
FormatResultT FormatResult)
{
typedef BOOST_STRING_TYPENAME
range_iterator<InputT>::type input_iterator_type;
typedef find_format_store<
input_iterator_type,
FormatterT,
FormatResultT > store_type;
// Create store for the find result
store_type M( FindResult, FormatResult, Formatter );
// Instantiate replacement storage
std::deque<
BOOST_STRING_TYPENAME range_value<InputT>::type> Storage;
// Initialize replacement iterators
input_iterator_type InsertIt=::boost::begin(Input);
input_iterator_type SearchIt=::boost::begin(Input);
while( M )
{
// process the segment
InsertIt=process_segment(
Storage,
Input,
InsertIt,
SearchIt,
M.begin() );
// Adjust search iterator
SearchIt=M.end();
// Copy formatted replace to the storage
::boost::algorithm::detail::copy_to_storage( Storage, M.format_result() );
// Find range for a next match
M=Finder( SearchIt, ::boost::end(Input) );
}
// process the last segment
InsertIt=::boost::algorithm::detail::process_segment(
Storage,
Input,
InsertIt,
SearchIt,
::boost::end(Input) );
if ( Storage.empty() )
{
// Truncate input
::boost::algorithm::detail::erase( Input, InsertIt, ::boost::end(Input) );
}
else
{
// Copy remaining data to the end of input
::boost::algorithm::detail::insert( Input, ::boost::end(Input), Storage.begin(), Storage.end() );
}
}
template<
typename InputT,
typename FinderT,
typename FormatterT,
typename FindResultT >
inline void find_format_all_impl(
InputT& Input,
FinderT Finder,
FormatterT Formatter,
FindResultT FindResult)
{
if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) {
::boost::algorithm::detail::find_format_all_impl2(
Input,
Finder,
Formatter,
FindResult,
Formatter(FindResult) );
}
}
} // namespace detail
} // namespace algorithm
} // namespace boost
#endif // BOOST_STRING_FIND_FORMAT_ALL_DETAIL_HPP

View File

@ -0,0 +1,89 @@
// Boost string_algo library find_format_store.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_FIND_FORMAT_STORE_DETAIL_HPP
#define BOOST_STRING_FIND_FORMAT_STORE_DETAIL_HPP
#include <boost/algorithm/string/config.hpp>
#include <boost/range/iterator_range_core.hpp>
namespace boost {
namespace algorithm {
namespace detail {
// temporary format and find result storage --------------------------------//
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(push)
#pragma warning(disable:4512) //assignment operator could not be generated
#endif
template<
typename ForwardIteratorT,
typename FormatterT,
typename FormatResultT >
class find_format_store :
public iterator_range<ForwardIteratorT>
{
public:
// typedefs
typedef iterator_range<ForwardIteratorT> base_type;
typedef FormatterT formatter_type;
typedef FormatResultT format_result_type;
public:
// Construction
find_format_store(
const base_type& FindResult,
const format_result_type& FormatResult,
const formatter_type& Formatter ) :
base_type(FindResult),
m_FormatResult(FormatResult),
m_Formatter(Formatter) {}
// Assignment
template< typename FindResultT >
find_format_store& operator=( FindResultT FindResult )
{
iterator_range<ForwardIteratorT>::operator=(FindResult);
if( !this->empty() ) {
m_FormatResult=m_Formatter(FindResult);
}
return *this;
}
// Retrieve format result
const format_result_type& format_result()
{
return m_FormatResult;
}
private:
format_result_type m_FormatResult;
const formatter_type& m_Formatter;
};
template<typename InputT, typename FindResultT>
bool check_find_result(InputT&, FindResultT& FindResult)
{
typedef BOOST_STRING_TYPENAME
range_const_iterator<InputT>::type input_iterator_type;
iterator_range<input_iterator_type> ResultRange(FindResult);
return !ResultRange.empty();
}
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
#pragma warning(pop)
#endif
} // namespace detail
} // namespace algorithm
} // namespace boost
#endif // BOOST_STRING_FIND_FORMAT_STORE_DETAIL_HPP

View File

@ -40,10 +40,18 @@ namespace boost {
// Protected construction/destruction
// Default constructor
find_iterator_base() {}
BOOST_DEFAULTED_FUNCTION(find_iterator_base(), {})
// Copy construction
find_iterator_base( const find_iterator_base& Other ) :
BOOST_DEFAULTED_FUNCTION(find_iterator_base( const find_iterator_base& Other ), :
m_Finder(Other.m_Finder) {}
)
// Assignment
BOOST_DEFAULTED_FUNCTION(find_iterator_base& operator=( const find_iterator_base& Other ), {
m_Finder = Other.m_Finder;
return *this;
})
// Constructor
template<typename FinderT>
@ -51,7 +59,7 @@ namespace boost {
m_Finder(Finder) {}
// Destructor
~find_iterator_base() {}
BOOST_DEFAULTED_FUNCTION(~find_iterator_base(), {})
// Find operation
match_type do_find(

View File

@ -0,0 +1,119 @@
// Boost string_algo library formatter.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_STRING_FORMATTER_DETAIL_HPP
#define BOOST_STRING_FORMATTER_DETAIL_HPP
#include <boost/range/iterator_range_core.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/const_iterator.hpp>
#include <boost/algorithm/string/detail/util.hpp>
// generic replace functors -----------------------------------------------//
namespace boost {
namespace algorithm {
namespace detail {
// const format functor ----------------------------------------------------//
// constant format functor
template<typename RangeT>
struct const_formatF
{
private:
typedef BOOST_STRING_TYPENAME
range_const_iterator<RangeT>::type format_iterator;
typedef iterator_range<format_iterator> result_type;
public:
// Construction
const_formatF(const RangeT& Format) :
m_Format(::boost::begin(Format), ::boost::end(Format)) {}
// Operation
#if BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x564))
template<typename Range2T>
result_type& operator()(const Range2T&)
{
return m_Format;
}
#endif
template<typename Range2T>
const result_type& operator()(const Range2T&) const
{
return m_Format;
}
private:
result_type m_Format;
};
// identity format functor ----------------------------------------------------//
// identity format functor
template<typename RangeT>
struct identity_formatF
{
// Operation
template< typename Range2T >
const RangeT& operator()(const Range2T& Replace) const
{
return RangeT(::boost::begin(Replace), ::boost::end(Replace));
}
};
// empty format functor ( used by erase ) ------------------------------------//
// empty format functor
template< typename CharT >
struct empty_formatF
{
template< typename ReplaceT >
empty_container<CharT> operator()(const ReplaceT&) const
{
return empty_container<CharT>();
}
};
// dissect format functor ----------------------------------------------------//
// dissect format functor
template<typename FinderT>
struct dissect_formatF
{
public:
// Construction
dissect_formatF(FinderT Finder) :
m_Finder(Finder) {}
// Operation
template<typename RangeT>
inline iterator_range<
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type>
operator()(const RangeT& Replace) const
{
return m_Finder(::boost::begin(Replace), ::boost::end(Replace));
}
private:
FinderT m_Finder;
};
} // namespace detail
} // namespace algorithm
} // namespace boost
#endif // BOOST_STRING_FORMATTER_DETAIL_HPP

View File

@ -0,0 +1,77 @@
// Boost string_algo library predicate.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_PREDICATE_DETAIL_HPP
#define BOOST_STRING_PREDICATE_DETAIL_HPP
#include <iterator>
#include <boost/algorithm/string/find.hpp>
namespace boost {
namespace algorithm {
namespace detail {
// ends_with predicate implementation ----------------------------------//
template<
typename ForwardIterator1T,
typename ForwardIterator2T,
typename PredicateT>
inline bool ends_with_iter_select(
ForwardIterator1T Begin,
ForwardIterator1T End,
ForwardIterator2T SubBegin,
ForwardIterator2T SubEnd,
PredicateT Comp,
std::bidirectional_iterator_tag)
{
ForwardIterator1T it=End;
ForwardIterator2T pit=SubEnd;
for(;it!=Begin && pit!=SubBegin;)
{
if( !(Comp(*(--it),*(--pit))) )
return false;
}
return pit==SubBegin;
}
template<
typename ForwardIterator1T,
typename ForwardIterator2T,
typename PredicateT>
inline bool ends_with_iter_select(
ForwardIterator1T Begin,
ForwardIterator1T End,
ForwardIterator2T SubBegin,
ForwardIterator2T SubEnd,
PredicateT Comp,
std::forward_iterator_tag)
{
if ( SubBegin==SubEnd )
{
// empty subsequence check
return true;
}
iterator_range<ForwardIterator1T> Result
=last_finder(
::boost::make_iterator_range(SubBegin, SubEnd),
Comp)(Begin, End);
return !Result.empty() && Result.end()==End;
}
} // namespace detail
} // namespace algorithm
} // namespace boost
#endif // BOOST_STRING_PREDICATE_DETAIL_HPP

View File

@ -0,0 +1,159 @@
// Boost string_algo library replace_storage.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_REPLACE_STORAGE_DETAIL_HPP
#define BOOST_STRING_REPLACE_STORAGE_DETAIL_HPP
#include <boost/algorithm/string/config.hpp>
#include <algorithm>
#include <boost/mpl/bool.hpp>
#include <boost/algorithm/string/sequence_traits.hpp>
#include <boost/algorithm/string/detail/sequence.hpp>
namespace boost {
namespace algorithm {
namespace detail {
// storage handling routines -----------------------------------------------//
template< typename StorageT, typename OutputIteratorT >
inline OutputIteratorT move_from_storage(
StorageT& Storage,
OutputIteratorT DestBegin,
OutputIteratorT DestEnd )
{
OutputIteratorT OutputIt=DestBegin;
while( !Storage.empty() && OutputIt!=DestEnd )
{
*OutputIt=Storage.front();
Storage.pop_front();
++OutputIt;
}
return OutputIt;
}
template< typename StorageT, typename WhatT >
inline void copy_to_storage(
StorageT& Storage,
const WhatT& What )
{
Storage.insert( Storage.end(), ::boost::begin(What), ::boost::end(What) );
}
// process segment routine -----------------------------------------------//
template< bool HasStableIterators >
struct process_segment_helper
{
// Optimized version of process_segment for generic sequence
template<
typename StorageT,
typename InputT,
typename ForwardIteratorT >
ForwardIteratorT operator()(
StorageT& Storage,
InputT& /*Input*/,
ForwardIteratorT InsertIt,
ForwardIteratorT SegmentBegin,
ForwardIteratorT SegmentEnd )
{
// Copy data from the storage until the beginning of the segment
ForwardIteratorT It=::boost::algorithm::detail::move_from_storage( Storage, InsertIt, SegmentBegin );
// 3 cases are possible :
// a) Storage is empty, It==SegmentBegin
// b) Storage is empty, It!=SegmentBegin
// c) Storage is not empty
if( Storage.empty() )
{
if( It==SegmentBegin )
{
// Case a) everything is grand, just return end of segment
return SegmentEnd;
}
else
{
// Case b) move the segment backwards
return std::copy( SegmentBegin, SegmentEnd, It );
}
}
else
{
// Case c) -> shift the segment to the left and keep the overlap in the storage
while( It!=SegmentEnd )
{
// Store value into storage
Storage.push_back( *It );
// Get the top from the storage and put it here
*It=Storage.front();
Storage.pop_front();
// Advance
++It;
}
return It;
}
}
};
template<>
struct process_segment_helper< true >
{
// Optimized version of process_segment for list-like sequence
template<
typename StorageT,
typename InputT,
typename ForwardIteratorT >
ForwardIteratorT operator()(
StorageT& Storage,
InputT& Input,
ForwardIteratorT InsertIt,
ForwardIteratorT SegmentBegin,
ForwardIteratorT SegmentEnd )
{
// Call replace to do the job
::boost::algorithm::detail::replace( Input, InsertIt, SegmentBegin, Storage );
// Empty the storage
Storage.clear();
// Iterators were not changed, simply return the end of segment
return SegmentEnd;
}
};
// Process one segment in the replace_all algorithm
template<
typename StorageT,
typename InputT,
typename ForwardIteratorT >
inline ForwardIteratorT process_segment(
StorageT& Storage,
InputT& Input,
ForwardIteratorT InsertIt,
ForwardIteratorT SegmentBegin,
ForwardIteratorT SegmentEnd )
{
return
process_segment_helper<
has_stable_iterators<InputT>::value>()(
Storage, Input, InsertIt, SegmentBegin, SegmentEnd );
}
} // namespace detail
} // namespace algorithm
} // namespace boost
#endif // BOOST_STRING_REPLACE_STORAGE_DETAIL_HPP

View File

@ -0,0 +1,200 @@
// Boost string_algo library sequence.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_DETAIL_SEQUENCE_HPP
#define BOOST_STRING_DETAIL_SEQUENCE_HPP
#include <boost/algorithm/string/config.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/logical.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/algorithm/string/sequence_traits.hpp>
namespace boost {
namespace algorithm {
namespace detail {
// insert helpers -------------------------------------------------//
template< typename InputT, typename ForwardIteratorT >
inline void insert(
InputT& Input,
BOOST_STRING_TYPENAME InputT::iterator At,
ForwardIteratorT Begin,
ForwardIteratorT End )
{
Input.insert( At, Begin, End );
}
template< typename InputT, typename InsertT >
inline void insert(
InputT& Input,
BOOST_STRING_TYPENAME InputT::iterator At,
const InsertT& Insert )
{
::boost::algorithm::detail::insert( Input, At, ::boost::begin(Insert), ::boost::end(Insert) );
}
// erase helper ---------------------------------------------------//
// Erase a range in the sequence
/*
Returns the iterator pointing just after the erase subrange
*/
template< typename InputT >
inline typename InputT::iterator erase(
InputT& Input,
BOOST_STRING_TYPENAME InputT::iterator From,
BOOST_STRING_TYPENAME InputT::iterator To )
{
return Input.erase( From, To );
}
// replace helper implementation ----------------------------------//
// Optimized version of replace for generic sequence containers
// Assumption: insert and erase are expensive
template< bool HasConstTimeOperations >
struct replace_const_time_helper
{
template< typename InputT, typename ForwardIteratorT >
void operator()(
InputT& Input,
BOOST_STRING_TYPENAME InputT::iterator From,
BOOST_STRING_TYPENAME InputT::iterator To,
ForwardIteratorT Begin,
ForwardIteratorT End )
{
// Copy data to the container ( as much as possible )
ForwardIteratorT InsertIt=Begin;
BOOST_STRING_TYPENAME InputT::iterator InputIt=From;
for(; InsertIt!=End && InputIt!=To; InsertIt++, InputIt++ )
{
*InputIt=*InsertIt;
}
if ( InsertIt!=End )
{
// Replace sequence is longer, insert it
Input.insert( InputIt, InsertIt, End );
}
else
{
if ( InputIt!=To )
{
// Replace sequence is shorter, erase the rest
Input.erase( InputIt, To );
}
}
}
};
template<>
struct replace_const_time_helper< true >
{
// Const-time erase and insert methods -> use them
template< typename InputT, typename ForwardIteratorT >
void operator()(
InputT& Input,
BOOST_STRING_TYPENAME InputT::iterator From,
BOOST_STRING_TYPENAME InputT::iterator To,
ForwardIteratorT Begin,
ForwardIteratorT End )
{
BOOST_STRING_TYPENAME InputT::iterator At=Input.erase( From, To );
if ( Begin!=End )
{
if(!Input.empty())
{
Input.insert( At, Begin, End );
}
else
{
Input.insert( Input.begin(), Begin, End );
}
}
}
};
// No native replace method
template< bool HasNative >
struct replace_native_helper
{
template< typename InputT, typename ForwardIteratorT >
void operator()(
InputT& Input,
BOOST_STRING_TYPENAME InputT::iterator From,
BOOST_STRING_TYPENAME InputT::iterator To,
ForwardIteratorT Begin,
ForwardIteratorT End )
{
replace_const_time_helper<
boost::mpl::and_<
has_const_time_insert<InputT>,
has_const_time_erase<InputT> >::value >()(
Input, From, To, Begin, End );
}
};
// Container has native replace method
template<>
struct replace_native_helper< true >
{
template< typename InputT, typename ForwardIteratorT >
void operator()(
InputT& Input,
BOOST_STRING_TYPENAME InputT::iterator From,
BOOST_STRING_TYPENAME InputT::iterator To,
ForwardIteratorT Begin,
ForwardIteratorT End )
{
Input.replace( From, To, Begin, End );
}
};
// replace helper -------------------------------------------------//
template< typename InputT, typename ForwardIteratorT >
inline void replace(
InputT& Input,
BOOST_STRING_TYPENAME InputT::iterator From,
BOOST_STRING_TYPENAME InputT::iterator To,
ForwardIteratorT Begin,
ForwardIteratorT End )
{
replace_native_helper< has_native_replace<InputT>::value >()(
Input, From, To, Begin, End );
}
template< typename InputT, typename InsertT >
inline void replace(
InputT& Input,
BOOST_STRING_TYPENAME InputT::iterator From,
BOOST_STRING_TYPENAME InputT::iterator To,
const InsertT& Insert )
{
if(From!=To)
{
::boost::algorithm::detail::replace( Input, From, To, ::boost::begin(Insert), ::boost::end(Insert) );
}
else
{
::boost::algorithm::detail::insert( Input, From, ::boost::begin(Insert), ::boost::end(Insert) );
}
}
} // namespace detail
} // namespace algorithm
} // namespace boost
#endif // BOOST_STRING_DETAIL_SEQUENCE_HPP

View File

@ -0,0 +1,844 @@
// Boost string_algo library erase.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2006.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_ERASE_HPP
#define BOOST_STRING_ERASE_HPP
#include <boost/algorithm/string/config.hpp>
#include <boost/range/iterator_range_core.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator.hpp>
#include <boost/range/const_iterator.hpp>
#include <boost/algorithm/string/find_format.hpp>
#include <boost/algorithm/string/finder.hpp>
#include <boost/algorithm/string/formatter.hpp>
/*! \file
Defines various erase algorithms. Each algorithm removes
part(s) of the input according to a searching criteria.
*/
namespace boost {
namespace algorithm {
// erase_range -------------------------------------------------------//
//! Erase range algorithm
/*!
Remove the given range from the input. The result is a modified copy of
the input. It is returned as a sequence or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input sequence
\param SearchRange A range in the input to be removed
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<typename OutputIteratorT, typename RangeT>
inline OutputIteratorT erase_range_copy(
OutputIteratorT Output,
const RangeT& Input,
const iterator_range<
BOOST_STRING_TYPENAME
range_const_iterator<RangeT>::type>& SearchRange )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::range_finder(SearchRange),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase range algorithm
/*!
\overload
*/
template<typename SequenceT>
inline SequenceT erase_range_copy(
const SequenceT& Input,
const iterator_range<
BOOST_STRING_TYPENAME
range_const_iterator<SequenceT>::type>& SearchRange )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::range_finder(SearchRange),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase range algorithm
/*!
Remove the given range from the input.
The input sequence is modified in-place.
\param Input An input sequence
\param SearchRange A range in the input to be removed
*/
template<typename SequenceT>
inline void erase_range(
SequenceT& Input,
const iterator_range<
BOOST_STRING_TYPENAME
range_iterator<SequenceT>::type>& SearchRange )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::range_finder(SearchRange),
::boost::algorithm::empty_formatter(Input) );
}
// erase_first --------------------------------------------------------//
//! Erase first algorithm
/*!
Remove the first occurrence of the substring from the input.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T>
inline OutputIteratorT erase_first_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::first_finder(Search),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase first algorithm
/*!
\overload
*/
template<typename SequenceT, typename RangeT>
inline SequenceT erase_first_copy(
const SequenceT& Input,
const RangeT& Search )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::first_finder(Search),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase first algorithm
/*!
Remove the first occurrence of the substring from the input.
The input sequence is modified in-place.
\param Input An input string
\param Search A substring to be searched for.
*/
template<typename SequenceT, typename RangeT>
inline void erase_first(
SequenceT& Input,
const RangeT& Search )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::first_finder(Search),
::boost::algorithm::empty_formatter(Input) );
}
// erase_first ( case insensitive ) ------------------------------------//
//! Erase first algorithm ( case insensitive )
/*!
Remove the first occurrence of the substring from the input.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
Searching is case insensitive.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for
\param Loc A locale used for case insensitive comparison
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T>
inline OutputIteratorT ierase_first_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase first algorithm ( case insensitive )
/*!
\overload
*/
template<typename SequenceT, typename RangeT>
inline SequenceT ierase_first_copy(
const SequenceT& Input,
const RangeT& Search,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase first algorithm ( case insensitive )
/*!
Remove the first occurrence of the substring from the input.
The input sequence is modified in-place. Searching is case insensitive.
\param Input An input string
\param Search A substring to be searched for
\param Loc A locale used for case insensitive comparison
*/
template<typename SequenceT, typename RangeT>
inline void ierase_first(
SequenceT& Input,
const RangeT& Search,
const std::locale& Loc=std::locale() )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
::boost::algorithm::empty_formatter(Input) );
}
// erase_last --------------------------------------------------------//
//! Erase last algorithm
/*!
Remove the last occurrence of the substring from the input.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for.
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T>
inline OutputIteratorT erase_last_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::last_finder(Search),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase last algorithm
/*!
\overload
*/
template<typename SequenceT, typename RangeT>
inline SequenceT erase_last_copy(
const SequenceT& Input,
const RangeT& Search )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::last_finder(Search),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase last algorithm
/*!
Remove the last occurrence of the substring from the input.
The input sequence is modified in-place.
\param Input An input string
\param Search A substring to be searched for
*/
template<typename SequenceT, typename RangeT>
inline void erase_last(
SequenceT& Input,
const RangeT& Search )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::last_finder(Search),
::boost::algorithm::empty_formatter(Input) );
}
// erase_last ( case insensitive ) ------------------------------------//
//! Erase last algorithm ( case insensitive )
/*!
Remove the last occurrence of the substring from the input.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
Searching is case insensitive.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for
\param Loc A locale used for case insensitive comparison
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T>
inline OutputIteratorT ierase_last_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::last_finder(Search, is_iequal(Loc)),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase last algorithm ( case insensitive )
/*!
\overload
*/
template<typename SequenceT, typename RangeT>
inline SequenceT ierase_last_copy(
const SequenceT& Input,
const RangeT& Search,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::last_finder(Search, is_iequal(Loc)),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase last algorithm ( case insensitive )
/*!
Remove the last occurrence of the substring from the input.
The input sequence is modified in-place. Searching is case insensitive.
\param Input An input string
\param Search A substring to be searched for
\param Loc A locale used for case insensitive comparison
*/
template<typename SequenceT, typename RangeT>
inline void ierase_last(
SequenceT& Input,
const RangeT& Search,
const std::locale& Loc=std::locale() )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::last_finder(Search, is_iequal(Loc)),
::boost::algorithm::empty_formatter(Input) );
}
// erase_nth --------------------------------------------------------------------//
//! Erase nth algorithm
/*!
Remove the Nth occurrence of the substring in the input.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for
\param Nth An index of the match to be replaced. The index is 0-based.
For negative N, matches are counted from the end of string.
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T>
inline OutputIteratorT erase_nth_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search,
int Nth )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::nth_finder(Search, Nth),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase nth algorithm
/*!
\overload
*/
template<typename SequenceT, typename RangeT>
inline SequenceT erase_nth_copy(
const SequenceT& Input,
const RangeT& Search,
int Nth )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::nth_finder(Search, Nth),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase nth algorithm
/*!
Remove the Nth occurrence of the substring in the input.
The input sequence is modified in-place.
\param Input An input string
\param Search A substring to be searched for.
\param Nth An index of the match to be replaced. The index is 0-based.
For negative N, matches are counted from the end of string.
*/
template<typename SequenceT, typename RangeT>
inline void erase_nth(
SequenceT& Input,
const RangeT& Search,
int Nth )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::nth_finder(Search, Nth),
::boost::algorithm::empty_formatter(Input) );
}
// erase_nth ( case insensitive ) ---------------------------------------------//
//! Erase nth algorithm ( case insensitive )
/*!
Remove the Nth occurrence of the substring in the input.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
Searching is case insensitive.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for.
\param Nth An index of the match to be replaced. The index is 0-based.
For negative N, matches are counted from the end of string.
\param Loc A locale used for case insensitive comparison
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T>
inline OutputIteratorT ierase_nth_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search,
int Nth,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase nth algorithm
/*!
\overload
*/
template<typename SequenceT, typename RangeT>
inline SequenceT ierase_nth_copy(
const SequenceT& Input,
const RangeT& Search,
int Nth,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)),
empty_formatter(Input) );
}
//! Erase nth algorithm
/*!
Remove the Nth occurrence of the substring in the input.
The input sequence is modified in-place. Searching is case insensitive.
\param Input An input string
\param Search A substring to be searched for.
\param Nth An index of the match to be replaced. The index is 0-based.
For negative N, matches are counted from the end of string.
\param Loc A locale used for case insensitive comparison
*/
template<typename SequenceT, typename RangeT>
inline void ierase_nth(
SequenceT& Input,
const RangeT& Search,
int Nth,
const std::locale& Loc=std::locale() )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)),
::boost::algorithm::empty_formatter(Input) );
}
// erase_all --------------------------------------------------------//
//! Erase all algorithm
/*!
Remove all the occurrences of the string from the input.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input sequence
\param Search A substring to be searched for.
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T>
inline OutputIteratorT erase_all_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search )
{
return ::boost::algorithm::find_format_all_copy(
Output,
Input,
::boost::algorithm::first_finder(Search),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase all algorithm
/*!
\overload
*/
template<typename SequenceT, typename RangeT>
inline SequenceT erase_all_copy(
const SequenceT& Input,
const RangeT& Search )
{
return ::boost::algorithm::find_format_all_copy(
Input,
::boost::algorithm::first_finder(Search),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase all algorithm
/*!
Remove all the occurrences of the string from the input.
The input sequence is modified in-place.
\param Input An input string
\param Search A substring to be searched for.
*/
template<typename SequenceT, typename RangeT>
inline void erase_all(
SequenceT& Input,
const RangeT& Search )
{
::boost::algorithm::find_format_all(
Input,
::boost::algorithm::first_finder(Search),
::boost::algorithm::empty_formatter(Input) );
}
// erase_all ( case insensitive ) ------------------------------------//
//! Erase all algorithm ( case insensitive )
/*!
Remove all the occurrences of the string from the input.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
Searching is case insensitive.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for
\param Loc A locale used for case insensitive comparison
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T>
inline OutputIteratorT ierase_all_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_all_copy(
Output,
Input,
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase all algorithm ( case insensitive )
/*!
\overload
*/
template<typename SequenceT, typename RangeT>
inline SequenceT ierase_all_copy(
const SequenceT& Input,
const RangeT& Search,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_all_copy(
Input,
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
::boost::algorithm::empty_formatter(Input) );
}
//! Erase all algorithm ( case insensitive )
/*!
Remove all the occurrences of the string from the input.
The input sequence is modified in-place. Searching is case insensitive.
\param Input An input string
\param Search A substring to be searched for.
\param Loc A locale used for case insensitive comparison
*/
template<typename SequenceT, typename RangeT>
inline void ierase_all(
SequenceT& Input,
const RangeT& Search,
const std::locale& Loc=std::locale() )
{
::boost::algorithm::find_format_all(
Input,
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
::boost::algorithm::empty_formatter(Input) );
}
// erase_head --------------------------------------------------------------------//
//! Erase head algorithm
/*!
Remove the head from the input. The head is a prefix of a sequence of given size.
If the sequence is shorter then required, the whole string is
considered to be the head. The result is a modified copy of the input.
It is returned as a sequence or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param N Length of the head.
For N>=0, at most N characters are extracted.
For N<0, size(Input)-|N| characters are extracted.
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename RangeT>
inline OutputIteratorT erase_head_copy(
OutputIteratorT Output,
const RangeT& Input,
int N )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::head_finder(N),
::boost::algorithm::empty_formatter( Input ) );
}
//! Erase head algorithm
/*!
\overload
*/
template<typename SequenceT>
inline SequenceT erase_head_copy(
const SequenceT& Input,
int N )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::head_finder(N),
::boost::algorithm::empty_formatter( Input ) );
}
//! Erase head algorithm
/*!
Remove the head from the input. The head is a prefix of a sequence of given size.
If the sequence is shorter then required, the whole string is
considered to be the head. The input sequence is modified in-place.
\param Input An input string
\param N Length of the head
For N>=0, at most N characters are extracted.
For N<0, size(Input)-|N| characters are extracted.
*/
template<typename SequenceT>
inline void erase_head(
SequenceT& Input,
int N )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::head_finder(N),
::boost::algorithm::empty_formatter( Input ) );
}
// erase_tail --------------------------------------------------------------------//
//! Erase tail algorithm
/*!
Remove the tail from the input. The tail is a suffix of a sequence of given size.
If the sequence is shorter then required, the whole string is
considered to be the tail.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param N Length of the tail.
For N>=0, at most N characters are extracted.
For N<0, size(Input)-|N| characters are extracted.
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename RangeT>
inline OutputIteratorT erase_tail_copy(
OutputIteratorT Output,
const RangeT& Input,
int N )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::tail_finder(N),
::boost::algorithm::empty_formatter( Input ) );
}
//! Erase tail algorithm
/*!
\overload
*/
template<typename SequenceT>
inline SequenceT erase_tail_copy(
const SequenceT& Input,
int N )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::tail_finder(N),
::boost::algorithm::empty_formatter( Input ) );
}
//! Erase tail algorithm
/*!
Remove the tail from the input. The tail is a suffix of a sequence of given size.
If the sequence is shorter then required, the whole string is
considered to be the tail. The input sequence is modified in-place.
\param Input An input string
\param N Length of the tail
For N>=0, at most N characters are extracted.
For N<0, size(Input)-|N| characters are extracted.
*/
template<typename SequenceT>
inline void erase_tail(
SequenceT& Input,
int N )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::tail_finder(N),
::boost::algorithm::empty_formatter( Input ) );
}
} // namespace algorithm
// pull names into the boost namespace
using algorithm::erase_range_copy;
using algorithm::erase_range;
using algorithm::erase_first_copy;
using algorithm::erase_first;
using algorithm::ierase_first_copy;
using algorithm::ierase_first;
using algorithm::erase_last_copy;
using algorithm::erase_last;
using algorithm::ierase_last_copy;
using algorithm::ierase_last;
using algorithm::erase_nth_copy;
using algorithm::erase_nth;
using algorithm::ierase_nth_copy;
using algorithm::ierase_nth;
using algorithm::erase_all_copy;
using algorithm::erase_all;
using algorithm::ierase_all_copy;
using algorithm::ierase_all;
using algorithm::erase_head_copy;
using algorithm::erase_head;
using algorithm::erase_tail_copy;
using algorithm::erase_tail;
} // namespace boost
#endif // BOOST_ERASE_HPP

View File

@ -0,0 +1,334 @@
// Boost string_algo library find.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_FIND_HPP
#define BOOST_STRING_FIND_HPP
#include <boost/algorithm/string/config.hpp>
#include <boost/range/iterator_range_core.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator.hpp>
#include <boost/range/as_literal.hpp>
#include <boost/algorithm/string/finder.hpp>
#include <boost/algorithm/string/compare.hpp>
#include <boost/algorithm/string/constants.hpp>
/*! \file
Defines a set of find algorithms. The algorithms are searching
for a substring of the input. The result is given as an \c iterator_range
delimiting the substring.
*/
namespace boost {
namespace algorithm {
// Generic find -----------------------------------------------//
//! Generic find algorithm
/*!
Search the input using the given finder.
\param Input A string which will be searched.
\param Finder Finder object used for searching.
\return
An \c iterator_range delimiting the match.
Returned iterator is either \c RangeT::iterator or
\c RangeT::const_iterator, depending on the constness of
the input parameter.
*/
template<typename RangeT, typename FinderT>
inline iterator_range<
BOOST_STRING_TYPENAME range_iterator<RangeT>::type>
find(
RangeT& Input,
const FinderT& Finder)
{
iterator_range<BOOST_STRING_TYPENAME range_iterator<RangeT>::type> lit_input(::boost::as_literal(Input));
return Finder(::boost::begin(lit_input),::boost::end(lit_input));
}
// find_first -----------------------------------------------//
//! Find first algorithm
/*!
Search for the first occurrence of the substring in the input.
\param Input A string which will be searched.
\param Search A substring to be searched for.
\return
An \c iterator_range delimiting the match.
Returned iterator is either \c RangeT::iterator or
\c RangeT::const_iterator, depending on the constness of
the input parameter.
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T>
inline iterator_range<
BOOST_STRING_TYPENAME range_iterator<Range1T>::type>
find_first(
Range1T& Input,
const Range2T& Search)
{
return ::boost::algorithm::find(Input, ::boost::algorithm::first_finder(Search));
}
//! Find first algorithm ( case insensitive )
/*!
Search for the first occurrence of the substring in the input.
Searching is case insensitive.
\param Input A string which will be searched.
\param Search A substring to be searched for.
\param Loc A locale used for case insensitive comparison
\return
An \c iterator_range delimiting the match.
Returned iterator is either \c Range1T::iterator or
\c Range1T::const_iterator, depending on the constness of
the input parameter.
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T>
inline iterator_range<
BOOST_STRING_TYPENAME range_iterator<Range1T>::type>
ifind_first(
Range1T& Input,
const Range2T& Search,
const std::locale& Loc=std::locale())
{
return ::boost::algorithm::find(Input, ::boost::algorithm::first_finder(Search,is_iequal(Loc)));
}
// find_last -----------------------------------------------//
//! Find last algorithm
/*!
Search for the last occurrence of the substring in the input.
\param Input A string which will be searched.
\param Search A substring to be searched for.
\return
An \c iterator_range delimiting the match.
Returned iterator is either \c Range1T::iterator or
\c Range1T::const_iterator, depending on the constness of
the input parameter.
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T>
inline iterator_range<
BOOST_STRING_TYPENAME range_iterator<Range1T>::type>
find_last(
Range1T& Input,
const Range2T& Search)
{
return ::boost::algorithm::find(Input, ::boost::algorithm::last_finder(Search));
}
//! Find last algorithm ( case insensitive )
/*!
Search for the last match a string in the input.
Searching is case insensitive.
\param Input A string which will be searched.
\param Search A substring to be searched for.
\param Loc A locale used for case insensitive comparison
\return
An \c iterator_range delimiting the match.
Returned iterator is either \c Range1T::iterator or
\c Range1T::const_iterator, depending on the constness of
the input parameter.
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T>
inline iterator_range<
BOOST_STRING_TYPENAME range_iterator<Range1T>::type>
ifind_last(
Range1T& Input,
const Range2T& Search,
const std::locale& Loc=std::locale())
{
return ::boost::algorithm::find(Input, ::boost::algorithm::last_finder(Search, is_iequal(Loc)));
}
// find_nth ----------------------------------------------------------------------//
//! Find n-th algorithm
/*!
Search for the n-th (zero-indexed) occurrence of the substring in the
input.
\param Input A string which will be searched.
\param Search A substring to be searched for.
\param Nth An index (zero-indexed) of the match to be found.
For negative N, the matches are counted from the end of string.
\return
An \c iterator_range delimiting the match.
Returned iterator is either \c Range1T::iterator or
\c Range1T::const_iterator, depending on the constness of
the input parameter.
*/
template<typename Range1T, typename Range2T>
inline iterator_range<
BOOST_STRING_TYPENAME range_iterator<Range1T>::type>
find_nth(
Range1T& Input,
const Range2T& Search,
int Nth)
{
return ::boost::algorithm::find(Input, ::boost::algorithm::nth_finder(Search,Nth));
}
//! Find n-th algorithm ( case insensitive ).
/*!
Search for the n-th (zero-indexed) occurrence of the substring in the
input. Searching is case insensitive.
\param Input A string which will be searched.
\param Search A substring to be searched for.
\param Nth An index (zero-indexed) of the match to be found.
For negative N, the matches are counted from the end of string.
\param Loc A locale used for case insensitive comparison
\return
An \c iterator_range delimiting the match.
Returned iterator is either \c Range1T::iterator or
\c Range1T::const_iterator, depending on the constness of
the input parameter.
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T>
inline iterator_range<
BOOST_STRING_TYPENAME range_iterator<Range1T>::type>
ifind_nth(
Range1T& Input,
const Range2T& Search,
int Nth,
const std::locale& Loc=std::locale())
{
return ::boost::algorithm::find(Input, ::boost::algorithm::nth_finder(Search,Nth,is_iequal(Loc)));
}
// find_head ----------------------------------------------------------------------//
//! Find head algorithm
/*!
Get the head of the input. Head is a prefix of the string of the
given size. If the input is shorter then required, whole input is considered
to be the head.
\param Input An input string
\param N Length of the head
For N>=0, at most N characters are extracted.
For N<0, at most size(Input)-|N| characters are extracted.
\return
An \c iterator_range delimiting the match.
Returned iterator is either \c Range1T::iterator or
\c Range1T::const_iterator, depending on the constness of
the input parameter.
\note This function provides the strong exception-safety guarantee
*/
template<typename RangeT>
inline iterator_range<
BOOST_STRING_TYPENAME range_iterator<RangeT>::type>
find_head(
RangeT& Input,
int N)
{
return ::boost::algorithm::find(Input, ::boost::algorithm::head_finder(N));
}
// find_tail ----------------------------------------------------------------------//
//! Find tail algorithm
/*!
Get the tail of the input. Tail is a suffix of the string of the
given size. If the input is shorter then required, whole input is considered
to be the tail.
\param Input An input string
\param N Length of the tail.
For N>=0, at most N characters are extracted.
For N<0, at most size(Input)-|N| characters are extracted.
\return
An \c iterator_range delimiting the match.
Returned iterator is either \c RangeT::iterator or
\c RangeT::const_iterator, depending on the constness of
the input parameter.
\note This function provides the strong exception-safety guarantee
*/
template<typename RangeT>
inline iterator_range<
BOOST_STRING_TYPENAME range_iterator<RangeT>::type>
find_tail(
RangeT& Input,
int N)
{
return ::boost::algorithm::find(Input, ::boost::algorithm::tail_finder(N));
}
// find_token --------------------------------------------------------------------//
//! Find token algorithm
/*!
Look for a given token in the string. Token is a character that matches the
given predicate.
If the "token compress mode" is enabled, adjacent tokens are considered to be one match.
\param Input A input string.
\param Pred A unary predicate to identify a token
\param eCompress Enable/Disable compressing of adjacent tokens
\return
An \c iterator_range delimiting the match.
Returned iterator is either \c RangeT::iterator or
\c RangeT::const_iterator, depending on the constness of
the input parameter.
\note This function provides the strong exception-safety guarantee
*/
template<typename RangeT, typename PredicateT>
inline iterator_range<
BOOST_STRING_TYPENAME range_iterator<RangeT>::type>
find_token(
RangeT& Input,
PredicateT Pred,
token_compress_mode_type eCompress=token_compress_off)
{
return ::boost::algorithm::find(Input, ::boost::algorithm::token_finder(Pred, eCompress));
}
} // namespace algorithm
// pull names to the boost namespace
using algorithm::find;
using algorithm::find_first;
using algorithm::ifind_first;
using algorithm::find_last;
using algorithm::ifind_last;
using algorithm::find_nth;
using algorithm::ifind_nth;
using algorithm::find_head;
using algorithm::find_tail;
using algorithm::find_token;
} // namespace boost
#endif // BOOST_STRING_FIND_HPP

View File

@ -0,0 +1,286 @@
// Boost string_algo library find_format.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_FIND_FORMAT_HPP
#define BOOST_STRING_FIND_FORMAT_HPP
#include <deque>
#include <boost/range/iterator_range_core.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/const_iterator.hpp>
#include <boost/range/as_literal.hpp>
#include <boost/algorithm/string/concept.hpp>
#include <boost/algorithm/string/detail/find_format.hpp>
#include <boost/algorithm/string/detail/find_format_all.hpp>
/*! \file
Defines generic replace algorithms. Each algorithm replaces
part(s) of the input. The part to be replaced is looked up using a Finder object.
Result of finding is then used by a Formatter object to generate the replacement.
*/
namespace boost {
namespace algorithm {
// generic replace -----------------------------------------------------------------//
//! Generic replace algorithm
/*!
Use the Finder to search for a substring. Use the Formatter to format
this substring and replace it in the input.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input sequence
\param Finder A Finder object used to search for a match to be replaced
\param Formatter A Formatter object used to format a match
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename RangeT,
typename FinderT,
typename FormatterT>
inline OutputIteratorT find_format_copy(
OutputIteratorT Output,
const RangeT& Input,
FinderT Finder,
FormatterT Formatter )
{
// Concept check
BOOST_CONCEPT_ASSERT((
FinderConcept<
FinderT,
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type>
));
BOOST_CONCEPT_ASSERT((
FormatterConcept<
FormatterT,
FinderT,BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type>
));
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> lit_input(::boost::as_literal(Input));
return detail::find_format_copy_impl(
Output,
lit_input,
Formatter,
Finder( ::boost::begin(lit_input), ::boost::end(lit_input) ) );
}
//! Generic replace algorithm
/*!
\overload
*/
template<
typename SequenceT,
typename FinderT,
typename FormatterT>
inline SequenceT find_format_copy(
const SequenceT& Input,
FinderT Finder,
FormatterT Formatter )
{
// Concept check
BOOST_CONCEPT_ASSERT((
FinderConcept<
FinderT,
BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
));
BOOST_CONCEPT_ASSERT((
FormatterConcept<
FormatterT,
FinderT,BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
));
return detail::find_format_copy_impl(
Input,
Formatter,
Finder(::boost::begin(Input), ::boost::end(Input)));
}
//! Generic replace algorithm
/*!
Use the Finder to search for a substring. Use the Formatter to format
this substring and replace it in the input. The input is modified in-place.
\param Input An input sequence
\param Finder A Finder object used to search for a match to be replaced
\param Formatter A Formatter object used to format a match
*/
template<
typename SequenceT,
typename FinderT,
typename FormatterT>
inline void find_format(
SequenceT& Input,
FinderT Finder,
FormatterT Formatter)
{
// Concept check
BOOST_CONCEPT_ASSERT((
FinderConcept<
FinderT,
BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
));
BOOST_CONCEPT_ASSERT((
FormatterConcept<
FormatterT,
FinderT,BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
));
detail::find_format_impl(
Input,
Formatter,
Finder(::boost::begin(Input), ::boost::end(Input)));
}
// find_format_all generic ----------------------------------------------------------------//
//! Generic replace all algorithm
/*!
Use the Finder to search for a substring. Use the Formatter to format
this substring and replace it in the input. Repeat this for all matching
substrings.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input sequence
\param Finder A Finder object used to search for a match to be replaced
\param Formatter A Formatter object used to format a match
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename RangeT,
typename FinderT,
typename FormatterT>
inline OutputIteratorT find_format_all_copy(
OutputIteratorT Output,
const RangeT& Input,
FinderT Finder,
FormatterT Formatter)
{
// Concept check
BOOST_CONCEPT_ASSERT((
FinderConcept<
FinderT,
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type>
));
BOOST_CONCEPT_ASSERT((
FormatterConcept<
FormatterT,
FinderT,BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type>
));
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> lit_input(::boost::as_literal(Input));
return detail::find_format_all_copy_impl(
Output,
lit_input,
Finder,
Formatter,
Finder(::boost::begin(lit_input), ::boost::end(lit_input)));
}
//! Generic replace all algorithm
/*!
\overload
*/
template<
typename SequenceT,
typename FinderT,
typename FormatterT >
inline SequenceT find_format_all_copy(
const SequenceT& Input,
FinderT Finder,
FormatterT Formatter )
{
// Concept check
BOOST_CONCEPT_ASSERT((
FinderConcept<
FinderT,
BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
));
BOOST_CONCEPT_ASSERT((
FormatterConcept<
FormatterT,
FinderT,BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
));
return detail::find_format_all_copy_impl(
Input,
Finder,
Formatter,
Finder( ::boost::begin(Input), ::boost::end(Input) ) );
}
//! Generic replace all algorithm
/*!
Use the Finder to search for a substring. Use the Formatter to format
this substring and replace it in the input. Repeat this for all matching
substrings.The input is modified in-place.
\param Input An input sequence
\param Finder A Finder object used to search for a match to be replaced
\param Formatter A Formatter object used to format a match
*/
template<
typename SequenceT,
typename FinderT,
typename FormatterT >
inline void find_format_all(
SequenceT& Input,
FinderT Finder,
FormatterT Formatter )
{
// Concept check
BOOST_CONCEPT_ASSERT((
FinderConcept<
FinderT,
BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
));
BOOST_CONCEPT_ASSERT((
FormatterConcept<
FormatterT,
FinderT,BOOST_STRING_TYPENAME range_const_iterator<SequenceT>::type>
));
detail::find_format_all_impl(
Input,
Finder,
Formatter,
Finder(::boost::begin(Input), ::boost::end(Input)));
}
} // namespace algorithm
// pull the names to the boost namespace
using algorithm::find_format_copy;
using algorithm::find_format;
using algorithm::find_format_all_copy;
using algorithm::find_format_all;
} // namespace boost
#endif // BOOST_STRING_FIND_FORMAT_HPP

View File

@ -74,7 +74,7 @@ namespace boost {
\post eof()==true
*/
find_iterator() {}
BOOST_DEFAULTED_FUNCTION(find_iterator(), {})
//! Copy constructor
/*!
@ -85,6 +85,18 @@ namespace boost {
m_Match(Other.m_Match),
m_End(Other.m_End) {}
//! Copy assignment
/*!
Assigns a copy of the find_iterator
*/
BOOST_DEFAULTED_FUNCTION(find_iterator& operator=( const find_iterator& Other ), {
if (this == &Other) return *this;
this->base_type::operator=(Other);
m_Match = Other.m_Match;
m_End = Other.m_End;
return *this;
})
//! Constructor
/*!
Construct new find_iterator for a given finder
@ -248,6 +260,20 @@ namespace boost {
m_bEof(Other.m_bEof)
{}
//! Assignment operator
/*!
Assigns a copy of the split_iterator
*/
BOOST_DEFAULTED_FUNCTION(split_iterator& operator=( const split_iterator& Other ), {
if (this == &Other) return *this;
this->base_type::operator=(Other);
m_Match = Other.m_Match;
m_Next = Other.m_Next;
m_End = Other.m_End;
m_bEof = Other.m_bEof;
return *this;
})
//! Constructor
/*!
Construct new split_iterator for a given finder

View File

@ -0,0 +1,119 @@
// Boost string_algo library formatter.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_FORMATTER_HPP
#define BOOST_STRING_FORMATTER_HPP
#include <boost/range/value_type.hpp>
#include <boost/range/iterator_range_core.hpp>
#include <boost/range/as_literal.hpp>
#include <boost/algorithm/string/detail/formatter.hpp>
/*! \file
Defines Formatter generators. Formatter is a functor which formats
a string according to given parameters. A Formatter works
in conjunction with a Finder. A Finder can provide additional information
for a specific Formatter. An example of such a cooperation is regex_finder
and regex_formatter.
Formatters are used as pluggable components for replace facilities.
This header contains generator functions for the Formatters provided in this library.
*/
namespace boost {
namespace algorithm {
// generic formatters ---------------------------------------------------------------//
//! Constant formatter
/*!
Constructs a \c const_formatter. Const formatter always returns
the same value, regardless of the parameter.
\param Format A predefined value used as a result for formatting
\return An instance of the \c const_formatter object.
*/
template<typename RangeT>
inline detail::const_formatF<
iterator_range<
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> >
const_formatter(const RangeT& Format)
{
return detail::const_formatF<
iterator_range<
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> >(::boost::as_literal(Format));
}
//! Identity formatter
/*!
Constructs an \c identity_formatter. Identity formatter always returns
the parameter.
\return An instance of the \c identity_formatter object.
*/
template<typename RangeT>
inline detail::identity_formatF<
iterator_range<
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> >
identity_formatter()
{
return detail::identity_formatF<
iterator_range<
BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> >();
}
//! Empty formatter
/*!
Constructs an \c empty_formatter. Empty formatter always returns an empty
sequence.
\param Input container used to select a correct value_type for the
resulting empty_container<>.
\return An instance of the \c empty_formatter object.
*/
template<typename RangeT>
inline detail::empty_formatF<
BOOST_STRING_TYPENAME range_value<RangeT>::type>
empty_formatter(const RangeT&)
{
return detail::empty_formatF<
BOOST_STRING_TYPENAME range_value<RangeT>::type>();
}
//! Empty formatter
/*!
Constructs a \c dissect_formatter. Dissect formatter uses a specified finder
to extract a portion of the formatted sequence. The first finder's match is returned
as a result
\param Finder a finder used to select a portion of the formatted sequence
\return An instance of the \c dissect_formatter object.
*/
template<typename FinderT>
inline detail::dissect_formatF< FinderT >
dissect_formatter(const FinderT& Finder)
{
return detail::dissect_formatF<FinderT>(Finder);
}
} // namespace algorithm
// pull the names to the boost namespace
using algorithm::const_formatter;
using algorithm::identity_formatter;
using algorithm::empty_formatter;
using algorithm::dissect_formatter;
} // namespace boost
#endif // BOOST_FORMATTER_HPP

View File

@ -0,0 +1,145 @@
// Boost string_algo library join.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2006.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_JOIN_HPP
#define BOOST_STRING_JOIN_HPP
#include <boost/algorithm/string/config.hpp>
#include <boost/algorithm/string/detail/sequence.hpp>
#include <boost/range/value_type.hpp>
#include <boost/range/as_literal.hpp>
/*! \file
Defines join algorithm.
Join algorithm is a counterpart to split algorithms.
It joins strings from a 'list' by adding user defined separator.
Additionally there is a version that allows simple filtering
by providing a predicate.
*/
namespace boost {
namespace algorithm {
// join --------------------------------------------------------------//
//! Join algorithm
/*!
This algorithm joins all strings in a 'list' into one long string.
Segments are concatenated by given separator.
\param Input A container that holds the input strings. It must be a container-of-containers.
\param Separator A string that will separate the joined segments.
\return Concatenated string.
\note This function provides the strong exception-safety guarantee
*/
template< typename SequenceSequenceT, typename Range1T>
inline typename range_value<SequenceSequenceT>::type
join(
const SequenceSequenceT& Input,
const Range1T& Separator)
{
// Define working types
typedef typename range_value<SequenceSequenceT>::type ResultT;
typedef typename range_const_iterator<SequenceSequenceT>::type InputIteratorT;
// Parse input
InputIteratorT itBegin=::boost::begin(Input);
InputIteratorT itEnd=::boost::end(Input);
// Construct container to hold the result
ResultT Result;
// Append first element
if(itBegin!=itEnd)
{
detail::insert(Result, ::boost::end(Result), *itBegin);
++itBegin;
}
for(;itBegin!=itEnd; ++itBegin)
{
// Add separator
detail::insert(Result, ::boost::end(Result), ::boost::as_literal(Separator));
// Add element
detail::insert(Result, ::boost::end(Result), *itBegin);
}
return Result;
}
// join_if ----------------------------------------------------------//
//! Conditional join algorithm
/*!
This algorithm joins all strings in a 'list' into one long string.
Segments are concatenated by given separator. Only segments that
satisfy the predicate will be added to the result.
\param Input A container that holds the input strings. It must be a container-of-containers.
\param Separator A string that will separate the joined segments.
\param Pred A segment selection predicate
\return Concatenated string.
\note This function provides the strong exception-safety guarantee
*/
template< typename SequenceSequenceT, typename Range1T, typename PredicateT>
inline typename range_value<SequenceSequenceT>::type
join_if(
const SequenceSequenceT& Input,
const Range1T& Separator,
PredicateT Pred)
{
// Define working types
typedef typename range_value<SequenceSequenceT>::type ResultT;
typedef typename range_const_iterator<SequenceSequenceT>::type InputIteratorT;
// Parse input
InputIteratorT itBegin=::boost::begin(Input);
InputIteratorT itEnd=::boost::end(Input);
// Construct container to hold the result
ResultT Result;
// Roll to the first element that will be added
while(itBegin!=itEnd && !Pred(*itBegin)) ++itBegin;
// Add this element
if(itBegin!=itEnd)
{
detail::insert(Result, ::boost::end(Result), *itBegin);
++itBegin;
}
for(;itBegin!=itEnd; ++itBegin)
{
if(Pred(*itBegin))
{
// Add separator
detail::insert(Result, ::boost::end(Result), ::boost::as_literal(Separator));
// Add element
detail::insert(Result, ::boost::end(Result), *itBegin);
}
}
return Result;
}
} // namespace algorithm
// pull names to the boost namespace
using algorithm::join;
using algorithm::join_if;
} // namespace boost
#endif // BOOST_STRING_JOIN_HPP

View File

@ -0,0 +1,476 @@
// Boost string_algo library predicate.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_PREDICATE_HPP
#define BOOST_STRING_PREDICATE_HPP
#include <iterator>
#include <boost/algorithm/string/config.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator.hpp>
#include <boost/range/const_iterator.hpp>
#include <boost/range/as_literal.hpp>
#include <boost/range/iterator_range_core.hpp>
#include <boost/algorithm/string/compare.hpp>
#include <boost/algorithm/string/find.hpp>
#include <boost/algorithm/string/detail/predicate.hpp>
/*! \file boost/algorithm/string/predicate.hpp
Defines string-related predicates.
The predicates determine whether a substring is contained in the input string
under various conditions: a string starts with the substring, ends with the
substring, simply contains the substring or if both strings are equal.
Additionaly the algorithm \c all() checks all elements of a container to satisfy a
condition.
All predicates provide the strong exception guarantee.
*/
namespace boost {
namespace algorithm {
// starts_with predicate -----------------------------------------------//
//! 'Starts with' predicate
/*!
This predicate holds when the test string is a prefix of the Input.
In other words, if the input starts with the test.
When the optional predicate is specified, it is used for character-wise
comparison.
\param Input An input sequence
\param Test A test sequence
\param Comp An element comparison predicate
\return The result of the test
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T, typename PredicateT>
inline bool starts_with(
const Range1T& Input,
const Range2T& Test,
PredicateT Comp)
{
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range1T>::type> lit_input(::boost::as_literal(Input));
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range2T>::type> lit_test(::boost::as_literal(Test));
typedef BOOST_STRING_TYPENAME
range_const_iterator<Range1T>::type Iterator1T;
typedef BOOST_STRING_TYPENAME
range_const_iterator<Range2T>::type Iterator2T;
Iterator1T InputEnd=::boost::end(lit_input);
Iterator2T TestEnd=::boost::end(lit_test);
Iterator1T it=::boost::begin(lit_input);
Iterator2T pit=::boost::begin(lit_test);
for(;
it!=InputEnd && pit!=TestEnd;
++it,++pit)
{
if( !(Comp(*it,*pit)) )
return false;
}
return pit==TestEnd;
}
//! 'Starts with' predicate
/*!
\overload
*/
template<typename Range1T, typename Range2T>
inline bool starts_with(
const Range1T& Input,
const Range2T& Test)
{
return ::boost::algorithm::starts_with(Input, Test, is_equal());
}
//! 'Starts with' predicate ( case insensitive )
/*!
This predicate holds when the test string is a prefix of the Input.
In other words, if the input starts with the test.
Elements are compared case insensitively.
\param Input An input sequence
\param Test A test sequence
\param Loc A locale used for case insensitive comparison
\return The result of the test
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T>
inline bool istarts_with(
const Range1T& Input,
const Range2T& Test,
const std::locale& Loc=std::locale())
{
return ::boost::algorithm::starts_with(Input, Test, is_iequal(Loc));
}
// ends_with predicate -----------------------------------------------//
//! 'Ends with' predicate
/*!
This predicate holds when the test string is a suffix of the Input.
In other words, if the input ends with the test.
When the optional predicate is specified, it is used for character-wise
comparison.
\param Input An input sequence
\param Test A test sequence
\param Comp An element comparison predicate
\return The result of the test
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T, typename PredicateT>
inline bool ends_with(
const Range1T& Input,
const Range2T& Test,
PredicateT Comp)
{
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range1T>::type> lit_input(::boost::as_literal(Input));
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range2T>::type> lit_test(::boost::as_literal(Test));
typedef BOOST_STRING_TYPENAME
range_const_iterator<Range1T>::type Iterator1T;
typedef BOOST_STRING_TYPENAME
std::iterator_traits<Iterator1T>::iterator_category category;
return detail::
ends_with_iter_select(
::boost::begin(lit_input),
::boost::end(lit_input),
::boost::begin(lit_test),
::boost::end(lit_test),
Comp,
category());
}
//! 'Ends with' predicate
/*!
\overload
*/
template<typename Range1T, typename Range2T>
inline bool ends_with(
const Range1T& Input,
const Range2T& Test)
{
return ::boost::algorithm::ends_with(Input, Test, is_equal());
}
//! 'Ends with' predicate ( case insensitive )
/*!
This predicate holds when the test container is a suffix of the Input.
In other words, if the input ends with the test.
Elements are compared case insensitively.
\param Input An input sequence
\param Test A test sequence
\param Loc A locale used for case insensitive comparison
\return The result of the test
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T>
inline bool iends_with(
const Range1T& Input,
const Range2T& Test,
const std::locale& Loc=std::locale())
{
return ::boost::algorithm::ends_with(Input, Test, is_iequal(Loc));
}
// contains predicate -----------------------------------------------//
//! 'Contains' predicate
/*!
This predicate holds when the test container is contained in the Input.
When the optional predicate is specified, it is used for character-wise
comparison.
\param Input An input sequence
\param Test A test sequence
\param Comp An element comparison predicate
\return The result of the test
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T, typename PredicateT>
inline bool contains(
const Range1T& Input,
const Range2T& Test,
PredicateT Comp)
{
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range1T>::type> lit_input(::boost::as_literal(Input));
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range2T>::type> lit_test(::boost::as_literal(Test));
if (::boost::empty(lit_test))
{
// Empty range is contained always
return true;
}
// Use the temporary variable to make VACPP happy
bool bResult=(::boost::algorithm::first_finder(lit_test,Comp)(::boost::begin(lit_input), ::boost::end(lit_input)));
return bResult;
}
//! 'Contains' predicate
/*!
\overload
*/
template<typename Range1T, typename Range2T>
inline bool contains(
const Range1T& Input,
const Range2T& Test)
{
return ::boost::algorithm::contains(Input, Test, is_equal());
}
//! 'Contains' predicate ( case insensitive )
/*!
This predicate holds when the test container is contained in the Input.
Elements are compared case insensitively.
\param Input An input sequence
\param Test A test sequence
\param Loc A locale used for case insensitive comparison
\return The result of the test
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T>
inline bool icontains(
const Range1T& Input,
const Range2T& Test,
const std::locale& Loc=std::locale())
{
return ::boost::algorithm::contains(Input, Test, is_iequal(Loc));
}
// equals predicate -----------------------------------------------//
//! 'Equals' predicate
/*!
This predicate holds when the test container is equal to the
input container i.e. all elements in both containers are same.
When the optional predicate is specified, it is used for character-wise
comparison.
\param Input An input sequence
\param Test A test sequence
\param Comp An element comparison predicate
\return The result of the test
\note This is a two-way version of \c std::equal algorithm
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T, typename PredicateT>
inline bool equals(
const Range1T& Input,
const Range2T& Test,
PredicateT Comp)
{
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range1T>::type> lit_input(::boost::as_literal(Input));
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range2T>::type> lit_test(::boost::as_literal(Test));
typedef BOOST_STRING_TYPENAME
range_const_iterator<Range1T>::type Iterator1T;
typedef BOOST_STRING_TYPENAME
range_const_iterator<Range2T>::type Iterator2T;
Iterator1T InputEnd=::boost::end(lit_input);
Iterator2T TestEnd=::boost::end(lit_test);
Iterator1T it=::boost::begin(lit_input);
Iterator2T pit=::boost::begin(lit_test);
for(;
it!=InputEnd && pit!=TestEnd;
++it,++pit)
{
if( !(Comp(*it,*pit)) )
return false;
}
return (pit==TestEnd) && (it==InputEnd);
}
//! 'Equals' predicate
/*!
\overload
*/
template<typename Range1T, typename Range2T>
inline bool equals(
const Range1T& Input,
const Range2T& Test)
{
return ::boost::algorithm::equals(Input, Test, is_equal());
}
//! 'Equals' predicate ( case insensitive )
/*!
This predicate holds when the test container is equal to the
input container i.e. all elements in both containers are same.
Elements are compared case insensitively.
\param Input An input sequence
\param Test A test sequence
\param Loc A locale used for case insensitive comparison
\return The result of the test
\note This is a two-way version of \c std::equal algorithm
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T>
inline bool iequals(
const Range1T& Input,
const Range2T& Test,
const std::locale& Loc=std::locale())
{
return ::boost::algorithm::equals(Input, Test, is_iequal(Loc));
}
// lexicographical_compare predicate -----------------------------//
//! Lexicographical compare predicate
/*!
This predicate is an overload of std::lexicographical_compare
for range arguments
It check whether the first argument is lexicographically less
then the second one.
If the optional predicate is specified, it is used for character-wise
comparison
\param Arg1 First argument
\param Arg2 Second argument
\param Pred Comparison predicate
\return The result of the test
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T, typename PredicateT>
inline bool lexicographical_compare(
const Range1T& Arg1,
const Range2T& Arg2,
PredicateT Pred)
{
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range1T>::type> lit_arg1(::boost::as_literal(Arg1));
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<Range2T>::type> lit_arg2(::boost::as_literal(Arg2));
return std::lexicographical_compare(
::boost::begin(lit_arg1),
::boost::end(lit_arg1),
::boost::begin(lit_arg2),
::boost::end(lit_arg2),
Pred);
}
//! Lexicographical compare predicate
/*!
\overload
*/
template<typename Range1T, typename Range2T>
inline bool lexicographical_compare(
const Range1T& Arg1,
const Range2T& Arg2)
{
return ::boost::algorithm::lexicographical_compare(Arg1, Arg2, is_less());
}
//! Lexicographical compare predicate (case-insensitive)
/*!
This predicate is an overload of std::lexicographical_compare
for range arguments.
It check whether the first argument is lexicographically less
then the second one.
Elements are compared case insensitively
\param Arg1 First argument
\param Arg2 Second argument
\param Loc A locale used for case insensitive comparison
\return The result of the test
\note This function provides the strong exception-safety guarantee
*/
template<typename Range1T, typename Range2T>
inline bool ilexicographical_compare(
const Range1T& Arg1,
const Range2T& Arg2,
const std::locale& Loc=std::locale())
{
return ::boost::algorithm::lexicographical_compare(Arg1, Arg2, is_iless(Loc));
}
// all predicate -----------------------------------------------//
//! 'All' predicate
/*!
This predicate holds it all its elements satisfy a given
condition, represented by the predicate.
\param Input An input sequence
\param Pred A predicate
\return The result of the test
\note This function provides the strong exception-safety guarantee
*/
template<typename RangeT, typename PredicateT>
inline bool all(
const RangeT& Input,
PredicateT Pred)
{
iterator_range<BOOST_STRING_TYPENAME range_const_iterator<RangeT>::type> lit_input(::boost::as_literal(Input));
typedef BOOST_STRING_TYPENAME
range_const_iterator<RangeT>::type Iterator1T;
Iterator1T InputEnd=::boost::end(lit_input);
for( Iterator1T It=::boost::begin(lit_input); It!=InputEnd; ++It)
{
if (!Pred(*It))
return false;
}
return true;
}
} // namespace algorithm
// pull names to the boost namespace
using algorithm::starts_with;
using algorithm::istarts_with;
using algorithm::ends_with;
using algorithm::iends_with;
using algorithm::contains;
using algorithm::icontains;
using algorithm::equals;
using algorithm::iequals;
using algorithm::all;
using algorithm::lexicographical_compare;
using algorithm::ilexicographical_compare;
} // namespace boost
#endif // BOOST_STRING_PREDICATE_HPP

View File

@ -0,0 +1,926 @@
// Boost string_algo library replace.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2006.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_REPLACE_HPP
#define BOOST_STRING_REPLACE_HPP
#include <boost/algorithm/string/config.hpp>
#include <boost/range/iterator_range_core.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator.hpp>
#include <boost/range/const_iterator.hpp>
#include <boost/algorithm/string/find_format.hpp>
#include <boost/algorithm/string/finder.hpp>
#include <boost/algorithm/string/formatter.hpp>
#include <boost/algorithm/string/compare.hpp>
/*! \file
Defines various replace algorithms. Each algorithm replaces
part(s) of the input according to set of searching and replace criteria.
*/
namespace boost {
namespace algorithm {
// replace_range --------------------------------------------------------------------//
//! Replace range algorithm
/*!
Replace the given range in the input string.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param SearchRange A range in the input to be substituted
\param Format A substitute string
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T>
inline OutputIteratorT replace_range_copy(
OutputIteratorT Output,
const Range1T& Input,
const iterator_range<
BOOST_STRING_TYPENAME
range_const_iterator<Range1T>::type>& SearchRange,
const Range2T& Format)
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::range_finder(SearchRange),
::boost::algorithm::const_formatter(Format));
}
//! Replace range algorithm
/*!
\overload
*/
template<typename SequenceT, typename RangeT>
inline SequenceT replace_range_copy(
const SequenceT& Input,
const iterator_range<
BOOST_STRING_TYPENAME
range_const_iterator<SequenceT>::type>& SearchRange,
const RangeT& Format)
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::range_finder(SearchRange),
::boost::algorithm::const_formatter(Format));
}
//! Replace range algorithm
/*!
Replace the given range in the input string.
The input sequence is modified in-place.
\param Input An input string
\param SearchRange A range in the input to be substituted
\param Format A substitute string
*/
template<typename SequenceT, typename RangeT>
inline void replace_range(
SequenceT& Input,
const iterator_range<
BOOST_STRING_TYPENAME
range_iterator<SequenceT>::type>& SearchRange,
const RangeT& Format)
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::range_finder(SearchRange),
::boost::algorithm::const_formatter(Format));
}
// replace_first --------------------------------------------------------------------//
//! Replace first algorithm
/*!
Replace the first match of the search substring in the input
with the format string.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for
\param Format A substitute string
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T,
typename Range3T>
inline OutputIteratorT replace_first_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search,
const Range3T& Format)
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::first_finder(Search),
::boost::algorithm::const_formatter(Format) );
}
//! Replace first algorithm
/*!
\overload
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline SequenceT replace_first_copy(
const SequenceT& Input,
const Range1T& Search,
const Range2T& Format )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::first_finder(Search),
::boost::algorithm::const_formatter(Format) );
}
//! Replace first algorithm
/*!
replace the first match of the search substring in the input
with the format string. The input sequence is modified in-place.
\param Input An input string
\param Search A substring to be searched for
\param Format A substitute string
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline void replace_first(
SequenceT& Input,
const Range1T& Search,
const Range2T& Format )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::first_finder(Search),
::boost::algorithm::const_formatter(Format) );
}
// replace_first ( case insensitive ) ---------------------------------------------//
//! Replace first algorithm ( case insensitive )
/*!
Replace the first match of the search substring in the input
with the format string.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
Searching is case insensitive.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for
\param Format A substitute string
\param Loc A locale used for case insensitive comparison
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T,
typename Range3T>
inline OutputIteratorT ireplace_first_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search,
const Range3T& Format,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
::boost::algorithm::const_formatter(Format) );
}
//! Replace first algorithm ( case insensitive )
/*!
\overload
*/
template<typename SequenceT, typename Range2T, typename Range1T>
inline SequenceT ireplace_first_copy(
const SequenceT& Input,
const Range2T& Search,
const Range1T& Format,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
::boost::algorithm::const_formatter(Format) );
}
//! Replace first algorithm ( case insensitive )
/*!
Replace the first match of the search substring in the input
with the format string. Input sequence is modified in-place.
Searching is case insensitive.
\param Input An input string
\param Search A substring to be searched for
\param Format A substitute string
\param Loc A locale used for case insensitive comparison
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline void ireplace_first(
SequenceT& Input,
const Range1T& Search,
const Range2T& Format,
const std::locale& Loc=std::locale() )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
::boost::algorithm::const_formatter(Format) );
}
// replace_last --------------------------------------------------------------------//
//! Replace last algorithm
/*!
Replace the last match of the search string in the input
with the format string.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for
\param Format A substitute string
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T,
typename Range3T>
inline OutputIteratorT replace_last_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search,
const Range3T& Format )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::last_finder(Search),
::boost::algorithm::const_formatter(Format) );
}
//! Replace last algorithm
/*!
\overload
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline SequenceT replace_last_copy(
const SequenceT& Input,
const Range1T& Search,
const Range2T& Format )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::last_finder(Search),
::boost::algorithm::const_formatter(Format) );
}
//! Replace last algorithm
/*!
Replace the last match of the search string in the input
with the format string. Input sequence is modified in-place.
\param Input An input string
\param Search A substring to be searched for
\param Format A substitute string
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline void replace_last(
SequenceT& Input,
const Range1T& Search,
const Range2T& Format )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::last_finder(Search),
::boost::algorithm::const_formatter(Format) );
}
// replace_last ( case insensitive ) -----------------------------------------------//
//! Replace last algorithm ( case insensitive )
/*!
Replace the last match of the search string in the input
with the format string.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
Searching is case insensitive.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for
\param Format A substitute string
\param Loc A locale used for case insensitive comparison
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T,
typename Range3T>
inline OutputIteratorT ireplace_last_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search,
const Range3T& Format,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::last_finder(Search, is_iequal(Loc)),
::boost::algorithm::const_formatter(Format) );
}
//! Replace last algorithm ( case insensitive )
/*!
\overload
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline SequenceT ireplace_last_copy(
const SequenceT& Input,
const Range1T& Search,
const Range2T& Format,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::last_finder(Search, is_iequal(Loc)),
::boost::algorithm::const_formatter(Format) );
}
//! Replace last algorithm ( case insensitive )
/*!
Replace the last match of the search string in the input
with the format string.The input sequence is modified in-place.
Searching is case insensitive.
\param Input An input string
\param Search A substring to be searched for
\param Format A substitute string
\param Loc A locale used for case insensitive comparison
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline void ireplace_last(
SequenceT& Input,
const Range1T& Search,
const Range2T& Format,
const std::locale& Loc=std::locale() )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::last_finder(Search, is_iequal(Loc)),
::boost::algorithm::const_formatter(Format) );
}
// replace_nth --------------------------------------------------------------------//
//! Replace nth algorithm
/*!
Replace an Nth (zero-indexed) match of the search string in the input
with the format string.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for
\param Nth An index of the match to be replaced. The index is 0-based.
For negative N, matches are counted from the end of string.
\param Format A substitute string
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T,
typename Range3T>
inline OutputIteratorT replace_nth_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search,
int Nth,
const Range3T& Format )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::nth_finder(Search, Nth),
::boost::algorithm::const_formatter(Format) );
}
//! Replace nth algorithm
/*!
\overload
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline SequenceT replace_nth_copy(
const SequenceT& Input,
const Range1T& Search,
int Nth,
const Range2T& Format )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::nth_finder(Search, Nth),
::boost::algorithm::const_formatter(Format) );
}
//! Replace nth algorithm
/*!
Replace an Nth (zero-indexed) match of the search string in the input
with the format string. Input sequence is modified in-place.
\param Input An input string
\param Search A substring to be searched for
\param Nth An index of the match to be replaced. The index is 0-based.
For negative N, matches are counted from the end of string.
\param Format A substitute string
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline void replace_nth(
SequenceT& Input,
const Range1T& Search,
int Nth,
const Range2T& Format )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::nth_finder(Search, Nth),
::boost::algorithm::const_formatter(Format) );
}
// replace_nth ( case insensitive ) -----------------------------------------------//
//! Replace nth algorithm ( case insensitive )
/*!
Replace an Nth (zero-indexed) match of the search string in the input
with the format string.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
Searching is case insensitive.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for
\param Nth An index of the match to be replaced. The index is 0-based.
For negative N, matches are counted from the end of string.
\param Format A substitute string
\param Loc A locale used for case insensitive comparison
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T,
typename Range3T>
inline OutputIteratorT ireplace_nth_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search,
int Nth,
const Range3T& Format,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc) ),
::boost::algorithm::const_formatter(Format) );
}
//! Replace nth algorithm ( case insensitive )
/*!
\overload
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline SequenceT ireplace_nth_copy(
const SequenceT& Input,
const Range1T& Search,
int Nth,
const Range2T& Format,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)),
::boost::algorithm::const_formatter(Format) );
}
//! Replace nth algorithm ( case insensitive )
/*!
Replace an Nth (zero-indexed) match of the search string in the input
with the format string. Input sequence is modified in-place.
Searching is case insensitive.
\param Input An input string
\param Search A substring to be searched for
\param Nth An index of the match to be replaced. The index is 0-based.
For negative N, matches are counted from the end of string.
\param Format A substitute string
\param Loc A locale used for case insensitive comparison
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline void ireplace_nth(
SequenceT& Input,
const Range1T& Search,
int Nth,
const Range2T& Format,
const std::locale& Loc=std::locale() )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)),
::boost::algorithm::const_formatter(Format) );
}
// replace_all --------------------------------------------------------------------//
//! Replace all algorithm
/*!
Replace all occurrences of the search string in the input
with the format string.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for
\param Format A substitute string
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T,
typename Range3T>
inline OutputIteratorT replace_all_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search,
const Range3T& Format )
{
return ::boost::algorithm::find_format_all_copy(
Output,
Input,
::boost::algorithm::first_finder(Search),
::boost::algorithm::const_formatter(Format) );
}
//! Replace all algorithm
/*!
\overload
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline SequenceT replace_all_copy(
const SequenceT& Input,
const Range1T& Search,
const Range2T& Format )
{
return ::boost::algorithm::find_format_all_copy(
Input,
::boost::algorithm::first_finder(Search),
::boost::algorithm::const_formatter(Format) );
}
//! Replace all algorithm
/*!
Replace all occurrences of the search string in the input
with the format string. The input sequence is modified in-place.
\param Input An input string
\param Search A substring to be searched for
\param Format A substitute string
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline void replace_all(
SequenceT& Input,
const Range1T& Search,
const Range2T& Format )
{
::boost::algorithm::find_format_all(
Input,
::boost::algorithm::first_finder(Search),
::boost::algorithm::const_formatter(Format) );
}
// replace_all ( case insensitive ) -----------------------------------------------//
//! Replace all algorithm ( case insensitive )
/*!
Replace all occurrences of the search string in the input
with the format string.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
Searching is case insensitive.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param Search A substring to be searched for
\param Format A substitute string
\param Loc A locale used for case insensitive comparison
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T,
typename Range3T>
inline OutputIteratorT ireplace_all_copy(
OutputIteratorT Output,
const Range1T& Input,
const Range2T& Search,
const Range3T& Format,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_all_copy(
Output,
Input,
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
::boost::algorithm::const_formatter(Format) );
}
//! Replace all algorithm ( case insensitive )
/*!
\overload
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline SequenceT ireplace_all_copy(
const SequenceT& Input,
const Range1T& Search,
const Range2T& Format,
const std::locale& Loc=std::locale() )
{
return ::boost::algorithm::find_format_all_copy(
Input,
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
::boost::algorithm::const_formatter(Format) );
}
//! Replace all algorithm ( case insensitive )
/*!
Replace all occurrences of the search string in the input
with the format string.The input sequence is modified in-place.
Searching is case insensitive.
\param Input An input string
\param Search A substring to be searched for
\param Format A substitute string
\param Loc A locale used for case insensitive comparison
*/
template<typename SequenceT, typename Range1T, typename Range2T>
inline void ireplace_all(
SequenceT& Input,
const Range1T& Search,
const Range2T& Format,
const std::locale& Loc=std::locale() )
{
::boost::algorithm::find_format_all(
Input,
::boost::algorithm::first_finder(Search, is_iequal(Loc)),
::boost::algorithm::const_formatter(Format) );
}
// replace_head --------------------------------------------------------------------//
//! Replace head algorithm
/*!
Replace the head of the input with the given format string.
The head is a prefix of a string of given size.
If the sequence is shorter then required, whole string if
considered to be the head.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param N Length of the head.
For N>=0, at most N characters are extracted.
For N<0, size(Input)-|N| characters are extracted.
\param Format A substitute string
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T>
inline OutputIteratorT replace_head_copy(
OutputIteratorT Output,
const Range1T& Input,
int N,
const Range2T& Format )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::head_finder(N),
::boost::algorithm::const_formatter(Format) );
}
//! Replace head algorithm
/*!
\overload
*/
template<typename SequenceT, typename RangeT>
inline SequenceT replace_head_copy(
const SequenceT& Input,
int N,
const RangeT& Format )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::head_finder(N),
::boost::algorithm::const_formatter(Format) );
}
//! Replace head algorithm
/*!
Replace the head of the input with the given format string.
The head is a prefix of a string of given size.
If the sequence is shorter then required, the whole string is
considered to be the head. The input sequence is modified in-place.
\param Input An input string
\param N Length of the head.
For N>=0, at most N characters are extracted.
For N<0, size(Input)-|N| characters are extracted.
\param Format A substitute string
*/
template<typename SequenceT, typename RangeT>
inline void replace_head(
SequenceT& Input,
int N,
const RangeT& Format )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::head_finder(N),
::boost::algorithm::const_formatter(Format) );
}
// replace_tail --------------------------------------------------------------------//
//! Replace tail algorithm
/*!
Replace the tail of the input with the given format string.
The tail is a suffix of a string of given size.
If the sequence is shorter then required, whole string is
considered to be the tail.
The result is a modified copy of the input. It is returned as a sequence
or copied to the output iterator.
\param Output An output iterator to which the result will be copied
\param Input An input string
\param N Length of the tail.
For N>=0, at most N characters are extracted.
For N<0, size(Input)-|N| characters are extracted.
\param Format A substitute string
\return An output iterator pointing just after the last inserted character or
a modified copy of the input
\note The second variant of this function provides the strong exception-safety guarantee
*/
template<
typename OutputIteratorT,
typename Range1T,
typename Range2T>
inline OutputIteratorT replace_tail_copy(
OutputIteratorT Output,
const Range1T& Input,
int N,
const Range2T& Format )
{
return ::boost::algorithm::find_format_copy(
Output,
Input,
::boost::algorithm::tail_finder(N),
::boost::algorithm::const_formatter(Format) );
}
//! Replace tail algorithm
/*!
\overload
*/
template<typename SequenceT, typename RangeT>
inline SequenceT replace_tail_copy(
const SequenceT& Input,
int N,
const RangeT& Format )
{
return ::boost::algorithm::find_format_copy(
Input,
::boost::algorithm::tail_finder(N),
::boost::algorithm::const_formatter(Format) );
}
//! Replace tail algorithm
/*!
Replace the tail of the input with the given format sequence.
The tail is a suffix of a string of given size.
If the sequence is shorter then required, the whole string is
considered to be the tail. The input sequence is modified in-place.
\param Input An input string
\param N Length of the tail.
For N>=0, at most N characters are extracted.
For N<0, size(Input)-|N| characters are extracted.
\param Format A substitute string
*/
template<typename SequenceT, typename RangeT>
inline void replace_tail(
SequenceT& Input,
int N,
const RangeT& Format )
{
::boost::algorithm::find_format(
Input,
::boost::algorithm::tail_finder(N),
::boost::algorithm::const_formatter(Format) );
}
} // namespace algorithm
// pull names to the boost namespace
using algorithm::replace_range_copy;
using algorithm::replace_range;
using algorithm::replace_first_copy;
using algorithm::replace_first;
using algorithm::ireplace_first_copy;
using algorithm::ireplace_first;
using algorithm::replace_last_copy;
using algorithm::replace_last;
using algorithm::ireplace_last_copy;
using algorithm::ireplace_last;
using algorithm::replace_nth_copy;
using algorithm::replace_nth;
using algorithm::ireplace_nth_copy;
using algorithm::ireplace_nth;
using algorithm::replace_all_copy;
using algorithm::replace_all;
using algorithm::ireplace_all_copy;
using algorithm::ireplace_all;
using algorithm::replace_head_copy;
using algorithm::replace_head;
using algorithm::replace_tail_copy;
using algorithm::replace_tail;
} // namespace boost
#endif // BOOST_REPLACE_HPP

View File

@ -0,0 +1,120 @@
// Boost string_algo library sequence_traits.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_SEQUENCE_TRAITS_HPP
#define BOOST_STRING_SEQUENCE_TRAITS_HPP
#include <boost/config.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/algorithm/string/yes_no_type.hpp>
/*! \file
Traits defined in this header are used by various algorithms to achieve
better performance for specific containers.
Traits provide fail-safe defaults. If a container supports some of these
features, it is possible to specialize the specific trait for this container.
For lacking compilers, it is possible of define an override for a specific tester
function.
Due to a language restriction, it is not currently possible to define specializations for
stl containers without including the corresponding header. To decrease the overhead
needed by this inclusion, user can selectively include a specialization
header for a specific container. They are located in boost/algorithm/string/stl
directory. Alternatively she can include boost/algorithm/string/std_collection_traits.hpp
header which contains specializations for all stl containers.
*/
namespace boost {
namespace algorithm {
// sequence traits -----------------------------------------------//
//! Native replace trait
/*!
This trait specifies that the sequence has \c std::string like replace method
*/
template< typename T >
class has_native_replace
{
public:
# if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
enum { value = false };
# else
BOOST_STATIC_CONSTANT(bool, value=false);
# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
typedef mpl::bool_<has_native_replace<T>::value> type;
};
//! Stable iterators trait
/*!
This trait specifies that the sequence has stable iterators. It means
that operations like insert/erase/replace do not invalidate iterators.
*/
template< typename T >
class has_stable_iterators
{
public:
# if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
enum { value = false };
# else
BOOST_STATIC_CONSTANT(bool, value=false);
# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
typedef mpl::bool_<has_stable_iterators<T>::value> type;
};
//! Const time insert trait
/*!
This trait specifies that the sequence's insert method has
constant time complexity.
*/
template< typename T >
class has_const_time_insert
{
public:
# if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
enum { value = false };
# else
BOOST_STATIC_CONSTANT(bool, value=false);
# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
typedef mpl::bool_<has_const_time_insert<T>::value> type;
};
//! Const time erase trait
/*!
This trait specifies that the sequence's erase method has
constant time complexity.
*/
template< typename T >
class has_const_time_erase
{
public:
# if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
enum { value = false };
# else
BOOST_STATIC_CONSTANT(bool, value=false);
# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
typedef mpl::bool_<has_const_time_erase<T>::value> type;
};
} // namespace algorithm
} // namespace boost
#endif // BOOST_STRING_SEQUENCE_TRAITS_HPP

View File

@ -0,0 +1,68 @@
// Boost string_algo library list_traits.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_STD_LIST_TRAITS_HPP
#define BOOST_STRING_STD_LIST_TRAITS_HPP
#include <boost/algorithm/string/yes_no_type.hpp>
#include <list>
#include <boost/algorithm/string/sequence_traits.hpp>
namespace boost {
namespace algorithm {
// std::list<> traits -----------------------------------------------//
// stable iterators trait
template<typename T, typename AllocT>
class has_stable_iterators< ::std::list<T,AllocT> >
{
public:
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
enum { value = true };
#else
BOOST_STATIC_CONSTANT(bool, value=true);
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
typedef mpl::bool_<has_stable_iterators<T>::value> type;
};
// const time insert trait
template<typename T, typename AllocT>
class has_const_time_insert< ::std::list<T,AllocT> >
{
public:
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
enum { value = true };
#else
BOOST_STATIC_CONSTANT(bool, value=true);
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
typedef mpl::bool_<has_const_time_insert<T>::value> type;
};
// const time erase trait
template<typename T, typename AllocT>
class has_const_time_erase< ::std::list<T,AllocT> >
{
public:
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
enum { value = true };
#else
BOOST_STATIC_CONSTANT(bool, value=true);
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
typedef mpl::bool_<has_const_time_erase<T>::value> type;
};
} // namespace algorithm
} // namespace boost
#endif // BOOST_STRING_STD_LIST_TRAITS_HPP

View File

@ -0,0 +1,69 @@
// Boost string_algo library slist_traits.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_STD_SLIST_TRAITS_HPP
#define BOOST_STRING_STD_SLIST_TRAITS_HPP
#include <boost/algorithm/string/config.hpp>
#include <boost/algorithm/string/yes_no_type.hpp>
#include BOOST_SLIST_HEADER
#include <boost/algorithm/string/sequence_traits.hpp>
namespace boost {
namespace algorithm {
// SGI's std::slist<> traits -----------------------------------------------//
// stable iterators trait
template<typename T, typename AllocT>
class has_stable_iterators< BOOST_STD_EXTENSION_NAMESPACE::slist<T,AllocT> >
{
public:
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
enum { value = true };
#else
BOOST_STATIC_CONSTANT(bool, value=true);
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
typedef mpl::bool_<has_stable_iterators<T>::value> type;
};
// const time insert trait
template<typename T, typename AllocT>
class has_const_time_insert< BOOST_STD_EXTENSION_NAMESPACE::slist<T,AllocT> >
{
public:
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
enum { value = true };
#else
BOOST_STATIC_CONSTANT(bool, value=true);
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
typedef mpl::bool_<has_const_time_insert<T>::value> type;
};
// const time erase trait
template<typename T, typename AllocT>
class has_const_time_erase< BOOST_STD_EXTENSION_NAMESPACE::slist<T,AllocT> >
{
public:
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
enum { value = true };
#else
BOOST_STATIC_CONSTANT(bool, value=true);
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
typedef mpl::bool_<has_const_time_erase<T>::value> type;
};
} // namespace algorithm
} // namespace boost
#endif // BOOST_STRING_STD_LIST_TRAITS_HPP

View File

@ -0,0 +1,44 @@
// Boost string_algo library string_traits.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_STD_STRING_TRAITS_HPP
#define BOOST_STRING_STD_STRING_TRAITS_HPP
#include <boost/algorithm/string/yes_no_type.hpp>
#include <string>
#include <boost/algorithm/string/sequence_traits.hpp>
namespace boost {
namespace algorithm {
// std::basic_string<> traits -----------------------------------------------//
// native replace trait
template<typename T, typename TraitsT, typename AllocT>
class has_native_replace< std::basic_string<T, TraitsT, AllocT> >
{
public:
#if BOOST_WORKAROUND( __IBMCPP__, <= 600 )
enum { value = true } ;
#else
BOOST_STATIC_CONSTANT(bool, value=true);
#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 )
typedef mpl::bool_<has_native_replace<T>::value> type;
};
} // namespace algorithm
} // namespace boost
#endif // BOOST_STRING_LIST_TRAITS_HPP

View File

@ -0,0 +1,26 @@
// Boost string_algo library std_containers_traits.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_STD_CONTAINERS_TRAITS_HPP
#define BOOST_STRING_STD_CONTAINERS_TRAITS_HPP
/*!\file
This file includes sequence traits for stl containers.
*/
#include <boost/config.hpp>
#include <boost/algorithm/string/std/string_traits.hpp>
#include <boost/algorithm/string/std/list_traits.hpp>
#ifdef BOOST_HAS_SLIST
# include <boost/algorithm/string/std/slist_traits.hpp>
#endif
#endif // BOOST_STRING_STD_CONTAINERS_TRAITS_HPP

View File

@ -0,0 +1,33 @@
// Boost string_algo library yes_no_type.hpp header file ---------------------------//
// Copyright Pavol Droba 2002-2003.
//
// 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)
// See http://www.boost.org/ for updates, documentation, and revision history.
#ifndef BOOST_STRING_YES_NO_TYPE_DETAIL_HPP
#define BOOST_STRING_YES_NO_TYPE_DETAIL_HPP
namespace boost {
namespace algorithm {
// taken from boost mailing-list
// when yes_no_type will become officially
// a part of boost distribution, this header
// will be deprecated
template<int I> struct size_descriptor
{
typedef char (& type)[I];
};
typedef size_descriptor<1>::type yes_type;
typedef size_descriptor<2>::type no_type;
} // namespace algorithm
} // namespace boost
#endif // BOOST_STRING_YES_NO_TYPE_DETAIL_HPP

View File

@ -38,7 +38,7 @@ Distributed under the Boost Software License, Version 1.0.
#include <boost/align/detail/aligned_alloc_posix.hpp>
#elif defined(sun) || defined(__sun)
#include <boost/align/detail/aligned_alloc_sunos.hpp>
#elif (_POSIX_C_SOURCE >= 200112L) || (_XOPEN_SOURCE >= 600)
#elif defined(_POSIX_VERSION)
#include <boost/align/detail/aligned_alloc_posix.hpp>
#else
#include <boost/align/detail/aligned_alloc.hpp>

View File

@ -1,456 +0,0 @@
/* The following code declares class array,
* an STL container (as wrapper) for arrays of constant size.
*
* See
* http://www.boost.org/libs/array/
* for documentation.
*
* The original author site is at: http://www.josuttis.com/
*
* (C) Copyright Nicolai M. Josuttis 2001.
*
* 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)
*
* 9 Jan 2013 - (mtc) Added constexpr
* 14 Apr 2012 - (mtc) Added support for boost::hash
* 28 Dec 2010 - (mtc) Added cbegin and cend (and crbegin and crend) for C++Ox compatibility.
* 10 Mar 2010 - (mtc) fill method added, matching resolution of the standard library working group.
* See <http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#776> or Trac issue #3168
* Eventually, we should remove "assign" which is now a synonym for "fill" (Marshall Clow)
* 10 Mar 2010 - added workaround for SUNCC and !STLPort [trac #3893] (Marshall Clow)
* 29 Jan 2004 - c_array() added, BOOST_NO_PRIVATE_IN_AGGREGATE removed (Nico Josuttis)
* 23 Aug 2002 - fix for Non-MSVC compilers combined with MSVC libraries.
* 05 Aug 2001 - minor update (Nico Josuttis)
* 20 Jan 2001 - STLport fix (Beman Dawes)
* 29 Sep 2000 - Initial Revision (Nico Josuttis)
*
* Jan 29, 2004
*/
#ifndef BOOST_ARRAY_HPP
#define BOOST_ARRAY_HPP
#include <boost/detail/workaround.hpp>
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
# pragma warning(push)
# pragma warning(disable:4996) // 'std::equal': Function call with parameters that may be unsafe
# pragma warning(disable:4510) // boost::array<T,N>' : default constructor could not be generated
# pragma warning(disable:4610) // warning C4610: class 'boost::array<T,N>' can never be instantiated - user defined constructor required
#endif
#include <cstddef>
#include <iterator>
#include <stdexcept>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/swap.hpp>
#include <boost/throw_exception.hpp>
#include <algorithm>
// FIXES for broken compilers
#include <boost/config.hpp>
namespace boost {
template<class T, std::size_t N>
class array {
public:
T elems[N]; // fixed-size array of elements of type T
public:
// type definitions
typedef T value_type;
typedef T* iterator;
typedef const T* const_iterator;
typedef T& reference;
typedef const T& const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
// iterator support
iterator begin() { return elems; }
const_iterator begin() const { return elems; }
const_iterator cbegin() const { return elems; }
iterator end() { return elems+N; }
const_iterator end() const { return elems+N; }
const_iterator cend() const { return elems+N; }
// reverse iterator support
#if !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS)
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
#elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC)
typedef std::reverse_iterator<iterator, std::random_access_iterator_tag,
value_type, reference, iterator, difference_type> reverse_iterator;
typedef std::reverse_iterator<const_iterator, std::random_access_iterator_tag,
value_type, const_reference, const_iterator, difference_type> const_reverse_iterator;
#else
// workaround for broken reverse_iterator implementations
typedef std::reverse_iterator<iterator,T> reverse_iterator;
typedef std::reverse_iterator<const_iterator,T> const_reverse_iterator;
#endif
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
const_reverse_iterator crbegin() const {
return const_reverse_iterator(end());
}
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
const_reverse_iterator crend() const {
return const_reverse_iterator(begin());
}
// operator[]
reference operator[](size_type i)
{
return BOOST_ASSERT_MSG( i < N, "out of range" ), elems[i];
}
/*BOOST_CONSTEXPR*/ const_reference operator[](size_type i) const
{
return BOOST_ASSERT_MSG( i < N, "out of range" ), elems[i];
}
// at() with range check
reference at(size_type i) { return rangecheck(i), elems[i]; }
/*BOOST_CONSTEXPR*/ const_reference at(size_type i) const { return rangecheck(i), elems[i]; }
// front() and back()
reference front()
{
return elems[0];
}
BOOST_CONSTEXPR const_reference front() const
{
return elems[0];
}
reference back()
{
return elems[N-1];
}
BOOST_CONSTEXPR const_reference back() const
{
return elems[N-1];
}
// size is constant
static BOOST_CONSTEXPR size_type size() { return N; }
static BOOST_CONSTEXPR bool empty() { return false; }
static BOOST_CONSTEXPR size_type max_size() { return N; }
enum { static_size = N };
// swap (note: linear complexity)
void swap (array<T,N>& y) {
for (size_type i = 0; i < N; ++i)
boost::swap(elems[i],y.elems[i]);
}
// direct access to data (read-only)
const T* data() const { return elems; }
T* data() { return elems; }
// use array as C array (direct read/write access to data)
T* c_array() { return elems; }
// assignment with type conversion
template <typename T2>
array<T,N>& operator= (const array<T2,N>& rhs) {
std::copy(rhs.begin(),rhs.end(), begin());
return *this;
}
// assign one value to all elements
void assign (const T& value) { fill ( value ); } // A synonym for fill
void fill (const T& value)
{
std::fill_n(begin(),size(),value);
}
// check range (may be private because it is static)
static BOOST_CONSTEXPR bool rangecheck (size_type i) {
return i >= size() ? boost::throw_exception(std::out_of_range ("array<>: index out of range")), true : true;
}
};
template< class T >
class array< T, 0 > {
public:
// type definitions
typedef T value_type;
typedef T* iterator;
typedef const T* const_iterator;
typedef T& reference;
typedef const T& const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
// iterator support
iterator begin() { return iterator( reinterpret_cast< T * >( this ) ); }
const_iterator begin() const { return const_iterator( reinterpret_cast< const T * >( this ) ); }
const_iterator cbegin() const { return const_iterator( reinterpret_cast< const T * >( this ) ); }
iterator end() { return begin(); }
const_iterator end() const { return begin(); }
const_iterator cend() const { return cbegin(); }
// reverse iterator support
#if !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS)
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
#elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC)
typedef std::reverse_iterator<iterator, std::random_access_iterator_tag,
value_type, reference, iterator, difference_type> reverse_iterator;
typedef std::reverse_iterator<const_iterator, std::random_access_iterator_tag,
value_type, const_reference, const_iterator, difference_type> const_reverse_iterator;
#else
// workaround for broken reverse_iterator implementations
typedef std::reverse_iterator<iterator,T> reverse_iterator;
typedef std::reverse_iterator<const_iterator,T> const_reverse_iterator;
#endif
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
const_reverse_iterator crbegin() const {
return const_reverse_iterator(end());
}
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
const_reverse_iterator crend() const {
return const_reverse_iterator(begin());
}
// operator[]
reference operator[](size_type /*i*/)
{
return failed_rangecheck();
}
/*BOOST_CONSTEXPR*/ const_reference operator[](size_type /*i*/) const
{
return failed_rangecheck();
}
// at() with range check
reference at(size_type /*i*/) { return failed_rangecheck(); }
/*BOOST_CONSTEXPR*/ const_reference at(size_type /*i*/) const { return failed_rangecheck(); }
// front() and back()
reference front()
{
return failed_rangecheck();
}
BOOST_CONSTEXPR const_reference front() const
{
return failed_rangecheck();
}
reference back()
{
return failed_rangecheck();
}
BOOST_CONSTEXPR const_reference back() const
{
return failed_rangecheck();
}
// size is constant
static BOOST_CONSTEXPR size_type size() { return 0; }
static BOOST_CONSTEXPR bool empty() { return true; }
static BOOST_CONSTEXPR size_type max_size() { return 0; }
enum { static_size = 0 };
void swap (array<T,0>& /*y*/) {
}
// direct access to data (read-only)
const T* data() const { return 0; }
T* data() { return 0; }
// use array as C array (direct read/write access to data)
T* c_array() { return 0; }
// assignment with type conversion
template <typename T2>
array<T,0>& operator= (const array<T2,0>& ) {
return *this;
}
// assign one value to all elements
void assign (const T& value) { fill ( value ); }
void fill (const T& ) {}
// check range (may be private because it is static)
static reference failed_rangecheck () {
std::out_of_range e("attempt to access element of an empty array");
boost::throw_exception(e);
#if defined(BOOST_NO_EXCEPTIONS) || (!defined(BOOST_MSVC) && !defined(__PATHSCALE__))
//
// We need to return something here to keep
// some compilers happy: however we will never
// actually get here....
//
static T placeholder;
return placeholder;
#endif
}
};
// comparisons
template<class T, std::size_t N>
bool operator== (const array<T,N>& x, const array<T,N>& y) {
return std::equal(x.begin(), x.end(), y.begin());
}
template<class T, std::size_t N>
bool operator< (const array<T,N>& x, const array<T,N>& y) {
return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end());
}
template<class T, std::size_t N>
bool operator!= (const array<T,N>& x, const array<T,N>& y) {
return !(x==y);
}
template<class T, std::size_t N>
bool operator> (const array<T,N>& x, const array<T,N>& y) {
return y<x;
}
template<class T, std::size_t N>
bool operator<= (const array<T,N>& x, const array<T,N>& y) {
return !(y<x);
}
template<class T, std::size_t N>
bool operator>= (const array<T,N>& x, const array<T,N>& y) {
return !(x<y);
}
// global swap()
template<class T, std::size_t N>
inline void swap (array<T,N>& x, array<T,N>& y) {
x.swap(y);
}
#if defined(__SUNPRO_CC)
// Trac ticket #4757; the Sun Solaris compiler can't handle
// syntax like 'T(&get_c_array(boost::array<T,N>& arg))[N]'
//
// We can't just use this for all compilers, because the
// borland compilers can't handle this form.
namespace detail {
template <typename T, std::size_t N> struct c_array
{
typedef T type[N];
};
}
// Specific for boost::array: simply returns its elems data member.
template <typename T, std::size_t N>
typename detail::c_array<T,N>::type& get_c_array(boost::array<T,N>& arg)
{
return arg.elems;
}
// Specific for boost::array: simply returns its elems data member.
template <typename T, std::size_t N>
typename detail::c_array<T,N>::type const& get_c_array(const boost::array<T,N>& arg)
{
return arg.elems;
}
#else
// Specific for boost::array: simply returns its elems data member.
template <typename T, std::size_t N>
T(&get_c_array(boost::array<T,N>& arg))[N]
{
return arg.elems;
}
// Const version.
template <typename T, std::size_t N>
const T(&get_c_array(const boost::array<T,N>& arg))[N]
{
return arg.elems;
}
#endif
#if 0
// Overload for std::array, assuming that std::array will have
// explicit conversion functions as discussed at the WG21 meeting
// in Summit, March 2009.
template <typename T, std::size_t N>
T(&get_c_array(std::array<T,N>& arg))[N]
{
return static_cast<T(&)[N]>(arg);
}
// Const version.
template <typename T, std::size_t N>
const T(&get_c_array(const std::array<T,N>& arg))[N]
{
return static_cast<T(&)[N]>(arg);
}
#endif
template <class It> std::size_t hash_range(It, It);
template<class T, std::size_t N>
std::size_t hash_value(const array<T,N>& arr)
{
return boost::hash_range(arr.begin(), arr.end());
}
template <size_t Idx, typename T, size_t N>
T &get(boost::array<T,N> &arr) BOOST_NOEXCEPT {
BOOST_STATIC_ASSERT_MSG ( Idx < N, "boost::get<>(boost::array &) index out of range" );
return arr[Idx];
}
template <size_t Idx, typename T, size_t N>
const T &get(const boost::array<T,N> &arr) BOOST_NOEXCEPT {
BOOST_STATIC_ASSERT_MSG ( Idx < N, "boost::get<>(const boost::array &) index out of range" );
return arr[Idx];
}
} /* namespace boost */
#ifndef BOOST_NO_CXX11_HDR_ARRAY
// If we don't have std::array, I'm assuming that we don't have std::get
namespace std {
template <size_t Idx, typename T, size_t N>
T &get(boost::array<T,N> &arr) BOOST_NOEXCEPT {
BOOST_STATIC_ASSERT_MSG ( Idx < N, "std::get<>(boost::array &) index out of range" );
return arr[Idx];
}
template <size_t Idx, typename T, size_t N>
const T &get(const boost::array<T,N> &arr) BOOST_NOEXCEPT {
BOOST_STATIC_ASSERT_MSG ( Idx < N, "std::get<>(const boost::array &) index out of range" );
return arr[Idx];
}
}
#endif
#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400)
# pragma warning(pop)
#endif
#endif /*BOOST_ARRAY_HPP*/

204
extern/boost/boost/asio.hpp vendored Normal file
View File

@ -0,0 +1,204 @@
//
// asio.hpp
// ~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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)
//
// See www.boost.org/libs/asio for documentation.
//
#ifndef BOOST_ASIO_HPP
#define BOOST_ASIO_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/any_completion_executor.hpp>
#include <boost/asio/any_completion_handler.hpp>
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/append.hpp>
#include <boost/asio/as_tuple.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_cancellation_slot.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/associated_immediate_executor.hpp>
#include <boost/asio/associator.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/basic_datagram_socket.hpp>
#include <boost/asio/basic_deadline_timer.hpp>
#include <boost/asio/basic_file.hpp>
#include <boost/asio/basic_io_object.hpp>
#include <boost/asio/basic_random_access_file.hpp>
#include <boost/asio/basic_raw_socket.hpp>
#include <boost/asio/basic_readable_pipe.hpp>
#include <boost/asio/basic_seq_packet_socket.hpp>
#include <boost/asio/basic_serial_port.hpp>
#include <boost/asio/basic_signal_set.hpp>
#include <boost/asio/basic_socket.hpp>
#include <boost/asio/basic_socket_acceptor.hpp>
#include <boost/asio/basic_socket_iostream.hpp>
#include <boost/asio/basic_socket_streambuf.hpp>
#include <boost/asio/basic_stream_file.hpp>
#include <boost/asio/basic_stream_socket.hpp>
#include <boost/asio/basic_streambuf.hpp>
#include <boost/asio/basic_waitable_timer.hpp>
#include <boost/asio/basic_writable_pipe.hpp>
#include <boost/asio/bind_allocator.hpp>
#include <boost/asio/bind_cancellation_slot.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/bind_immediate_executor.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/buffer_registration.hpp>
#include <boost/asio/buffered_read_stream_fwd.hpp>
#include <boost/asio/buffered_read_stream.hpp>
#include <boost/asio/buffered_stream_fwd.hpp>
#include <boost/asio/buffered_stream.hpp>
#include <boost/asio/buffered_write_stream_fwd.hpp>
#include <boost/asio/buffered_write_stream.hpp>
#include <boost/asio/buffers_iterator.hpp>
#include <boost/asio/cancel_after.hpp>
#include <boost/asio/cancel_at.hpp>
#include <boost/asio/cancellation_signal.hpp>
#include <boost/asio/cancellation_state.hpp>
#include <boost/asio/cancellation_type.hpp>
#include <boost/asio/co_composed.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/completion_condition.hpp>
#include <boost/asio/compose.hpp>
#include <boost/asio/composed.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/connect_pipe.hpp>
#include <boost/asio/consign.hpp>
#include <boost/asio/coroutine.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/defer.hpp>
#include <boost/asio/deferred.hpp>
#include <boost/asio/default_completion_token.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/execution.hpp>
#include <boost/asio/execution/allocator.hpp>
#include <boost/asio/execution/any_executor.hpp>
#include <boost/asio/execution/blocking.hpp>
#include <boost/asio/execution/blocking_adaptation.hpp>
#include <boost/asio/execution/context.hpp>
#include <boost/asio/execution/context_as.hpp>
#include <boost/asio/execution/executor.hpp>
#include <boost/asio/execution/invocable_archetype.hpp>
#include <boost/asio/execution/mapping.hpp>
#include <boost/asio/execution/occupancy.hpp>
#include <boost/asio/execution/outstanding_work.hpp>
#include <boost/asio/execution/prefer_only.hpp>
#include <boost/asio/execution/relationship.hpp>
#include <boost/asio/executor.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/file_base.hpp>
#include <boost/asio/generic/basic_endpoint.hpp>
#include <boost/asio/generic/datagram_protocol.hpp>
#include <boost/asio/generic/raw_protocol.hpp>
#include <boost/asio/generic/seq_packet_protocol.hpp>
#include <boost/asio/generic/stream_protocol.hpp>
#include <boost/asio/handler_continuation_hook.hpp>
#include <boost/asio/high_resolution_timer.hpp>
#include <boost/asio/immediate.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/io_context_strand.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_service_strand.hpp>
#include <boost/asio/ip/address.hpp>
#include <boost/asio/ip/address_v4.hpp>
#include <boost/asio/ip/address_v4_iterator.hpp>
#include <boost/asio/ip/address_v4_range.hpp>
#include <boost/asio/ip/address_v6.hpp>
#include <boost/asio/ip/address_v6_iterator.hpp>
#include <boost/asio/ip/address_v6_range.hpp>
#include <boost/asio/ip/network_v4.hpp>
#include <boost/asio/ip/network_v6.hpp>
#include <boost/asio/ip/bad_address_cast.hpp>
#include <boost/asio/ip/basic_endpoint.hpp>
#include <boost/asio/ip/basic_resolver.hpp>
#include <boost/asio/ip/basic_resolver_entry.hpp>
#include <boost/asio/ip/basic_resolver_iterator.hpp>
#include <boost/asio/ip/basic_resolver_query.hpp>
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/icmp.hpp>
#include <boost/asio/ip/multicast.hpp>
#include <boost/asio/ip/resolver_base.hpp>
#include <boost/asio/ip/resolver_query_base.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ip/udp.hpp>
#include <boost/asio/ip/unicast.hpp>
#include <boost/asio/ip/v6_only.hpp>
#include <boost/asio/is_applicable_property.hpp>
#include <boost/asio/is_contiguous_iterator.hpp>
#include <boost/asio/is_executor.hpp>
#include <boost/asio/is_read_buffered.hpp>
#include <boost/asio/is_write_buffered.hpp>
#include <boost/asio/local/basic_endpoint.hpp>
#include <boost/asio/local/connect_pair.hpp>
#include <boost/asio/local/datagram_protocol.hpp>
#include <boost/asio/local/seq_packet_protocol.hpp>
#include <boost/asio/local/stream_protocol.hpp>
#include <boost/asio/multiple_exceptions.hpp>
#include <boost/asio/packaged_task.hpp>
#include <boost/asio/placeholders.hpp>
#include <boost/asio/posix/basic_descriptor.hpp>
#include <boost/asio/posix/basic_stream_descriptor.hpp>
#include <boost/asio/posix/descriptor.hpp>
#include <boost/asio/posix/descriptor_base.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/prefer.hpp>
#include <boost/asio/prepend.hpp>
#include <boost/asio/query.hpp>
#include <boost/asio/random_access_file.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/read_at.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/asio/readable_pipe.hpp>
#include <boost/asio/recycling_allocator.hpp>
#include <boost/asio/redirect_error.hpp>
#include <boost/asio/registered_buffer.hpp>
#include <boost/asio/require.hpp>
#include <boost/asio/require_concept.hpp>
#include <boost/asio/serial_port.hpp>
#include <boost/asio/serial_port_base.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/asio/signal_set_base.hpp>
#include <boost/asio/socket_base.hpp>
#include <boost/asio/static_thread_pool.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/stream_file.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/system_context.hpp>
#include <boost/asio/system_executor.hpp>
#include <boost/asio/system_timer.hpp>
#include <boost/asio/this_coro.hpp>
#include <boost/asio/thread_pool.hpp>
#include <boost/asio/time_traits.hpp>
#include <boost/asio/use_awaitable.hpp>
#include <boost/asio/use_future.hpp>
#include <boost/asio/uses_executor.hpp>
#include <boost/asio/version.hpp>
#include <boost/asio/wait_traits.hpp>
#include <boost/asio/windows/basic_object_handle.hpp>
#include <boost/asio/windows/basic_overlapped_handle.hpp>
#include <boost/asio/windows/basic_random_access_handle.hpp>
#include <boost/asio/windows/basic_stream_handle.hpp>
#include <boost/asio/windows/object_handle.hpp>
#include <boost/asio/windows/overlapped_handle.hpp>
#include <boost/asio/windows/overlapped_ptr.hpp>
#include <boost/asio/windows/random_access_handle.hpp>
#include <boost/asio/windows/stream_handle.hpp>
#include <boost/asio/writable_pipe.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/write_at.hpp>
#endif // BOOST_ASIO_HPP

View File

@ -0,0 +1,338 @@
//
// any_completion_executor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_ANY_COMPLETION_EXECUTOR_HPP
#define BOOST_ASIO_ANY_COMPLETION_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include <boost/asio/executor.hpp>
#else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include <boost/asio/execution.hpp>
#endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
#if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
typedef executor any_completion_executor;
#else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
/// Polymorphic executor type for use with I/O objects.
/**
* The @c any_completion_executor type is a polymorphic executor that supports
* the set of properties required for the execution of completion handlers. It
* is defined as the execution::any_executor class template parameterised as
* follows:
* @code execution::any_executor<
* execution::prefer_only<execution::outstanding_work_t::tracked_t>,
* execution::prefer_only<execution::outstanding_work_t::untracked_t>
* execution::prefer_only<execution::relationship_t::fork_t>,
* execution::prefer_only<execution::relationship_t::continuation_t>
* > @endcode
*/
class any_completion_executor :
#if defined(GENERATING_DOCUMENTATION)
public execution::any_executor<...>
#else // defined(GENERATING_DOCUMENTATION)
public execution::any_executor<
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
>
#endif // defined(GENERATING_DOCUMENTATION)
{
public:
#if !defined(GENERATING_DOCUMENTATION)
typedef execution::any_executor<
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
> base_type;
typedef void supportable_properties_type(
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
);
#endif // !defined(GENERATING_DOCUMENTATION)
/// Default constructor.
BOOST_ASIO_DECL any_completion_executor() noexcept;
/// Construct in an empty state. Equivalent effects to default constructor.
BOOST_ASIO_DECL any_completion_executor(nullptr_t) noexcept;
/// Copy constructor.
BOOST_ASIO_DECL any_completion_executor(
const any_completion_executor& e) noexcept;
/// Move constructor.
BOOST_ASIO_DECL any_completion_executor(
any_completion_executor&& e) noexcept;
/// Construct to point to the same target as another any_executor.
#if defined(GENERATING_DOCUMENTATION)
template <class... OtherSupportableProperties>
any_completion_executor(
execution::any_executor<OtherSupportableProperties...> e);
#else // defined(GENERATING_DOCUMENTATION)
template <typename OtherAnyExecutor>
any_completion_executor(OtherAnyExecutor e,
constraint_t<
conditional<
!is_same<OtherAnyExecutor, any_completion_executor>::value
&& is_base_of<execution::detail::any_executor_base,
OtherAnyExecutor>::value,
typename execution::detail::supportable_properties<
0, supportable_properties_type>::template
is_valid_target<OtherAnyExecutor>,
false_type
>::type::value
> = 0)
: base_type(static_cast<OtherAnyExecutor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct to point to the same target as another any_executor.
#if defined(GENERATING_DOCUMENTATION)
template <class... OtherSupportableProperties>
any_completion_executor(std::nothrow_t,
execution::any_executor<OtherSupportableProperties...> e);
#else // defined(GENERATING_DOCUMENTATION)
template <typename OtherAnyExecutor>
any_completion_executor(std::nothrow_t, OtherAnyExecutor e,
constraint_t<
conditional<
!is_same<OtherAnyExecutor, any_completion_executor>::value
&& is_base_of<execution::detail::any_executor_base,
OtherAnyExecutor>::value,
typename execution::detail::supportable_properties<
0, supportable_properties_type>::template
is_valid_target<OtherAnyExecutor>,
false_type
>::type::value
> = 0) noexcept
: base_type(std::nothrow, static_cast<OtherAnyExecutor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct to point to the same target as another any_executor.
BOOST_ASIO_DECL any_completion_executor(std::nothrow_t,
const any_completion_executor& e) noexcept;
/// Construct to point to the same target as another any_executor.
BOOST_ASIO_DECL any_completion_executor(std::nothrow_t,
any_completion_executor&& e) noexcept;
/// Construct a polymorphic wrapper for the specified executor.
#if defined(GENERATING_DOCUMENTATION)
template <BOOST_ASIO_EXECUTION_EXECUTOR Executor>
any_completion_executor(Executor e);
#else // defined(GENERATING_DOCUMENTATION)
template <BOOST_ASIO_EXECUTION_EXECUTOR Executor>
any_completion_executor(Executor e,
constraint_t<
conditional<
!is_same<Executor, any_completion_executor>::value
&& !is_base_of<execution::detail::any_executor_base,
Executor>::value,
execution::detail::is_valid_target_executor<
Executor, supportable_properties_type>,
false_type
>::type::value
> = 0)
: base_type(static_cast<Executor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct a polymorphic wrapper for the specified executor.
#if defined(GENERATING_DOCUMENTATION)
template <BOOST_ASIO_EXECUTION_EXECUTOR Executor>
any_completion_executor(std::nothrow_t, Executor e);
#else // defined(GENERATING_DOCUMENTATION)
template <BOOST_ASIO_EXECUTION_EXECUTOR Executor>
any_completion_executor(std::nothrow_t, Executor e,
constraint_t<
conditional<
!is_same<Executor, any_completion_executor>::value
&& !is_base_of<execution::detail::any_executor_base,
Executor>::value,
execution::detail::is_valid_target_executor<
Executor, supportable_properties_type>,
false_type
>::type::value
> = 0) noexcept
: base_type(std::nothrow, static_cast<Executor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Assignment operator.
BOOST_ASIO_DECL any_completion_executor& operator=(
const any_completion_executor& e) noexcept;
/// Move assignment operator.
BOOST_ASIO_DECL any_completion_executor& operator=(
any_completion_executor&& e) noexcept;
/// Assignment operator that sets the polymorphic wrapper to the empty state.
BOOST_ASIO_DECL any_completion_executor& operator=(nullptr_t);
/// Destructor.
BOOST_ASIO_DECL ~any_completion_executor();
/// Swap targets with another polymorphic wrapper.
BOOST_ASIO_DECL void swap(any_completion_executor& other) noexcept;
/// Obtain a polymorphic wrapper with the specified property.
/**
* Do not call this function directly. It is intended for use with the
* boost::asio::require and boost::asio::prefer customisation points.
*
* For example:
* @code any_completion_executor ex = ...;
* auto ex2 = boost::asio::require(ex, execution::relationship.fork); @endcode
*/
template <typename Property>
any_completion_executor require(const Property& p,
constraint_t<
traits::require_member<const base_type&, const Property&>::is_valid
> = 0) const
{
return static_cast<const base_type&>(*this).require(p);
}
/// Obtain a polymorphic wrapper with the specified property.
/**
* Do not call this function directly. It is intended for use with the
* boost::asio::prefer customisation point.
*
* For example:
* @code any_completion_executor ex = ...;
* auto ex2 = boost::asio::prefer(ex, execution::relationship.fork); @endcode
*/
template <typename Property>
any_completion_executor prefer(const Property& p,
constraint_t<
traits::prefer_member<const base_type&, const Property&>::is_valid
> = 0) const
{
return static_cast<const base_type&>(*this).prefer(p);
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <>
BOOST_ASIO_DECL any_completion_executor any_completion_executor::prefer(
const execution::outstanding_work_t::tracked_t&, int) const;
template <>
BOOST_ASIO_DECL any_completion_executor any_completion_executor::prefer(
const execution::outstanding_work_t::untracked_t&, int) const;
template <>
BOOST_ASIO_DECL any_completion_executor any_completion_executor::prefer(
const execution::relationship_t::fork_t&, int) const;
template <>
BOOST_ASIO_DECL any_completion_executor any_completion_executor::prefer(
const execution::relationship_t::continuation_t&, int) const;
namespace traits {
#if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
template <>
struct equality_comparable<any_completion_executor>
{
static const bool is_valid = true;
static const bool is_noexcept = true;
};
#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
template <typename F>
struct execute_member<any_completion_executor, F>
{
static const bool is_valid = true;
static const bool is_noexcept = false;
typedef void result_type;
};
#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
template <typename Prop>
struct query_member<any_completion_executor, Prop> :
query_member<any_completion_executor::base_type, Prop>
{
};
#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
template <typename Prop>
struct require_member<any_completion_executor, Prop> :
require_member<any_completion_executor::base_type, Prop>
{
typedef any_completion_executor result_type;
};
#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
template <typename Prop>
struct prefer_member<any_completion_executor, Prop> :
prefer_member<any_completion_executor::base_type, Prop>
{
typedef any_completion_executor result_type;
};
#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
} // namespace traits
#endif // !defined(GENERATING_DOCUMENTATION)
#endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#if defined(BOOST_ASIO_HEADER_ONLY) \
&& !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include <boost/asio/impl/any_completion_executor.ipp>
#endif // defined(BOOST_ASIO_HEADER_ONLY)
// && !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
#endif // BOOST_ASIO_ANY_COMPLETION_EXECUTOR_HPP

View File

@ -0,0 +1,824 @@
//
// any_completion_handler.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_ANY_COMPLETION_HANDLER_HPP
#define BOOST_ASIO_ANY_COMPLETION_HANDLER_HPP
#include <boost/asio/detail/config.hpp>
#include <cstring>
#include <functional>
#include <memory>
#include <utility>
#include <boost/asio/any_completion_executor.hpp>
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_cancellation_slot.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/associated_immediate_executor.hpp>
#include <boost/asio/cancellation_state.hpp>
#include <boost/asio/recycling_allocator.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
class any_completion_handler_impl_base
{
public:
template <typename S>
explicit any_completion_handler_impl_base(S&& slot)
: cancel_state_(static_cast<S&&>(slot), enable_total_cancellation())
{
}
cancellation_slot get_cancellation_slot() const noexcept
{
return cancel_state_.slot();
}
private:
cancellation_state cancel_state_;
};
template <typename Handler>
class any_completion_handler_impl :
public any_completion_handler_impl_base
{
public:
template <typename S, typename H>
any_completion_handler_impl(S&& slot, H&& h)
: any_completion_handler_impl_base(static_cast<S&&>(slot)),
handler_(static_cast<H&&>(h))
{
}
struct uninit_deleter
{
typename std::allocator_traits<
associated_allocator_t<Handler,
boost::asio::recycling_allocator<void>>>::template
rebind_alloc<any_completion_handler_impl> alloc;
void operator()(any_completion_handler_impl* ptr)
{
std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1);
}
};
struct deleter
{
typename std::allocator_traits<
associated_allocator_t<Handler,
boost::asio::recycling_allocator<void>>>::template
rebind_alloc<any_completion_handler_impl> alloc;
void operator()(any_completion_handler_impl* ptr)
{
std::allocator_traits<decltype(alloc)>::destroy(alloc, ptr);
std::allocator_traits<decltype(alloc)>::deallocate(alloc, ptr, 1);
}
};
template <typename S, typename H>
static any_completion_handler_impl* create(S&& slot, H&& h)
{
uninit_deleter d{
(get_associated_allocator)(h,
boost::asio::recycling_allocator<void>())};
std::unique_ptr<any_completion_handler_impl, uninit_deleter> uninit_ptr(
std::allocator_traits<decltype(d.alloc)>::allocate(d.alloc, 1), d);
any_completion_handler_impl* ptr =
new (uninit_ptr.get()) any_completion_handler_impl(
static_cast<S&&>(slot), static_cast<H&&>(h));
uninit_ptr.release();
return ptr;
}
void destroy()
{
deleter d{
(get_associated_allocator)(handler_,
boost::asio::recycling_allocator<void>())};
d(this);
}
any_completion_executor executor(
const any_completion_executor& candidate) const noexcept
{
return any_completion_executor(std::nothrow,
(get_associated_executor)(handler_, candidate));
}
any_completion_executor immediate_executor(
const any_io_executor& candidate) const noexcept
{
return any_completion_executor(std::nothrow,
(get_associated_immediate_executor)(handler_, candidate));
}
void* allocate(std::size_t size, std::size_t align) const
{
typename std::allocator_traits<
associated_allocator_t<Handler,
boost::asio::recycling_allocator<void>>>::template
rebind_alloc<unsigned char> alloc(
(get_associated_allocator)(handler_,
boost::asio::recycling_allocator<void>()));
std::size_t space = size + align - 1;
unsigned char* base =
std::allocator_traits<decltype(alloc)>::allocate(
alloc, space + sizeof(std::ptrdiff_t));
void* p = base;
if (detail::align(align, size, p, space))
{
std::ptrdiff_t off = static_cast<unsigned char*>(p) - base;
std::memcpy(static_cast<unsigned char*>(p) + size, &off, sizeof(off));
return p;
}
std::bad_alloc ex;
boost::asio::detail::throw_exception(ex);
return nullptr;
}
void deallocate(void* p, std::size_t size, std::size_t align) const
{
if (p)
{
typename std::allocator_traits<
associated_allocator_t<Handler,
boost::asio::recycling_allocator<void>>>::template
rebind_alloc<unsigned char> alloc(
(get_associated_allocator)(handler_,
boost::asio::recycling_allocator<void>()));
std::ptrdiff_t off;
std::memcpy(&off, static_cast<unsigned char*>(p) + size, sizeof(off));
unsigned char* base = static_cast<unsigned char*>(p) - off;
std::allocator_traits<decltype(alloc)>::deallocate(
alloc, base, size + align -1 + sizeof(std::ptrdiff_t));
}
}
template <typename... Args>
void call(Args&&... args)
{
deleter d{
(get_associated_allocator)(handler_,
boost::asio::recycling_allocator<void>())};
std::unique_ptr<any_completion_handler_impl, deleter> ptr(this, d);
Handler handler(static_cast<Handler&&>(handler_));
ptr.reset();
static_cast<Handler&&>(handler)(
static_cast<Args&&>(args)...);
}
private:
Handler handler_;
};
template <typename Signature>
class any_completion_handler_call_fn;
template <typename R, typename... Args>
class any_completion_handler_call_fn<R(Args...)>
{
public:
using type = void(*)(any_completion_handler_impl_base*, Args...);
constexpr any_completion_handler_call_fn(type fn)
: call_fn_(fn)
{
}
void call(any_completion_handler_impl_base* impl, Args... args) const
{
call_fn_(impl, static_cast<Args&&>(args)...);
}
template <typename Handler>
static void impl(any_completion_handler_impl_base* impl, Args... args)
{
static_cast<any_completion_handler_impl<Handler>*>(impl)->call(
static_cast<Args&&>(args)...);
}
private:
type call_fn_;
};
template <typename... Signatures>
class any_completion_handler_call_fns;
template <typename Signature>
class any_completion_handler_call_fns<Signature> :
public any_completion_handler_call_fn<Signature>
{
public:
using any_completion_handler_call_fn<
Signature>::any_completion_handler_call_fn;
using any_completion_handler_call_fn<Signature>::call;
};
template <typename Signature, typename... Signatures>
class any_completion_handler_call_fns<Signature, Signatures...> :
public any_completion_handler_call_fn<Signature>,
public any_completion_handler_call_fns<Signatures...>
{
public:
template <typename CallFn, typename... CallFns>
constexpr any_completion_handler_call_fns(CallFn fn, CallFns... fns)
: any_completion_handler_call_fn<Signature>(fn),
any_completion_handler_call_fns<Signatures...>(fns...)
{
}
using any_completion_handler_call_fn<Signature>::call;
using any_completion_handler_call_fns<Signatures...>::call;
};
class any_completion_handler_destroy_fn
{
public:
using type = void(*)(any_completion_handler_impl_base*);
constexpr any_completion_handler_destroy_fn(type fn)
: destroy_fn_(fn)
{
}
void destroy(any_completion_handler_impl_base* impl) const
{
destroy_fn_(impl);
}
template <typename Handler>
static void impl(any_completion_handler_impl_base* impl)
{
static_cast<any_completion_handler_impl<Handler>*>(impl)->destroy();
}
private:
type destroy_fn_;
};
class any_completion_handler_executor_fn
{
public:
using type = any_completion_executor(*)(
any_completion_handler_impl_base*, const any_completion_executor&);
constexpr any_completion_handler_executor_fn(type fn)
: executor_fn_(fn)
{
}
any_completion_executor executor(any_completion_handler_impl_base* impl,
const any_completion_executor& candidate) const
{
return executor_fn_(impl, candidate);
}
template <typename Handler>
static any_completion_executor impl(any_completion_handler_impl_base* impl,
const any_completion_executor& candidate)
{
return static_cast<any_completion_handler_impl<Handler>*>(impl)->executor(
candidate);
}
private:
type executor_fn_;
};
class any_completion_handler_immediate_executor_fn
{
public:
using type = any_completion_executor(*)(
any_completion_handler_impl_base*, const any_io_executor&);
constexpr any_completion_handler_immediate_executor_fn(type fn)
: immediate_executor_fn_(fn)
{
}
any_completion_executor immediate_executor(
any_completion_handler_impl_base* impl,
const any_io_executor& candidate) const
{
return immediate_executor_fn_(impl, candidate);
}
template <typename Handler>
static any_completion_executor impl(any_completion_handler_impl_base* impl,
const any_io_executor& candidate)
{
return static_cast<any_completion_handler_impl<Handler>*>(
impl)->immediate_executor(candidate);
}
private:
type immediate_executor_fn_;
};
class any_completion_handler_allocate_fn
{
public:
using type = void*(*)(any_completion_handler_impl_base*,
std::size_t, std::size_t);
constexpr any_completion_handler_allocate_fn(type fn)
: allocate_fn_(fn)
{
}
void* allocate(any_completion_handler_impl_base* impl,
std::size_t size, std::size_t align) const
{
return allocate_fn_(impl, size, align);
}
template <typename Handler>
static void* impl(any_completion_handler_impl_base* impl,
std::size_t size, std::size_t align)
{
return static_cast<any_completion_handler_impl<Handler>*>(impl)->allocate(
size, align);
}
private:
type allocate_fn_;
};
class any_completion_handler_deallocate_fn
{
public:
using type = void(*)(any_completion_handler_impl_base*,
void*, std::size_t, std::size_t);
constexpr any_completion_handler_deallocate_fn(type fn)
: deallocate_fn_(fn)
{
}
void deallocate(any_completion_handler_impl_base* impl,
void* p, std::size_t size, std::size_t align) const
{
deallocate_fn_(impl, p, size, align);
}
template <typename Handler>
static void impl(any_completion_handler_impl_base* impl,
void* p, std::size_t size, std::size_t align)
{
static_cast<any_completion_handler_impl<Handler>*>(impl)->deallocate(
p, size, align);
}
private:
type deallocate_fn_;
};
template <typename... Signatures>
class any_completion_handler_fn_table
: private any_completion_handler_destroy_fn,
private any_completion_handler_executor_fn,
private any_completion_handler_immediate_executor_fn,
private any_completion_handler_allocate_fn,
private any_completion_handler_deallocate_fn,
private any_completion_handler_call_fns<Signatures...>
{
public:
template <typename... CallFns>
constexpr any_completion_handler_fn_table(
any_completion_handler_destroy_fn::type destroy_fn,
any_completion_handler_executor_fn::type executor_fn,
any_completion_handler_immediate_executor_fn::type immediate_executor_fn,
any_completion_handler_allocate_fn::type allocate_fn,
any_completion_handler_deallocate_fn::type deallocate_fn,
CallFns... call_fns)
: any_completion_handler_destroy_fn(destroy_fn),
any_completion_handler_executor_fn(executor_fn),
any_completion_handler_immediate_executor_fn(immediate_executor_fn),
any_completion_handler_allocate_fn(allocate_fn),
any_completion_handler_deallocate_fn(deallocate_fn),
any_completion_handler_call_fns<Signatures...>(call_fns...)
{
}
using any_completion_handler_destroy_fn::destroy;
using any_completion_handler_executor_fn::executor;
using any_completion_handler_immediate_executor_fn::immediate_executor;
using any_completion_handler_allocate_fn::allocate;
using any_completion_handler_deallocate_fn::deallocate;
using any_completion_handler_call_fns<Signatures...>::call;
};
template <typename Handler, typename... Signatures>
struct any_completion_handler_fn_table_instance
{
static constexpr any_completion_handler_fn_table<Signatures...>
value = any_completion_handler_fn_table<Signatures...>(
&any_completion_handler_destroy_fn::impl<Handler>,
&any_completion_handler_executor_fn::impl<Handler>,
&any_completion_handler_immediate_executor_fn::impl<Handler>,
&any_completion_handler_allocate_fn::impl<Handler>,
&any_completion_handler_deallocate_fn::impl<Handler>,
&any_completion_handler_call_fn<Signatures>::template impl<Handler>...);
};
template <typename Handler, typename... Signatures>
constexpr any_completion_handler_fn_table<Signatures...>
any_completion_handler_fn_table_instance<Handler, Signatures...>::value;
} // namespace detail
template <typename... Signatures>
class any_completion_handler;
/// An allocator type that forwards memory allocation operations through an
/// instance of @c any_completion_handler.
template <typename T, typename... Signatures>
class any_completion_handler_allocator
{
private:
template <typename...>
friend class any_completion_handler;
template <typename, typename...>
friend class any_completion_handler_allocator;
const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
detail::any_completion_handler_impl_base* impl_;
constexpr any_completion_handler_allocator(int,
const any_completion_handler<Signatures...>& h) noexcept
: fn_table_(h.fn_table_),
impl_(h.impl_)
{
}
public:
/// The type of objects that may be allocated by the allocator.
typedef T value_type;
/// Rebinds an allocator to another value type.
template <typename U>
struct rebind
{
/// Specifies the type of the rebound allocator.
typedef any_completion_handler_allocator<U, Signatures...> other;
};
/// Construct from another @c any_completion_handler_allocator.
template <typename U>
constexpr any_completion_handler_allocator(
const any_completion_handler_allocator<U, Signatures...>& a)
noexcept
: fn_table_(a.fn_table_),
impl_(a.impl_)
{
}
/// Equality operator.
constexpr bool operator==(
const any_completion_handler_allocator& other) const noexcept
{
return fn_table_ == other.fn_table_ && impl_ == other.impl_;
}
/// Inequality operator.
constexpr bool operator!=(
const any_completion_handler_allocator& other) const noexcept
{
return fn_table_ != other.fn_table_ || impl_ != other.impl_;
}
/// Allocate space for @c n objects of the allocator's value type.
T* allocate(std::size_t n) const
{
if (fn_table_)
{
return static_cast<T*>(
fn_table_->allocate(
impl_, sizeof(T) * n, alignof(T)));
}
std::bad_alloc ex;
boost::asio::detail::throw_exception(ex);
return nullptr;
}
/// Deallocate space for @c n objects of the allocator's value type.
void deallocate(T* p, std::size_t n) const
{
fn_table_->deallocate(impl_, p, sizeof(T) * n, alignof(T));
}
};
/// A protoco-allocator type that may be rebound to obtain an allocator that
/// forwards memory allocation operations through an instance of
/// @c any_completion_handler.
template <typename... Signatures>
class any_completion_handler_allocator<void, Signatures...>
{
private:
template <typename...>
friend class any_completion_handler;
template <typename, typename...>
friend class any_completion_handler_allocator;
const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
detail::any_completion_handler_impl_base* impl_;
constexpr any_completion_handler_allocator(int,
const any_completion_handler<Signatures...>& h) noexcept
: fn_table_(h.fn_table_),
impl_(h.impl_)
{
}
public:
/// @c void as no objects can be allocated through a proto-allocator.
typedef void value_type;
/// Rebinds an allocator to another value type.
template <typename U>
struct rebind
{
/// Specifies the type of the rebound allocator.
typedef any_completion_handler_allocator<U, Signatures...> other;
};
/// Construct from another @c any_completion_handler_allocator.
template <typename U>
constexpr any_completion_handler_allocator(
const any_completion_handler_allocator<U, Signatures...>& a)
noexcept
: fn_table_(a.fn_table_),
impl_(a.impl_)
{
}
/// Equality operator.
constexpr bool operator==(
const any_completion_handler_allocator& other) const noexcept
{
return fn_table_ == other.fn_table_ && impl_ == other.impl_;
}
/// Inequality operator.
constexpr bool operator!=(
const any_completion_handler_allocator& other) const noexcept
{
return fn_table_ != other.fn_table_ || impl_ != other.impl_;
}
};
/// Polymorphic wrapper for completion handlers.
/**
* The @c any_completion_handler class template is a polymorphic wrapper for
* completion handlers that propagates the associated executor, associated
* allocator, and associated cancellation slot through a type-erasing interface.
*
* When using @c any_completion_handler, specify one or more completion
* signatures as template parameters. These will dictate the arguments that may
* be passed to the handler through the polymorphic interface.
*
* Typical uses for @c any_completion_handler include:
*
* @li Separate compilation of asynchronous operation implementations.
*
* @li Enabling interoperability between asynchronous operations and virtual
* functions.
*/
template <typename... Signatures>
class any_completion_handler
{
#if !defined(GENERATING_DOCUMENTATION)
private:
template <typename, typename...>
friend class any_completion_handler_allocator;
template <typename, typename>
friend struct associated_executor;
template <typename, typename>
friend struct associated_immediate_executor;
const detail::any_completion_handler_fn_table<Signatures...>* fn_table_;
detail::any_completion_handler_impl_base* impl_;
#endif // !defined(GENERATING_DOCUMENTATION)
public:
/// The associated allocator type.
using allocator_type = any_completion_handler_allocator<void, Signatures...>;
/// The associated cancellation slot type.
using cancellation_slot_type = cancellation_slot;
/// Construct an @c any_completion_handler in an empty state, without a target
/// object.
constexpr any_completion_handler()
: fn_table_(nullptr),
impl_(nullptr)
{
}
/// Construct an @c any_completion_handler in an empty state, without a target
/// object.
constexpr any_completion_handler(nullptr_t)
: fn_table_(nullptr),
impl_(nullptr)
{
}
/// Construct an @c any_completion_handler to contain the specified target.
template <typename H, typename Handler = decay_t<H>>
any_completion_handler(H&& h,
constraint_t<
!is_same<decay_t<H>, any_completion_handler>::value
> = 0)
: fn_table_(
&detail::any_completion_handler_fn_table_instance<
Handler, Signatures...>::value),
impl_(detail::any_completion_handler_impl<Handler>::create(
(get_associated_cancellation_slot)(h), static_cast<H&&>(h)))
{
}
/// Move-construct an @c any_completion_handler from another.
/**
* After the operation, the moved-from object @c other has no target.
*/
any_completion_handler(any_completion_handler&& other) noexcept
: fn_table_(other.fn_table_),
impl_(other.impl_)
{
other.fn_table_ = nullptr;
other.impl_ = nullptr;
}
/// Move-assign an @c any_completion_handler from another.
/**
* After the operation, the moved-from object @c other has no target.
*/
any_completion_handler& operator=(
any_completion_handler&& other) noexcept
{
any_completion_handler(
static_cast<any_completion_handler&&>(other)).swap(*this);
return *this;
}
/// Assignment operator that sets the polymorphic wrapper to the empty state.
any_completion_handler& operator=(nullptr_t) noexcept
{
any_completion_handler().swap(*this);
return *this;
}
/// Destructor.
~any_completion_handler()
{
if (impl_)
fn_table_->destroy(impl_);
}
/// Test if the polymorphic wrapper is empty.
constexpr explicit operator bool() const noexcept
{
return impl_ != nullptr;
}
/// Test if the polymorphic wrapper is non-empty.
constexpr bool operator!() const noexcept
{
return impl_ == nullptr;
}
/// Swap the content of an @c any_completion_handler with another.
void swap(any_completion_handler& other) noexcept
{
std::swap(fn_table_, other.fn_table_);
std::swap(impl_, other.impl_);
}
/// Get the associated allocator.
allocator_type get_allocator() const noexcept
{
return allocator_type(0, *this);
}
/// Get the associated cancellation slot.
cancellation_slot_type get_cancellation_slot() const noexcept
{
return impl_ ? impl_->get_cancellation_slot() : cancellation_slot_type();
}
/// Function call operator.
/**
* Invokes target completion handler with the supplied arguments.
*
* This function may only be called once, as the target handler is moved from.
* The polymorphic wrapper is left in an empty state.
*
* Throws @c std::bad_function_call if the polymorphic wrapper is empty.
*/
template <typename... Args>
auto operator()(Args&&... args)
-> decltype(fn_table_->call(impl_, static_cast<Args&&>(args)...))
{
if (detail::any_completion_handler_impl_base* impl = impl_)
{
impl_ = nullptr;
return fn_table_->call(impl, static_cast<Args&&>(args)...);
}
std::bad_function_call ex;
boost::asio::detail::throw_exception(ex);
}
/// Equality operator.
friend constexpr bool operator==(
const any_completion_handler& a, nullptr_t) noexcept
{
return a.impl_ == nullptr;
}
/// Equality operator.
friend constexpr bool operator==(
nullptr_t, const any_completion_handler& b) noexcept
{
return nullptr == b.impl_;
}
/// Inequality operator.
friend constexpr bool operator!=(
const any_completion_handler& a, nullptr_t) noexcept
{
return a.impl_ != nullptr;
}
/// Inequality operator.
friend constexpr bool operator!=(
nullptr_t, const any_completion_handler& b) noexcept
{
return nullptr != b.impl_;
}
};
template <typename... Signatures, typename Candidate>
struct associated_executor<any_completion_handler<Signatures...>, Candidate>
{
using type = any_completion_executor;
static type get(const any_completion_handler<Signatures...>& handler,
const Candidate& candidate = Candidate()) noexcept
{
any_completion_executor any_candidate(std::nothrow, candidate);
return handler.fn_table_
? handler.fn_table_->executor(handler.impl_, any_candidate)
: any_candidate;
}
};
template <typename... Signatures, typename Candidate>
struct associated_immediate_executor<
any_completion_handler<Signatures...>, Candidate>
{
using type = any_completion_executor;
static type get(const any_completion_handler<Signatures...>& handler,
const Candidate& candidate = Candidate()) noexcept
{
any_io_executor any_candidate(std::nothrow, candidate);
return handler.fn_table_
? handler.fn_table_->immediate_executor(handler.impl_, any_candidate)
: any_candidate;
}
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_ANY_COMPLETION_HANDLER_HPP

View File

@ -0,0 +1,353 @@
//
// any_io_executor.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_ANY_IO_EXECUTOR_HPP
#define BOOST_ASIO_ANY_IO_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include <boost/asio/executor.hpp>
#else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include <boost/asio/execution.hpp>
# include <boost/asio/execution_context.hpp>
#endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
#if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
typedef executor any_io_executor;
#else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
/// Polymorphic executor type for use with I/O objects.
/**
* The @c any_io_executor type is a polymorphic executor that supports the set
* of properties required by I/O objects. It is defined as the
* execution::any_executor class template parameterised as follows:
* @code execution::any_executor<
* execution::context_as_t<execution_context&>,
* execution::blocking_t::never_t,
* execution::prefer_only<execution::blocking_t::possibly_t>,
* execution::prefer_only<execution::outstanding_work_t::tracked_t>,
* execution::prefer_only<execution::outstanding_work_t::untracked_t>,
* execution::prefer_only<execution::relationship_t::fork_t>,
* execution::prefer_only<execution::relationship_t::continuation_t>
* > @endcode
*/
class any_io_executor :
#if defined(GENERATING_DOCUMENTATION)
public execution::any_executor<...>
#else // defined(GENERATING_DOCUMENTATION)
public execution::any_executor<
execution::context_as_t<execution_context&>,
execution::blocking_t::never_t,
execution::prefer_only<execution::blocking_t::possibly_t>,
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
>
#endif // defined(GENERATING_DOCUMENTATION)
{
public:
#if !defined(GENERATING_DOCUMENTATION)
typedef execution::any_executor<
execution::context_as_t<execution_context&>,
execution::blocking_t::never_t,
execution::prefer_only<execution::blocking_t::possibly_t>,
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
> base_type;
typedef void supportable_properties_type(
execution::context_as_t<execution_context&>,
execution::blocking_t::never_t,
execution::prefer_only<execution::blocking_t::possibly_t>,
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
);
#endif // !defined(GENERATING_DOCUMENTATION)
/// Default constructor.
BOOST_ASIO_DECL any_io_executor() noexcept;
/// Construct in an empty state. Equivalent effects to default constructor.
BOOST_ASIO_DECL any_io_executor(nullptr_t) noexcept;
/// Copy constructor.
BOOST_ASIO_DECL any_io_executor(const any_io_executor& e) noexcept;
/// Move constructor.
BOOST_ASIO_DECL any_io_executor(any_io_executor&& e) noexcept;
/// Construct to point to the same target as another any_executor.
#if defined(GENERATING_DOCUMENTATION)
template <class... OtherSupportableProperties>
any_io_executor(execution::any_executor<OtherSupportableProperties...> e);
#else // defined(GENERATING_DOCUMENTATION)
template <typename OtherAnyExecutor>
any_io_executor(OtherAnyExecutor e,
constraint_t<
conditional_t<
!is_same<OtherAnyExecutor, any_io_executor>::value
&& is_base_of<execution::detail::any_executor_base,
OtherAnyExecutor>::value,
typename execution::detail::supportable_properties<
0, supportable_properties_type>::template
is_valid_target<OtherAnyExecutor>,
false_type
>::value
> = 0)
: base_type(static_cast<OtherAnyExecutor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct to point to the same target as another any_executor.
#if defined(GENERATING_DOCUMENTATION)
template <class... OtherSupportableProperties>
any_io_executor(std::nothrow_t,
execution::any_executor<OtherSupportableProperties...> e);
#else // defined(GENERATING_DOCUMENTATION)
template <typename OtherAnyExecutor>
any_io_executor(std::nothrow_t, OtherAnyExecutor e,
constraint_t<
conditional_t<
!is_same<OtherAnyExecutor, any_io_executor>::value
&& is_base_of<execution::detail::any_executor_base,
OtherAnyExecutor>::value,
typename execution::detail::supportable_properties<
0, supportable_properties_type>::template
is_valid_target<OtherAnyExecutor>,
false_type
>::value
> = 0) noexcept
: base_type(std::nothrow, static_cast<OtherAnyExecutor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct to point to the same target as another any_executor.
BOOST_ASIO_DECL any_io_executor(std::nothrow_t,
const any_io_executor& e) noexcept;
/// Construct to point to the same target as another any_executor.
BOOST_ASIO_DECL any_io_executor(std::nothrow_t, any_io_executor&& e) noexcept;
/// Construct a polymorphic wrapper for the specified executor.
#if defined(GENERATING_DOCUMENTATION)
template <BOOST_ASIO_EXECUTION_EXECUTOR Executor>
any_io_executor(Executor e);
#else // defined(GENERATING_DOCUMENTATION)
template <BOOST_ASIO_EXECUTION_EXECUTOR Executor>
any_io_executor(Executor e,
constraint_t<
conditional_t<
!is_same<Executor, any_io_executor>::value
&& !is_base_of<execution::detail::any_executor_base,
Executor>::value,
execution::detail::is_valid_target_executor<
Executor, supportable_properties_type>,
false_type
>::value
> = 0)
: base_type(static_cast<Executor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct a polymorphic wrapper for the specified executor.
#if defined(GENERATING_DOCUMENTATION)
template <BOOST_ASIO_EXECUTION_EXECUTOR Executor>
any_io_executor(std::nothrow_t, Executor e);
#else // defined(GENERATING_DOCUMENTATION)
template <BOOST_ASIO_EXECUTION_EXECUTOR Executor>
any_io_executor(std::nothrow_t, Executor e,
constraint_t<
conditional_t<
!is_same<Executor, any_io_executor>::value
&& !is_base_of<execution::detail::any_executor_base,
Executor>::value,
execution::detail::is_valid_target_executor<
Executor, supportable_properties_type>,
false_type
>::value
> = 0) noexcept
: base_type(std::nothrow, static_cast<Executor&&>(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Assignment operator.
BOOST_ASIO_DECL any_io_executor& operator=(
const any_io_executor& e) noexcept;
/// Move assignment operator.
BOOST_ASIO_DECL any_io_executor& operator=(any_io_executor&& e) noexcept;
/// Assignment operator that sets the polymorphic wrapper to the empty state.
BOOST_ASIO_DECL any_io_executor& operator=(nullptr_t);
/// Destructor.
BOOST_ASIO_DECL ~any_io_executor();
/// Swap targets with another polymorphic wrapper.
BOOST_ASIO_DECL void swap(any_io_executor& other) noexcept;
/// Obtain a polymorphic wrapper with the specified property.
/**
* Do not call this function directly. It is intended for use with the
* boost::asio::require and boost::asio::prefer customisation points.
*
* For example:
* @code any_io_executor ex = ...;
* auto ex2 = boost::asio::require(ex, execution::blocking.possibly); @endcode
*/
template <typename Property>
any_io_executor require(const Property& p,
constraint_t<
traits::require_member<const base_type&, const Property&>::is_valid
> = 0) const
{
return static_cast<const base_type&>(*this).require(p);
}
/// Obtain a polymorphic wrapper with the specified property.
/**
* Do not call this function directly. It is intended for use with the
* boost::asio::prefer customisation point.
*
* For example:
* @code any_io_executor ex = ...;
* auto ex2 = boost::asio::prefer(ex, execution::blocking.possibly); @endcode
*/
template <typename Property>
any_io_executor prefer(const Property& p,
constraint_t<
traits::prefer_member<const base_type&, const Property&>::is_valid
> = 0) const
{
return static_cast<const base_type&>(*this).prefer(p);
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <>
BOOST_ASIO_DECL any_io_executor any_io_executor::require(
const execution::blocking_t::never_t&, int) const;
template <>
BOOST_ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::blocking_t::possibly_t&, int) const;
template <>
BOOST_ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::outstanding_work_t::tracked_t&, int) const;
template <>
BOOST_ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::outstanding_work_t::untracked_t&, int) const;
template <>
BOOST_ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::relationship_t::fork_t&, int) const;
template <>
BOOST_ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::relationship_t::continuation_t&, int) const;
namespace traits {
#if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
template <>
struct equality_comparable<any_io_executor>
{
static const bool is_valid = true;
static const bool is_noexcept = true;
};
#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
#if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
template <typename F>
struct execute_member<any_io_executor, F>
{
static const bool is_valid = true;
static const bool is_noexcept = false;
typedef void result_type;
};
#endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
#if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
template <typename Prop>
struct query_member<any_io_executor, Prop> :
query_member<any_io_executor::base_type, Prop>
{
};
#endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
#if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
template <typename Prop>
struct require_member<any_io_executor, Prop> :
require_member<any_io_executor::base_type, Prop>
{
typedef any_io_executor result_type;
};
#endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
#if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
template <typename Prop>
struct prefer_member<any_io_executor, Prop> :
prefer_member<any_io_executor::base_type, Prop>
{
typedef any_io_executor result_type;
};
#endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
} // namespace traits
#endif // !defined(GENERATING_DOCUMENTATION)
#endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#if defined(BOOST_ASIO_HEADER_ONLY) \
&& !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include <boost/asio/impl/any_io_executor.ipp>
#endif // defined(BOOST_ASIO_HEADER_ONLY)
// && !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
#endif // BOOST_ASIO_ANY_IO_EXECUTOR_HPP

67
extern/boost/boost/asio/append.hpp vendored Normal file
View File

@ -0,0 +1,67 @@
//
// append.hpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_APPEND_HPP
#define BOOST_ASIO_APPEND_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <tuple>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Completion token type used to specify that the completion handler
/// arguments should be passed additional values after the results of the
/// operation.
template <typename CompletionToken, typename... Values>
class append_t
{
public:
/// Constructor.
template <typename T, typename... V>
constexpr explicit append_t(T&& completion_token, V&&... values)
: token_(static_cast<T&&>(completion_token)),
values_(static_cast<V&&>(values)...)
{
}
//private:
CompletionToken token_;
std::tuple<Values...> values_;
};
/// Completion token type used to specify that the completion handler
/// arguments should be passed additional values after the results of the
/// operation.
template <typename CompletionToken, typename... Values>
BOOST_ASIO_NODISCARD inline constexpr
append_t<decay_t<CompletionToken>, decay_t<Values>...>
append(CompletionToken&& completion_token, Values&&... values)
{
return append_t<decay_t<CompletionToken>, decay_t<Values>...>(
static_cast<CompletionToken&&>(completion_token),
static_cast<Values&&>(values)...);
}
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/impl/append.hpp>
#endif // BOOST_ASIO_APPEND_HPP

154
extern/boost/boost/asio/as_tuple.hpp vendored Normal file
View File

@ -0,0 +1,154 @@
//
// as_tuple.hpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_AS_TUPLE_HPP
#define BOOST_ASIO_AS_TUPLE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// A @ref completion_token adapter used to specify that the completion handler
/// arguments should be combined into a single tuple argument.
/**
* The as_tuple_t class is used to indicate that any arguments to the
* completion handler should be combined and passed as a single tuple argument.
* The arguments are first moved into a @c std::tuple and that tuple is then
* passed to the completion handler.
*/
template <typename CompletionToken>
class as_tuple_t
{
public:
/// Tag type used to prevent the "default" constructor from being used for
/// conversions.
struct default_constructor_tag {};
/// Default constructor.
/**
* This constructor is only valid if the underlying completion token is
* default constructible and move constructible. The underlying completion
* token is itself defaulted as an argument to allow it to capture a source
* location.
*/
constexpr as_tuple_t(
default_constructor_tag = default_constructor_tag(),
CompletionToken token = CompletionToken())
: token_(static_cast<CompletionToken&&>(token))
{
}
/// Constructor.
template <typename T>
constexpr explicit as_tuple_t(
T&& completion_token)
: token_(static_cast<T&&>(completion_token))
{
}
/// Adapts an executor to add the @c as_tuple_t completion token as the
/// default.
template <typename InnerExecutor>
struct executor_with_default : InnerExecutor
{
/// Specify @c as_tuple_t as the default completion token type.
typedef as_tuple_t default_completion_token_type;
/// Construct the adapted executor from the inner executor type.
template <typename InnerExecutor1>
executor_with_default(const InnerExecutor1& ex,
constraint_t<
conditional_t<
!is_same<InnerExecutor1, executor_with_default>::value,
is_convertible<InnerExecutor1, InnerExecutor>,
false_type
>::value
> = 0) noexcept
: InnerExecutor(ex)
{
}
};
/// Type alias to adapt an I/O object to use @c as_tuple_t as its
/// default completion token type.
template <typename T>
using as_default_on_t = typename T::template rebind_executor<
executor_with_default<typename T::executor_type>>::other;
/// Function helper to adapt an I/O object to use @c as_tuple_t as its
/// default completion token type.
template <typename T>
static typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other
as_default_on(T&& object)
{
return typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other(static_cast<T&&>(object));
}
//private:
CompletionToken token_;
};
/// A function object type that adapts a @ref completion_token to specify that
/// the completion handler arguments should be combined into a single tuple
/// argument.
/**
* May also be used directly as a completion token, in which case it adapts the
* asynchronous operation's default completion token (or boost::asio::deferred
* if no default is available).
*/
struct partial_as_tuple
{
/// Default constructor.
constexpr partial_as_tuple()
{
}
/// Adapt a @ref completion_token to specify that the completion handler
/// arguments should be combined into a single tuple argument.
template <typename CompletionToken>
BOOST_ASIO_NODISCARD inline
constexpr as_tuple_t<decay_t<CompletionToken>>
operator()(CompletionToken&& completion_token) const
{
return as_tuple_t<decay_t<CompletionToken>>(
static_cast<CompletionToken&&>(completion_token));
}
};
/// A function object that adapts a @ref completion_token to specify that the
/// completion handler arguments should be combined into a single tuple
/// argument.
/**
* May also be used directly as a completion token, in which case it adapts the
* asynchronous operation's default completion token (or boost::asio::deferred
* if no default is available).
*/
BOOST_ASIO_INLINE_VARIABLE constexpr partial_as_tuple as_tuple;
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/impl/as_tuple.hpp>
#endif // BOOST_ASIO_AS_TUPLE_HPP

View File

@ -0,0 +1,216 @@
//
// associated_allocator.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP
#define BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <memory>
#include <boost/asio/associator.hpp>
#include <boost/asio/detail/functional.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
template <typename T, typename Allocator>
struct associated_allocator;
namespace detail {
template <typename T, typename = void>
struct has_allocator_type : false_type
{
};
template <typename T>
struct has_allocator_type<T, void_t<typename T::allocator_type>> : true_type
{
};
template <typename T, typename A, typename = void, typename = void>
struct associated_allocator_impl
{
typedef void asio_associated_allocator_is_unspecialised;
typedef A type;
static type get(const T&) noexcept
{
return type();
}
static const type& get(const T&, const A& a) noexcept
{
return a;
}
};
template <typename T, typename A>
struct associated_allocator_impl<T, A, void_t<typename T::allocator_type>>
{
typedef typename T::allocator_type type;
static auto get(const T& t) noexcept
-> decltype(t.get_allocator())
{
return t.get_allocator();
}
static auto get(const T& t, const A&) noexcept
-> decltype(t.get_allocator())
{
return t.get_allocator();
}
};
template <typename T, typename A>
struct associated_allocator_impl<T, A,
enable_if_t<
!has_allocator_type<T>::value
>,
void_t<
typename associator<associated_allocator, T, A>::type
>> : associator<associated_allocator, T, A>
{
};
} // namespace detail
/// Traits type used to obtain the allocator associated with an object.
/**
* A program may specialise this traits type if the @c T template parameter in
* the specialisation is a user-defined type. The template parameter @c
* Allocator shall be a type meeting the Allocator requirements.
*
* Specialisations shall meet the following requirements, where @c t is a const
* reference to an object of type @c T, and @c a is an object of type @c
* Allocator.
*
* @li Provide a nested typedef @c type that identifies a type meeting the
* Allocator requirements.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type or a (possibly const) reference to @c
* type.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t,a) and with return type @c type or a (possibly const) reference to @c
* type.
*/
template <typename T, typename Allocator = std::allocator<void>>
struct associated_allocator
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_allocator_impl<T, Allocator>
#endif // !defined(GENERATING_DOCUMENTATION)
{
#if defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>.
/// Otherwise @c Allocator.
typedef see_below type;
/// If @c T has a nested type @c allocator_type, returns
/// <tt>t.get_allocator()</tt>. Otherwise returns @c type().
static decltype(auto) get(const T& t) noexcept;
/// If @c T has a nested type @c allocator_type, returns
/// <tt>t.get_allocator()</tt>. Otherwise returns @c a.
static decltype(auto) get(const T& t, const Allocator& a) noexcept;
#endif // defined(GENERATING_DOCUMENTATION)
};
/// Helper function to obtain an object's associated allocator.
/**
* @returns <tt>associated_allocator<T>::get(t)</tt>
*/
template <typename T>
BOOST_ASIO_NODISCARD inline typename associated_allocator<T>::type
get_associated_allocator(const T& t) noexcept
{
return associated_allocator<T>::get(t);
}
/// Helper function to obtain an object's associated allocator.
/**
* @returns <tt>associated_allocator<T, Allocator>::get(t, a)</tt>
*/
template <typename T, typename Allocator>
BOOST_ASIO_NODISCARD inline auto get_associated_allocator(
const T& t, const Allocator& a) noexcept
-> decltype(associated_allocator<T, Allocator>::get(t, a))
{
return associated_allocator<T, Allocator>::get(t, a);
}
template <typename T, typename Allocator = std::allocator<void>>
using associated_allocator_t
= typename associated_allocator<T, Allocator>::type;
namespace detail {
template <typename T, typename A, typename = void>
struct associated_allocator_forwarding_base
{
};
template <typename T, typename A>
struct associated_allocator_forwarding_base<T, A,
enable_if_t<
is_same<
typename associated_allocator<T,
A>::asio_associated_allocator_is_unspecialised,
void
>::value
>>
{
typedef void asio_associated_allocator_is_unspecialised;
};
} // namespace detail
/// Specialisation of associated_allocator for @c std::reference_wrapper.
template <typename T, typename Allocator>
struct associated_allocator<reference_wrapper<T>, Allocator>
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_allocator_forwarding_base<T, Allocator>
#endif // !defined(GENERATING_DOCUMENTATION)
{
/// Forwards @c type to the associator specialisation for the unwrapped type
/// @c T.
typedef typename associated_allocator<T, Allocator>::type type;
/// Forwards the request to get the allocator to the associator specialisation
/// for the unwrapped type @c T.
static type get(reference_wrapper<T> t) noexcept
{
return associated_allocator<T, Allocator>::get(t.get());
}
/// Forwards the request to get the allocator to the associator specialisation
/// for the unwrapped type @c T.
static auto get(reference_wrapper<T> t, const Allocator& a) noexcept
-> decltype(associated_allocator<T, Allocator>::get(t.get(), a))
{
return associated_allocator<T, Allocator>::get(t.get(), a);
}
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP

View File

@ -0,0 +1,223 @@
//
// associated_cancellation_slot.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP
#define BOOST_ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/associator.hpp>
#include <boost/asio/cancellation_signal.hpp>
#include <boost/asio/detail/functional.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
template <typename T, typename CancellationSlot>
struct associated_cancellation_slot;
namespace detail {
template <typename T, typename = void>
struct has_cancellation_slot_type : false_type
{
};
template <typename T>
struct has_cancellation_slot_type<T, void_t<typename T::cancellation_slot_type>>
: true_type
{
};
template <typename T, typename S, typename = void, typename = void>
struct associated_cancellation_slot_impl
{
typedef void asio_associated_cancellation_slot_is_unspecialised;
typedef S type;
static type get(const T&) noexcept
{
return type();
}
static const type& get(const T&, const S& s) noexcept
{
return s;
}
};
template <typename T, typename S>
struct associated_cancellation_slot_impl<T, S,
void_t<typename T::cancellation_slot_type>>
{
typedef typename T::cancellation_slot_type type;
static auto get(const T& t) noexcept
-> decltype(t.get_cancellation_slot())
{
return t.get_cancellation_slot();
}
static auto get(const T& t, const S&) noexcept
-> decltype(t.get_cancellation_slot())
{
return t.get_cancellation_slot();
}
};
template <typename T, typename S>
struct associated_cancellation_slot_impl<T, S,
enable_if_t<
!has_cancellation_slot_type<T>::value
>,
void_t<
typename associator<associated_cancellation_slot, T, S>::type
>> : associator<associated_cancellation_slot, T, S>
{
};
} // namespace detail
/// Traits type used to obtain the cancellation_slot associated with an object.
/**
* A program may specialise this traits type if the @c T template parameter in
* the specialisation is a user-defined type. The template parameter @c
* CancellationSlot shall be a type meeting the CancellationSlot requirements.
*
* Specialisations shall meet the following requirements, where @c t is a const
* reference to an object of type @c T, and @c s is an object of type @c
* CancellationSlot.
*
* @li Provide a nested typedef @c type that identifies a type meeting the
* CancellationSlot requirements.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type or a (possibly const) reference to @c
* type.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t,s) and with return type @c type or a (possibly const) reference to @c
* type.
*/
template <typename T, typename CancellationSlot = cancellation_slot>
struct associated_cancellation_slot
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_cancellation_slot_impl<T, CancellationSlot>
#endif // !defined(GENERATING_DOCUMENTATION)
{
#if defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c cancellation_slot_type,
/// <tt>T::cancellation_slot_type</tt>. Otherwise
/// @c CancellationSlot.
typedef see_below type;
/// If @c T has a nested type @c cancellation_slot_type, returns
/// <tt>t.get_cancellation_slot()</tt>. Otherwise returns @c type().
static decltype(auto) get(const T& t) noexcept;
/// If @c T has a nested type @c cancellation_slot_type, returns
/// <tt>t.get_cancellation_slot()</tt>. Otherwise returns @c s.
static decltype(auto) get(const T& t,
const CancellationSlot& s) noexcept;
#endif // defined(GENERATING_DOCUMENTATION)
};
/// Helper function to obtain an object's associated cancellation_slot.
/**
* @returns <tt>associated_cancellation_slot<T>::get(t)</tt>
*/
template <typename T>
BOOST_ASIO_NODISCARD inline typename associated_cancellation_slot<T>::type
get_associated_cancellation_slot(const T& t) noexcept
{
return associated_cancellation_slot<T>::get(t);
}
/// Helper function to obtain an object's associated cancellation_slot.
/**
* @returns <tt>associated_cancellation_slot<T,
* CancellationSlot>::get(t, st)</tt>
*/
template <typename T, typename CancellationSlot>
BOOST_ASIO_NODISCARD inline auto get_associated_cancellation_slot(
const T& t, const CancellationSlot& st) noexcept
-> decltype(associated_cancellation_slot<T, CancellationSlot>::get(t, st))
{
return associated_cancellation_slot<T, CancellationSlot>::get(t, st);
}
template <typename T, typename CancellationSlot = cancellation_slot>
using associated_cancellation_slot_t =
typename associated_cancellation_slot<T, CancellationSlot>::type;
namespace detail {
template <typename T, typename S, typename = void>
struct associated_cancellation_slot_forwarding_base
{
};
template <typename T, typename S>
struct associated_cancellation_slot_forwarding_base<T, S,
enable_if_t<
is_same<
typename associated_cancellation_slot<T,
S>::asio_associated_cancellation_slot_is_unspecialised,
void
>::value
>>
{
typedef void asio_associated_cancellation_slot_is_unspecialised;
};
} // namespace detail
/// Specialisation of associated_cancellation_slot for @c
/// std::reference_wrapper.
template <typename T, typename CancellationSlot>
struct associated_cancellation_slot<reference_wrapper<T>, CancellationSlot>
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_cancellation_slot_forwarding_base<T, CancellationSlot>
#endif // !defined(GENERATING_DOCUMENTATION)
{
/// Forwards @c type to the associator specialisation for the unwrapped type
/// @c T.
typedef typename associated_cancellation_slot<T, CancellationSlot>::type type;
/// Forwards the request to get the cancellation slot to the associator
/// specialisation for the unwrapped type @c T.
static type get(reference_wrapper<T> t) noexcept
{
return associated_cancellation_slot<T, CancellationSlot>::get(t.get());
}
/// Forwards the request to get the cancellation slot to the associator
/// specialisation for the unwrapped type @c T.
static auto get(reference_wrapper<T> t, const CancellationSlot& s) noexcept
-> decltype(
associated_cancellation_slot<T, CancellationSlot>::get(t.get(), s))
{
return associated_cancellation_slot<T, CancellationSlot>::get(t.get(), s);
}
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP

View File

@ -0,0 +1,237 @@
//
// associated_executor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_ASSOCIATED_EXECUTOR_HPP
#define BOOST_ASIO_ASSOCIATED_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/associator.hpp>
#include <boost/asio/detail/functional.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/execution/executor.hpp>
#include <boost/asio/is_executor.hpp>
#include <boost/asio/system_executor.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
template <typename T, typename Executor>
struct associated_executor;
namespace detail {
template <typename T, typename = void>
struct has_executor_type : false_type
{
};
template <typename T>
struct has_executor_type<T, void_t<typename T::executor_type>>
: true_type
{
};
template <typename T, typename E, typename = void, typename = void>
struct associated_executor_impl
{
typedef void asio_associated_executor_is_unspecialised;
typedef E type;
static type get(const T&) noexcept
{
return type();
}
static const type& get(const T&, const E& e) noexcept
{
return e;
}
};
template <typename T, typename E>
struct associated_executor_impl<T, E, void_t<typename T::executor_type>>
{
typedef typename T::executor_type type;
static auto get(const T& t) noexcept
-> decltype(t.get_executor())
{
return t.get_executor();
}
static auto get(const T& t, const E&) noexcept
-> decltype(t.get_executor())
{
return t.get_executor();
}
};
template <typename T, typename E>
struct associated_executor_impl<T, E,
enable_if_t<
!has_executor_type<T>::value
>,
void_t<
typename associator<associated_executor, T, E>::type
>> : associator<associated_executor, T, E>
{
};
} // namespace detail
/// Traits type used to obtain the executor associated with an object.
/**
* A program may specialise this traits type if the @c T template parameter in
* the specialisation is a user-defined type. The template parameter @c
* Executor shall be a type meeting the Executor requirements.
*
* Specialisations shall meet the following requirements, where @c t is a const
* reference to an object of type @c T, and @c e is an object of type @c
* Executor.
*
* @li Provide a nested typedef @c type that identifies a type meeting the
* Executor requirements.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type or a (possibly const) reference to @c
* type.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t,e) and with return type @c type or a (possibly const) reference to @c
* type.
*/
template <typename T, typename Executor = system_executor>
struct associated_executor
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_executor_impl<T, Executor>
#endif // !defined(GENERATING_DOCUMENTATION)
{
#if defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c executor_type, <tt>T::executor_type</tt>.
/// Otherwise @c Executor.
typedef see_below type;
/// If @c T has a nested type @c executor_type, returns
/// <tt>t.get_executor()</tt>. Otherwise returns @c type().
static decltype(auto) get(const T& t) noexcept;
/// If @c T has a nested type @c executor_type, returns
/// <tt>t.get_executor()</tt>. Otherwise returns @c ex.
static decltype(auto) get(const T& t, const Executor& ex) noexcept;
#endif // defined(GENERATING_DOCUMENTATION)
};
/// Helper function to obtain an object's associated executor.
/**
* @returns <tt>associated_executor<T>::get(t)</tt>
*/
template <typename T>
BOOST_ASIO_NODISCARD inline typename associated_executor<T>::type
get_associated_executor(const T& t) noexcept
{
return associated_executor<T>::get(t);
}
/// Helper function to obtain an object's associated executor.
/**
* @returns <tt>associated_executor<T, Executor>::get(t, ex)</tt>
*/
template <typename T, typename Executor>
BOOST_ASIO_NODISCARD inline auto get_associated_executor(
const T& t, const Executor& ex,
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0) noexcept
-> decltype(associated_executor<T, Executor>::get(t, ex))
{
return associated_executor<T, Executor>::get(t, ex);
}
/// Helper function to obtain an object's associated executor.
/**
* @returns <tt>associated_executor<T, typename
* ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt>
*/
template <typename T, typename ExecutionContext>
BOOST_ASIO_NODISCARD inline typename associated_executor<T,
typename ExecutionContext::executor_type>::type
get_associated_executor(const T& t, ExecutionContext& ctx,
constraint_t<is_convertible<ExecutionContext&,
execution_context&>::value> = 0) noexcept
{
return associated_executor<T,
typename ExecutionContext::executor_type>::get(t, ctx.get_executor());
}
template <typename T, typename Executor = system_executor>
using associated_executor_t = typename associated_executor<T, Executor>::type;
namespace detail {
template <typename T, typename E, typename = void>
struct associated_executor_forwarding_base
{
};
template <typename T, typename E>
struct associated_executor_forwarding_base<T, E,
enable_if_t<
is_same<
typename associated_executor<T,
E>::asio_associated_executor_is_unspecialised,
void
>::value
>>
{
typedef void asio_associated_executor_is_unspecialised;
};
} // namespace detail
/// Specialisation of associated_executor for @c std::reference_wrapper.
template <typename T, typename Executor>
struct associated_executor<reference_wrapper<T>, Executor>
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_executor_forwarding_base<T, Executor>
#endif // !defined(GENERATING_DOCUMENTATION)
{
/// Forwards @c type to the associator specialisation for the unwrapped type
/// @c T.
typedef typename associated_executor<T, Executor>::type type;
/// Forwards the request to get the executor to the associator specialisation
/// for the unwrapped type @c T.
static type get(reference_wrapper<T> t) noexcept
{
return associated_executor<T, Executor>::get(t.get());
}
/// Forwards the request to get the executor to the associator specialisation
/// for the unwrapped type @c T.
static auto get(reference_wrapper<T> t, const Executor& ex) noexcept
-> decltype(associated_executor<T, Executor>::get(t.get(), ex))
{
return associated_executor<T, Executor>::get(t.get(), ex);
}
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_ASSOCIATED_EXECUTOR_HPP

View File

@ -0,0 +1,283 @@
//
// associated_immediate_executor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP
#define BOOST_ASIO_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/associator.hpp>
#include <boost/asio/detail/functional.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/execution/blocking.hpp>
#include <boost/asio/execution/executor.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/is_executor.hpp>
#include <boost/asio/require.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
template <typename T, typename Executor>
struct associated_immediate_executor;
namespace detail {
template <typename T, typename = void>
struct has_immediate_executor_type : false_type
{
};
template <typename T>
struct has_immediate_executor_type<T,
void_t<typename T::immediate_executor_type>>
: true_type
{
};
template <typename E, typename = void, typename = void>
struct default_immediate_executor
{
typedef decay_t<require_result_t<E, execution::blocking_t::never_t>> type;
static auto get(const E& e) noexcept
-> decltype(boost::asio::require(e, execution::blocking.never))
{
return boost::asio::require(e, execution::blocking.never);
}
};
template <typename E>
struct default_immediate_executor<E,
enable_if_t<
!execution::is_executor<E>::value
>,
enable_if_t<
is_executor<E>::value
>>
{
class type : public E
{
public:
template <typename Executor1>
explicit type(const Executor1& e,
constraint_t<
conditional_t<
!is_same<Executor1, type>::value,
is_convertible<Executor1, E>,
false_type
>::value
> = 0) noexcept
: E(e)
{
}
type(const type& other) noexcept
: E(static_cast<const E&>(other))
{
}
type(type&& other) noexcept
: E(static_cast<E&&>(other))
{
}
template <typename Function, typename Allocator>
void dispatch(Function&& f, const Allocator& a) const
{
this->post(static_cast<Function&&>(f), a);
}
friend bool operator==(const type& a, const type& b) noexcept
{
return static_cast<const E&>(a) == static_cast<const E&>(b);
}
friend bool operator!=(const type& a, const type& b) noexcept
{
return static_cast<const E&>(a) != static_cast<const E&>(b);
}
};
static type get(const E& e) noexcept
{
return type(e);
}
};
template <typename T, typename E, typename = void, typename = void>
struct associated_immediate_executor_impl
{
typedef void asio_associated_immediate_executor_is_unspecialised;
typedef typename default_immediate_executor<E>::type type;
static auto get(const T&, const E& e) noexcept
-> decltype(default_immediate_executor<E>::get(e))
{
return default_immediate_executor<E>::get(e);
}
};
template <typename T, typename E>
struct associated_immediate_executor_impl<T, E,
void_t<typename T::immediate_executor_type>>
{
typedef typename T::immediate_executor_type type;
static auto get(const T& t, const E&) noexcept
-> decltype(t.get_immediate_executor())
{
return t.get_immediate_executor();
}
};
template <typename T, typename E>
struct associated_immediate_executor_impl<T, E,
enable_if_t<
!has_immediate_executor_type<T>::value
>,
void_t<
typename associator<associated_immediate_executor, T, E>::type
>> : associator<associated_immediate_executor, T, E>
{
};
} // namespace detail
/// Traits type used to obtain the immediate executor associated with an object.
/**
* A program may specialise this traits type if the @c T template parameter in
* the specialisation is a user-defined type. The template parameter @c
* Executor shall be a type meeting the Executor requirements.
*
* Specialisations shall meet the following requirements, where @c t is a const
* reference to an object of type @c T, and @c e is an object of type @c
* Executor.
*
* @li Provide a nested typedef @c type that identifies a type meeting the
* Executor requirements.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type or a (possibly const) reference to @c
* type.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t,e) and with return type @c type or a (possibly const) reference to @c
* type.
*/
template <typename T, typename Executor>
struct associated_immediate_executor
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_immediate_executor_impl<T, Executor>
#endif // !defined(GENERATING_DOCUMENTATION)
{
#if defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c immediate_executor_type,
// <tt>T::immediate_executor_type</tt>. Otherwise @c Executor.
typedef see_below type;
/// If @c T has a nested type @c immediate_executor_type, returns
/// <tt>t.get_immediate_executor()</tt>. Otherwise returns
/// <tt>boost::asio::require(ex, boost::asio::execution::blocking.never)</tt>.
static decltype(auto) get(const T& t, const Executor& ex) noexcept;
#endif // defined(GENERATING_DOCUMENTATION)
};
/// Helper function to obtain an object's associated executor.
/**
* @returns <tt>associated_immediate_executor<T, Executor>::get(t, ex)</tt>
*/
template <typename T, typename Executor>
BOOST_ASIO_NODISCARD inline auto get_associated_immediate_executor(
const T& t, const Executor& ex,
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0) noexcept
-> decltype(associated_immediate_executor<T, Executor>::get(t, ex))
{
return associated_immediate_executor<T, Executor>::get(t, ex);
}
/// Helper function to obtain an object's associated executor.
/**
* @returns <tt>associated_immediate_executor<T, typename
* ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt>
*/
template <typename T, typename ExecutionContext>
BOOST_ASIO_NODISCARD inline typename associated_immediate_executor<T,
typename ExecutionContext::executor_type>::type
get_associated_immediate_executor(const T& t, ExecutionContext& ctx,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0) noexcept
{
return associated_immediate_executor<T,
typename ExecutionContext::executor_type>::get(t, ctx.get_executor());
}
template <typename T, typename Executor>
using associated_immediate_executor_t =
typename associated_immediate_executor<T, Executor>::type;
namespace detail {
template <typename T, typename E, typename = void>
struct associated_immediate_executor_forwarding_base
{
};
template <typename T, typename E>
struct associated_immediate_executor_forwarding_base<T, E,
enable_if_t<
is_same<
typename associated_immediate_executor<T,
E>::asio_associated_immediate_executor_is_unspecialised,
void
>::value
>>
{
typedef void asio_associated_immediate_executor_is_unspecialised;
};
} // namespace detail
/// Specialisation of associated_immediate_executor for
/// @c std::reference_wrapper.
template <typename T, typename Executor>
struct associated_immediate_executor<reference_wrapper<T>, Executor>
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_immediate_executor_forwarding_base<T, Executor>
#endif // !defined(GENERATING_DOCUMENTATION)
{
/// Forwards @c type to the associator specialisation for the unwrapped type
/// @c T.
typedef typename associated_immediate_executor<T, Executor>::type type;
/// Forwards the request to get the executor to the associator specialisation
/// for the unwrapped type @c T.
static auto get(reference_wrapper<T> t, const Executor& ex) noexcept
-> decltype(associated_immediate_executor<T, Executor>::get(t.get(), ex))
{
return associated_immediate_executor<T, Executor>::get(t.get(), ex);
}
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_ASSOCIATED_IMMEDIATE_EXECUTOR_HPP

37
extern/boost/boost/asio/associator.hpp vendored Normal file
View File

@ -0,0 +1,37 @@
//
// associator.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_ASSOCIATOR_HPP
#define BOOST_ASIO_ASSOCIATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Used to generically specialise associators for a type.
template <template <typename, typename> class Associator,
typename T, typename DefaultCandidate, typename _ = void>
struct associator
{
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_ASSOCIATOR_HPP

950
extern/boost/boost/asio/async_result.hpp vendored Normal file
View File

@ -0,0 +1,950 @@
//
// async_result.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_ASYNC_RESULT_HPP
#define BOOST_ASIO_ASYNC_RESULT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename T>
struct is_completion_signature : false_type
{
};
template <typename R, typename... Args>
struct is_completion_signature<R(Args...)> : true_type
{
};
template <typename R, typename... Args>
struct is_completion_signature<R(Args...) &> : true_type
{
};
template <typename R, typename... Args>
struct is_completion_signature<R(Args...) &&> : true_type
{
};
# if defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
template <typename R, typename... Args>
struct is_completion_signature<R(Args...) noexcept> : true_type
{
};
template <typename R, typename... Args>
struct is_completion_signature<R(Args...) & noexcept> : true_type
{
};
template <typename R, typename... Args>
struct is_completion_signature<R(Args...) && noexcept> : true_type
{
};
# endif // defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
template <typename... T>
struct are_completion_signatures : false_type
{
};
template <>
struct are_completion_signatures<>
: true_type
{
};
template <typename T0>
struct are_completion_signatures<T0>
: is_completion_signature<T0>
{
};
template <typename T0, typename... TN>
struct are_completion_signatures<T0, TN...>
: integral_constant<bool, (
is_completion_signature<T0>::value
&& are_completion_signatures<TN...>::value)>
{
};
} // namespace detail
#if defined(BOOST_ASIO_HAS_CONCEPTS)
namespace detail {
template <typename T, typename... Args>
BOOST_ASIO_CONCEPT callable_with = requires(T&& t, Args&&... args)
{
static_cast<T&&>(t)(static_cast<Args&&>(args)...);
};
template <typename T, typename... Signatures>
struct is_completion_handler_for : false_type
{
};
template <typename T, typename R, typename... Args>
struct is_completion_handler_for<T, R(Args...)>
: integral_constant<bool, (callable_with<decay_t<T>, Args...>)>
{
};
template <typename T, typename R, typename... Args>
struct is_completion_handler_for<T, R(Args...) &>
: integral_constant<bool, (callable_with<decay_t<T>&, Args...>)>
{
};
template <typename T, typename R, typename... Args>
struct is_completion_handler_for<T, R(Args...) &&>
: integral_constant<bool, (callable_with<decay_t<T>&&, Args...>)>
{
};
# if defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
template <typename T, typename R, typename... Args>
struct is_completion_handler_for<T, R(Args...) noexcept>
: integral_constant<bool, (callable_with<decay_t<T>, Args...>)>
{
};
template <typename T, typename R, typename... Args>
struct is_completion_handler_for<T, R(Args...) & noexcept>
: integral_constant<bool, (callable_with<decay_t<T>&, Args...>)>
{
};
template <typename T, typename R, typename... Args>
struct is_completion_handler_for<T, R(Args...) && noexcept>
: integral_constant<bool, (callable_with<decay_t<T>&&, Args...>)>
{
};
# endif // defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
template <typename T, typename Signature0, typename... SignatureN>
struct is_completion_handler_for<T, Signature0, SignatureN...>
: integral_constant<bool, (
is_completion_handler_for<T, Signature0>::value
&& is_completion_handler_for<T, SignatureN...>::value)>
{
};
} // namespace detail
template <typename T>
BOOST_ASIO_CONCEPT completion_signature =
detail::is_completion_signature<T>::value;
#define BOOST_ASIO_COMPLETION_SIGNATURE \
::boost::asio::completion_signature
template <typename T, typename... Signatures>
BOOST_ASIO_CONCEPT completion_handler_for =
detail::are_completion_signatures<Signatures...>::value
&& detail::is_completion_handler_for<T, Signatures...>::value;
#define BOOST_ASIO_COMPLETION_HANDLER_FOR(sig) \
::boost::asio::completion_handler_for<sig>
#define BOOST_ASIO_COMPLETION_HANDLER_FOR2(sig0, sig1) \
::boost::asio::completion_handler_for<sig0, sig1>
#define BOOST_ASIO_COMPLETION_HANDLER_FOR3(sig0, sig1, sig2) \
::boost::asio::completion_handler_for<sig0, sig1, sig2>
#else // defined(BOOST_ASIO_HAS_CONCEPTS)
#define BOOST_ASIO_COMPLETION_SIGNATURE typename
#define BOOST_ASIO_COMPLETION_HANDLER_FOR(sig) typename
#define BOOST_ASIO_COMPLETION_HANDLER_FOR2(sig0, sig1) typename
#define BOOST_ASIO_COMPLETION_HANDLER_FOR3(sig0, sig1, sig2) typename
#endif // defined(BOOST_ASIO_HAS_CONCEPTS)
namespace detail {
template <typename T>
struct is_lvalue_completion_signature : false_type
{
};
template <typename R, typename... Args>
struct is_lvalue_completion_signature<R(Args...) &> : true_type
{
};
# if defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
template <typename R, typename... Args>
struct is_lvalue_completion_signature<R(Args...) & noexcept> : true_type
{
};
# endif // defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
template <typename... Signatures>
struct are_any_lvalue_completion_signatures : false_type
{
};
template <typename Sig0>
struct are_any_lvalue_completion_signatures<Sig0>
: is_lvalue_completion_signature<Sig0>
{
};
template <typename Sig0, typename... SigN>
struct are_any_lvalue_completion_signatures<Sig0, SigN...>
: integral_constant<bool, (
is_lvalue_completion_signature<Sig0>::value
|| are_any_lvalue_completion_signatures<SigN...>::value)>
{
};
template <typename T>
struct is_rvalue_completion_signature : false_type
{
};
template <typename R, typename... Args>
struct is_rvalue_completion_signature<R(Args...) &&> : true_type
{
};
# if defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
template <typename R, typename... Args>
struct is_rvalue_completion_signature<R(Args...) && noexcept> : true_type
{
};
# endif // defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
template <typename... Signatures>
struct are_any_rvalue_completion_signatures : false_type
{
};
template <typename Sig0>
struct are_any_rvalue_completion_signatures<Sig0>
: is_rvalue_completion_signature<Sig0>
{
};
template <typename Sig0, typename... SigN>
struct are_any_rvalue_completion_signatures<Sig0, SigN...>
: integral_constant<bool, (
is_rvalue_completion_signature<Sig0>::value
|| are_any_rvalue_completion_signatures<SigN...>::value)>
{
};
template <typename T>
struct simple_completion_signature;
template <typename R, typename... Args>
struct simple_completion_signature<R(Args...)>
{
typedef R type(Args...);
};
template <typename R, typename... Args>
struct simple_completion_signature<R(Args...) &>
{
typedef R type(Args...);
};
template <typename R, typename... Args>
struct simple_completion_signature<R(Args...) &&>
{
typedef R type(Args...);
};
# if defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
template <typename R, typename... Args>
struct simple_completion_signature<R(Args...) noexcept>
{
typedef R type(Args...);
};
template <typename R, typename... Args>
struct simple_completion_signature<R(Args...) & noexcept>
{
typedef R type(Args...);
};
template <typename R, typename... Args>
struct simple_completion_signature<R(Args...) && noexcept>
{
typedef R type(Args...);
};
# endif // defined(BOOST_ASIO_HAS_NOEXCEPT_FUNCTION_TYPE)
template <typename CompletionToken,
BOOST_ASIO_COMPLETION_SIGNATURE... Signatures>
class completion_handler_async_result
{
public:
typedef CompletionToken completion_handler_type;
typedef void return_type;
explicit completion_handler_async_result(completion_handler_type&)
{
}
return_type get()
{
}
template <typename Initiation,
BOOST_ASIO_COMPLETION_HANDLER_FOR(Signatures...) RawCompletionToken,
typename... Args>
static return_type initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
{
static_cast<Initiation&&>(initiation)(
static_cast<RawCompletionToken&&>(token),
static_cast<Args&&>(args)...);
}
private:
completion_handler_async_result(
const completion_handler_async_result&) = delete;
completion_handler_async_result& operator=(
const completion_handler_async_result&) = delete;
};
} // namespace detail
#if defined(GENERATING_DOCUMENTATION)
/// An interface for customising the behaviour of an initiating function.
/**
* The async_result traits class is used for determining:
*
* @li the concrete completion handler type to be called at the end of the
* asynchronous operation;
*
* @li the initiating function return type; and
*
* @li how the return value of the initiating function is obtained.
*
* The trait allows the handler and return types to be determined at the point
* where the specific completion handler signature is known.
*
* This template may be specialised for user-defined completion token types.
* The primary template assumes that the CompletionToken is the completion
* handler.
*/
template <typename CompletionToken,
BOOST_ASIO_COMPLETION_SIGNATURE... Signatures>
class async_result
{
public:
/// The concrete completion handler type for the specific signature.
typedef CompletionToken completion_handler_type;
/// The return type of the initiating function.
typedef void return_type;
/// Construct an async result from a given handler.
/**
* When using a specalised async_result, the constructor has an opportunity
* to initialise some state associated with the completion handler, which is
* then returned from the initiating function.
*/
explicit async_result(completion_handler_type& h);
/// Obtain the value to be returned from the initiating function.
return_type get();
/// Initiate the asynchronous operation that will produce the result, and
/// obtain the value to be returned from the initiating function.
template <typename Initiation, typename RawCompletionToken, typename... Args>
static return_type initiate(
Initiation&& initiation,
RawCompletionToken&& token,
Args&&... args);
private:
async_result(const async_result&) = delete;
async_result& operator=(const async_result&) = delete;
};
#else // defined(GENERATING_DOCUMENTATION)
template <typename CompletionToken,
BOOST_ASIO_COMPLETION_SIGNATURE... Signatures>
class async_result :
public conditional_t<
detail::are_any_lvalue_completion_signatures<Signatures...>::value
|| !detail::are_any_rvalue_completion_signatures<Signatures...>::value,
detail::completion_handler_async_result<CompletionToken, Signatures...>,
async_result<CompletionToken,
typename detail::simple_completion_signature<Signatures>::type...>
>
{
public:
typedef conditional_t<
detail::are_any_lvalue_completion_signatures<Signatures...>::value
|| !detail::are_any_rvalue_completion_signatures<Signatures...>::value,
detail::completion_handler_async_result<CompletionToken, Signatures...>,
async_result<CompletionToken,
typename detail::simple_completion_signature<Signatures>::type...>
> base_type;
using base_type::base_type;
private:
async_result(const async_result&) = delete;
async_result& operator=(const async_result&) = delete;
};
template <BOOST_ASIO_COMPLETION_SIGNATURE... Signatures>
class async_result<void, Signatures...>
{
// Empty.
};
#endif // defined(GENERATING_DOCUMENTATION)
/// Helper template to deduce the handler type from a CompletionToken, capture
/// a local copy of the handler, and then create an async_result for the
/// handler.
template <typename CompletionToken,
BOOST_ASIO_COMPLETION_SIGNATURE... Signatures>
struct async_completion
{
/// The real handler type to be used for the asynchronous operation.
typedef typename boost::asio::async_result<
decay_t<CompletionToken>, Signatures...>::completion_handler_type
completion_handler_type;
/// Constructor.
/**
* The constructor creates the concrete completion handler and makes the link
* between the handler and the asynchronous result.
*/
explicit async_completion(CompletionToken& token)
: completion_handler(static_cast<conditional_t<
is_same<CompletionToken, completion_handler_type>::value,
completion_handler_type&, CompletionToken&&>>(token)),
result(completion_handler)
{
}
/// A copy of, or reference to, a real handler object.
conditional_t<
is_same<CompletionToken, completion_handler_type>::value,
completion_handler_type&, completion_handler_type> completion_handler;
/// The result of the asynchronous operation's initiating function.
async_result<decay_t<CompletionToken>, Signatures...> result;
};
namespace detail {
struct async_result_memfns_base
{
void initiate();
};
template <typename T>
struct async_result_memfns_derived
: T, async_result_memfns_base
{
};
template <typename T, T>
struct async_result_memfns_check
{
};
template <typename>
char (&async_result_initiate_memfn_helper(...))[2];
template <typename T>
char async_result_initiate_memfn_helper(
async_result_memfns_check<
void (async_result_memfns_base::*)(),
&async_result_memfns_derived<T>::initiate>*);
template <typename CompletionToken,
BOOST_ASIO_COMPLETION_SIGNATURE... Signatures>
struct async_result_has_initiate_memfn
: integral_constant<bool, sizeof(async_result_initiate_memfn_helper<
async_result<decay_t<CompletionToken>, Signatures...>
>(0)) != 1>
{
};
} // namespace detail
#if defined(GENERATING_DOCUMENTATION)
# define BOOST_ASIO_INITFN_RESULT_TYPE(ct, sig) \
void_or_deduced
# define BOOST_ASIO_INITFN_RESULT_TYPE2(ct, sig0, sig1) \
void_or_deduced
# define BOOST_ASIO_INITFN_RESULT_TYPE3(ct, sig0, sig1, sig2) \
void_or_deduced
#else
# define BOOST_ASIO_INITFN_RESULT_TYPE(ct, sig) \
typename ::boost::asio::async_result< \
typename ::boost::asio::decay<ct>::type, sig>::return_type
# define BOOST_ASIO_INITFN_RESULT_TYPE2(ct, sig0, sig1) \
typename ::boost::asio::async_result< \
typename ::boost::asio::decay<ct>::type, sig0, sig1>::return_type
# define BOOST_ASIO_INITFN_RESULT_TYPE3(ct, sig0, sig1, sig2) \
typename ::boost::asio::async_result< \
typename ::boost::asio::decay<ct>::type, sig0, sig1, sig2>::return_type
#define BOOST_ASIO_HANDLER_TYPE(ct, sig) \
typename ::boost::asio::async_result< \
typename ::boost::asio::decay<ct>::type, sig>::completion_handler_type
#define BOOST_ASIO_HANDLER_TYPE2(ct, sig0, sig1) \
typename ::boost::asio::async_result< \
typename ::boost::asio::decay<ct>::type, \
sig0, sig1>::completion_handler_type
#define BOOST_ASIO_HANDLER_TYPE3(ct, sig0, sig1, sig2) \
typename ::boost::asio::async_result< \
typename ::boost::asio::decay<ct>::type, \
sig0, sig1, sig2>::completion_handler_type
#endif
#if defined(GENERATING_DOCUMENTATION)
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \
auto
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE2(ct, sig0, sig1) \
auto
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE3(ct, sig0, sig1, sig2) \
auto
#elif defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION)
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \
auto
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE2(ct, sig0, sig1) \
auto
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE3(ct, sig0, sig1, sig2) \
auto
#else
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \
BOOST_ASIO_INITFN_RESULT_TYPE(ct, sig)
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE2(ct, sig0, sig1) \
BOOST_ASIO_INITFN_RESULT_TYPE2(ct, sig0, sig1)
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE3(ct, sig0, sig1, sig2) \
BOOST_ASIO_INITFN_RESULT_TYPE3(ct, sig0, sig1, sig2)
#endif
#if defined(GENERATING_DOCUMENTATION)
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(ct, sig) \
auto
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX2(ct, sig0, sig1) \
auto
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX3(ct, sig0, sig1, sig2) \
auto
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX(expr)
#elif defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION)
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(ct, sig) \
auto
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX2(ct, sig0, sig1) \
auto
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX3(ct, sig0, sig1, sig2) \
auto
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX(expr)
#else
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX(ct, sig) \
auto
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX2(ct, sig0, sig1) \
auto
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_PREFIX3(ct, sig0, sig1, sig2) \
auto
# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE_SUFFIX(expr) -> decltype expr
#endif
#if defined(GENERATING_DOCUMENTATION)
# define BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \
void_or_deduced
# define BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE2(ct, sig0, sig1, expr) \
void_or_deduced
# define BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE3(ct, sig0, sig1, sig2, expr) \
void_or_deduced
#else
# define BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \
decltype expr
# define BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE2(ct, sig0, sig1, expr) \
decltype expr
# define BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE3(ct, sig0, sig1, sig2, expr) \
decltype expr
#endif
#if defined(GENERATING_DOCUMENTATION)
template <typename CompletionToken,
completion_signature... Signatures,
typename Initiation, typename... Args>
void_or_deduced async_initiate(
Initiation&& initiation,
type_identity_t<CompletionToken>& token,
Args&&... args);
#else // defined(GENERATING_DOCUMENTATION)
template <typename CompletionToken,
BOOST_ASIO_COMPLETION_SIGNATURE... Signatures,
typename Initiation, typename... Args>
inline auto async_initiate(Initiation&& initiation,
type_identity_t<CompletionToken>& token, Args&&... args)
-> decltype(enable_if_t<
enable_if_t<
detail::are_completion_signatures<Signatures...>::value,
detail::async_result_has_initiate_memfn<
CompletionToken, Signatures...>>::value,
async_result<decay_t<CompletionToken>, Signatures...>>::initiate(
static_cast<Initiation&&>(initiation),
static_cast<CompletionToken&&>(token),
static_cast<Args&&>(args)...))
{
return async_result<decay_t<CompletionToken>, Signatures...>::initiate(
static_cast<Initiation&&>(initiation),
static_cast<CompletionToken&&>(token),
static_cast<Args&&>(args)...);
}
template <
BOOST_ASIO_COMPLETION_SIGNATURE... Signatures,
typename CompletionToken, typename Initiation, typename... Args>
inline auto async_initiate(Initiation&& initiation,
CompletionToken&& token, Args&&... args)
-> decltype(enable_if_t<
enable_if_t<
detail::are_completion_signatures<Signatures...>::value,
detail::async_result_has_initiate_memfn<
CompletionToken, Signatures...>>::value,
async_result<decay_t<CompletionToken>, Signatures...>>::initiate(
static_cast<Initiation&&>(initiation),
static_cast<CompletionToken&&>(token),
static_cast<Args&&>(args)...))
{
return async_result<decay_t<CompletionToken>, Signatures...>::initiate(
static_cast<Initiation&&>(initiation),
static_cast<CompletionToken&&>(token),
static_cast<Args&&>(args)...);
}
template <typename CompletionToken,
BOOST_ASIO_COMPLETION_SIGNATURE... Signatures,
typename Initiation, typename... Args>
inline typename enable_if_t<
!enable_if_t<
detail::are_completion_signatures<Signatures...>::value,
detail::async_result_has_initiate_memfn<
CompletionToken, Signatures...>>::value,
async_result<decay_t<CompletionToken>, Signatures...>
>::return_type
async_initiate(Initiation&& initiation,
type_identity_t<CompletionToken>& token, Args&&... args)
{
async_completion<CompletionToken, Signatures...> completion(token);
static_cast<Initiation&&>(initiation)(
static_cast<
typename async_result<decay_t<CompletionToken>,
Signatures...>::completion_handler_type&&>(
completion.completion_handler),
static_cast<Args&&>(args)...);
return completion.result.get();
}
template <BOOST_ASIO_COMPLETION_SIGNATURE... Signatures,
typename CompletionToken, typename Initiation, typename... Args>
inline typename enable_if_t<
!enable_if_t<
detail::are_completion_signatures<Signatures...>::value,
detail::async_result_has_initiate_memfn<
CompletionToken, Signatures...>>::value,
async_result<decay_t<CompletionToken>, Signatures...>
>::return_type
async_initiate(Initiation&& initiation, CompletionToken&& token, Args&&... args)
{
async_completion<CompletionToken, Signatures...> completion(token);
static_cast<Initiation&&>(initiation)(
static_cast<
typename async_result<decay_t<CompletionToken>,
Signatures...>::completion_handler_type&&>(
completion.completion_handler),
static_cast<Args&&>(args)...);
return completion.result.get();
}
#endif // defined(GENERATING_DOCUMENTATION)
#if defined(BOOST_ASIO_HAS_CONCEPTS)
namespace detail {
template <typename... Signatures>
struct initiation_archetype
{
template <completion_handler_for<Signatures...> CompletionHandler>
void operator()(CompletionHandler&&) const
{
}
};
} // namespace detail
template <typename T, typename... Signatures>
BOOST_ASIO_CONCEPT completion_token_for =
detail::are_completion_signatures<Signatures...>::value
&&
requires(T&& t)
{
async_initiate<T, Signatures...>(
detail::initiation_archetype<Signatures...>{}, t);
};
#define BOOST_ASIO_COMPLETION_TOKEN_FOR(sig) \
::boost::asio::completion_token_for<sig>
#define BOOST_ASIO_COMPLETION_TOKEN_FOR2(sig0, sig1) \
::boost::asio::completion_token_for<sig0, sig1>
#define BOOST_ASIO_COMPLETION_TOKEN_FOR3(sig0, sig1, sig2) \
::boost::asio::completion_token_for<sig0, sig1, sig2>
#else // defined(BOOST_ASIO_HAS_CONCEPTS)
#define BOOST_ASIO_COMPLETION_TOKEN_FOR(sig) typename
#define BOOST_ASIO_COMPLETION_TOKEN_FOR2(sig0, sig1) typename
#define BOOST_ASIO_COMPLETION_TOKEN_FOR3(sig0, sig1, sig2) typename
#endif // defined(BOOST_ASIO_HAS_CONCEPTS)
namespace detail {
struct async_operation_probe {};
struct async_operation_probe_result {};
template <typename Call, typename = void>
struct is_async_operation_call : false_type
{
};
template <typename Call>
struct is_async_operation_call<Call,
void_t<
enable_if_t<
is_same<
result_of_t<Call>,
async_operation_probe_result
>::value
>
>
> : true_type
{
};
} // namespace detail
#if !defined(GENERATING_DOCUMENTATION)
template <typename... Signatures>
class async_result<detail::async_operation_probe, Signatures...>
{
public:
typedef detail::async_operation_probe_result return_type;
template <typename Initiation, typename... InitArgs>
static return_type initiate(Initiation&&,
detail::async_operation_probe, InitArgs&&...)
{
return return_type();
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
#if defined(GENERATING_DOCUMENTATION)
/// The is_async_operation trait detects whether a type @c T and arguments
/// @c Args... may be used to initiate an asynchronous operation.
/**
* Class template @c is_async_operation is a trait is derived from @c true_type
* if the expression <tt>T(Args..., token)</tt> initiates an asynchronous
* operation, where @c token is an unspecified completion token type. Otherwise,
* @c is_async_operation is derived from @c false_type.
*/
template <typename T, typename... Args>
struct is_async_operation : integral_constant<bool, automatically_determined>
{
};
#else // defined(GENERATING_DOCUMENTATION)
template <typename T, typename... Args>
struct is_async_operation :
detail::is_async_operation_call<
T(Args..., detail::async_operation_probe)>
{
};
#endif // defined(GENERATING_DOCUMENTATION)
#if defined(BOOST_ASIO_HAS_CONCEPTS)
template <typename T, typename... Args>
BOOST_ASIO_CONCEPT async_operation = is_async_operation<T, Args...>::value;
#define BOOST_ASIO_ASYNC_OPERATION(t) \
::boost::asio::async_operation<t>
#define BOOST_ASIO_ASYNC_OPERATION1(t, a0) \
::boost::asio::async_operation<t, a0>
#define BOOST_ASIO_ASYNC_OPERATION2(t, a0, a1) \
::boost::asio::async_operation<t, a0, a1>
#define BOOST_ASIO_ASYNC_OPERATION3(t, a0, a1, a2) \
::boost::asio::async_operation<t, a0, a1, a2>
#else // defined(BOOST_ASIO_HAS_CONCEPTS)
#define BOOST_ASIO_ASYNC_OPERATION(t) typename
#define BOOST_ASIO_ASYNC_OPERATION1(t, a0) typename
#define BOOST_ASIO_ASYNC_OPERATION2(t, a0, a1) typename
#define BOOST_ASIO_ASYNC_OPERATION3(t, a0, a1, a2) typename
#endif // defined(BOOST_ASIO_HAS_CONCEPTS)
namespace detail {
struct completion_signature_probe {};
template <typename... T>
struct completion_signature_probe_result
{
template <template <typename...> class Op>
struct apply
{
typedef Op<T...> type;
};
};
template <typename T>
struct completion_signature_probe_result<T>
{
typedef T type;
template <template <typename...> class Op>
struct apply
{
typedef Op<T> type;
};
};
template <>
struct completion_signature_probe_result<void>
{
template <template <typename...> class Op>
struct apply
{
typedef Op<> type;
};
};
} // namespace detail
#if !defined(GENERATING_DOCUMENTATION)
template <typename... Signatures>
class async_result<detail::completion_signature_probe, Signatures...>
{
public:
typedef detail::completion_signature_probe_result<Signatures...> return_type;
template <typename Initiation, typename... InitArgs>
static return_type initiate(Initiation&&,
detail::completion_signature_probe, InitArgs&&...)
{
return return_type();
}
};
template <typename Signature>
class async_result<detail::completion_signature_probe, Signature>
{
public:
typedef detail::completion_signature_probe_result<Signature> return_type;
template <typename Initiation, typename... InitArgs>
static return_type initiate(Initiation&&,
detail::completion_signature_probe, InitArgs&&...)
{
return return_type();
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
#if defined(GENERATING_DOCUMENTATION)
/// The completion_signature_of trait determines the completion signature
/// of an asynchronous operation.
/**
* Class template @c completion_signature_of is a trait with a member type
* alias @c type that denotes the completion signature of the asynchronous
* operation initiated by the expression <tt>T(Args..., token)</tt> operation,
* where @c token is an unspecified completion token type. If the asynchronous
* operation does not have exactly one completion signature, the instantion of
* the trait is well-formed but the member type alias @c type is omitted. If
* the expression <tt>T(Args..., token)</tt> is not an asynchronous operation
* then use of the trait is ill-formed.
*/
template <typename T, typename... Args>
struct completion_signature_of
{
typedef automatically_determined type;
};
#else // defined(GENERATING_DOCUMENTATION)
template <typename T, typename... Args>
struct completion_signature_of :
result_of_t<T(Args..., detail::completion_signature_probe)>
{
};
#endif // defined(GENERATING_DOCUMENTATION)
template <typename T, typename... Args>
using completion_signature_of_t =
typename completion_signature_of<T, Args...>::type;
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/default_completion_token.hpp>
#endif // BOOST_ASIO_ASYNC_RESULT_HPP

144
extern/boost/boost/asio/awaitable.hpp vendored Normal file
View File

@ -0,0 +1,144 @@
//
// awaitable.hpp
// ~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_AWAITABLE_HPP
#define BOOST_ASIO_AWAITABLE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
#if defined(BOOST_ASIO_HAS_STD_COROUTINE)
# include <coroutine>
#else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
# include <experimental/coroutine>
#endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
#include <utility>
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
#if defined(BOOST_ASIO_HAS_STD_COROUTINE)
using std::coroutine_handle;
using std::suspend_always;
#else // defined(BOOST_ASIO_HAS_STD_COROUTINE)
using std::experimental::coroutine_handle;
using std::experimental::suspend_always;
#endif // defined(BOOST_ASIO_HAS_STD_COROUTINE)
template <typename> class awaitable_thread;
template <typename, typename> class awaitable_frame;
} // namespace detail
/// The return type of a coroutine or asynchronous operation.
template <typename T, typename Executor = any_io_executor>
class BOOST_ASIO_NODISCARD awaitable
{
public:
/// The type of the awaited value.
typedef T value_type;
/// The executor type that will be used for the coroutine.
typedef Executor executor_type;
/// Default constructor.
constexpr awaitable() noexcept
: frame_(nullptr)
{
}
/// Move constructor.
awaitable(awaitable&& other) noexcept
: frame_(std::exchange(other.frame_, nullptr))
{
}
/// Destructor
~awaitable()
{
if (frame_)
frame_->destroy();
}
/// Move assignment.
awaitable& operator=(awaitable&& other) noexcept
{
if (this != &other)
frame_ = std::exchange(other.frame_, nullptr);
return *this;
}
/// Checks if the awaitable refers to a future result.
bool valid() const noexcept
{
return !!frame_;
}
#if !defined(GENERATING_DOCUMENTATION)
// Support for co_await keyword.
bool await_ready() const noexcept
{
return false;
}
// Support for co_await keyword.
template <class U>
void await_suspend(
detail::coroutine_handle<detail::awaitable_frame<U, Executor>> h)
{
frame_->push_frame(&h.promise());
}
// Support for co_await keyword.
T await_resume()
{
return awaitable(static_cast<awaitable&&>(*this)).frame_->get();
}
#endif // !defined(GENERATING_DOCUMENTATION)
private:
template <typename> friend class detail::awaitable_thread;
template <typename, typename> friend class detail::awaitable_frame;
// Not copy constructible or copy assignable.
awaitable(const awaitable&) = delete;
awaitable& operator=(const awaitable&) = delete;
// Construct the awaitable from a coroutine's frame object.
explicit awaitable(detail::awaitable_frame<T, Executor>* a)
: frame_(a)
{
}
detail::awaitable_frame<T, Executor>* frame_;
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/impl/awaitable.hpp>
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
#endif // BOOST_ASIO_AWAITABLE_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,712 @@
//
// basic_deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_DEADLINE_TIMER_HPP
#define BOOST_ASIO_BASIC_DEADLINE_TIMER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
|| defined(GENERATING_DOCUMENTATION)
#include <cstddef>
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/detail/deadline_timer_service.hpp>
#include <boost/asio/detail/handler_type_requirements.hpp>
#include <boost/asio/detail/io_object_impl.hpp>
#include <boost/asio/detail/non_const_lvalue.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/time_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Provides waitable timer functionality.
/**
* The basic_deadline_timer class template provides the ability to perform a
* blocking or asynchronous wait for a timer to expire.
*
* A deadline timer is always in one of two states: "expired" or "not expired".
* If the wait() or async_wait() function is called on an expired timer, the
* wait operation will complete immediately.
*
* Most applications will use the boost::asio::deadline_timer typedef.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Examples
* Performing a blocking wait:
* @code
* // Construct a timer without setting an expiry time.
* boost::asio::deadline_timer timer(my_context);
*
* // Set an expiry time relative to now.
* timer.expires_from_now(boost::posix_time::seconds(5));
*
* // Wait for the timer to expire.
* timer.wait();
* @endcode
*
* @par
* Performing an asynchronous wait:
* @code
* void handler(const boost::system::error_code& error)
* {
* if (!error)
* {
* // Timer expired.
* }
* }
*
* ...
*
* // Construct a timer with an absolute expiry time.
* boost::asio::deadline_timer timer(my_context,
* boost::posix_time::time_from_string("2005-12-07 23:59:59.000"));
*
* // Start an asynchronous wait.
* timer.async_wait(handler);
* @endcode
*
* @par Changing an active deadline_timer's expiry time
*
* Changing the expiry time of a timer while there are pending asynchronous
* waits causes those wait operations to be cancelled. To ensure that the action
* associated with the timer is performed only once, use something like this:
* used:
*
* @code
* void on_some_event()
* {
* if (my_timer.expires_from_now(seconds(5)) > 0)
* {
* // We managed to cancel the timer. Start new asynchronous wait.
* my_timer.async_wait(on_timeout);
* }
* else
* {
* // Too late, timer has already expired!
* }
* }
*
* void on_timeout(const boost::system::error_code& e)
* {
* if (e != boost::asio::error::operation_aborted)
* {
* // Timer was not cancelled, take necessary action.
* }
* }
* @endcode
*
* @li The boost::asio::basic_deadline_timer::expires_from_now() function
* cancels any pending asynchronous waits, and returns the number of
* asynchronous waits that were cancelled. If it returns 0 then you were too
* late and the wait handler has already been executed, or will soon be
* executed. If it returns 1 then the wait handler was successfully cancelled.
*
* @li If a wait handler is cancelled, the boost::system::error_code passed to
* it contains the value boost::asio::error::operation_aborted.
*/
template <typename Time,
typename TimeTraits = boost::asio::time_traits<Time>,
typename Executor = any_io_executor>
class basic_deadline_timer
{
private:
class initiate_async_wait;
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the timer type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The timer type when rebound to the specified executor.
typedef basic_deadline_timer<Time, TimeTraits, Executor1> other;
};
/// The time traits type.
typedef TimeTraits traits_type;
/// The time type.
typedef typename traits_type::time_type time_type;
/// The duration type.
typedef typename traits_type::duration_type duration_type;
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_from_now() functions must be called to set an
* expiry time before the timer can be waited on.
*
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*/
explicit basic_deadline_timer(const executor_type& ex)
: impl_(0, ex)
{
}
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_from_now() functions must be called to set an
* expiry time before the timer can be waited on.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*/
template <typename ExecutionContext>
explicit basic_deadline_timer(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
basic_deadline_timer(const executor_type& ex, const time_type& expiry_time)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
boost::asio::detail::throw_error(ec, "expires_at");
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
template <typename ExecutionContext>
basic_deadline_timer(ExecutionContext& context, const time_type& expiry_time,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
boost::asio::detail::throw_error(ec, "expires_at");
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
basic_deadline_timer(const executor_type& ex,
const duration_type& expiry_time)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
boost::asio::detail::throw_error(ec, "expires_from_now");
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
template <typename ExecutionContext>
basic_deadline_timer(ExecutionContext& context,
const duration_type& expiry_time,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
boost::asio::detail::throw_error(ec, "expires_from_now");
}
/// Move-construct a basic_deadline_timer from another.
/**
* This constructor moves a timer from one object to another.
*
* @param other The other basic_deadline_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_deadline_timer(const executor_type&)
* constructor.
*/
basic_deadline_timer(basic_deadline_timer&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_deadline_timer from another.
/**
* This assignment operator moves a timer from one object to another. Cancels
* any outstanding asynchronous operations associated with the target object.
*
* @param other The other basic_deadline_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_deadline_timer(const executor_type&)
* constructor.
*/
basic_deadline_timer& operator=(basic_deadline_timer&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
/// Destroys the timer.
/**
* This function destroys the timer, cancelling any outstanding asynchronous
* wait operations associated with the timer as if by calling @c cancel.
*/
~basic_deadline_timer()
{
}
/// Get the executor associated with the object.
const executor_type& get_executor() noexcept
{
return impl_.get_executor();
}
/// Cancel any asynchronous operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the timer. The handler for each cancelled operation will
* be invoked with the boost::asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note If the timer has already expired when cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel()
{
boost::system::error_code ec;
std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "cancel");
return s;
}
/// Cancel any asynchronous operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the timer. The handler for each cancelled operation will
* be invoked with the boost::asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*
* @note If the timer has already expired when cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel(boost::system::error_code& ec)
{
return impl_.get_service().cancel(impl_.get_implementation(), ec);
}
/// Cancels one asynchronous operation that is waiting on the timer.
/**
* This function forces the completion of one pending asynchronous wait
* operation against the timer. Handlers are cancelled in FIFO order. The
* handler for the cancelled operation will be invoked with the
* boost::asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @return The number of asynchronous operations that were cancelled. That is,
* either 0 or 1.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note If the timer has already expired when cancel_one() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel_one()
{
boost::system::error_code ec;
std::size_t s = impl_.get_service().cancel_one(
impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "cancel_one");
return s;
}
/// Cancels one asynchronous operation that is waiting on the timer.
/**
* This function forces the completion of one pending asynchronous wait
* operation against the timer. Handlers are cancelled in FIFO order. The
* handler for the cancelled operation will be invoked with the
* boost::asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled. That is,
* either 0 or 1.
*
* @note If the timer has already expired when cancel_one() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel_one(boost::system::error_code& ec)
{
return impl_.get_service().cancel_one(impl_.get_implementation(), ec);
}
/// Get the timer's expiry time as an absolute time.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
time_type expires_at() const
{
return impl_.get_service().expires_at(impl_.get_implementation());
}
/// Set the timer's expiry time as an absolute time.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the boost::asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note If the timer has already expired when expires_at() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_at(const time_type& expiry_time)
{
boost::system::error_code ec;
std::size_t s = impl_.get_service().expires_at(
impl_.get_implementation(), expiry_time, ec);
boost::asio::detail::throw_error(ec, "expires_at");
return s;
}
/// Set the timer's expiry time as an absolute time.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the boost::asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*
* @note If the timer has already expired when expires_at() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_at(const time_type& expiry_time,
boost::system::error_code& ec)
{
return impl_.get_service().expires_at(
impl_.get_implementation(), expiry_time, ec);
}
/// Get the timer's expiry time relative to now.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
duration_type expires_from_now() const
{
return impl_.get_service().expires_from_now(impl_.get_implementation());
}
/// Set the timer's expiry time relative to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the boost::asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note If the timer has already expired when expires_from_now() is called,
* then the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_from_now(const duration_type& expiry_time)
{
boost::system::error_code ec;
std::size_t s = impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
boost::asio::detail::throw_error(ec, "expires_from_now");
return s;
}
/// Set the timer's expiry time relative to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the boost::asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*
* @note If the timer has already expired when expires_from_now() is called,
* then the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_from_now(const duration_type& expiry_time,
boost::system::error_code& ec)
{
return impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
}
/// Perform a blocking wait on the timer.
/**
* This function is used to wait for the timer to expire. This function
* blocks and does not return until the timer has expired.
*
* @throws boost::system::system_error Thrown on failure.
*/
void wait()
{
boost::system::error_code ec;
impl_.get_service().wait(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "wait");
}
/// Perform a blocking wait on the timer.
/**
* This function is used to wait for the timer to expire. This function
* blocks and does not return until the timer has expired.
*
* @param ec Set to indicate what error occurred, if any.
*/
void wait(boost::system::error_code& ec)
{
impl_.get_service().wait(impl_.get_implementation(), ec);
}
/// Start an asynchronous wait on the timer.
/**
* This function may be used to initiate an asynchronous wait against the
* timer. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
*
* For each call to async_wait(), the completion handler will be called
* exactly once. The completion handler will be called when:
*
* @li The timer has expired.
*
* @li The timer was cancelled, in which case the handler is passed the error
* code boost::asio::error::operation_aborted.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the timer expires. Potential
* completion tokens include @ref use_future, @ref use_awaitable, @ref
* yield_context, or a function object with the correct completion signature.
* The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code) @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* boost::asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code))
WaitToken = default_completion_token_t<executor_type>>
auto async_wait(
WaitToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WaitToken, void (boost::system::error_code)>(
declval<initiate_async_wait>(), token))
{
return async_initiate<WaitToken, void (boost::system::error_code)>(
initiate_async_wait(this), token);
}
private:
// Disallow copying and assignment.
basic_deadline_timer(const basic_deadline_timer&) = delete;
basic_deadline_timer& operator=(
const basic_deadline_timer&) = delete;
class initiate_async_wait
{
public:
typedef Executor executor_type;
explicit initiate_async_wait(basic_deadline_timer* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WaitHandler>
void operator()(WaitHandler&& handler) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WaitHandler.
BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
detail::non_const_lvalue<WaitHandler> handler2(handler);
self_->impl_.get_service().async_wait(
self_->impl_.get_implementation(),
handler2.value, self_->impl_.get_executor());
}
private:
basic_deadline_timer* self_;
};
detail::io_object_impl<
detail::deadline_timer_service<TimeTraits>, Executor> impl_;
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// || defined(GENERATING_DOCUMENTATION)
#endif // BOOST_ASIO_BASIC_DEADLINE_TIMER_HPP

826
extern/boost/boost/asio/basic_file.hpp vendored Normal file
View File

@ -0,0 +1,826 @@
//
// basic_file.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_FILE_HPP
#define BOOST_ASIO_BASIC_FILE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_FILE) \
|| defined(GENERATING_DOCUMENTATION)
#include <string>
#include <utility>
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/cstdint.hpp>
#include <boost/asio/detail/handler_type_requirements.hpp>
#include <boost/asio/detail/io_object_impl.hpp>
#include <boost/asio/detail/non_const_lvalue.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/file_base.hpp>
#if defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/win_iocp_file_service.hpp>
#elif defined(BOOST_ASIO_HAS_IO_URING)
# include <boost/asio/detail/io_uring_file_service.hpp>
#endif
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
#if !defined(BOOST_ASIO_BASIC_FILE_FWD_DECL)
#define BOOST_ASIO_BASIC_FILE_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Executor = any_io_executor>
class basic_file;
#endif // !defined(BOOST_ASIO_BASIC_FILE_FWD_DECL)
/// Provides file functionality.
/**
* The basic_file class template provides functionality that is common to both
* stream-oriented and random-access files.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Executor>
class basic_file
: public file_base
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the file type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The file type when rebound to the specified executor.
typedef basic_file<Executor1> other;
};
/// The native representation of a file.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(BOOST_ASIO_HAS_IOCP)
typedef detail::win_iocp_file_service::native_handle_type native_handle_type;
#elif defined(BOOST_ASIO_HAS_IO_URING)
typedef detail::io_uring_file_service::native_handle_type native_handle_type;
#endif
/// Construct a basic_file without opening it.
/**
* This constructor initialises a file without opening it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*/
explicit basic_file(const executor_type& ex)
: impl_(0, ex)
{
}
/// Construct a basic_file without opening it.
/**
* This constructor initialises a file without opening it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*/
template <typename ExecutionContext>
explicit basic_file(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
}
/// Construct and open a basic_file.
/**
* This constructor initialises a file and opens it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*/
explicit basic_file(const executor_type& ex,
const char* path, file_base::flags open_flags)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Construct a basic_file without opening it.
/**
* This constructor initialises a file and opens it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*/
template <typename ExecutionContext>
explicit basic_file(ExecutionContext& context,
const char* path, file_base::flags open_flags,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_file.
/**
* This constructor initialises a file and opens it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*/
explicit basic_file(const executor_type& ex,
const std::string& path, file_base::flags open_flags)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().open(impl_.get_implementation(),
path.c_str(), open_flags, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Construct a basic_file without opening it.
/**
* This constructor initialises a file and opens it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*/
template <typename ExecutionContext>
explicit basic_file(ExecutionContext& context,
const std::string& path, file_base::flags open_flags,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().open(impl_.get_implementation(),
path.c_str(), open_flags, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Construct a basic_file on an existing native file handle.
/**
* This constructor initialises a file object to hold an existing native file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param native_file A native file handle.
*
* @throws boost::system::system_error Thrown on failure.
*/
basic_file(const executor_type& ex, const native_handle_type& native_file)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().assign(
impl_.get_implementation(), native_file, ec);
boost::asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_file on an existing native file.
/**
* This constructor initialises a file object to hold an existing native file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param native_file A native file.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_file(ExecutionContext& context, const native_handle_type& native_file,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().assign(
impl_.get_implementation(), native_file, ec);
boost::asio::detail::throw_error(ec, "assign");
}
/// Move-construct a basic_file from another.
/**
* This constructor moves a file from one object to another.
*
* @param other The other basic_file object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_file(const executor_type&) constructor.
*/
basic_file(basic_file&& other) noexcept
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_file from another.
/**
* This assignment operator moves a file from one object to another.
*
* @param other The other basic_file object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_file(const executor_type&) constructor.
*/
basic_file& operator=(basic_file&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
// All files have access to each other's implementations.
template <typename Executor1>
friend class basic_file;
/// Move-construct a basic_file from a file of another executor type.
/**
* This constructor moves a file from one object to another.
*
* @param other The other basic_file object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_file(const executor_type&) constructor.
*/
template <typename Executor1>
basic_file(basic_file<Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_file from a file of another executor type.
/**
* This assignment operator moves a file from one object to another.
*
* @param other The other basic_file object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_file(const executor_type&) constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_file&
> operator=(basic_file<Executor1>&& other)
{
basic_file tmp(std::move(other));
impl_ = std::move(tmp.impl_);
return *this;
}
/// Get the executor associated with the object.
const executor_type& get_executor() noexcept
{
return impl_.get_executor();
}
/// Open the file using the specified path.
/**
* This function opens the file so that it will use the specified path.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws boost::system::system_error Thrown on failure.
*
* @par Example
* @code
* boost::asio::stream_file file(my_context);
* file.open("/path/to/my/file", boost::asio::stream_file::read_only);
* @endcode
*/
void open(const char* path, file_base::flags open_flags)
{
boost::system::error_code ec;
impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Open the file using the specified path.
/**
* This function opens the file so that it will use the specified path.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* boost::asio::stream_file file(my_context);
* boost::system::error_code ec;
* file.open("/path/to/my/file", boost::asio::stream_file::read_only, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
BOOST_ASIO_SYNC_OP_VOID open(const char* path,
file_base::flags open_flags, boost::system::error_code& ec)
{
impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Open the file using the specified path.
/**
* This function opens the file so that it will use the specified path.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws boost::system::system_error Thrown on failure.
*
* @par Example
* @code
* boost::asio::stream_file file(my_context);
* file.open("/path/to/my/file", boost::asio::stream_file::read_only);
* @endcode
*/
void open(const std::string& path, file_base::flags open_flags)
{
boost::system::error_code ec;
impl_.get_service().open(impl_.get_implementation(),
path.c_str(), open_flags, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Open the file using the specified path.
/**
* This function opens the file so that it will use the specified path.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* boost::asio::stream_file file(my_context);
* boost::system::error_code ec;
* file.open("/path/to/my/file", boost::asio::stream_file::read_only, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
BOOST_ASIO_SYNC_OP_VOID open(const std::string& path,
file_base::flags open_flags, boost::system::error_code& ec)
{
impl_.get_service().open(impl_.get_implementation(),
path.c_str(), open_flags, ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Assign an existing native file to the file.
/*
* This function opens the file to hold an existing native file.
*
* @param native_file A native file.
*
* @throws boost::system::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_file)
{
boost::system::error_code ec;
impl_.get_service().assign(
impl_.get_implementation(), native_file, ec);
boost::asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native file to the file.
/*
* This function opens the file to hold an existing native file.
*
* @param native_file A native file.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_file,
boost::system::error_code& ec)
{
impl_.get_service().assign(
impl_.get_implementation(), native_file, ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the file is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the file.
/**
* This function is used to close the file. Any asynchronous read or write
* operations will be cancelled immediately, and will complete with the
* boost::asio::error::operation_aborted error.
*
* @throws boost::system::system_error Thrown on failure. Note that, even if
* the function indicates an error, the underlying descriptor is closed.
*/
void close()
{
boost::system::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "close");
}
/// Close the file.
/**
* This function is used to close the file. Any asynchronous read or write
* operations will be cancelled immediately, and will complete with the
* boost::asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any. Note that, even if
* the function indicates an error, the underlying descriptor is closed.
*
* @par Example
* @code
* boost::asio::stream_file file(my_context);
* ...
* boost::system::error_code ec;
* file.close(ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Release ownership of the underlying native file.
/**
* This function causes all outstanding asynchronous read and write
* operations to finish immediately, and the handlers for cancelled
* operations will be passed the boost::asio::error::operation_aborted error.
* Ownership of the native file is then transferred to the caller.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with boost::asio::error::operation_not_supported on
* these platforms.
*/
#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release()
{
boost::system::error_code ec;
native_handle_type s = impl_.get_service().release(
impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "release");
return s;
}
/// Release ownership of the underlying native file.
/**
* This function causes all outstanding asynchronous read and write
* operations to finish immediately, and the handlers for cancelled
* operations will be passed the boost::asio::error::operation_aborted error.
* Ownership of the native file is then transferred to the caller.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with boost::asio::error::operation_not_supported on
* these platforms.
*/
#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release(boost::system::error_code& ec)
{
return impl_.get_service().release(impl_.get_implementation(), ec);
}
/// Get the native file representation.
/**
* This function may be used to obtain the underlying representation of the
* file. This is intended to allow access to native file functionality
* that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the file.
/**
* This function causes all outstanding asynchronous read and write
* operations to finish immediately, and the handlers for cancelled
* operations will be passed the boost::asio::error::operation_aborted error.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note Calls to cancel() will always fail with
* boost::asio::error::operation_not_supported when run on Windows XP, Windows
* Server 2003, and earlier versions of Windows, unless
* BOOST_ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
* two issues that should be considered before enabling its use:
*
* @li It will only cancel asynchronous operations that were initiated in the
* current thread.
*
* @li It can appear to complete without error, but the request to cancel the
* unfinished operations may be silently ignored by the operating system.
* Whether it works or not seems to depend on the drivers that are installed.
*
* For portable cancellation, consider using the close() function to
* simultaneously cancel the outstanding operations and close the file.
*
* When running on Windows Vista, Windows Server 2008, and later, the
* CancelIoEx function is always used. This function does not have the
* problems described above.
*/
#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
&& !defined(BOOST_ASIO_ENABLE_CANCELIO)
__declspec(deprecated("By default, this function always fails with "
"operation_not_supported when used on Windows XP, Windows Server 2003, "
"or earlier. Consult documentation for details."))
#endif
void cancel()
{
boost::system::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the file.
/**
* This function causes all outstanding asynchronous read and write
* operations to finish immediately, and the handlers for cancelled
* operations will be passed the boost::asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note Calls to cancel() will always fail with
* boost::asio::error::operation_not_supported when run on Windows XP, Windows
* Server 2003, and earlier versions of Windows, unless
* BOOST_ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
* two issues that should be considered before enabling its use:
*
* @li It will only cancel asynchronous operations that were initiated in the
* current thread.
*
* @li It can appear to complete without error, but the request to cancel the
* unfinished operations may be silently ignored by the operating system.
* Whether it works or not seems to depend on the drivers that are installed.
*
* For portable cancellation, consider using the close() function to
* simultaneously cancel the outstanding operations and close the file.
*
* When running on Windows Vista, Windows Server 2008, and later, the
* CancelIoEx function is always used. This function does not have the
* problems described above.
*/
#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
&& !defined(BOOST_ASIO_ENABLE_CANCELIO)
__declspec(deprecated("By default, this function always fails with "
"operation_not_supported when used on Windows XP, Windows Server 2003, "
"or earlier. Consult documentation for details."))
#endif
BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Get the size of the file.
/**
* This function determines the size of the file, in bytes.
*
* @throws boost::system::system_error Thrown on failure.
*/
uint64_t size() const
{
boost::system::error_code ec;
uint64_t s = impl_.get_service().size(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "size");
return s;
}
/// Get the size of the file.
/**
* This function determines the size of the file, in bytes.
*
* @param ec Set to indicate what error occurred, if any.
*/
uint64_t size(boost::system::error_code& ec) const
{
return impl_.get_service().size(impl_.get_implementation(), ec);
}
/// Alter the size of the file.
/**
* This function resizes the file to the specified size, in bytes. If the
* current file size exceeds @c n then any extra data is discarded. If the
* current size is less than @c n then the file is extended and filled with
* zeroes.
*
* @param n The new size for the file.
*
* @throws boost::system::system_error Thrown on failure.
*/
void resize(uint64_t n)
{
boost::system::error_code ec;
impl_.get_service().resize(impl_.get_implementation(), n, ec);
boost::asio::detail::throw_error(ec, "resize");
}
/// Alter the size of the file.
/**
* This function resizes the file to the specified size, in bytes. If the
* current file size exceeds @c n then any extra data is discarded. If the
* current size is less than @c n then the file is extended and filled with
* zeroes.
*
* @param n The new size for the file.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID resize(uint64_t n, boost::system::error_code& ec)
{
impl_.get_service().resize(impl_.get_implementation(), n, ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Synchronise the file to disk.
/**
* This function synchronises the file data and metadata to disk. Note that
* the semantics of this synchronisation vary between operation systems.
*
* @throws boost::system::system_error Thrown on failure.
*/
void sync_all()
{
boost::system::error_code ec;
impl_.get_service().sync_all(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "sync_all");
}
/// Synchronise the file to disk.
/**
* This function synchronises the file data and metadata to disk. Note that
* the semantics of this synchronisation vary between operation systems.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID sync_all(boost::system::error_code& ec)
{
impl_.get_service().sync_all(impl_.get_implementation(), ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Synchronise the file data to disk.
/**
* This function synchronises the file data to disk. Note that the semantics
* of this synchronisation vary between operation systems.
*
* @throws boost::system::system_error Thrown on failure.
*/
void sync_data()
{
boost::system::error_code ec;
impl_.get_service().sync_data(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "sync_data");
}
/// Synchronise the file data to disk.
/**
* This function synchronises the file data to disk. Note that the semantics
* of this synchronisation vary between operation systems.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID sync_data(boost::system::error_code& ec)
{
impl_.get_service().sync_data(impl_.get_implementation(), ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
protected:
/// Protected destructor to prevent deletion through this type.
/**
* This function destroys the file, cancelling any outstanding asynchronous
* operations associated with the file as if by calling @c cancel.
*/
~basic_file()
{
}
#if defined(BOOST_ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_file_service, Executor> impl_;
#elif defined(BOOST_ASIO_HAS_IO_URING)
detail::io_object_impl<detail::io_uring_file_service, Executor> impl_;
#endif
private:
// Disallow copying and assignment.
basic_file(const basic_file&) = delete;
basic_file& operator=(const basic_file&) = delete;
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_FILE)
// || defined(GENERATING_DOCUMENTATION)
#endif // BOOST_ASIO_BASIC_FILE_HPP

View File

@ -0,0 +1,288 @@
//
// basic_io_object.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_IO_OBJECT_HPP
#define BOOST_ASIO_BASIC_IO_OBJECT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail
{
// Type trait used to determine whether a service supports move.
template <typename IoObjectService>
class service_has_move
{
private:
typedef IoObjectService service_type;
typedef typename service_type::implementation_type implementation_type;
template <typename T, typename U>
static auto asio_service_has_move_eval(T* t, U* u)
-> decltype(t->move_construct(*u, *u), char());
static char (&asio_service_has_move_eval(...))[2];
public:
static const bool value =
sizeof(asio_service_has_move_eval(
static_cast<service_type*>(0),
static_cast<implementation_type*>(0))) == 1;
};
}
/// Base class for all I/O objects.
/**
* @note All I/O objects are non-copyable. However, when using C++0x, certain
* I/O objects do support move construction and move assignment.
*/
#if defined(GENERATING_DOCUMENTATION)
template <typename IoObjectService>
#else
template <typename IoObjectService,
bool Movable = detail::service_has_move<IoObjectService>::value>
#endif
class basic_io_object
{
public:
/// The type of the service that will be used to provide I/O operations.
typedef IoObjectService service_type;
/// The underlying implementation type of I/O object.
typedef typename service_type::implementation_type implementation_type;
#if !defined(BOOST_ASIO_NO_DEPRECATED)
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
/**
* This function may be used to obtain the io_context object that the I/O
* object uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_context object that the I/O object will use
* to dispatch handlers. Ownership is not transferred to the caller.
*/
boost::asio::io_context& get_io_context()
{
return service_.get_io_context();
}
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
/**
* This function may be used to obtain the io_context object that the I/O
* object uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_context object that the I/O object will use
* to dispatch handlers. Ownership is not transferred to the caller.
*/
boost::asio::io_context& get_io_service()
{
return service_.get_io_context();
}
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
/// The type of the executor associated with the object.
typedef boost::asio::io_context::executor_type executor_type;
/// Get the executor associated with the object.
executor_type get_executor() noexcept
{
return service_.get_io_context().get_executor();
}
protected:
/// Construct a basic_io_object.
/**
* Performs:
* @code get_service().construct(get_implementation()); @endcode
*/
explicit basic_io_object(boost::asio::io_context& io_context)
: service_(boost::asio::use_service<IoObjectService>(io_context))
{
service_.construct(implementation_);
}
#if defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_io_object.
/**
* Performs:
* @code get_service().move_construct(
* get_implementation(), other.get_implementation()); @endcode
*
* @note Available only for services that support movability,
*/
basic_io_object(basic_io_object&& other);
/// Move-assign a basic_io_object.
/**
* Performs:
* @code get_service().move_assign(get_implementation(),
* other.get_service(), other.get_implementation()); @endcode
*
* @note Available only for services that support movability,
*/
basic_io_object& operator=(basic_io_object&& other);
/// Perform a converting move-construction of a basic_io_object.
template <typename IoObjectService1>
basic_io_object(IoObjectService1& other_service,
typename IoObjectService1::implementation_type& other_implementation);
#endif // defined(GENERATING_DOCUMENTATION)
/// Protected destructor to prevent deletion through this type.
/**
* Performs:
* @code get_service().destroy(get_implementation()); @endcode
*/
~basic_io_object()
{
service_.destroy(implementation_);
}
/// Get the service associated with the I/O object.
service_type& get_service()
{
return service_;
}
/// Get the service associated with the I/O object.
const service_type& get_service() const
{
return service_;
}
/// Get the underlying implementation of the I/O object.
implementation_type& get_implementation()
{
return implementation_;
}
/// Get the underlying implementation of the I/O object.
const implementation_type& get_implementation() const
{
return implementation_;
}
private:
basic_io_object(const basic_io_object&);
basic_io_object& operator=(const basic_io_object&);
// The service associated with the I/O object.
service_type& service_;
/// The underlying implementation of the I/O object.
implementation_type implementation_;
};
// Specialisation for movable objects.
template <typename IoObjectService>
class basic_io_object<IoObjectService, true>
{
public:
typedef IoObjectService service_type;
typedef typename service_type::implementation_type implementation_type;
#if !defined(BOOST_ASIO_NO_DEPRECATED)
boost::asio::io_context& get_io_context()
{
return service_->get_io_context();
}
boost::asio::io_context& get_io_service()
{
return service_->get_io_context();
}
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
typedef boost::asio::io_context::executor_type executor_type;
executor_type get_executor() noexcept
{
return service_->get_io_context().get_executor();
}
protected:
explicit basic_io_object(boost::asio::io_context& io_context)
: service_(&boost::asio::use_service<IoObjectService>(io_context))
{
service_->construct(implementation_);
}
basic_io_object(basic_io_object&& other)
: service_(&other.get_service())
{
service_->move_construct(implementation_, other.implementation_);
}
template <typename IoObjectService1>
basic_io_object(IoObjectService1& other_service,
typename IoObjectService1::implementation_type& other_implementation)
: service_(&boost::asio::use_service<IoObjectService>(
other_service.get_io_context()))
{
service_->converting_move_construct(implementation_,
other_service, other_implementation);
}
~basic_io_object()
{
service_->destroy(implementation_);
}
basic_io_object& operator=(basic_io_object&& other)
{
service_->move_assign(implementation_,
*other.service_, other.implementation_);
service_ = other.service_;
return *this;
}
service_type& get_service()
{
return *service_;
}
const service_type& get_service() const
{
return *service_;
}
implementation_type& get_implementation()
{
return implementation_;
}
const implementation_type& get_implementation() const
{
return implementation_;
}
private:
basic_io_object(const basic_io_object&);
void operator=(const basic_io_object&);
IoObjectService* service_;
implementation_type implementation_;
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_BASIC_IO_OBJECT_HPP

View File

@ -0,0 +1,691 @@
//
// basic_random_access_file.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_HPP
#define BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_FILE) \
|| defined(GENERATING_DOCUMENTATION)
#include <cstddef>
#include <boost/asio/async_result.hpp>
#include <boost/asio/basic_file.hpp>
#include <boost/asio/detail/handler_type_requirements.hpp>
#include <boost/asio/detail/non_const_lvalue.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
#if !defined(BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL)
#define BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Executor = any_io_executor>
class basic_random_access_file;
#endif // !defined(BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL)
/// Provides random-access file functionality.
/**
* The basic_random_access_file class template provides asynchronous and
* blocking random-access file functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* Synchronous @c read_some_at and @c write_some_at operations are thread safe
* with respect to each other, if the underlying operating system calls are
* also thread safe. This means that it is permitted to perform concurrent
* calls to these synchronous operations on a single file object. Other
* synchronous operations, such as @c open or @c close, are not thread safe.
*/
template <typename Executor>
class basic_random_access_file
: public basic_file<Executor>
{
private:
class initiate_async_write_some_at;
class initiate_async_read_some_at;
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the file type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The file type when rebound to the specified executor.
typedef basic_random_access_file<Executor1> other;
};
/// The native representation of a file.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_file<Executor>::native_handle_type native_handle_type;
#endif
/// Construct a basic_random_access_file without opening it.
/**
* This constructor initialises a file without opening it. The file needs to
* be opened before data can be read from or or written to it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*/
explicit basic_random_access_file(const executor_type& ex)
: basic_file<Executor>(ex)
{
}
/// Construct a basic_random_access_file without opening it.
/**
* This constructor initialises a file without opening it. The file needs to
* be opened before data can be read from or or written to it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*/
template <typename ExecutionContext>
explicit basic_random_access_file(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context)
{
}
/// Construct and open a basic_random_access_file.
/**
* This constructor initialises and opens a file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws boost::system::system_error Thrown on failure.
*/
basic_random_access_file(const executor_type& ex,
const char* path, file_base::flags open_flags)
: basic_file<Executor>(ex, path, open_flags)
{
}
/// Construct and open a basic_random_access_file.
/**
* This constructor initialises and opens a file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_random_access_file(ExecutionContext& context,
const char* path, file_base::flags open_flags,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context, path, open_flags)
{
}
/// Construct and open a basic_random_access_file.
/**
* This constructor initialises and opens a file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws boost::system::system_error Thrown on failure.
*/
basic_random_access_file(const executor_type& ex,
const std::string& path, file_base::flags open_flags)
: basic_file<Executor>(ex, path, open_flags)
{
}
/// Construct and open a basic_random_access_file.
/**
* This constructor initialises and opens a file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_random_access_file(ExecutionContext& context,
const std::string& path, file_base::flags open_flags,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context, path, open_flags)
{
}
/// Construct a basic_random_access_file on an existing native file.
/**
* This constructor initialises a random-access file object to hold an
* existing native file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param native_file The new underlying file implementation.
*
* @throws boost::system::system_error Thrown on failure.
*/
basic_random_access_file(const executor_type& ex,
const native_handle_type& native_file)
: basic_file<Executor>(ex, native_file)
{
}
/// Construct a basic_random_access_file on an existing native file.
/**
* This constructor initialises a random-access file object to hold an
* existing native file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param native_file The new underlying file implementation.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_random_access_file(ExecutionContext& context,
const native_handle_type& native_file,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context, native_file)
{
}
/// Move-construct a basic_random_access_file from another.
/**
* This constructor moves a random-access file from one object to another.
*
* @param other The other basic_random_access_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_random_access_file(const executor_type&)
* constructor.
*/
basic_random_access_file(basic_random_access_file&& other) noexcept
: basic_file<Executor>(std::move(other))
{
}
/// Move-assign a basic_random_access_file from another.
/**
* This assignment operator moves a random-access file from one object to
* another.
*
* @param other The other basic_random_access_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_random_access_file(const executor_type&)
* constructor.
*/
basic_random_access_file& operator=(basic_random_access_file&& other)
{
basic_file<Executor>::operator=(std::move(other));
return *this;
}
/// Move-construct a basic_random_access_file from a file of another executor
/// type.
/**
* This constructor moves a random-access file from one object to another.
*
* @param other The other basic_random_access_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_random_access_file(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_random_access_file(basic_random_access_file<Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(std::move(other))
{
}
/// Move-assign a basic_random_access_file from a file of another executor
/// type.
/**
* This assignment operator moves a random-access file from one object to
* another.
*
* @param other The other basic_random_access_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_random_access_file(const executor_type&)
* constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_random_access_file&
> operator=(basic_random_access_file<Executor1>&& other)
{
basic_file<Executor>::operator=(std::move(other));
return *this;
}
/// Destroys the file.
/**
* This function destroys the file, cancelling any outstanding asynchronous
* operations associated with the file as if by calling @c cancel.
*/
~basic_random_access_file()
{
}
/// Write some data to the handle at the specified offset.
/**
* This function is used to write data to the random-access handle. The
* function call will block until one or more bytes of the data has been
* written successfully, or until an error occurs.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more data buffers to be written to the handle.
*
* @returns The number of bytes written.
*
* @throws boost::system::system_error Thrown on failure. An error code of
* boost::asio::error::eof indicates that the end of the file was reached.
*
* @note The write_some_at operation may not write all of the data. Consider
* using the @ref write_at function if you need to ensure that all data is
* written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* handle.write_some_at(42, boost::asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some_at(uint64_t offset,
const ConstBufferSequence& buffers)
{
boost::system::error_code ec;
std::size_t s = this->impl_.get_service().write_some_at(
this->impl_.get_implementation(), offset, buffers, ec);
boost::asio::detail::throw_error(ec, "write_some_at");
return s;
}
/// Write some data to the handle at the specified offset.
/**
* This function is used to write data to the random-access handle. The
* function call will block until one or more bytes of the data has been
* written successfully, or until an error occurs.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more data buffers to be written to the handle.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not write all of the data to the
* file. Consider using the @ref write_at function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some_at(uint64_t offset,
const ConstBufferSequence& buffers, boost::system::error_code& ec)
{
return this->impl_.get_service().write_some_at(
this->impl_.get_implementation(), offset, buffers, ec);
}
/// Start an asynchronous write at the specified offset.
/**
* This function is used to asynchronously write data to the random-access
* handle. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more data buffers to be written to the handle.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the write completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*
* @note The write operation may not write all of the data to the file.
* Consider using the @ref async_write_at function if you need to ensure that
* all data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* handle.async_write_some_at(42, boost::asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* boost::asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename ConstBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) WriteToken = default_completion_token_t<executor_type>>
auto async_write_some_at(uint64_t offset, const ConstBufferSequence& buffers,
WriteToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteToken,
void (boost::system::error_code, std::size_t)>(
declval<initiate_async_write_some_at>(), token, offset, buffers))
{
return async_initiate<WriteToken,
void (boost::system::error_code, std::size_t)>(
initiate_async_write_some_at(this), token, offset, buffers);
}
/// Read some data from the handle at the specified offset.
/**
* This function is used to read data from the random-access handle. The
* function call will block until one or more bytes of data has been read
* successfully, or until an error occurs.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws boost::system::system_error Thrown on failure. An error code of
* boost::asio::error::eof indicates that the end of the file was reached.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read_at function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* handle.read_some_at(42, boost::asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some_at(uint64_t offset,
const MutableBufferSequence& buffers)
{
boost::system::error_code ec;
std::size_t s = this->impl_.get_service().read_some_at(
this->impl_.get_implementation(), offset, buffers, ec);
boost::asio::detail::throw_error(ec, "read_some_at");
return s;
}
/// Read some data from the handle at the specified offset.
/**
* This function is used to read data from the random-access handle. The
* function call will block until one or more bytes of data has been read
* successfully, or until an error occurs.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read_at function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some_at(uint64_t offset,
const MutableBufferSequence& buffers, boost::system::error_code& ec)
{
return this->impl_.get_service().read_some_at(
this->impl_.get_implementation(), offset, buffers, ec);
}
/// Start an asynchronous read at the specified offset.
/**
* This function is used to asynchronously read data from the random-access
* handle. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the read completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read_at function if you need to ensure that
* the requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* handle.async_read_some_at(42, boost::asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* boost::asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename MutableBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) ReadToken = default_completion_token_t<executor_type>>
auto async_read_some_at(uint64_t offset, const MutableBufferSequence& buffers,
ReadToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadToken,
void (boost::system::error_code, std::size_t)>(
declval<initiate_async_read_some_at>(), token, offset, buffers))
{
return async_initiate<ReadToken,
void (boost::system::error_code, std::size_t)>(
initiate_async_read_some_at(this), token, offset, buffers);
}
private:
// Disallow copying and assignment.
basic_random_access_file(const basic_random_access_file&) = delete;
basic_random_access_file& operator=(
const basic_random_access_file&) = delete;
class initiate_async_write_some_at
{
public:
typedef Executor executor_type;
explicit initiate_async_write_some_at(basic_random_access_file* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(WriteHandler&& handler,
uint64_t offset, const ConstBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_write_some_at(
self_->impl_.get_implementation(), offset, buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_random_access_file* self_;
};
class initiate_async_read_some_at
{
public:
typedef Executor executor_type;
explicit initiate_async_read_some_at(basic_random_access_file* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ReadHandler&& handler,
uint64_t offset, const MutableBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
detail::non_const_lvalue<ReadHandler> handler2(handler);
self_->impl_.get_service().async_read_some_at(
self_->impl_.get_implementation(), offset, buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_random_access_file* self_;
};
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_FILE)
// || defined(GENERATING_DOCUMENTATION)
#endif // BOOST_ASIO_BASIC_RANDOM_ACCESS_FILE_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,628 @@
//
// basic_readable_pipe.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_READABLE_PIPE_HPP
#define BOOST_ASIO_BASIC_READABLE_PIPE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_PIPE) \
|| defined(GENERATING_DOCUMENTATION)
#include <string>
#include <utility>
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/handler_type_requirements.hpp>
#include <boost/asio/detail/io_object_impl.hpp>
#include <boost/asio/detail/non_const_lvalue.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/execution_context.hpp>
#if defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/win_iocp_handle_service.hpp>
#elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
# include <boost/asio/detail/io_uring_descriptor_service.hpp>
#else
# include <boost/asio/detail/reactive_descriptor_service.hpp>
#endif
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Provides pipe functionality.
/**
* The basic_readable_pipe class provides a wrapper over pipe
* functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Executor = any_io_executor>
class basic_readable_pipe
{
private:
class initiate_async_read_some;
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the pipe type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The pipe type when rebound to the specified executor.
typedef basic_readable_pipe<Executor1> other;
};
/// The native representation of a pipe.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(BOOST_ASIO_HAS_IOCP)
typedef detail::win_iocp_handle_service::native_handle_type
native_handle_type;
#elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
typedef detail::io_uring_descriptor_service::native_handle_type
native_handle_type;
#else
typedef detail::reactive_descriptor_service::native_handle_type
native_handle_type;
#endif
/// A basic_readable_pipe is always the lowest layer.
typedef basic_readable_pipe lowest_layer_type;
/// Construct a basic_readable_pipe without opening it.
/**
* This constructor creates a pipe without opening it.
*
* @param ex The I/O executor that the pipe will use, by default, to dispatch
* handlers for any asynchronous operations performed on the pipe.
*/
explicit basic_readable_pipe(const executor_type& ex)
: impl_(0, ex)
{
}
/// Construct a basic_readable_pipe without opening it.
/**
* This constructor creates a pipe without opening it.
*
* @param context An execution context which provides the I/O executor that
* the pipe will use, by default, to dispatch handlers for any asynchronous
* operations performed on the pipe.
*/
template <typename ExecutionContext>
explicit basic_readable_pipe(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
}
/// Construct a basic_readable_pipe on an existing native pipe.
/**
* This constructor creates a pipe object to hold an existing native
* pipe.
*
* @param ex The I/O executor that the pipe will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* pipe.
*
* @param native_pipe A native pipe.
*
* @throws boost::system::system_error Thrown on failure.
*/
basic_readable_pipe(const executor_type& ex,
const native_handle_type& native_pipe)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_pipe, ec);
boost::asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_readable_pipe on an existing native pipe.
/**
* This constructor creates a pipe object to hold an existing native
* pipe.
*
* @param context An execution context which provides the I/O executor that
* the pipe will use, by default, to dispatch handlers for any
* asynchronous operations performed on the pipe.
*
* @param native_pipe A native pipe.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_readable_pipe(ExecutionContext& context,
const native_handle_type& native_pipe,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_pipe, ec);
boost::asio::detail::throw_error(ec, "assign");
}
/// Move-construct a basic_readable_pipe from another.
/**
* This constructor moves a pipe from one object to another.
*
* @param other The other basic_readable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_readable_pipe(const executor_type&)
* constructor.
*/
basic_readable_pipe(basic_readable_pipe&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_readable_pipe from another.
/**
* This assignment operator moves a pipe from one object to another.
*
* @param other The other basic_readable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_readable_pipe(const executor_type&)
* constructor.
*/
basic_readable_pipe& operator=(basic_readable_pipe&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
// All pipes have access to each other's implementations.
template <typename Executor1>
friend class basic_readable_pipe;
/// Move-construct a basic_readable_pipe from a pipe of another executor type.
/**
* This constructor moves a pipe from one object to another.
*
* @param other The other basic_readable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_readable_pipe(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_readable_pipe(basic_readable_pipe<Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_readable_pipe from a pipe of another executor type.
/**
* This assignment operator moves a pipe from one object to another.
*
* @param other The other basic_readable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_readable_pipe(const executor_type&)
* constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_readable_pipe&
> operator=(basic_readable_pipe<Executor1>&& other)
{
basic_readable_pipe tmp(std::move(other));
impl_ = std::move(tmp.impl_);
return *this;
}
/// Destroys the pipe.
/**
* This function destroys the pipe, cancelling any outstanding
* asynchronous wait operations associated with the pipe as if by
* calling @c cancel.
*/
~basic_readable_pipe()
{
}
/// Get the executor associated with the object.
const executor_type& get_executor() noexcept
{
return impl_.get_executor();
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a basic_readable_pipe cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a basic_readable_pipe cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Assign an existing native pipe to the pipe.
/*
* This function opens the pipe to hold an existing native pipe.
*
* @param native_pipe A native pipe.
*
* @throws boost::system::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_pipe)
{
boost::system::error_code ec;
impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
boost::asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native pipe to the pipe.
/*
* This function opens the pipe to hold an existing native pipe.
*
* @param native_pipe A native pipe.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_pipe,
boost::system::error_code& ec)
{
impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the pipe is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the pipe.
/**
* This function is used to close the pipe. Any asynchronous read operations
* will be cancelled immediately, and will complete with the
* boost::asio::error::operation_aborted error.
*
* @throws boost::system::system_error Thrown on failure.
*/
void close()
{
boost::system::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "close");
}
/// Close the pipe.
/**
* This function is used to close the pipe. Any asynchronous read operations
* will be cancelled immediately, and will complete with the
* boost::asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Release ownership of the underlying native pipe.
/**
* This function causes all outstanding asynchronous read operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the boost::asio::error::operation_aborted error. Ownership of the
* native pipe is then transferred to the caller.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with boost::asio::error::operation_not_supported on
* these platforms.
*/
#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release()
{
boost::system::error_code ec;
native_handle_type s = impl_.get_service().release(
impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "release");
return s;
}
/// Release ownership of the underlying native pipe.
/**
* This function causes all outstanding asynchronous read operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the boost::asio::error::operation_aborted error. Ownership of the
* native pipe is then transferred to the caller.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with boost::asio::error::operation_not_supported on
* these platforms.
*/
#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release(boost::system::error_code& ec)
{
return impl_.get_service().release(impl_.get_implementation(), ec);
}
/// Get the native pipe representation.
/**
* This function may be used to obtain the underlying representation of the
* pipe. This is intended to allow access to native pipe
* functionality that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the pipe.
/**
* This function causes all outstanding asynchronous read operations to finish
* immediately, and the handlers for cancelled operations will be passed the
* boost::asio::error::operation_aborted error.
*
* @throws boost::system::system_error Thrown on failure.
*/
void cancel()
{
boost::system::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the pipe.
/**
* This function causes all outstanding asynchronous read operations to finish
* immediately, and the handlers for cancelled operations will be passed the
* boost::asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Read some data from the pipe.
/**
* This function is used to read data from the pipe. The function call will
* block until one or more bytes of data has been read successfully, or until
* an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws boost::system::system_error Thrown on failure. An error code of
* boost::asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_readable_pipe.read_some(boost::asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
boost::system::error_code ec;
std::size_t s = impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
boost::asio::detail::throw_error(ec, "read_some");
return s;
}
/// Read some data from the pipe.
/**
* This function is used to read data from the pipe. The function call will
* block until one or more bytes of data has been read successfully, or until
* an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
boost::system::error_code& ec)
{
return impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the pipe. It is an
* initiating function for an @ref asynchronous_operation, and always returns
* immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the read completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_readable_pipe.async_read_some(
* boost::asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) ReadToken = default_completion_token_t<executor_type>>
auto async_read_some(const MutableBufferSequence& buffers,
ReadToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadToken,
void (boost::system::error_code, std::size_t)>(
declval<initiate_async_read_some>(), token, buffers))
{
return async_initiate<ReadToken,
void (boost::system::error_code, std::size_t)>(
initiate_async_read_some(this), token, buffers);
}
private:
// Disallow copying and assignment.
basic_readable_pipe(const basic_readable_pipe&) = delete;
basic_readable_pipe& operator=(const basic_readable_pipe&) = delete;
class initiate_async_read_some
{
public:
typedef Executor executor_type;
explicit initiate_async_read_some(basic_readable_pipe* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ReadHandler&& handler,
const MutableBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
detail::non_const_lvalue<ReadHandler> handler2(handler);
self_->impl_.get_service().async_read_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_readable_pipe* self_;
};
#if defined(BOOST_ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_handle_service, Executor> impl_;
#elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_;
#else
detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_;
#endif
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_PIPE)
// || defined(GENERATING_DOCUMENTATION)
#endif // BOOST_ASIO_BASIC_READABLE_PIPE_HPP

View File

@ -0,0 +1,825 @@
//
// basic_seq_packet_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_HPP
#define BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <cstddef>
#include <boost/asio/basic_socket.hpp>
#include <boost/asio/detail/handler_type_requirements.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
#if !defined(BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL)
#define BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Protocol, typename Executor = any_io_executor>
class basic_seq_packet_socket;
#endif // !defined(BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL)
/// Provides sequenced packet socket functionality.
/**
* The basic_seq_packet_socket class template provides asynchronous and blocking
* sequenced packet socket functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* Synchronous @c send, @c receive, @c connect, and @c shutdown operations are
* thread safe with respect to each other, if the underlying operating system
* calls are also thread safe. This means that it is permitted to perform
* concurrent calls to these synchronous operations on a single socket object.
* Other synchronous operations, such as @c open or @c close, are not thread
* safe.
*/
template <typename Protocol, typename Executor>
class basic_seq_packet_socket
: public basic_socket<Protocol, Executor>
{
private:
class initiate_async_send;
class initiate_async_receive_with_flags;
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the socket type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_seq_packet_socket<Protocol, Executor1> other;
};
/// The native representation of a socket.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_socket<Protocol,
Executor>::native_handle_type native_handle_type;
#endif
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// Construct a basic_seq_packet_socket without opening it.
/**
* This constructor creates a sequenced packet socket without opening it. The
* socket needs to be opened and then connected or accepted before data can
* be sent or received on it.
*
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_seq_packet_socket(const executor_type& ex)
: basic_socket<Protocol, Executor>(ex)
{
}
/// Construct a basic_seq_packet_socket without opening it.
/**
* This constructor creates a sequenced packet socket without opening it. The
* socket needs to be opened and then connected or accepted before data can
* be sent or received on it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*/
template <typename ExecutionContext>
explicit basic_seq_packet_socket(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: basic_socket<Protocol, Executor>(context)
{
}
/// Construct and open a basic_seq_packet_socket.
/**
* This constructor creates and opens a sequenced_packet socket. The socket
* needs to be connected or accepted before data can be sent or received on
* it.
*
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws boost::system::system_error Thrown on failure.
*/
basic_seq_packet_socket(const executor_type& ex,
const protocol_type& protocol)
: basic_socket<Protocol, Executor>(ex, protocol)
{
}
/// Construct and open a basic_seq_packet_socket.
/**
* This constructor creates and opens a sequenced_packet socket. The socket
* needs to be connected or accepted before data can be sent or received on
* it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const protocol_type& protocol,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_socket<Protocol, Executor>(context, protocol)
{
}
/// Construct a basic_seq_packet_socket, opening it and binding it to the
/// given local endpoint.
/**
* This constructor creates a sequenced packet socket and automatically opens
* it bound to the specified endpoint on the local machine. The protocol used
* is the protocol associated with the given endpoint.
*
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the sequenced
* packet socket will be bound.
*
* @throws boost::system::system_error Thrown on failure.
*/
basic_seq_packet_socket(const executor_type& ex,
const endpoint_type& endpoint)
: basic_socket<Protocol, Executor>(ex, endpoint)
{
}
/// Construct a basic_seq_packet_socket, opening it and binding it to the
/// given local endpoint.
/**
* This constructor creates a sequenced packet socket and automatically opens
* it bound to the specified endpoint on the local machine. The protocol used
* is the protocol associated with the given endpoint.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the sequenced
* packet socket will be bound.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const endpoint_type& endpoint,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: basic_socket<Protocol, Executor>(context, endpoint)
{
}
/// Construct a basic_seq_packet_socket on an existing native socket.
/**
* This constructor creates a sequenced packet socket object to hold an
* existing native socket.
*
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws boost::system::system_error Thrown on failure.
*/
basic_seq_packet_socket(const executor_type& ex,
const protocol_type& protocol, const native_handle_type& native_socket)
: basic_socket<Protocol, Executor>(ex, protocol, native_socket)
{
}
/// Construct a basic_seq_packet_socket on an existing native socket.
/**
* This constructor creates a sequenced packet socket object to hold an
* existing native socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const protocol_type& protocol, const native_handle_type& native_socket,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: basic_socket<Protocol, Executor>(context, protocol, native_socket)
{
}
/// Move-construct a basic_seq_packet_socket from another.
/**
* This constructor moves a sequenced packet socket from one object to
* another.
*
* @param other The other basic_seq_packet_socket object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
basic_seq_packet_socket(basic_seq_packet_socket&& other) noexcept
: basic_socket<Protocol, Executor>(std::move(other))
{
}
/// Move-assign a basic_seq_packet_socket from another.
/**
* This assignment operator moves a sequenced packet socket from one object to
* another.
*
* @param other The other basic_seq_packet_socket object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other)
{
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
/// Move-construct a basic_seq_packet_socket from a socket of another protocol
/// type.
/**
* This constructor moves a sequenced packet socket from one object to
* another.
*
* @param other The other basic_seq_packet_socket object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1, typename Executor1>
basic_seq_packet_socket(basic_seq_packet_socket<Protocol1, Executor1>&& other,
constraint_t<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value
> = 0)
: basic_socket<Protocol, Executor>(std::move(other))
{
}
/// Move-assign a basic_seq_packet_socket from a socket of another protocol
/// type.
/**
* This assignment operator moves a sequenced packet socket from one object to
* another.
*
* @param other The other basic_seq_packet_socket object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1, typename Executor1>
constraint_t<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value,
basic_seq_packet_socket&
> operator=(basic_seq_packet_socket<Protocol1, Executor1>&& other)
{
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
/// Destroys the socket.
/**
* This function destroys the socket, cancelling any outstanding asynchronous
* operations associated with the socket as if by calling @c cancel.
*/
~basic_seq_packet_socket()
{
}
/// Send some data on the socket.
/**
* This function is used to send data on the sequenced packet socket. The
* function call will block until the data has been sent successfully, or an
* until error occurs.
*
* @param buffers One or more data buffers to be sent on the socket.
*
* @param flags Flags specifying how the send call is to be made.
*
* @returns The number of bytes sent.
*
* @throws boost::system::system_error Thrown on failure.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.send(boost::asio::buffer(data, size), 0);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags)
{
boost::system::error_code ec;
std::size_t s = this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, flags, ec);
boost::asio::detail::throw_error(ec, "send");
return s;
}
/// Send some data on the socket.
/**
* This function is used to send data on the sequenced packet socket. The
* function call will block the data has been sent successfully, or an until
* error occurs.
*
* @param buffers One or more data buffers to be sent on the socket.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes sent. Returns 0 if an error occurred.
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref write function if you need to ensure that all data
* is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, boost::system::error_code& ec)
{
return this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, flags, ec);
}
/// Start an asynchronous send.
/**
* This function is used to asynchronously send data on the sequenced packet
* socket. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
*
* @param buffers One or more data buffers to be sent on the socket. Although
* the buffers object may be copied as necessary, ownership of the underlying
* memory blocks is retained by the caller, which must guarantee that they
* remain valid until the completion handler is called.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the send completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.async_send(boost::asio::buffer(data, size), 0, handler);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following boost::asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename ConstBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) WriteToken
= default_completion_token_t<executor_type>>
auto async_send(const ConstBufferSequence& buffers,
socket_base::message_flags flags,
WriteToken&& token
= default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteToken,
void (boost::system::error_code, std::size_t)>(
declval<initiate_async_send>(), token, buffers, flags))
{
return async_initiate<WriteToken,
void (boost::system::error_code, std::size_t)>(
initiate_async_send(this), token, buffers, flags);
}
/// Receive some data on the socket.
/**
* This function is used to receive data on the sequenced packet socket. The
* function call will block until data has been received successfully, or
* until an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param out_flags After the receive call completes, contains flags
* associated with the received data. For example, if the
* socket_base::message_end_of_record bit is set then the received data marks
* the end of a record.
*
* @returns The number of bytes received.
*
* @throws boost::system::system_error Thrown on failure. An error code of
* boost::asio::error::eof indicates that the connection was closed by the
* peer.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.receive(boost::asio::buffer(data, size), out_flags);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags& out_flags)
{
boost::system::error_code ec;
std::size_t s = this->impl_.get_service().receive_with_flags(
this->impl_.get_implementation(), buffers, 0, out_flags, ec);
boost::asio::detail::throw_error(ec, "receive");
return s;
}
/// Receive some data on the socket.
/**
* This function is used to receive data on the sequenced packet socket. The
* function call will block until data has been received successfully, or
* until an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param in_flags Flags specifying how the receive call is to be made.
*
* @param out_flags After the receive call completes, contains flags
* associated with the received data. For example, if the
* socket_base::message_end_of_record bit is set then the received data marks
* the end of a record.
*
* @returns The number of bytes received.
*
* @throws boost::system::system_error Thrown on failure. An error code of
* boost::asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that the
* requested amount of data is read before the blocking operation completes.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.receive(boost::asio::buffer(data, size), 0, out_flags);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags in_flags,
socket_base::message_flags& out_flags)
{
boost::system::error_code ec;
std::size_t s = this->impl_.get_service().receive_with_flags(
this->impl_.get_implementation(), buffers, in_flags, out_flags, ec);
boost::asio::detail::throw_error(ec, "receive");
return s;
}
/// Receive some data on a connected socket.
/**
* This function is used to receive data on the sequenced packet socket. The
* function call will block until data has been received successfully, or
* until an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param in_flags Flags specifying how the receive call is to be made.
*
* @param out_flags After the receive call completes, contains flags
* associated with the received data. For example, if the
* socket_base::message_end_of_record bit is set then the received data marks
* the end of a record.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes received. Returns 0 if an error occurred.
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that the
* requested amount of data is read before the blocking operation completes.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags in_flags,
socket_base::message_flags& out_flags, boost::system::error_code& ec)
{
return this->impl_.get_service().receive_with_flags(
this->impl_.get_implementation(), buffers, in_flags, out_flags, ec);
}
/// Start an asynchronous receive.
/**
* This function is used to asynchronously receive data from the sequenced
* packet socket. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param out_flags Once the asynchronous operation completes, contains flags
* associated with the received data. For example, if the
* socket_base::message_end_of_record bit is set then the received data marks
* the end of a record. The caller must guarantee that the referenced
* variable remains valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the receive completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.async_receive(boost::asio::buffer(data, size), out_flags, handler);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following boost::asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename MutableBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) ReadToken = default_completion_token_t<executor_type>>
auto async_receive(const MutableBufferSequence& buffers,
socket_base::message_flags& out_flags,
ReadToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadToken,
void (boost::system::error_code, std::size_t)>(
declval<initiate_async_receive_with_flags>(), token,
buffers, socket_base::message_flags(0), &out_flags))
{
return async_initiate<ReadToken,
void (boost::system::error_code, std::size_t)>(
initiate_async_receive_with_flags(this), token,
buffers, socket_base::message_flags(0), &out_flags);
}
/// Start an asynchronous receive.
/**
* This function is used to asynchronously receive data from the sequenced
* data socket. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param in_flags Flags specifying how the receive call is to be made.
*
* @param out_flags Once the asynchronous operation completes, contains flags
* associated with the received data. For example, if the
* socket_base::message_end_of_record bit is set then the received data marks
* the end of a record. The caller must guarantee that the referenced
* variable remains valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the receive completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.async_receive(
* boost::asio::buffer(data, size),
* 0, out_flags, handler);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following boost::asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename MutableBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) ReadToken = default_completion_token_t<executor_type>>
auto async_receive(const MutableBufferSequence& buffers,
socket_base::message_flags in_flags,
socket_base::message_flags& out_flags,
ReadToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadToken,
void (boost::system::error_code, std::size_t)>(
declval<initiate_async_receive_with_flags>(),
token, buffers, in_flags, &out_flags))
{
return async_initiate<ReadToken,
void (boost::system::error_code, std::size_t)>(
initiate_async_receive_with_flags(this),
token, buffers, in_flags, &out_flags);
}
private:
// Disallow copying and assignment.
basic_seq_packet_socket(const basic_seq_packet_socket&) = delete;
basic_seq_packet_socket& operator=(
const basic_seq_packet_socket&) = delete;
class initiate_async_send
{
public:
typedef Executor executor_type;
explicit initiate_async_send(basic_seq_packet_socket* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(WriteHandler&& handler,
const ConstBufferSequence& buffers,
socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_send(
self_->impl_.get_implementation(), buffers, flags,
handler2.value, self_->impl_.get_executor());
}
private:
basic_seq_packet_socket* self_;
};
class initiate_async_receive_with_flags
{
public:
typedef Executor executor_type;
explicit initiate_async_receive_with_flags(basic_seq_packet_socket* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ReadHandler&& handler,
const MutableBufferSequence& buffers,
socket_base::message_flags in_flags,
socket_base::message_flags* out_flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
detail::non_const_lvalue<ReadHandler> handler2(handler);
self_->impl_.get_service().async_receive_with_flags(
self_->impl_.get_implementation(), buffers, in_flags,
*out_flags, handler2.value, self_->impl_.get_executor());
}
private:
basic_seq_packet_socket* self_;
};
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_HPP

View File

@ -0,0 +1,989 @@
//
// basic_serial_port.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
//
// 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 BOOST_ASIO_BASIC_SERIAL_PORT_HPP
#define BOOST_ASIO_BASIC_SERIAL_PORT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_SERIAL_PORT) \
|| defined(GENERATING_DOCUMENTATION)
#include <string>
#include <utility>
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/handler_type_requirements.hpp>
#include <boost/asio/detail/io_object_impl.hpp>
#include <boost/asio/detail/non_const_lvalue.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/serial_port_base.hpp>
#if defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/win_iocp_serial_port_service.hpp>
#else
# include <boost/asio/detail/posix_serial_port_service.hpp>
#endif
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Provides serial port functionality.
/**
* The basic_serial_port class provides a wrapper over serial port
* functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Executor = any_io_executor>
class basic_serial_port
: public serial_port_base
{
private:
class initiate_async_write_some;
class initiate_async_read_some;
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the serial port type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The serial port type when rebound to the specified executor.
typedef basic_serial_port<Executor1> other;
};
/// The native representation of a serial port.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(BOOST_ASIO_HAS_IOCP)
typedef detail::win_iocp_serial_port_service::native_handle_type
native_handle_type;
#else
typedef detail::posix_serial_port_service::native_handle_type
native_handle_type;
#endif
/// A basic_basic_serial_port is always the lowest layer.
typedef basic_serial_port lowest_layer_type;
/// Construct a basic_serial_port without opening it.
/**
* This constructor creates a serial port without opening it.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*/
explicit basic_serial_port(const executor_type& ex)
: impl_(0, ex)
{
}
/// Construct a basic_serial_port without opening it.
/**
* This constructor creates a serial port without opening it.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*/
template <typename ExecutionContext>
explicit basic_serial_port(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
basic_serial_port(const executor_type& ex, const char* device)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context, const char* device,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
basic_serial_port(const executor_type& ex, const std::string& device)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context, const std::string& device,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Construct a basic_serial_port on an existing native serial port.
/**
* This constructor creates a serial port object to hold an existing native
* serial port.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*
* @param native_serial_port A native serial port.
*
* @throws boost::system::system_error Thrown on failure.
*/
basic_serial_port(const executor_type& ex,
const native_handle_type& native_serial_port)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
boost::asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_serial_port on an existing native serial port.
/**
* This constructor creates a serial port object to hold an existing native
* serial port.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param native_serial_port A native serial port.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context,
const native_handle_type& native_serial_port,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
boost::asio::detail::throw_error(ec, "assign");
}
/// Move-construct a basic_serial_port from another.
/**
* This constructor moves a serial port from one object to another.
*
* @param other The other basic_serial_port object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/
basic_serial_port(basic_serial_port&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_serial_port from another.
/**
* This assignment operator moves a serial port from one object to another.
*
* @param other The other basic_serial_port object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/
basic_serial_port& operator=(basic_serial_port&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
// All serial ports have access to each other's implementations.
template <typename Executor1>
friend class basic_serial_port;
/// Move-construct a basic_serial_port from a serial port of another executor
/// type.
/**
* This constructor moves a serial port from one object to another.
*
* @param other The other basic_serial_port object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_serial_port(basic_serial_port<Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_serial_port from a serial port of another executor
/// type.
/**
* This assignment operator moves a serial port from one object to another.
*
* @param other The other basic_serial_port object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_serial_port&
> operator=(basic_serial_port<Executor1>&& other)
{
basic_serial_port tmp(std::move(other));
impl_ = std::move(tmp.impl_);
return *this;
}
/// Destroys the serial port.
/**
* This function destroys the serial port, cancelling any outstanding
* asynchronous wait operations associated with the serial port as if by
* calling @c cancel.
*/
~basic_serial_port()
{
}
/// Get the executor associated with the object.
const executor_type& get_executor() noexcept
{
return impl_.get_executor();
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a basic_serial_port cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a basic_serial_port cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Open the serial port using the specified device name.
/**
* This function opens the serial port for the specified device name.
*
* @param device The platform-specific device name.
*
* @throws boost::system::system_error Thrown on failure.
*/
void open(const std::string& device)
{
boost::system::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Open the serial port using the specified device name.
/**
* This function opens the serial port using the given platform-specific
* device name.
*
* @param device The platform-specific device name.
*
* @param ec Set the indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID open(const std::string& device,
boost::system::error_code& ec)
{
impl_.get_service().open(impl_.get_implementation(), device, ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Assign an existing native serial port to the serial port.
/*
* This function opens the serial port to hold an existing native serial port.
*
* @param native_serial_port A native serial port.
*
* @throws boost::system::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_serial_port)
{
boost::system::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
boost::asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native serial port to the serial port.
/*
* This function opens the serial port to hold an existing native serial port.
*
* @param native_serial_port A native serial port.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port,
boost::system::error_code& ec)
{
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the serial port is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the serial port.
/**
* This function is used to close the serial port. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* boost::asio::error::operation_aborted error.
*
* @throws boost::system::system_error Thrown on failure.
*/
void close()
{
boost::system::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "close");
}
/// Close the serial port.
/**
* This function is used to close the serial port. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* boost::asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Get the native serial port representation.
/**
* This function may be used to obtain the underlying representation of the
* serial port. This is intended to allow access to native serial port
* functionality that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the serial port.
/**
* This function causes all outstanding asynchronous read or write operations
* to finish immediately, and the handlers for cancelled operations will be
* passed the boost::asio::error::operation_aborted error.
*
* @throws boost::system::system_error Thrown on failure.
*/
void cancel()
{
boost::system::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the serial port.
/**
* This function causes all outstanding asynchronous read or write operations
* to finish immediately, and the handlers for cancelled operations will be
* passed the boost::asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Send a break sequence to the serial port.
/**
* This function causes a break sequence of platform-specific duration to be
* sent out the serial port.
*
* @throws boost::system::system_error Thrown on failure.
*/
void send_break()
{
boost::system::error_code ec;
impl_.get_service().send_break(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "send_break");
}
/// Send a break sequence to the serial port.
/**
* This function causes a break sequence of platform-specific duration to be
* sent out the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID send_break(boost::system::error_code& ec)
{
impl_.get_service().send_break(impl_.get_implementation(), ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Set an option on the serial port.
/**
* This function is used to set an option on the serial port.
*
* @param option The option value to be set on the serial port.
*
* @throws boost::system::system_error Thrown on failure.
*
* @sa SettableSerialPortOption @n
* boost::asio::serial_port_base::baud_rate @n
* boost::asio::serial_port_base::flow_control @n
* boost::asio::serial_port_base::parity @n
* boost::asio::serial_port_base::stop_bits @n
* boost::asio::serial_port_base::character_size
*/
template <typename SettableSerialPortOption>
void set_option(const SettableSerialPortOption& option)
{
boost::system::error_code ec;
impl_.get_service().set_option(impl_.get_implementation(), option, ec);
boost::asio::detail::throw_error(ec, "set_option");
}
/// Set an option on the serial port.
/**
* This function is used to set an option on the serial port.
*
* @param option The option value to be set on the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa SettableSerialPortOption @n
* boost::asio::serial_port_base::baud_rate @n
* boost::asio::serial_port_base::flow_control @n
* boost::asio::serial_port_base::parity @n
* boost::asio::serial_port_base::stop_bits @n
* boost::asio::serial_port_base::character_size
*/
template <typename SettableSerialPortOption>
BOOST_ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option,
boost::system::error_code& ec)
{
impl_.get_service().set_option(impl_.get_implementation(), option, ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Get an option from the serial port.
/**
* This function is used to get the current value of an option on the serial
* port.
*
* @param option The option value to be obtained from the serial port.
*
* @throws boost::system::system_error Thrown on failure.
*
* @sa GettableSerialPortOption @n
* boost::asio::serial_port_base::baud_rate @n
* boost::asio::serial_port_base::flow_control @n
* boost::asio::serial_port_base::parity @n
* boost::asio::serial_port_base::stop_bits @n
* boost::asio::serial_port_base::character_size
*/
template <typename GettableSerialPortOption>
void get_option(GettableSerialPortOption& option) const
{
boost::system::error_code ec;
impl_.get_service().get_option(impl_.get_implementation(), option, ec);
boost::asio::detail::throw_error(ec, "get_option");
}
/// Get an option from the serial port.
/**
* This function is used to get the current value of an option on the serial
* port.
*
* @param option The option value to be obtained from the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa GettableSerialPortOption @n
* boost::asio::serial_port_base::baud_rate @n
* boost::asio::serial_port_base::flow_control @n
* boost::asio::serial_port_base::parity @n
* boost::asio::serial_port_base::stop_bits @n
* boost::asio::serial_port_base::character_size
*/
template <typename GettableSerialPortOption>
BOOST_ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option,
boost::system::error_code& ec) const
{
impl_.get_service().get_option(impl_.get_implementation(), option, ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Write some data to the serial port.
/**
* This function is used to write data to the serial port. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the serial port.
*
* @returns The number of bytes written.
*
* @throws boost::system::system_error Thrown on failure. An error code of
* boost::asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* basic_serial_port.write_some(boost::asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
boost::system::error_code ec;
std::size_t s = impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
boost::asio::detail::throw_error(ec, "write_some");
return s;
}
/// Write some data to the serial port.
/**
* This function is used to write data to the serial port. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
boost::system::error_code& ec)
{
return impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the serial port.
* It is an initiating function for an @ref asynchronous_operation, and always
* returns immediately.
*
* @param buffers One or more data buffers to be written to the serial port.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the write completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* basic_serial_port.async_write_some(
* boost::asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following boost::asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename ConstBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) WriteToken = default_completion_token_t<executor_type>>
auto async_write_some(const ConstBufferSequence& buffers,
WriteToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteToken,
void (boost::system::error_code, std::size_t)>(
declval<initiate_async_write_some>(), token, buffers))
{
return async_initiate<WriteToken,
void (boost::system::error_code, std::size_t)>(
initiate_async_write_some(this), token, buffers);
}
/// Read some data from the serial port.
/**
* This function is used to read data from the serial port. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws boost::system::system_error Thrown on failure. An error code of
* boost::asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_serial_port.read_some(boost::asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
boost::system::error_code ec;
std::size_t s = impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
boost::asio::detail::throw_error(ec, "read_some");
return s;
}
/// Read some data from the serial port.
/**
* This function is used to read data from the serial port. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
boost::system::error_code& ec)
{
return impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the serial port.
* It is an initiating function for an @ref asynchronous_operation, and always
* returns immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the read completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_serial_port.async_read_some(
* boost::asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following boost::asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename MutableBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) ReadToken = default_completion_token_t<executor_type>>
auto async_read_some(const MutableBufferSequence& buffers,
ReadToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadToken,
void (boost::system::error_code, std::size_t)>(
declval<initiate_async_read_some>(), token, buffers))
{
return async_initiate<ReadToken,
void (boost::system::error_code, std::size_t)>(
initiate_async_read_some(this), token, buffers);
}
private:
// Disallow copying and assignment.
basic_serial_port(const basic_serial_port&) = delete;
basic_serial_port& operator=(const basic_serial_port&) = delete;
class initiate_async_write_some
{
public:
typedef Executor executor_type;
explicit initiate_async_write_some(basic_serial_port* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(WriteHandler&& handler,
const ConstBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_write_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_serial_port* self_;
};
class initiate_async_read_some
{
public:
typedef Executor executor_type;
explicit initiate_async_read_some(basic_serial_port* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ReadHandler&& handler,
const MutableBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
detail::non_const_lvalue<ReadHandler> handler2(handler);
self_->impl_.get_service().async_read_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_serial_port* self_;
};
#if defined(BOOST_ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_serial_port_service, Executor> impl_;
#else
detail::io_object_impl<detail::posix_serial_port_service, Executor> impl_;
#endif
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT)
// || defined(GENERATING_DOCUMENTATION)
#endif // BOOST_ASIO_BASIC_SERIAL_PORT_HPP

View File

@ -0,0 +1,650 @@
//
// basic_signal_set.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_SIGNAL_SET_HPP
#define BOOST_ASIO_BASIC_SIGNAL_SET_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/handler_type_requirements.hpp>
#include <boost/asio/detail/io_object_impl.hpp>
#include <boost/asio/detail/non_const_lvalue.hpp>
#include <boost/asio/detail/signal_set_service.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/signal_set_base.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Provides signal functionality.
/**
* The basic_signal_set class provides the ability to perform an asynchronous
* wait for one or more signals to occur.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Example
* Performing an asynchronous wait:
* @code
* void handler(
* const boost::system::error_code& error,
* int signal_number)
* {
* if (!error)
* {
* // A signal occurred.
* }
* }
*
* ...
*
* // Construct a signal set registered for process termination.
* boost::asio::signal_set signals(my_context, SIGINT, SIGTERM);
*
* // Start an asynchronous wait for one of the signals to occur.
* signals.async_wait(handler);
* @endcode
*
* @par Queueing of signal notifications
*
* If a signal is registered with a signal_set, and the signal occurs when
* there are no waiting handlers, then the signal notification is queued. The
* next async_wait operation on that signal_set will dequeue the notification.
* If multiple notifications are queued, subsequent async_wait operations
* dequeue them one at a time. Signal notifications are dequeued in order of
* ascending signal number.
*
* If a signal number is removed from a signal_set (using the @c remove or @c
* erase member functions) then any queued notifications for that signal are
* discarded.
*
* @par Multiple registration of signals
*
* The same signal number may be registered with different signal_set objects.
* When the signal occurs, one handler is called for each signal_set object.
*
* Note that multiple registration only works for signals that are registered
* using Asio. The application must not also register a signal handler using
* functions such as @c signal() or @c sigaction().
*
* @par Signal masking on POSIX platforms
*
* POSIX allows signals to be blocked using functions such as @c sigprocmask()
* and @c pthread_sigmask(). For signals to be delivered, programs must ensure
* that any signals registered using signal_set objects are unblocked in at
* least one thread.
*/
template <typename Executor = any_io_executor>
class basic_signal_set : public signal_set_base
{
private:
class initiate_async_wait;
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the signal set type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The signal set type when rebound to the specified executor.
typedef basic_signal_set<Executor1> other;
};
/// Construct a signal set without adding any signals.
/**
* This constructor creates a signal set without registering for any signals.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*/
explicit basic_signal_set(const executor_type& ex)
: impl_(0, ex)
{
}
/// Construct a signal set without adding any signals.
/**
* This constructor creates a signal set without registering for any signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*/
template <typename ExecutionContext>
explicit basic_signal_set(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
}
/// Construct a signal set and add one signal.
/**
* This constructor creates a signal set and registers for one signal.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*
* @param signal_number_1 The signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code boost::asio::signal_set signals(ex);
* signals.add(signal_number_1); @endcode
*/
basic_signal_set(const executor_type& ex, int signal_number_1)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
boost::asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add one signal.
/**
* This constructor creates a signal set and registers for one signal.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code boost::asio::signal_set signals(context);
* signals.add(signal_number_1); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
boost::asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add two signals.
/**
* This constructor creates a signal set and registers for two signals.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code boost::asio::signal_set signals(ex);
* signals.add(signal_number_1);
* signals.add(signal_number_2); @endcode
*/
basic_signal_set(const executor_type& ex, int signal_number_1,
int signal_number_2)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
boost::asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
boost::asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add two signals.
/**
* This constructor creates a signal set and registers for two signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code boost::asio::signal_set signals(context);
* signals.add(signal_number_1);
* signals.add(signal_number_2); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
int signal_number_2,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
boost::asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
boost::asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add three signals.
/**
* This constructor creates a signal set and registers for three signals.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @param signal_number_3 The third signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code boost::asio::signal_set signals(ex);
* signals.add(signal_number_1);
* signals.add(signal_number_2);
* signals.add(signal_number_3); @endcode
*/
basic_signal_set(const executor_type& ex, int signal_number_1,
int signal_number_2, int signal_number_3)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
boost::asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
boost::asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
boost::asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add three signals.
/**
* This constructor creates a signal set and registers for three signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @param signal_number_3 The third signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code boost::asio::signal_set signals(context);
* signals.add(signal_number_1);
* signals.add(signal_number_2);
* signals.add(signal_number_3); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
int signal_number_2, int signal_number_3,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
boost::asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
boost::asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
boost::asio::detail::throw_error(ec, "add");
}
/// Destroys the signal set.
/**
* This function destroys the signal set, cancelling any outstanding
* asynchronous wait operations associated with the signal set as if by
* calling @c cancel.
*/
~basic_signal_set()
{
}
/// Get the executor associated with the object.
const executor_type& get_executor() noexcept
{
return impl_.get_executor();
}
/// Add a signal to a signal_set.
/**
* This function adds the specified signal to the set. It has no effect if the
* signal is already in the set.
*
* @param signal_number The signal to be added to the set.
*
* @throws boost::system::system_error Thrown on failure.
*/
void add(int signal_number)
{
boost::system::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
boost::asio::detail::throw_error(ec, "add");
}
/// Add a signal to a signal_set.
/**
* This function adds the specified signal to the set. It has no effect if the
* signal is already in the set.
*
* @param signal_number The signal to be added to the set.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID add(int signal_number,
boost::system::error_code& ec)
{
impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Add a signal to a signal_set with the specified flags.
/**
* This function adds the specified signal to the set. It has no effect if the
* signal is already in the set.
*
* Flags other than flags::dont_care require OS support for the @c sigaction
* call, and this function will fail with @c error::operation_not_supported if
* this is unavailable.
*
* The specified flags will conflict with a prior, active registration of the
* same signal, if either specified a flags value other than flags::dont_care.
* In this case, the @c add will fail with @c error::invalid_argument.
*
* @param signal_number The signal to be added to the set.
*
* @param f Flags to modify the behaviour of the specified signal.
*
* @throws boost::system::system_error Thrown on failure.
*/
void add(int signal_number, flags_t f)
{
boost::system::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number, f, ec);
boost::asio::detail::throw_error(ec, "add");
}
/// Add a signal to a signal_set with the specified flags.
/**
* This function adds the specified signal to the set. It has no effect if the
* signal is already in the set.
*
* Flags other than flags::dont_care require OS support for the @c sigaction
* call, and this function will fail with @c error::operation_not_supported if
* this is unavailable.
*
* The specified flags will conflict with a prior, active registration of the
* same signal, if either specified a flags value other than flags::dont_care.
* In this case, the @c add will fail with @c error::invalid_argument.
*
* @param signal_number The signal to be added to the set.
*
* @param f Flags to modify the behaviour of the specified signal.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID add(int signal_number, flags_t f,
boost::system::error_code& ec)
{
impl_.get_service().add(impl_.get_implementation(), signal_number, f, ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Remove a signal from a signal_set.
/**
* This function removes the specified signal from the set. It has no effect
* if the signal is not in the set.
*
* @param signal_number The signal to be removed from the set.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note Removes any notifications that have been queued for the specified
* signal number.
*/
void remove(int signal_number)
{
boost::system::error_code ec;
impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
boost::asio::detail::throw_error(ec, "remove");
}
/// Remove a signal from a signal_set.
/**
* This function removes the specified signal from the set. It has no effect
* if the signal is not in the set.
*
* @param signal_number The signal to be removed from the set.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note Removes any notifications that have been queued for the specified
* signal number.
*/
BOOST_ASIO_SYNC_OP_VOID remove(int signal_number,
boost::system::error_code& ec)
{
impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Remove all signals from a signal_set.
/**
* This function removes all signals from the set. It has no effect if the set
* is already empty.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note Removes all queued notifications.
*/
void clear()
{
boost::system::error_code ec;
impl_.get_service().clear(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "clear");
}
/// Remove all signals from a signal_set.
/**
* This function removes all signals from the set. It has no effect if the set
* is already empty.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note Removes all queued notifications.
*/
BOOST_ASIO_SYNC_OP_VOID clear(boost::system::error_code& ec)
{
impl_.get_service().clear(impl_.get_implementation(), ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Cancel all operations associated with the signal set.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the signal set. The handler for each cancelled
* operation will be invoked with the boost::asio::error::operation_aborted
* error code.
*
* Cancellation does not alter the set of registered signals.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note If a registered signal occurred before cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
void cancel()
{
boost::system::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "cancel");
}
/// Cancel all operations associated with the signal set.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the signal set. The handler for each cancelled
* operation will be invoked with the boost::asio::error::operation_aborted
* error code.
*
* Cancellation does not alter the set of registered signals.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note If a registered signal occurred before cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Start an asynchronous operation to wait for a signal to be delivered.
/**
* This function may be used to initiate an asynchronous wait against the
* signal set. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
*
* For each call to async_wait(), the completion handler will be called
* exactly once. The completion handler will be called when:
*
* @li One of the registered signals in the signal set occurs; or
*
* @li The signal set was cancelled, in which case the handler is passed the
* error code boost::asio::error::operation_aborted.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the wait completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* int signal_number // Indicates which signal occurred.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code, int) @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* boost::asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, int))
SignalToken = default_completion_token_t<executor_type>>
auto async_wait(
SignalToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<SignalToken, void (boost::system::error_code, int)>(
declval<initiate_async_wait>(), token))
{
return async_initiate<SignalToken, void (boost::system::error_code, int)>(
initiate_async_wait(this), token);
}
private:
// Disallow copying and assignment.
basic_signal_set(const basic_signal_set&) = delete;
basic_signal_set& operator=(const basic_signal_set&) = delete;
class initiate_async_wait
{
public:
typedef Executor executor_type;
explicit initiate_async_wait(basic_signal_set* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename SignalHandler>
void operator()(SignalHandler&& handler) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a SignalHandler.
BOOST_ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check;
detail::non_const_lvalue<SignalHandler> handler2(handler);
self_->impl_.get_service().async_wait(
self_->impl_.get_implementation(),
handler2.value, self_->impl_.get_executor());
}
private:
basic_signal_set* self_;
};
detail::io_object_impl<detail::signal_set_service, Executor> impl_;
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_BASIC_SIGNAL_SET_HPP

1938
extern/boost/boost/asio/basic_socket.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,333 @@
//
// basic_socket_iostream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_SOCKET_IOSTREAM_HPP
#define BOOST_ASIO_BASIC_SOCKET_IOSTREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if !defined(BOOST_ASIO_NO_IOSTREAM)
#include <istream>
#include <ostream>
#include <boost/asio/basic_socket_streambuf.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
// A separate base class is used to ensure that the streambuf is initialised
// prior to the basic_socket_iostream's basic_iostream base class.
template <typename Protocol, typename Clock, typename WaitTraits>
class socket_iostream_base
{
protected:
socket_iostream_base()
{
}
socket_iostream_base(socket_iostream_base&& other)
: streambuf_(std::move(other.streambuf_))
{
}
socket_iostream_base(basic_stream_socket<Protocol> s)
: streambuf_(std::move(s))
{
}
socket_iostream_base& operator=(socket_iostream_base&& other)
{
streambuf_ = std::move(other.streambuf_);
return *this;
}
basic_socket_streambuf<Protocol, Clock, WaitTraits> streambuf_;
};
} // namespace detail
#if !defined(BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)
#define BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Protocol,
#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
&& defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = boost::posix_time::ptime,
typename WaitTraits = time_traits<Clock>>
#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock>>
#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
class basic_socket_iostream;
#endif // !defined(BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)
/// Iostream interface for a socket.
#if defined(GENERATING_DOCUMENTATION)
template <typename Protocol,
typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock>>
#else // defined(GENERATING_DOCUMENTATION)
template <typename Protocol, typename Clock, typename WaitTraits>
#endif // defined(GENERATING_DOCUMENTATION)
class basic_socket_iostream
: private detail::socket_iostream_base<Protocol, Clock, WaitTraits>,
public std::basic_iostream<char>
{
private:
// These typedefs are intended keep this class's implementation independent
// of whether it's using Boost.DateClock, Boost.Chrono or std::chrono.
#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
&& defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typedef WaitTraits traits_helper;
#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;
#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
public:
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// The clock type.
typedef Clock clock_type;
#if defined(GENERATING_DOCUMENTATION)
/// (Deprecated: Use time_point.) The time type.
typedef typename WaitTraits::time_type time_type;
/// The time type.
typedef typename WaitTraits::time_point time_point;
/// (Deprecated: Use duration.) The duration type.
typedef typename WaitTraits::duration_type duration_type;
/// The duration type.
typedef typename WaitTraits::duration duration;
#else
# if !defined(BOOST_ASIO_NO_DEPRECATED)
typedef typename traits_helper::time_type time_type;
typedef typename traits_helper::duration_type duration_type;
# endif // !defined(BOOST_ASIO_NO_DEPRECATED)
typedef typename traits_helper::time_type time_point;
typedef typename traits_helper::duration_type duration;
#endif
/// Construct a basic_socket_iostream without establishing a connection.
basic_socket_iostream()
: std::basic_iostream<char>(
&this->detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::streambuf_)
{
this->setf(std::ios_base::unitbuf);
}
/// Construct a basic_socket_iostream from the supplied socket.
explicit basic_socket_iostream(basic_stream_socket<protocol_type> s)
: detail::socket_iostream_base<
Protocol, Clock, WaitTraits>(std::move(s)),
std::basic_iostream<char>(
&this->detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::streambuf_)
{
this->setf(std::ios_base::unitbuf);
}
/// Move-construct a basic_socket_iostream from another.
basic_socket_iostream(basic_socket_iostream&& other)
: detail::socket_iostream_base<
Protocol, Clock, WaitTraits>(std::move(other)),
std::basic_iostream<char>(std::move(other))
{
this->set_rdbuf(&this->detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::streambuf_);
}
/// Move-assign a basic_socket_iostream from another.
basic_socket_iostream& operator=(basic_socket_iostream&& other)
{
std::basic_iostream<char>::operator=(std::move(other));
detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::operator=(std::move(other));
return *this;
}
/// Establish a connection to an endpoint corresponding to a resolver query.
/**
* This constructor automatically establishes a connection based on the
* supplied resolver query parameters. The arguments are used to construct
* a resolver query object.
*/
template <typename... T>
explicit basic_socket_iostream(T... x)
: std::basic_iostream<char>(
&this->detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::streambuf_)
{
this->setf(std::ios_base::unitbuf);
if (rdbuf()->connect(x...) == 0)
this->setstate(std::ios_base::failbit);
}
/// Establish a connection to an endpoint corresponding to a resolver query.
/**
* This function automatically establishes a connection based on the supplied
* resolver query parameters. The arguments are used to construct a resolver
* query object.
*/
template <typename... T>
void connect(T... x)
{
if (rdbuf()->connect(x...) == 0)
this->setstate(std::ios_base::failbit);
}
/// Close the connection.
void close()
{
if (rdbuf()->close() == 0)
this->setstate(std::ios_base::failbit);
}
/// Return a pointer to the underlying streambuf.
basic_socket_streambuf<Protocol, Clock, WaitTraits>* rdbuf() const
{
return const_cast<basic_socket_streambuf<Protocol, Clock, WaitTraits>*>(
&this->detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::streambuf_);
}
/// Get a reference to the underlying socket.
basic_socket<Protocol>& socket()
{
return rdbuf()->socket();
}
/// Get the last error associated with the stream.
/**
* @return An \c error_code corresponding to the last error from the stream.
*
* @par Example
* To print the error associated with a failure to establish a connection:
* @code tcp::iostream s("www.boost.org", "http");
* if (!s)
* {
* std::cout << "Error: " << s.error().message() << std::endl;
* } @endcode
*/
const boost::system::error_code& error() const
{
return rdbuf()->error();
}
#if !defined(BOOST_ASIO_NO_DEPRECATED)
/// (Deprecated: Use expiry().) Get the stream's expiry time as an absolute
/// time.
/**
* @return An absolute time value representing the stream's expiry time.
*/
time_point expires_at() const
{
return rdbuf()->expires_at();
}
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
/// Get the stream's expiry time as an absolute time.
/**
* @return An absolute time value representing the stream's expiry time.
*/
time_point expiry() const
{
return rdbuf()->expiry();
}
/// Set the stream's expiry time as an absolute time.
/**
* This function sets the expiry time associated with the stream. Stream
* operations performed after this time (where the operations cannot be
* completed using the internal buffers) will fail with the error
* boost::asio::error::operation_aborted.
*
* @param expiry_time The expiry time to be used for the stream.
*/
void expires_at(const time_point& expiry_time)
{
rdbuf()->expires_at(expiry_time);
}
/// Set the stream's expiry time relative to now.
/**
* This function sets the expiry time associated with the stream. Stream
* operations performed after this time (where the operations cannot be
* completed using the internal buffers) will fail with the error
* boost::asio::error::operation_aborted.
*
* @param expiry_time The expiry time to be used for the timer.
*/
void expires_after(const duration& expiry_time)
{
rdbuf()->expires_after(expiry_time);
}
#if !defined(BOOST_ASIO_NO_DEPRECATED)
/// (Deprecated: Use expiry().) Get the stream's expiry time relative to now.
/**
* @return A relative time value representing the stream's expiry time.
*/
duration expires_from_now() const
{
return rdbuf()->expires_from_now();
}
/// (Deprecated: Use expires_after().) Set the stream's expiry time relative
/// to now.
/**
* This function sets the expiry time associated with the stream. Stream
* operations performed after this time (where the operations cannot be
* completed using the internal buffers) will fail with the error
* boost::asio::error::operation_aborted.
*
* @param expiry_time The expiry time to be used for the timer.
*/
void expires_from_now(const duration& expiry_time)
{
rdbuf()->expires_from_now(expiry_time);
}
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
private:
// Disallow copying and assignment.
basic_socket_iostream(const basic_socket_iostream&) = delete;
basic_socket_iostream& operator=(
const basic_socket_iostream&) = delete;
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // !defined(BOOST_ASIO_NO_IOSTREAM)
#endif // BOOST_ASIO_BASIC_SOCKET_IOSTREAM_HPP

View File

@ -0,0 +1,644 @@
//
// basic_socket_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP
#define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if !defined(BOOST_ASIO_NO_IOSTREAM)
#include <streambuf>
#include <vector>
#include <boost/asio/basic_socket.hpp>
#include <boost/asio/basic_stream_socket.hpp>
#include <boost/asio/detail/buffer_sequence_adapter.hpp>
#include <boost/asio/detail/memory.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/io_context.hpp>
#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
&& defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
# include <boost/asio/detail/deadline_timer_service.hpp>
#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
# include <boost/asio/steady_timer.hpp>
#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
// A separate base class is used to ensure that the io_context member is
// initialised prior to the basic_socket_streambuf's basic_socket base class.
class socket_streambuf_io_context
{
protected:
socket_streambuf_io_context(io_context* ctx)
: default_io_context_(ctx)
{
}
shared_ptr<io_context> default_io_context_;
};
// A separate base class is used to ensure that the dynamically allocated
// buffers are constructed prior to the basic_socket_streambuf's basic_socket
// base class. This makes moving the socket is the last potentially throwing
// step in the streambuf's move constructor, giving the constructor a strong
// exception safety guarantee.
class socket_streambuf_buffers
{
protected:
socket_streambuf_buffers()
: get_buffer_(buffer_size),
put_buffer_(buffer_size)
{
}
enum { buffer_size = 512 };
std::vector<char> get_buffer_;
std::vector<char> put_buffer_;
};
} // namespace detail
#if !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)
#define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Protocol,
#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
&& defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = boost::posix_time::ptime,
typename WaitTraits = time_traits<Clock>>
#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock>>
#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
class basic_socket_streambuf;
#endif // !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)
/// Iostream streambuf for a socket.
#if defined(GENERATING_DOCUMENTATION)
template <typename Protocol,
typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock>>
#else // defined(GENERATING_DOCUMENTATION)
template <typename Protocol, typename Clock, typename WaitTraits>
#endif // defined(GENERATING_DOCUMENTATION)
class basic_socket_streambuf
: public std::streambuf,
private detail::socket_streambuf_io_context,
private detail::socket_streambuf_buffers,
#if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
private basic_socket<Protocol>
#else // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
public basic_socket<Protocol>
#endif // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
{
private:
// These typedefs are intended keep this class's implementation independent
// of whether it's using Boost.DateClock, Boost.Chrono or std::chrono.
#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
&& defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typedef WaitTraits traits_helper;
#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;
#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
public:
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// The clock type.
typedef Clock clock_type;
#if defined(GENERATING_DOCUMENTATION)
/// (Deprecated: Use time_point.) The time type.
typedef typename WaitTraits::time_type time_type;
/// The time type.
typedef typename WaitTraits::time_point time_point;
/// (Deprecated: Use duration.) The duration type.
typedef typename WaitTraits::duration_type duration_type;
/// The duration type.
typedef typename WaitTraits::duration duration;
#else
# if !defined(BOOST_ASIO_NO_DEPRECATED)
typedef typename traits_helper::time_type time_type;
typedef typename traits_helper::duration_type duration_type;
# endif // !defined(BOOST_ASIO_NO_DEPRECATED)
typedef typename traits_helper::time_type time_point;
typedef typename traits_helper::duration_type duration;
#endif
/// Construct a basic_socket_streambuf without establishing a connection.
basic_socket_streambuf()
: detail::socket_streambuf_io_context(new io_context),
basic_socket<Protocol>(*default_io_context_),
expiry_time_(max_expiry_time())
{
init_buffers();
}
/// Construct a basic_socket_streambuf from the supplied socket.
explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s)
: detail::socket_streambuf_io_context(0),
basic_socket<Protocol>(std::move(s)),
expiry_time_(max_expiry_time())
{
init_buffers();
}
/// Move-construct a basic_socket_streambuf from another.
basic_socket_streambuf(basic_socket_streambuf&& other)
: detail::socket_streambuf_io_context(other),
basic_socket<Protocol>(std::move(other.socket())),
ec_(other.ec_),
expiry_time_(other.expiry_time_)
{
get_buffer_.swap(other.get_buffer_);
put_buffer_.swap(other.put_buffer_);
setg(other.eback(), other.gptr(), other.egptr());
setp(other.pptr(), other.epptr());
other.ec_ = boost::system::error_code();
other.expiry_time_ = max_expiry_time();
other.init_buffers();
}
/// Move-assign a basic_socket_streambuf from another.
basic_socket_streambuf& operator=(basic_socket_streambuf&& other)
{
this->close();
socket() = std::move(other.socket());
detail::socket_streambuf_io_context::operator=(other);
ec_ = other.ec_;
expiry_time_ = other.expiry_time_;
get_buffer_.swap(other.get_buffer_);
put_buffer_.swap(other.put_buffer_);
setg(other.eback(), other.gptr(), other.egptr());
setp(other.pptr(), other.epptr());
other.ec_ = boost::system::error_code();
other.expiry_time_ = max_expiry_time();
other.put_buffer_.resize(buffer_size);
other.init_buffers();
return *this;
}
/// Destructor flushes buffered data.
virtual ~basic_socket_streambuf()
{
if (pptr() != pbase())
overflow(traits_type::eof());
}
/// Establish a connection.
/**
* This function establishes a connection to the specified endpoint.
*
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
basic_socket_streambuf* connect(const endpoint_type& endpoint)
{
init_buffers();
ec_ = boost::system::error_code();
this->connect_to_endpoints(&endpoint, &endpoint + 1);
return !ec_ ? this : 0;
}
/// Establish a connection.
/**
* This function automatically establishes a connection based on the supplied
* resolver query parameters. The arguments are used to construct a resolver
* query object.
*
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
template <typename... T>
basic_socket_streambuf* connect(T... x)
{
init_buffers();
typedef typename Protocol::resolver resolver_type;
resolver_type resolver(socket().get_executor());
connect_to_endpoints(resolver.resolve(x..., ec_));
return !ec_ ? this : 0;
}
/// Close the connection.
/**
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
basic_socket_streambuf* close()
{
sync();
socket().close(ec_);
if (!ec_)
init_buffers();
return !ec_ ? this : 0;
}
/// Get a reference to the underlying socket.
basic_socket<Protocol>& socket()
{
return *this;
}
/// Get the last error associated with the stream buffer.
/**
* @return An \c error_code corresponding to the last error from the stream
* buffer.
*/
const boost::system::error_code& error() const
{
return ec_;
}
#if !defined(BOOST_ASIO_NO_DEPRECATED)
/// (Deprecated: Use error().) Get the last error associated with the stream
/// buffer.
/**
* @return An \c error_code corresponding to the last error from the stream
* buffer.
*/
const boost::system::error_code& puberror() const
{
return error();
}
/// (Deprecated: Use expiry().) Get the stream buffer's expiry time as an
/// absolute time.
/**
* @return An absolute time value representing the stream buffer's expiry
* time.
*/
time_point expires_at() const
{
return expiry_time_;
}
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
/// Get the stream buffer's expiry time as an absolute time.
/**
* @return An absolute time value representing the stream buffer's expiry
* time.
*/
time_point expiry() const
{
return expiry_time_;
}
/// Set the stream buffer's expiry time as an absolute time.
/**
* This function sets the expiry time associated with the stream. Stream
* operations performed after this time (where the operations cannot be
* completed using the internal buffers) will fail with the error
* boost::asio::error::operation_aborted.
*
* @param expiry_time The expiry time to be used for the stream.
*/
void expires_at(const time_point& expiry_time)
{
expiry_time_ = expiry_time;
}
/// Set the stream buffer's expiry time relative to now.
/**
* This function sets the expiry time associated with the stream. Stream
* operations performed after this time (where the operations cannot be
* completed using the internal buffers) will fail with the error
* boost::asio::error::operation_aborted.
*
* @param expiry_time The expiry time to be used for the timer.
*/
void expires_after(const duration& expiry_time)
{
expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);
}
#if !defined(BOOST_ASIO_NO_DEPRECATED)
/// (Deprecated: Use expiry().) Get the stream buffer's expiry time relative
/// to now.
/**
* @return A relative time value representing the stream buffer's expiry time.
*/
duration expires_from_now() const
{
return traits_helper::subtract(expires_at(), traits_helper::now());
}
/// (Deprecated: Use expires_after().) Set the stream buffer's expiry time
/// relative to now.
/**
* This function sets the expiry time associated with the stream. Stream
* operations performed after this time (where the operations cannot be
* completed using the internal buffers) will fail with the error
* boost::asio::error::operation_aborted.
*
* @param expiry_time The expiry time to be used for the timer.
*/
void expires_from_now(const duration& expiry_time)
{
expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);
}
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
protected:
int_type underflow()
{
#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
ec_ = boost::asio::error::operation_not_supported;
return traits_type::eof();
#else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
if (gptr() != egptr())
return traits_type::eof();
for (;;)
{
// Check if we are past the expiry time.
if (traits_helper::less_than(expiry_time_, traits_helper::now()))
{
ec_ = boost::asio::error::timed_out;
return traits_type::eof();
}
// Try to complete the operation without blocking.
if (!socket().native_non_blocking())
socket().native_non_blocking(true, ec_);
detail::buffer_sequence_adapter<mutable_buffer, mutable_buffer>
bufs(boost::asio::buffer(get_buffer_) + putback_max);
detail::signed_size_type bytes = detail::socket_ops::recv(
socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);
// Check if operation succeeded.
if (bytes > 0)
{
setg(&get_buffer_[0], &get_buffer_[0] + putback_max,
&get_buffer_[0] + putback_max + bytes);
return traits_type::to_int_type(*gptr());
}
// Check for EOF.
if (bytes == 0)
{
ec_ = boost::asio::error::eof;
return traits_type::eof();
}
// Operation failed.
if (ec_ != boost::asio::error::would_block
&& ec_ != boost::asio::error::try_again)
return traits_type::eof();
// Wait for socket to become ready.
if (detail::socket_ops::poll_read(
socket().native_handle(), 0, timeout(), ec_) < 0)
return traits_type::eof();
}
#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
}
int_type overflow(int_type c)
{
#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
ec_ = boost::asio::error::operation_not_supported;
return traits_type::eof();
#else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
char_type ch = traits_type::to_char_type(c);
// Determine what needs to be sent.
const_buffer output_buffer;
if (put_buffer_.empty())
{
if (traits_type::eq_int_type(c, traits_type::eof()))
return traits_type::not_eof(c); // Nothing to do.
output_buffer = boost::asio::buffer(&ch, sizeof(char_type));
}
else
{
output_buffer = boost::asio::buffer(pbase(),
(pptr() - pbase()) * sizeof(char_type));
}
while (output_buffer.size() > 0)
{
// Check if we are past the expiry time.
if (traits_helper::less_than(expiry_time_, traits_helper::now()))
{
ec_ = boost::asio::error::timed_out;
return traits_type::eof();
}
// Try to complete the operation without blocking.
if (!socket().native_non_blocking())
socket().native_non_blocking(true, ec_);
detail::buffer_sequence_adapter<
const_buffer, const_buffer> bufs(output_buffer);
detail::signed_size_type bytes = detail::socket_ops::send(
socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);
// Check if operation succeeded.
if (bytes > 0)
{
output_buffer += static_cast<std::size_t>(bytes);
continue;
}
// Operation failed.
if (ec_ != boost::asio::error::would_block
&& ec_ != boost::asio::error::try_again)
return traits_type::eof();
// Wait for socket to become ready.
if (detail::socket_ops::poll_write(
socket().native_handle(), 0, timeout(), ec_) < 0)
return traits_type::eof();
}
if (!put_buffer_.empty())
{
setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
// If the new character is eof then our work here is done.
if (traits_type::eq_int_type(c, traits_type::eof()))
return traits_type::not_eof(c);
// Add the new character to the output buffer.
*pptr() = ch;
pbump(1);
}
return c;
#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
}
int sync()
{
return overflow(traits_type::eof());
}
std::streambuf* setbuf(char_type* s, std::streamsize n)
{
if (pptr() == pbase() && s == 0 && n == 0)
{
put_buffer_.clear();
setp(0, 0);
sync();
return this;
}
return 0;
}
private:
// Disallow copying and assignment.
basic_socket_streambuf(const basic_socket_streambuf&) = delete;
basic_socket_streambuf& operator=(
const basic_socket_streambuf&) = delete;
void init_buffers()
{
setg(&get_buffer_[0],
&get_buffer_[0] + putback_max,
&get_buffer_[0] + putback_max);
if (put_buffer_.empty())
setp(0, 0);
else
setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
}
int timeout() const
{
int64_t msec = traits_helper::to_posix_duration(
traits_helper::subtract(expiry_time_,
traits_helper::now())).total_milliseconds();
if (msec > (std::numeric_limits<int>::max)())
msec = (std::numeric_limits<int>::max)();
else if (msec < 0)
msec = 0;
return static_cast<int>(msec);
}
template <typename EndpointSequence>
void connect_to_endpoints(const EndpointSequence& endpoints)
{
this->connect_to_endpoints(endpoints.begin(), endpoints.end());
}
template <typename EndpointIterator>
void connect_to_endpoints(EndpointIterator begin, EndpointIterator end)
{
#if defined(BOOST_ASIO_WINDOWS_RUNTIME)
ec_ = boost::asio::error::operation_not_supported;
#else // defined(BOOST_ASIO_WINDOWS_RUNTIME)
if (ec_)
return;
ec_ = boost::asio::error::not_found;
for (EndpointIterator i = begin; i != end; ++i)
{
// Check if we are past the expiry time.
if (traits_helper::less_than(expiry_time_, traits_helper::now()))
{
ec_ = boost::asio::error::timed_out;
return;
}
// Close and reopen the socket.
typename Protocol::endpoint ep(*i);
socket().close(ec_);
socket().open(ep.protocol(), ec_);
if (ec_)
continue;
// Try to complete the operation without blocking.
if (!socket().native_non_blocking())
socket().native_non_blocking(true, ec_);
detail::socket_ops::connect(socket().native_handle(),
ep.data(), ep.size(), ec_);
// Check if operation succeeded.
if (!ec_)
return;
// Operation failed.
if (ec_ != boost::asio::error::in_progress
&& ec_ != boost::asio::error::would_block)
continue;
// Wait for socket to become ready.
if (detail::socket_ops::poll_connect(
socket().native_handle(), timeout(), ec_) < 0)
continue;
// Get the error code from the connect operation.
int connect_error = 0;
size_t connect_error_len = sizeof(connect_error);
if (detail::socket_ops::getsockopt(socket().native_handle(), 0,
SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len, ec_)
== detail::socket_error_retval)
return;
// Check the result of the connect operation.
ec_ = boost::system::error_code(connect_error,
boost::asio::error::get_system_category());
if (!ec_)
return;
}
#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME)
}
// Helper function to get the maximum expiry time.
static time_point max_expiry_time()
{
#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
&& defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
return boost::posix_time::pos_infin;
#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
return (time_point::max)();
#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
}
enum { putback_max = 8 };
boost::system::error_code ec_;
time_point expiry_time_;
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // !defined(BOOST_ASIO_NO_IOSTREAM)
#endif // BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP

View File

@ -0,0 +1,746 @@
//
// basic_stream_file.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_STREAM_FILE_HPP
#define BOOST_ASIO_BASIC_STREAM_FILE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_FILE) \
|| defined(GENERATING_DOCUMENTATION)
#include <cstddef>
#include <boost/asio/async_result.hpp>
#include <boost/asio/basic_file.hpp>
#include <boost/asio/detail/handler_type_requirements.hpp>
#include <boost/asio/detail/non_const_lvalue.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
#if !defined(BOOST_ASIO_BASIC_STREAM_FILE_FWD_DECL)
#define BOOST_ASIO_BASIC_STREAM_FILE_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Executor = any_io_executor>
class basic_stream_file;
#endif // !defined(BOOST_ASIO_BASIC_STREAM_FILE_FWD_DECL)
/// Provides stream-oriented file functionality.
/**
* The basic_stream_file class template provides asynchronous and blocking
* stream-oriented file functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Executor>
class basic_stream_file
: public basic_file<Executor>
{
private:
class initiate_async_write_some;
class initiate_async_read_some;
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the file type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The file type when rebound to the specified executor.
typedef basic_stream_file<Executor1> other;
};
/// The native representation of a file.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_file<Executor>::native_handle_type native_handle_type;
#endif
/// Construct a basic_stream_file without opening it.
/**
* This constructor initialises a file without opening it. The file needs to
* be opened before data can be read from or or written to it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*/
explicit basic_stream_file(const executor_type& ex)
: basic_file<Executor>(ex)
{
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
}
/// Construct a basic_stream_file without opening it.
/**
* This constructor initialises a file without opening it. The file needs to
* be opened before data can be read from or or written to it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*/
template <typename ExecutionContext>
explicit basic_stream_file(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context)
{
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
}
/// Construct and open a basic_stream_file.
/**
* This constructor initialises and opens a file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws boost::system::system_error Thrown on failure.
*/
basic_stream_file(const executor_type& ex,
const char* path, file_base::flags open_flags)
: basic_file<Executor>(ex)
{
boost::system::error_code ec;
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
this->impl_.get_service().open(
this->impl_.get_implementation(),
path, open_flags, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_stream_file.
/**
* This constructor initialises and opens a file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_file(ExecutionContext& context,
const char* path, file_base::flags open_flags,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context)
{
boost::system::error_code ec;
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
this->impl_.get_service().open(
this->impl_.get_implementation(),
path, open_flags, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_stream_file.
/**
* This constructor initialises and opens a file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws boost::system::system_error Thrown on failure.
*/
basic_stream_file(const executor_type& ex,
const std::string& path, file_base::flags open_flags)
: basic_file<Executor>(ex)
{
boost::system::error_code ec;
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
this->impl_.get_service().open(
this->impl_.get_implementation(),
path.c_str(), open_flags, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_stream_file.
/**
* This constructor initialises and opens a file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_file(ExecutionContext& context,
const std::string& path, file_base::flags open_flags,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context)
{
boost::system::error_code ec;
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
this->impl_.get_service().open(
this->impl_.get_implementation(),
path.c_str(), open_flags, ec);
boost::asio::detail::throw_error(ec, "open");
}
/// Construct a basic_stream_file on an existing native file.
/**
* This constructor initialises a stream file object to hold an existing
* native file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param native_file The new underlying file implementation.
*
* @throws boost::system::system_error Thrown on failure.
*/
basic_stream_file(const executor_type& ex,
const native_handle_type& native_file)
: basic_file<Executor>(ex, native_file)
{
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
}
/// Construct a basic_stream_file on an existing native file.
/**
* This constructor initialises a stream file object to hold an existing
* native file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param native_file The new underlying file implementation.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_file(ExecutionContext& context,
const native_handle_type& native_file,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(context, native_file)
{
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
}
/// Move-construct a basic_stream_file from another.
/**
* This constructor moves a stream file from one object to another.
*
* @param other The other basic_stream_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_file(const executor_type&)
* constructor.
*/
basic_stream_file(basic_stream_file&& other) noexcept
: basic_file<Executor>(std::move(other))
{
}
/// Move-assign a basic_stream_file from another.
/**
* This assignment operator moves a stream file from one object to another.
*
* @param other The other basic_stream_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_file(const executor_type&)
* constructor.
*/
basic_stream_file& operator=(basic_stream_file&& other)
{
basic_file<Executor>::operator=(std::move(other));
return *this;
}
/// Move-construct a basic_stream_file from a file of another executor
/// type.
/**
* This constructor moves a stream file from one object to another.
*
* @param other The other basic_stream_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_file(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_stream_file(basic_stream_file<Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
> = defaulted_constraint())
: basic_file<Executor>(std::move(other))
{
}
/// Move-assign a basic_stream_file from a file of another executor type.
/**
* This assignment operator moves a stream file from one object to another.
*
* @param other The other basic_stream_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_file(const executor_type&)
* constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_stream_file&
> operator=(basic_stream_file<Executor1>&& other)
{
basic_file<Executor>::operator=(std::move(other));
return *this;
}
/// Destroys the file.
/**
* This function destroys the file, cancelling any outstanding asynchronous
* operations associated with the file as if by calling @c cancel.
*/
~basic_stream_file()
{
}
/// Seek to a position in the file.
/**
* This function updates the current position in the file.
*
* @param offset The requested position in the file, relative to @c whence.
*
* @param whence One of @c seek_set, @c seek_cur or @c seek_end.
*
* @returns The new position relative to the beginning of the file.
*
* @throws boost::system::system_error Thrown on failure.
*/
uint64_t seek(int64_t offset, file_base::seek_basis whence)
{
boost::system::error_code ec;
uint64_t n = this->impl_.get_service().seek(
this->impl_.get_implementation(), offset, whence, ec);
boost::asio::detail::throw_error(ec, "seek");
return n;
}
/// Seek to a position in the file.
/**
* This function updates the current position in the file.
*
* @param offset The requested position in the file, relative to @c whence.
*
* @param whence One of @c seek_set, @c seek_cur or @c seek_end.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The new position relative to the beginning of the file.
*/
uint64_t seek(int64_t offset, file_base::seek_basis whence,
boost::system::error_code& ec)
{
return this->impl_.get_service().seek(
this->impl_.get_implementation(), offset, whence, ec);
}
/// Write some data to the file.
/**
* This function is used to write data to the stream file. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the file.
*
* @returns The number of bytes written.
*
* @throws boost::system::system_error Thrown on failure. An error code of
* boost::asio::error::eof indicates that the end of the file was reached.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* file.write_some(boost::asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
boost::system::error_code ec;
std::size_t s = this->impl_.get_service().write_some(
this->impl_.get_implementation(), buffers, ec);
boost::asio::detail::throw_error(ec, "write_some");
return s;
}
/// Write some data to the file.
/**
* This function is used to write data to the stream file. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the file.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
boost::system::error_code& ec)
{
return this->impl_.get_service().write_some(
this->impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the stream file.
* It is an initiating function for an @ref asynchronous_operation, and always
* returns immediately.
*
* @param buffers One or more data buffers to be written to the file.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the write completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* file.async_write_some(boost::asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following boost::asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename ConstBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) WriteToken = default_completion_token_t<executor_type>>
auto async_write_some(const ConstBufferSequence& buffers,
WriteToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteToken,
void (boost::system::error_code, std::size_t)>(
declval<initiate_async_write_some>(), token, buffers))
{
return async_initiate<WriteToken,
void (boost::system::error_code, std::size_t)>(
initiate_async_write_some(this), token, buffers);
}
/// Read some data from the file.
/**
* This function is used to read data from the stream file. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws boost::system::system_error Thrown on failure. An error code of
* boost::asio::error::eof indicates that the end of the file was reached.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* file.read_some(boost::asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
boost::system::error_code ec;
std::size_t s = this->impl_.get_service().read_some(
this->impl_.get_implementation(), buffers, ec);
boost::asio::detail::throw_error(ec, "read_some");
return s;
}
/// Read some data from the file.
/**
* This function is used to read data from the stream file. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
boost::system::error_code& ec)
{
return this->impl_.get_service().read_some(
this->impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the stream file.
* It is an initiating function for an @ref asynchronous_operation, and always
* returns immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the read completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* file.async_read_some(boost::asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following boost::asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename MutableBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) ReadToken = default_completion_token_t<executor_type>>
auto async_read_some(const MutableBufferSequence& buffers,
ReadToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadToken,
void (boost::system::error_code, std::size_t)>(
declval<initiate_async_read_some>(), token, buffers))
{
return async_initiate<ReadToken,
void (boost::system::error_code, std::size_t)>(
initiate_async_read_some(this), token, buffers);
}
private:
// Disallow copying and assignment.
basic_stream_file(const basic_stream_file&) = delete;
basic_stream_file& operator=(const basic_stream_file&) = delete;
class initiate_async_write_some
{
public:
typedef Executor executor_type;
explicit initiate_async_write_some(basic_stream_file* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(WriteHandler&& handler,
const ConstBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_write_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_stream_file* self_;
};
class initiate_async_read_some
{
public:
typedef Executor executor_type;
explicit initiate_async_read_some(basic_stream_file* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ReadHandler&& handler,
const MutableBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
detail::non_const_lvalue<ReadHandler> handler2(handler);
self_->impl_.get_service().async_read_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_stream_file* self_;
};
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_FILE)
// || defined(GENERATING_DOCUMENTATION)
#endif // BOOST_ASIO_BASIC_STREAM_FILE_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,452 @@
//
// basic_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_STREAMBUF_HPP
#define BOOST_ASIO_BASIC_STREAMBUF_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if !defined(BOOST_ASIO_NO_IOSTREAM)
#include <algorithm>
#include <cstring>
#include <stdexcept>
#include <streambuf>
#include <vector>
#include <boost/asio/basic_streambuf_fwd.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/detail/limits.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/throw_exception.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Automatically resizable buffer class based on std::streambuf.
/**
* The @c basic_streambuf class is derived from @c std::streambuf to associate
* the streambuf's input and output sequences with one or more character
* arrays. These character arrays are internal to the @c basic_streambuf
* object, but direct access to the array elements is provided to permit them
* to be used efficiently with I/O operations. Characters written to the output
* sequence of a @c basic_streambuf object are appended to the input sequence
* of the same object.
*
* The @c basic_streambuf class's public interface is intended to permit the
* following implementation strategies:
*
* @li A single contiguous character array, which is reallocated as necessary
* to accommodate changes in the size of the character sequence. This is the
* implementation approach currently used in Asio.
*
* @li A sequence of one or more character arrays, where each array is of the
* same size. Additional character array objects are appended to the sequence
* to accommodate changes in the size of the character sequence.
*
* @li A sequence of one or more character arrays of varying sizes. Additional
* character array objects are appended to the sequence to accommodate changes
* in the size of the character sequence.
*
* The constructor for basic_streambuf accepts a @c size_t argument specifying
* the maximum of the sum of the sizes of the input sequence and output
* sequence. During the lifetime of the @c basic_streambuf object, the following
* invariant holds:
* @code size() <= max_size()@endcode
* Any member function that would, if successful, cause the invariant to be
* violated shall throw an exception of class @c std::length_error.
*
* The constructor for @c basic_streambuf takes an Allocator argument. A copy
* of this argument is used for any memory allocation performed, by the
* constructor and by all member functions, during the lifetime of each @c
* basic_streambuf object.
*
* @par Examples
* Writing directly from an streambuf to a socket:
* @code
* boost::asio::streambuf b;
* std::ostream os(&b);
* os << "Hello, World!\n";
*
* // try sending some data in input sequence
* size_t n = sock.send(b.data());
*
* b.consume(n); // sent data is removed from input sequence
* @endcode
*
* Reading from a socket directly into a streambuf:
* @code
* boost::asio::streambuf b;
*
* // reserve 512 bytes in output sequence
* boost::asio::streambuf::mutable_buffers_type bufs = b.prepare(512);
*
* size_t n = sock.receive(bufs);
*
* // received data is "committed" from output sequence to input sequence
* b.commit(n);
*
* std::istream is(&b);
* std::string s;
* is >> s;
* @endcode
*/
#if defined(GENERATING_DOCUMENTATION)
template <typename Allocator = std::allocator<char>>
#else
template <typename Allocator>
#endif
class basic_streambuf
: public std::streambuf,
private noncopyable
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The type used to represent the input sequence as a list of buffers.
typedef implementation_defined const_buffers_type;
/// The type used to represent the output sequence as a list of buffers.
typedef implementation_defined mutable_buffers_type;
#else
typedef BOOST_ASIO_CONST_BUFFER const_buffers_type;
typedef BOOST_ASIO_MUTABLE_BUFFER mutable_buffers_type;
#endif
/// Construct a basic_streambuf object.
/**
* Constructs a streambuf with the specified maximum size. The initial size
* of the streambuf's input sequence is 0.
*/
explicit basic_streambuf(
std::size_t maximum_size = (std::numeric_limits<std::size_t>::max)(),
const Allocator& allocator = Allocator())
: max_size_(maximum_size),
buffer_(allocator)
{
std::size_t pend = (std::min<std::size_t>)(max_size_, buffer_delta);
buffer_.resize((std::max<std::size_t>)(pend, 1));
setg(&buffer_[0], &buffer_[0], &buffer_[0]);
setp(&buffer_[0], &buffer_[0] + pend);
}
/// Get the size of the input sequence.
/**
* @returns The size of the input sequence. The value is equal to that
* calculated for @c s in the following code:
* @code
* size_t s = 0;
* const_buffers_type bufs = data();
* const_buffers_type::const_iterator i = bufs.begin();
* while (i != bufs.end())
* {
* const_buffer buf(*i++);
* s += buf.size();
* }
* @endcode
*/
std::size_t size() const noexcept
{
return pptr() - gptr();
}
/// Get the maximum size of the basic_streambuf.
/**
* @returns The allowed maximum of the sum of the sizes of the input sequence
* and output sequence.
*/
std::size_t max_size() const noexcept
{
return max_size_;
}
/// Get the current capacity of the basic_streambuf.
/**
* @returns The current total capacity of the streambuf, i.e. for both the
* input sequence and output sequence.
*/
std::size_t capacity() const noexcept
{
return buffer_.capacity();
}
/// Get a list of buffers that represents the input sequence.
/**
* @returns An object of type @c const_buffers_type that satisfies
* ConstBufferSequence requirements, representing all character arrays in the
* input sequence.
*
* @note The returned object is invalidated by any @c basic_streambuf member
* function that modifies the input sequence or output sequence.
*/
const_buffers_type data() const noexcept
{
return boost::asio::buffer(boost::asio::const_buffer(gptr(),
(pptr() - gptr()) * sizeof(char_type)));
}
/// Get a list of buffers that represents the output sequence, with the given
/// size.
/**
* Ensures that the output sequence can accommodate @c n characters,
* reallocating character array objects as necessary.
*
* @returns An object of type @c mutable_buffers_type that satisfies
* MutableBufferSequence requirements, representing character array objects
* at the start of the output sequence such that the sum of the buffer sizes
* is @c n.
*
* @throws std::length_error If <tt>size() + n > max_size()</tt>.
*
* @note The returned object is invalidated by any @c basic_streambuf member
* function that modifies the input sequence or output sequence.
*/
mutable_buffers_type prepare(std::size_t n)
{
reserve(n);
return boost::asio::buffer(boost::asio::mutable_buffer(
pptr(), n * sizeof(char_type)));
}
/// Move characters from the output sequence to the input sequence.
/**
* Appends @c n characters from the start of the output sequence to the input
* sequence. The beginning of the output sequence is advanced by @c n
* characters.
*
* Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and
* no intervening operations that modify the input or output sequence.
*
* @note If @c n is greater than the size of the output sequence, the entire
* output sequence is moved to the input sequence and no error is issued.
*/
void commit(std::size_t n)
{
n = std::min<std::size_t>(n, epptr() - pptr());
pbump(static_cast<int>(n));
setg(eback(), gptr(), pptr());
}
/// Remove characters from the input sequence.
/**
* Removes @c n characters from the beginning of the input sequence.
*
* @note If @c n is greater than the size of the input sequence, the entire
* input sequence is consumed and no error is issued.
*/
void consume(std::size_t n)
{
if (egptr() < pptr())
setg(&buffer_[0], gptr(), pptr());
if (gptr() + n > pptr())
n = pptr() - gptr();
gbump(static_cast<int>(n));
}
protected:
enum { buffer_delta = 128 };
/// Override std::streambuf behaviour.
/**
* Behaves according to the specification of @c std::streambuf::underflow().
*/
int_type underflow()
{
if (gptr() < pptr())
{
setg(&buffer_[0], gptr(), pptr());
return traits_type::to_int_type(*gptr());
}
else
{
return traits_type::eof();
}
}
/// Override std::streambuf behaviour.
/**
* Behaves according to the specification of @c std::streambuf::overflow(),
* with the specialisation that @c std::length_error is thrown if appending
* the character to the input sequence would require the condition
* <tt>size() > max_size()</tt> to be true.
*/
int_type overflow(int_type c)
{
if (!traits_type::eq_int_type(c, traits_type::eof()))
{
if (pptr() == epptr())
{
std::size_t buffer_size = pptr() - gptr();
if (buffer_size < max_size_ && max_size_ - buffer_size < buffer_delta)
{
reserve(max_size_ - buffer_size);
}
else
{
reserve(buffer_delta);
}
}
*pptr() = traits_type::to_char_type(c);
pbump(1);
return c;
}
return traits_type::not_eof(c);
}
void reserve(std::size_t n)
{
// Get current stream positions as offsets.
std::size_t gnext = gptr() - &buffer_[0];
std::size_t pnext = pptr() - &buffer_[0];
std::size_t pend = epptr() - &buffer_[0];
// Check if there is already enough space in the put area.
if (n <= pend - pnext)
{
return;
}
// Shift existing contents of get area to start of buffer.
if (gnext > 0)
{
pnext -= gnext;
std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext);
}
// Ensure buffer is large enough to hold at least the specified size.
if (n > pend - pnext)
{
if (n <= max_size_ && pnext <= max_size_ - n)
{
pend = pnext + n;
buffer_.resize((std::max<std::size_t>)(pend, 1));
}
else
{
std::length_error ex("boost::asio::streambuf too long");
boost::asio::detail::throw_exception(ex);
}
}
// Update stream positions.
setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext);
setp(&buffer_[0] + pnext, &buffer_[0] + pend);
}
private:
std::size_t max_size_;
std::vector<char_type, Allocator> buffer_;
// Helper function to get the preferred size for reading data.
friend std::size_t read_size_helper(
basic_streambuf& sb, std::size_t max_size)
{
return std::min<std::size_t>(
std::max<std::size_t>(512, sb.buffer_.capacity() - sb.size()),
std::min<std::size_t>(max_size, sb.max_size() - sb.size()));
}
};
/// Adapts basic_streambuf to the dynamic buffer sequence type requirements.
#if defined(GENERATING_DOCUMENTATION)
template <typename Allocator = std::allocator<char>>
#else
template <typename Allocator>
#endif
class basic_streambuf_ref
{
public:
/// The type used to represent the input sequence as a list of buffers.
typedef typename basic_streambuf<Allocator>::const_buffers_type
const_buffers_type;
/// The type used to represent the output sequence as a list of buffers.
typedef typename basic_streambuf<Allocator>::mutable_buffers_type
mutable_buffers_type;
/// Construct a basic_streambuf_ref for the given basic_streambuf object.
explicit basic_streambuf_ref(basic_streambuf<Allocator>& sb)
: sb_(sb)
{
}
/// Copy construct a basic_streambuf_ref.
basic_streambuf_ref(const basic_streambuf_ref& other) noexcept
: sb_(other.sb_)
{
}
/// Move construct a basic_streambuf_ref.
basic_streambuf_ref(basic_streambuf_ref&& other) noexcept
: sb_(other.sb_)
{
}
/// Get the size of the input sequence.
std::size_t size() const noexcept
{
return sb_.size();
}
/// Get the maximum size of the dynamic buffer.
std::size_t max_size() const noexcept
{
return sb_.max_size();
}
/// Get the current capacity of the dynamic buffer.
std::size_t capacity() const noexcept
{
return sb_.capacity();
}
/// Get a list of buffers that represents the input sequence.
const_buffers_type data() const noexcept
{
return sb_.data();
}
/// Get a list of buffers that represents the output sequence, with the given
/// size.
mutable_buffers_type prepare(std::size_t n)
{
return sb_.prepare(n);
}
/// Move bytes from the output sequence to the input sequence.
void commit(std::size_t n)
{
return sb_.commit(n);
}
/// Remove characters from the input sequence.
void consume(std::size_t n)
{
return sb_.consume(n);
}
private:
basic_streambuf<Allocator>& sb_;
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // !defined(BOOST_ASIO_NO_IOSTREAM)
#endif // BOOST_ASIO_BASIC_STREAMBUF_HPP

View File

@ -0,0 +1,38 @@
//
// basic_streambuf_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_STREAMBUF_FWD_HPP
#define BOOST_ASIO_BASIC_STREAMBUF_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if !defined(BOOST_ASIO_NO_IOSTREAM)
#include <memory>
namespace boost {
namespace asio {
template <typename Allocator = std::allocator<char>>
class basic_streambuf;
template <typename Allocator = std::allocator<char>>
class basic_streambuf_ref;
} // namespace asio
} // namespace boost
#endif // !defined(BOOST_ASIO_NO_IOSTREAM)
#endif // BOOST_ASIO_BASIC_STREAMBUF_FWD_HPP

View File

@ -0,0 +1,826 @@
//
// basic_waitable_timer.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_WAITABLE_TIMER_HPP
#define BOOST_ASIO_BASIC_WAITABLE_TIMER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <cstddef>
#include <utility>
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/detail/chrono_time_traits.hpp>
#include <boost/asio/detail/deadline_timer_service.hpp>
#include <boost/asio/detail/handler_type_requirements.hpp>
#include <boost/asio/detail/io_object_impl.hpp>
#include <boost/asio/detail/non_const_lvalue.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/wait_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
#if !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
#define BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Clock,
typename WaitTraits = boost::asio::wait_traits<Clock>,
typename Executor = any_io_executor>
class basic_waitable_timer;
#endif // !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
/// Provides waitable timer functionality.
/**
* The basic_waitable_timer class template provides the ability to perform a
* blocking or asynchronous wait for a timer to expire.
*
* A waitable timer is always in one of two states: "expired" or "not expired".
* If the wait() or async_wait() function is called on an expired timer, the
* wait operation will complete immediately.
*
* Most applications will use one of the boost::asio::steady_timer,
* boost::asio::system_timer or boost::asio::high_resolution_timer typedefs.
*
* @note This waitable timer functionality is for use with the C++11 standard
* library's @c &lt;chrono&gt; facility, or with the Boost.Chrono library.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Examples
* Performing a blocking wait (C++11):
* @code
* // Construct a timer without setting an expiry time.
* boost::asio::steady_timer timer(my_context);
*
* // Set an expiry time relative to now.
* timer.expires_after(std::chrono::seconds(5));
*
* // Wait for the timer to expire.
* timer.wait();
* @endcode
*
* @par
* Performing an asynchronous wait (C++11):
* @code
* void handler(const boost::system::error_code& error)
* {
* if (!error)
* {
* // Timer expired.
* }
* }
*
* ...
*
* // Construct a timer with an absolute expiry time.
* boost::asio::steady_timer timer(my_context,
* std::chrono::steady_clock::now() + std::chrono::seconds(60));
*
* // Start an asynchronous wait.
* timer.async_wait(handler);
* @endcode
*
* @par Changing an active waitable timer's expiry time
*
* Changing the expiry time of a timer while there are pending asynchronous
* waits causes those wait operations to be cancelled. To ensure that the action
* associated with the timer is performed only once, use something like this:
* used:
*
* @code
* void on_some_event()
* {
* if (my_timer.expires_after(seconds(5)) > 0)
* {
* // We managed to cancel the timer. Start new asynchronous wait.
* my_timer.async_wait(on_timeout);
* }
* else
* {
* // Too late, timer has already expired!
* }
* }
*
* void on_timeout(const boost::system::error_code& e)
* {
* if (e != boost::asio::error::operation_aborted)
* {
* // Timer was not cancelled, take necessary action.
* }
* }
* @endcode
*
* @li The boost::asio::basic_waitable_timer::expires_after() function
* cancels any pending asynchronous waits, and returns the number of
* asynchronous waits that were cancelled. If it returns 0 then you were too
* late and the wait handler has already been executed, or will soon be
* executed. If it returns 1 then the wait handler was successfully cancelled.
*
* @li If a wait handler is cancelled, the boost::system::error_code passed to
* it contains the value boost::asio::error::operation_aborted.
*/
template <typename Clock, typename WaitTraits, typename Executor>
class basic_waitable_timer
{
private:
class initiate_async_wait;
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the timer type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The timer type when rebound to the specified executor.
typedef basic_waitable_timer<Clock, WaitTraits, Executor1> other;
};
/// The clock type.
typedef Clock clock_type;
/// The duration type of the clock.
typedef typename clock_type::duration duration;
/// The time point type of the clock.
typedef typename clock_type::time_point time_point;
/// The wait traits type.
typedef WaitTraits traits_type;
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_after() functions must be called to set an expiry
* time before the timer can be waited on.
*
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*/
explicit basic_waitable_timer(const executor_type& ex)
: impl_(0, ex)
{
}
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_after() functions must be called to set an expiry
* time before the timer can be waited on.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param ex The I/O executor object that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
basic_waitable_timer(const executor_type& ex, const time_point& expiry_time)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
boost::asio::detail::throw_error(ec, "expires_at");
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
const time_point& expiry_time,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
boost::asio::detail::throw_error(ec, "expires_at");
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
basic_waitable_timer(const executor_type& ex, const duration& expiry_time)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().expires_after(
impl_.get_implementation(), expiry_time, ec);
boost::asio::detail::throw_error(ec, "expires_after");
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
const duration& expiry_time,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().expires_after(
impl_.get_implementation(), expiry_time, ec);
boost::asio::detail::throw_error(ec, "expires_after");
}
/// Move-construct a basic_waitable_timer from another.
/**
* This constructor moves a timer from one object to another.
*
* @param other The other basic_waitable_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
basic_waitable_timer(basic_waitable_timer&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_waitable_timer from another.
/**
* This assignment operator moves a timer from one object to another. Cancels
* any outstanding asynchronous operations associated with the target object.
*
* @param other The other basic_waitable_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
basic_waitable_timer& operator=(basic_waitable_timer&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
// All timers have access to each other's implementations.
template <typename Clock1, typename WaitTraits1, typename Executor1>
friend class basic_waitable_timer;
/// Move-construct a basic_waitable_timer from another.
/**
* This constructor moves a timer from one object to another.
*
* @param other The other basic_waitable_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_waitable_timer(
basic_waitable_timer<Clock, WaitTraits, Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value
> = 0)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_waitable_timer from another.
/**
* This assignment operator moves a timer from one object to another. Cancels
* any outstanding asynchronous operations associated with the target object.
*
* @param other The other basic_waitable_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_waitable_timer&
> operator=(basic_waitable_timer<Clock, WaitTraits, Executor1>&& other)
{
basic_waitable_timer tmp(std::move(other));
impl_ = std::move(tmp.impl_);
return *this;
}
/// Destroys the timer.
/**
* This function destroys the timer, cancelling any outstanding asynchronous
* wait operations associated with the timer as if by calling @c cancel.
*/
~basic_waitable_timer()
{
}
/// Get the executor associated with the object.
const executor_type& get_executor() noexcept
{
return impl_.get_executor();
}
/// Cancel any asynchronous operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the timer. The handler for each cancelled operation will
* be invoked with the boost::asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note If the timer has already expired when cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel()
{
boost::system::error_code ec;
std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "cancel");
return s;
}
#if !defined(BOOST_ASIO_NO_DEPRECATED)
/// (Deprecated: Use non-error_code overload.) Cancel any asynchronous
/// operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the timer. The handler for each cancelled operation will
* be invoked with the boost::asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*
* @note If the timer has already expired when cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel(boost::system::error_code& ec)
{
return impl_.get_service().cancel(impl_.get_implementation(), ec);
}
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
/// Cancels one asynchronous operation that is waiting on the timer.
/**
* This function forces the completion of one pending asynchronous wait
* operation against the timer. Handlers are cancelled in FIFO order. The
* handler for the cancelled operation will be invoked with the
* boost::asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @return The number of asynchronous operations that were cancelled. That is,
* either 0 or 1.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note If the timer has already expired when cancel_one() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel_one()
{
boost::system::error_code ec;
std::size_t s = impl_.get_service().cancel_one(
impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "cancel_one");
return s;
}
#if !defined(BOOST_ASIO_NO_DEPRECATED)
/// (Deprecated: Use non-error_code overload.) Cancels one asynchronous
/// operation that is waiting on the timer.
/**
* This function forces the completion of one pending asynchronous wait
* operation against the timer. Handlers are cancelled in FIFO order. The
* handler for the cancelled operation will be invoked with the
* boost::asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled. That is,
* either 0 or 1.
*
* @note If the timer has already expired when cancel_one() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel_one(boost::system::error_code& ec)
{
return impl_.get_service().cancel_one(impl_.get_implementation(), ec);
}
/// (Deprecated: Use expiry().) Get the timer's expiry time as an absolute
/// time.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
time_point expires_at() const
{
return impl_.get_service().expires_at(impl_.get_implementation());
}
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
/// Get the timer's expiry time as an absolute time.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
time_point expiry() const
{
return impl_.get_service().expiry(impl_.get_implementation());
}
/// Set the timer's expiry time as an absolute time.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the boost::asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note If the timer has already expired when expires_at() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_at(const time_point& expiry_time)
{
boost::system::error_code ec;
std::size_t s = impl_.get_service().expires_at(
impl_.get_implementation(), expiry_time, ec);
boost::asio::detail::throw_error(ec, "expires_at");
return s;
}
#if !defined(BOOST_ASIO_NO_DEPRECATED)
/// (Deprecated: Use non-error_code overload.) Set the timer's expiry time as
/// an absolute time.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the boost::asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*
* @note If the timer has already expired when expires_at() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_at(const time_point& expiry_time,
boost::system::error_code& ec)
{
return impl_.get_service().expires_at(
impl_.get_implementation(), expiry_time, ec);
}
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
/// Set the timer's expiry time relative to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the boost::asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note If the timer has already expired when expires_after() is called,
* then the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_after(const duration& expiry_time)
{
boost::system::error_code ec;
std::size_t s = impl_.get_service().expires_after(
impl_.get_implementation(), expiry_time, ec);
boost::asio::detail::throw_error(ec, "expires_after");
return s;
}
#if !defined(BOOST_ASIO_NO_DEPRECATED)
/// (Deprecated: Use expiry().) Get the timer's expiry time relative to now.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
duration expires_from_now() const
{
return impl_.get_service().expires_from_now(impl_.get_implementation());
}
/// (Deprecated: Use expires_after().) Set the timer's expiry time relative
/// to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the boost::asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note If the timer has already expired when expires_from_now() is called,
* then the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_from_now(const duration& expiry_time)
{
boost::system::error_code ec;
std::size_t s = impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
boost::asio::detail::throw_error(ec, "expires_from_now");
return s;
}
/// (Deprecated: Use expires_after().) Set the timer's expiry time relative
/// to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the boost::asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*
* @note If the timer has already expired when expires_from_now() is called,
* then the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_from_now(const duration& expiry_time,
boost::system::error_code& ec)
{
return impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
}
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
/// Perform a blocking wait on the timer.
/**
* This function is used to wait for the timer to expire. This function
* blocks and does not return until the timer has expired.
*
* @throws boost::system::system_error Thrown on failure.
*/
void wait()
{
boost::system::error_code ec;
impl_.get_service().wait(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "wait");
}
/// Perform a blocking wait on the timer.
/**
* This function is used to wait for the timer to expire. This function
* blocks and does not return until the timer has expired.
*
* @param ec Set to indicate what error occurred, if any.
*/
void wait(boost::system::error_code& ec)
{
impl_.get_service().wait(impl_.get_implementation(), ec);
}
/// Start an asynchronous wait on the timer.
/**
* This function may be used to initiate an asynchronous wait against the
* timer. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
*
* For each call to async_wait(), the completion handler will be called
* exactly once. The completion handler will be called when:
*
* @li The timer has expired.
*
* @li The timer was cancelled, in which case the handler is passed the error
* code boost::asio::error::operation_aborted.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the timer expires. Potential
* completion tokens include @ref use_future, @ref use_awaitable, @ref
* yield_context, or a function object with the correct completion signature.
* The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code) @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* boost::asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code))
WaitToken = default_completion_token_t<executor_type>>
auto async_wait(
WaitToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WaitToken, void (boost::system::error_code)>(
declval<initiate_async_wait>(), token))
{
return async_initiate<WaitToken, void (boost::system::error_code)>(
initiate_async_wait(this), token);
}
private:
// Disallow copying and assignment.
basic_waitable_timer(const basic_waitable_timer&) = delete;
basic_waitable_timer& operator=(const basic_waitable_timer&) = delete;
class initiate_async_wait
{
public:
typedef Executor executor_type;
explicit initiate_async_wait(basic_waitable_timer* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WaitHandler>
void operator()(WaitHandler&& handler) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WaitHandler.
BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
detail::non_const_lvalue<WaitHandler> handler2(handler);
self_->impl_.get_service().async_wait(
self_->impl_.get_implementation(),
handler2.value, self_->impl_.get_executor());
}
private:
basic_waitable_timer* self_;
};
detail::io_object_impl<
detail::deadline_timer_service<
detail::chrono_time_traits<Clock, WaitTraits>>,
executor_type > impl_;
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_BASIC_WAITABLE_TIMER_HPP

View File

@ -0,0 +1,624 @@
//
// basic_writable_pipe.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BASIC_WRITABLE_PIPE_HPP
#define BOOST_ASIO_BASIC_WRITABLE_PIPE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_PIPE) \
|| defined(GENERATING_DOCUMENTATION)
#include <string>
#include <utility>
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/handler_type_requirements.hpp>
#include <boost/asio/detail/io_object_impl.hpp>
#include <boost/asio/detail/non_const_lvalue.hpp>
#include <boost/asio/detail/throw_error.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/execution_context.hpp>
#if defined(BOOST_ASIO_HAS_IOCP)
# include <boost/asio/detail/win_iocp_handle_service.hpp>
#elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
# include <boost/asio/detail/io_uring_descriptor_service.hpp>
#else
# include <boost/asio/detail/reactive_descriptor_service.hpp>
#endif
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Provides pipe functionality.
/**
* The basic_writable_pipe class provides a wrapper over pipe
* functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Executor = any_io_executor>
class basic_writable_pipe
{
private:
class initiate_async_write_some;
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the pipe type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The pipe type when rebound to the specified executor.
typedef basic_writable_pipe<Executor1> other;
};
/// The native representation of a pipe.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(BOOST_ASIO_HAS_IOCP)
typedef detail::win_iocp_handle_service::native_handle_type
native_handle_type;
#elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
typedef detail::io_uring_descriptor_service::native_handle_type
native_handle_type;
#else
typedef detail::reactive_descriptor_service::native_handle_type
native_handle_type;
#endif
/// A basic_writable_pipe is always the lowest layer.
typedef basic_writable_pipe lowest_layer_type;
/// Construct a basic_writable_pipe without opening it.
/**
* This constructor creates a pipe without opening it.
*
* @param ex The I/O executor that the pipe will use, by default, to dispatch
* handlers for any asynchronous operations performed on the pipe.
*/
explicit basic_writable_pipe(const executor_type& ex)
: impl_(0, ex)
{
}
/// Construct a basic_writable_pipe without opening it.
/**
* This constructor creates a pipe without opening it.
*
* @param context An execution context which provides the I/O executor that
* the pipe will use, by default, to dispatch handlers for any asynchronous
* operations performed on the pipe.
*/
template <typename ExecutionContext>
explicit basic_writable_pipe(ExecutionContext& context,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(0, 0, context)
{
}
/// Construct a basic_writable_pipe on an existing native pipe.
/**
* This constructor creates a pipe object to hold an existing native
* pipe.
*
* @param ex The I/O executor that the pipe will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* pipe.
*
* @param native_pipe A native pipe.
*
* @throws boost::system::system_error Thrown on failure.
*/
basic_writable_pipe(const executor_type& ex,
const native_handle_type& native_pipe)
: impl_(0, ex)
{
boost::system::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_pipe, ec);
boost::asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_writable_pipe on an existing native pipe.
/**
* This constructor creates a pipe object to hold an existing native
* pipe.
*
* @param context An execution context which provides the I/O executor that
* the pipe will use, by default, to dispatch handlers for any
* asynchronous operations performed on the pipe.
*
* @param native_pipe A native pipe.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_writable_pipe(ExecutionContext& context,
const native_handle_type& native_pipe,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: impl_(0, 0, context)
{
boost::system::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_pipe, ec);
boost::asio::detail::throw_error(ec, "assign");
}
/// Move-construct a basic_writable_pipe from another.
/**
* This constructor moves a pipe from one object to another.
*
* @param other The other basic_writable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_writable_pipe(const executor_type&)
* constructor.
*/
basic_writable_pipe(basic_writable_pipe&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_writable_pipe from another.
/**
* This assignment operator moves a pipe from one object to another.
*
* @param other The other basic_writable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_writable_pipe(const executor_type&)
* constructor.
*/
basic_writable_pipe& operator=(basic_writable_pipe&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
// All pipes have access to each other's implementations.
template <typename Executor1>
friend class basic_writable_pipe;
/// Move-construct a basic_writable_pipe from a pipe of another executor type.
/**
* This constructor moves a pipe from one object to another.
*
* @param other The other basic_writable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_writable_pipe(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_writable_pipe(basic_writable_pipe<Executor1>&& other,
constraint_t<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
> = defaulted_constraint())
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_writable_pipe from a pipe of another executor type.
/**
* This assignment operator moves a pipe from one object to another.
*
* @param other The other basic_writable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_writable_pipe(const executor_type&)
* constructor.
*/
template <typename Executor1>
constraint_t<
is_convertible<Executor1, Executor>::value,
basic_writable_pipe&
> operator=(basic_writable_pipe<Executor1>&& other)
{
basic_writable_pipe tmp(std::move(other));
impl_ = std::move(tmp.impl_);
return *this;
}
/// Destroys the pipe.
/**
* This function destroys the pipe, cancelling any outstanding
* asynchronous wait operations associated with the pipe as if by
* calling @c cancel.
*/
~basic_writable_pipe()
{
}
/// Get the executor associated with the object.
const executor_type& get_executor() noexcept
{
return impl_.get_executor();
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a basic_writable_pipe cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a basic_writable_pipe cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Assign an existing native pipe to the pipe.
/*
* This function opens the pipe to hold an existing native pipe.
*
* @param native_pipe A native pipe.
*
* @throws boost::system::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_pipe)
{
boost::system::error_code ec;
impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
boost::asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native pipe to the pipe.
/*
* This function opens the pipe to hold an existing native pipe.
*
* @param native_pipe A native pipe.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_pipe,
boost::system::error_code& ec)
{
impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the pipe is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the pipe.
/**
* This function is used to close the pipe. Any asynchronous write operations
* will be cancelled immediately, and will complete with the
* boost::asio::error::operation_aborted error.
*
* @throws boost::system::system_error Thrown on failure.
*/
void close()
{
boost::system::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "close");
}
/// Close the pipe.
/**
* This function is used to close the pipe. Any asynchronous write operations
* will be cancelled immediately, and will complete with the
* boost::asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Release ownership of the underlying native pipe.
/**
* This function causes all outstanding asynchronous write operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the boost::asio::error::operation_aborted error. Ownership of the
* native pipe is then transferred to the caller.
*
* @throws boost::system::system_error Thrown on failure.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with boost::asio::error::operation_not_supported on
* these platforms.
*/
#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release()
{
boost::system::error_code ec;
native_handle_type s = impl_.get_service().release(
impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "release");
return s;
}
/// Release ownership of the underlying native pipe.
/**
* This function causes all outstanding asynchronous write operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the boost::asio::error::operation_aborted error. Ownership of the
* native pipe is then transferred to the caller.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with boost::asio::error::operation_not_supported on
* these platforms.
*/
#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release(boost::system::error_code& ec)
{
return impl_.get_service().release(impl_.get_implementation(), ec);
}
/// Get the native pipe representation.
/**
* This function may be used to obtain the underlying representation of the
* pipe. This is intended to allow access to native pipe
* functionality that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the pipe.
/**
* This function causes all outstanding asynchronous write operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the boost::asio::error::operation_aborted error.
*
* @throws boost::system::system_error Thrown on failure.
*/
void cancel()
{
boost::system::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
boost::asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the pipe.
/**
* This function causes all outstanding asynchronous write operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the boost::asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Write some data to the pipe.
/**
* This function is used to write data to the pipe. The function call will
* block until one or more bytes of the data has been written successfully,
* or until an error occurs.
*
* @param buffers One or more data buffers to be written to the pipe.
*
* @returns The number of bytes written.
*
* @throws boost::system::system_error Thrown on failure. An error code of
* boost::asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* pipe.write_some(boost::asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
boost::system::error_code ec;
std::size_t s = impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
boost::asio::detail::throw_error(ec, "write_some");
return s;
}
/// Write some data to the pipe.
/**
* This function is used to write data to the pipe. The function call will
* block until one or more bytes of the data has been written successfully,
* or until an error occurs.
*
* @param buffers One or more data buffers to be written to the pipe.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
boost::system::error_code& ec)
{
return impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the pipe. It is an
* initiating function for an @ref asynchronous_operation, and always returns
* immediately.
*
* @param buffers One or more data buffers to be written to the pipe.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the write completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::async_immediate().
*
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* pipe.async_write_some(boost::asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) WriteToken = default_completion_token_t<executor_type>>
auto async_write_some(const ConstBufferSequence& buffers,
WriteToken&& token = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteToken,
void (boost::system::error_code, std::size_t)>(
declval<initiate_async_write_some>(), token, buffers))
{
return async_initiate<WriteToken,
void (boost::system::error_code, std::size_t)>(
initiate_async_write_some(this), token, buffers);
}
private:
// Disallow copying and assignment.
basic_writable_pipe(const basic_writable_pipe&) = delete;
basic_writable_pipe& operator=(const basic_writable_pipe&) = delete;
class initiate_async_write_some
{
public:
typedef Executor executor_type;
explicit initiate_async_write_some(basic_writable_pipe* self)
: self_(self)
{
}
const executor_type& get_executor() const noexcept
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(WriteHandler&& handler,
const ConstBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_write_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_writable_pipe* self_;
};
#if defined(BOOST_ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_handle_service, Executor> impl_;
#elif defined(BOOST_ASIO_HAS_IO_URING_AS_DEFAULT)
detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_;
#else
detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_;
#endif
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // defined(BOOST_ASIO_HAS_PIPE)
// || defined(GENERATING_DOCUMENTATION)
#endif // BOOST_ASIO_BASIC_WRITABLE_PIPE_HPP

View File

@ -0,0 +1,598 @@
//
// bind_allocator.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BIND_ALLOCATOR_HPP
#define BOOST_ASIO_BIND_ALLOCATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/associated_allocator.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/associator.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/initiation_base.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
// Helper to automatically define nested typedef result_type.
template <typename T, typename = void>
struct allocator_binder_result_type
{
protected:
typedef void result_type_or_void;
};
template <typename T>
struct allocator_binder_result_type<T, void_t<typename T::result_type>>
{
typedef typename T::result_type result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct allocator_binder_result_type<R(*)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct allocator_binder_result_type<R(&)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct allocator_binder_result_type<R(*)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct allocator_binder_result_type<R(&)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct allocator_binder_result_type<R(*)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct allocator_binder_result_type<R(&)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
// Helper to automatically define nested typedef argument_type.
template <typename T, typename = void>
struct allocator_binder_argument_type {};
template <typename T>
struct allocator_binder_argument_type<T, void_t<typename T::argument_type>>
{
typedef typename T::argument_type argument_type;
};
template <typename R, typename A1>
struct allocator_binder_argument_type<R(*)(A1)>
{
typedef A1 argument_type;
};
template <typename R, typename A1>
struct allocator_binder_argument_type<R(&)(A1)>
{
typedef A1 argument_type;
};
// Helper to automatically define nested typedefs first_argument_type and
// second_argument_type.
template <typename T, typename = void>
struct allocator_binder_argument_types {};
template <typename T>
struct allocator_binder_argument_types<T,
void_t<typename T::first_argument_type>>
{
typedef typename T::first_argument_type first_argument_type;
typedef typename T::second_argument_type second_argument_type;
};
template <typename R, typename A1, typename A2>
struct allocator_binder_argument_type<R(*)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
template <typename R, typename A1, typename A2>
struct allocator_binder_argument_type<R(&)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
} // namespace detail
/// A call wrapper type to bind an allocator of type @c Allocator
/// to an object of type @c T.
template <typename T, typename Allocator>
class allocator_binder
#if !defined(GENERATING_DOCUMENTATION)
: public detail::allocator_binder_result_type<T>,
public detail::allocator_binder_argument_type<T>,
public detail::allocator_binder_argument_types<T>
#endif // !defined(GENERATING_DOCUMENTATION)
{
public:
/// The type of the target object.
typedef T target_type;
/// The type of the associated allocator.
typedef Allocator allocator_type;
#if defined(GENERATING_DOCUMENTATION)
/// The return type if a function.
/**
* The type of @c result_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to function type, @c result_type is a synonym for
* the return type of @c T;
*
* @li if @c T is a class type with a member type @c result_type, then @c
* result_type is a synonym for @c T::result_type;
*
* @li otherwise @c result_type is not defined.
*/
typedef see_below result_type;
/// The type of the function's argument.
/**
* The type of @c argument_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to a function type accepting a single argument,
* @c argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c argument_type, then @c
* argument_type is a synonym for @c T::argument_type;
*
* @li otherwise @c argument_type is not defined.
*/
typedef see_below argument_type;
/// The type of the function's first argument.
/**
* The type of @c first_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* first_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c first_argument_type is a synonym for @c T::first_argument_type;
*
* @li otherwise @c first_argument_type is not defined.
*/
typedef see_below first_argument_type;
/// The type of the function's second argument.
/**
* The type of @c second_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* second_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c second_argument_type is a synonym for @c T::second_argument_type;
*
* @li otherwise @c second_argument_type is not defined.
*/
typedef see_below second_argument_type;
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct an allocator wrapper for the specified object.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U>
allocator_binder(const allocator_type& s, U&& u)
: allocator_(s),
target_(static_cast<U&&>(u))
{
}
/// Copy constructor.
allocator_binder(const allocator_binder& other)
: allocator_(other.get_allocator()),
target_(other.get())
{
}
/// Construct a copy, but specify a different allocator.
allocator_binder(const allocator_type& s, const allocator_binder& other)
: allocator_(s),
target_(other.get())
{
}
/// Construct a copy of a different allocator wrapper type.
/**
* This constructor is only valid if the @c Allocator type is
* constructible from type @c OtherAllocator, and the type @c T is
* constructible from type @c U.
*/
template <typename U, typename OtherAllocator>
allocator_binder(const allocator_binder<U, OtherAllocator>& other,
constraint_t<is_constructible<Allocator, OtherAllocator>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: allocator_(other.get_allocator()),
target_(other.get())
{
}
/// Construct a copy of a different allocator wrapper type, but
/// specify a different allocator.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U, typename OtherAllocator>
allocator_binder(const allocator_type& s,
const allocator_binder<U, OtherAllocator>& other,
constraint_t<is_constructible<T, U>::value> = 0)
: allocator_(s),
target_(other.get())
{
}
/// Move constructor.
allocator_binder(allocator_binder&& other)
: allocator_(static_cast<allocator_type&&>(
other.get_allocator())),
target_(static_cast<T&&>(other.get()))
{
}
/// Move construct the target object, but specify a different allocator.
allocator_binder(const allocator_type& s,
allocator_binder&& other)
: allocator_(s),
target_(static_cast<T&&>(other.get()))
{
}
/// Move construct from a different allocator wrapper type.
template <typename U, typename OtherAllocator>
allocator_binder(
allocator_binder<U, OtherAllocator>&& other,
constraint_t<is_constructible<Allocator, OtherAllocator>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: allocator_(static_cast<OtherAllocator&&>(
other.get_allocator())),
target_(static_cast<U&&>(other.get()))
{
}
/// Move construct from a different allocator wrapper type, but
/// specify a different allocator.
template <typename U, typename OtherAllocator>
allocator_binder(const allocator_type& s,
allocator_binder<U, OtherAllocator>&& other,
constraint_t<is_constructible<T, U>::value> = 0)
: allocator_(s),
target_(static_cast<U&&>(other.get()))
{
}
/// Destructor.
~allocator_binder()
{
}
/// Obtain a reference to the target object.
target_type& get() noexcept
{
return target_;
}
/// Obtain a reference to the target object.
const target_type& get() const noexcept
{
return target_;
}
/// Obtain the associated allocator.
allocator_type get_allocator() const noexcept
{
return allocator_;
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args)
{
return target_(static_cast<Args&&>(args)...);
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args) const
{
return target_(static_cast<Args&&>(args)...);
}
private:
Allocator allocator_;
T target_;
};
/// A function object type that adapts a @ref completion_token to specify that
/// the completion handler should have the supplied allocator as its associated
/// allocator.
/**
* May also be used directly as a completion token, in which case it adapts the
* asynchronous operation's default completion token (or boost::asio::deferred
* if no default is available).
*/
template <typename Allocator>
struct partial_allocator_binder
{
/// Constructor that specifies associated allocator.
explicit partial_allocator_binder(const Allocator& ex)
: allocator_(ex)
{
}
/// Adapt a @ref completion_token to specify that the completion handler
/// should have the allocator as its associated allocator.
template <typename CompletionToken>
BOOST_ASIO_NODISCARD inline
constexpr allocator_binder<decay_t<CompletionToken>, Allocator>
operator()(CompletionToken&& completion_token) const
{
return allocator_binder<decay_t<CompletionToken>, Allocator>(
allocator_, static_cast<CompletionToken&&>(completion_token));
}
//private:
Allocator allocator_;
};
/// Create a partial completion token that associates an allocator.
template <typename Allocator>
BOOST_ASIO_NODISCARD inline partial_allocator_binder<Allocator>
bind_allocator(const Allocator& ex)
{
return partial_allocator_binder<Allocator>(ex);
}
/// Associate an object of type @c T with an allocator of type
/// @c Allocator.
template <typename Allocator, typename T>
BOOST_ASIO_NODISCARD inline allocator_binder<decay_t<T>, Allocator>
bind_allocator(const Allocator& s, T&& t)
{
return allocator_binder<decay_t<T>, Allocator>(s, static_cast<T&&>(t));
}
#if !defined(GENERATING_DOCUMENTATION)
namespace detail {
template <typename TargetAsyncResult, typename Allocator, typename = void>
class allocator_binder_completion_handler_async_result
{
public:
template <typename T>
explicit allocator_binder_completion_handler_async_result(T&)
{
}
};
template <typename TargetAsyncResult, typename Allocator>
class allocator_binder_completion_handler_async_result<
TargetAsyncResult, Allocator,
void_t<typename TargetAsyncResult::completion_handler_type>>
{
private:
TargetAsyncResult target_;
public:
typedef allocator_binder<
typename TargetAsyncResult::completion_handler_type, Allocator>
completion_handler_type;
explicit allocator_binder_completion_handler_async_result(
typename TargetAsyncResult::completion_handler_type& handler)
: target_(handler)
{
}
auto get() -> decltype(target_.get())
{
return target_.get();
}
};
template <typename TargetAsyncResult, typename = void>
struct allocator_binder_async_result_return_type
{
};
template <typename TargetAsyncResult>
struct allocator_binder_async_result_return_type<
TargetAsyncResult, void_type<typename TargetAsyncResult::return_type>>
{
typedef typename TargetAsyncResult::return_type return_type;
};
} // namespace detail
template <typename T, typename Allocator, typename Signature>
class async_result<allocator_binder<T, Allocator>, Signature> :
public detail::allocator_binder_completion_handler_async_result<
async_result<T, Signature>, Allocator>,
public detail::allocator_binder_async_result_return_type<
async_result<T, Signature>>
{
public:
explicit async_result(allocator_binder<T, Allocator>& b)
: detail::allocator_binder_completion_handler_async_result<
async_result<T, Signature>, Allocator>(b.get())
{
}
template <typename Initiation>
struct init_wrapper : detail::initiation_base<Initiation>
{
using detail::initiation_base<Initiation>::initiation_base;
template <typename Handler, typename... Args>
void operator()(Handler&& handler, const Allocator& a, Args&&... args) &&
{
static_cast<Initiation&&>(*this)(
allocator_binder<decay_t<Handler>, Allocator>(
a, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler,
const Allocator& a, Args&&... args) const &
{
static_cast<const Initiation&>(*this)(
allocator_binder<decay_t<Handler>, Allocator>(
a, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
};
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<
conditional_t<
is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
Signature>(
declval<init_wrapper<decay_t<Initiation>>>(),
token.get(), token.get_allocator(), static_cast<Args&&>(args)...))
{
return async_initiate<
conditional_t<
is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
Signature>(
init_wrapper<decay_t<Initiation>>(
static_cast<Initiation&&>(initiation)),
token.get(), token.get_allocator(), static_cast<Args&&>(args)...);
}
private:
async_result(const async_result&) = delete;
async_result& operator=(const async_result&) = delete;
async_result<T, Signature> target_;
};
template <typename Allocator, typename... Signatures>
struct async_result<partial_allocator_binder<Allocator>, Signatures...>
{
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
allocator_binder<
default_completion_token_t<associated_executor_t<Initiation>>,
Allocator>(token.allocator_,
default_completion_token_t<associated_executor_t<Initiation>>{}),
static_cast<Args&&>(args)...))
{
return async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
allocator_binder<
default_completion_token_t<associated_executor_t<Initiation>>,
Allocator>(token.allocator_,
default_completion_token_t<associated_executor_t<Initiation>>{}),
static_cast<Args&&>(args)...);
}
};
template <template <typename, typename> class Associator,
typename T, typename Allocator, typename DefaultCandidate>
struct associator<Associator, allocator_binder<T, Allocator>, DefaultCandidate>
: Associator<T, DefaultCandidate>
{
static typename Associator<T, DefaultCandidate>::type get(
const allocator_binder<T, Allocator>& b) noexcept
{
return Associator<T, DefaultCandidate>::get(b.get());
}
static auto get(const allocator_binder<T, Allocator>& b,
const DefaultCandidate& c) noexcept
-> decltype(Associator<T, DefaultCandidate>::get(b.get(), c))
{
return Associator<T, DefaultCandidate>::get(b.get(), c);
}
};
template <typename T, typename Allocator, typename Allocator1>
struct associated_allocator<allocator_binder<T, Allocator>, Allocator1>
{
typedef Allocator type;
static auto get(const allocator_binder<T, Allocator>& b,
const Allocator1& = Allocator1()) noexcept
-> decltype(b.get_allocator())
{
return b.get_allocator();
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_BIND_ALLOCATOR_HPP

View File

@ -0,0 +1,615 @@
//
// bind_cancellation_slot.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BIND_CANCELLATION_SLOT_HPP
#define BOOST_ASIO_BIND_CANCELLATION_SLOT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/associated_cancellation_slot.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/associator.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/initiation_base.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
// Helper to automatically define nested typedef result_type.
template <typename T, typename = void>
struct cancellation_slot_binder_result_type
{
protected:
typedef void result_type_or_void;
};
template <typename T>
struct cancellation_slot_binder_result_type<T, void_t<typename T::result_type>>
{
typedef typename T::result_type result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct cancellation_slot_binder_result_type<R(*)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct cancellation_slot_binder_result_type<R(&)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct cancellation_slot_binder_result_type<R(*)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct cancellation_slot_binder_result_type<R(&)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct cancellation_slot_binder_result_type<R(*)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct cancellation_slot_binder_result_type<R(&)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
// Helper to automatically define nested typedef argument_type.
template <typename T, typename = void>
struct cancellation_slot_binder_argument_type {};
template <typename T>
struct cancellation_slot_binder_argument_type<T,
void_t<typename T::argument_type>>
{
typedef typename T::argument_type argument_type;
};
template <typename R, typename A1>
struct cancellation_slot_binder_argument_type<R(*)(A1)>
{
typedef A1 argument_type;
};
template <typename R, typename A1>
struct cancellation_slot_binder_argument_type<R(&)(A1)>
{
typedef A1 argument_type;
};
// Helper to automatically define nested typedefs first_argument_type and
// second_argument_type.
template <typename T, typename = void>
struct cancellation_slot_binder_argument_types {};
template <typename T>
struct cancellation_slot_binder_argument_types<T,
void_t<typename T::first_argument_type>>
{
typedef typename T::first_argument_type first_argument_type;
typedef typename T::second_argument_type second_argument_type;
};
template <typename R, typename A1, typename A2>
struct cancellation_slot_binder_argument_type<R(*)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
template <typename R, typename A1, typename A2>
struct cancellation_slot_binder_argument_type<R(&)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
} // namespace detail
/// A call wrapper type to bind a cancellation slot of type @c CancellationSlot
/// to an object of type @c T.
template <typename T, typename CancellationSlot>
class cancellation_slot_binder
#if !defined(GENERATING_DOCUMENTATION)
: public detail::cancellation_slot_binder_result_type<T>,
public detail::cancellation_slot_binder_argument_type<T>,
public detail::cancellation_slot_binder_argument_types<T>
#endif // !defined(GENERATING_DOCUMENTATION)
{
public:
/// The type of the target object.
typedef T target_type;
/// The type of the associated cancellation slot.
typedef CancellationSlot cancellation_slot_type;
#if defined(GENERATING_DOCUMENTATION)
/// The return type if a function.
/**
* The type of @c result_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to function type, @c result_type is a synonym for
* the return type of @c T;
*
* @li if @c T is a class type with a member type @c result_type, then @c
* result_type is a synonym for @c T::result_type;
*
* @li otherwise @c result_type is not defined.
*/
typedef see_below result_type;
/// The type of the function's argument.
/**
* The type of @c argument_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to a function type accepting a single argument,
* @c argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c argument_type, then @c
* argument_type is a synonym for @c T::argument_type;
*
* @li otherwise @c argument_type is not defined.
*/
typedef see_below argument_type;
/// The type of the function's first argument.
/**
* The type of @c first_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* first_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c first_argument_type is a synonym for @c T::first_argument_type;
*
* @li otherwise @c first_argument_type is not defined.
*/
typedef see_below first_argument_type;
/// The type of the function's second argument.
/**
* The type of @c second_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* second_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c second_argument_type is a synonym for @c T::second_argument_type;
*
* @li otherwise @c second_argument_type is not defined.
*/
typedef see_below second_argument_type;
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct a cancellation slot wrapper for the specified object.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U>
cancellation_slot_binder(const cancellation_slot_type& s, U&& u)
: slot_(s),
target_(static_cast<U&&>(u))
{
}
/// Copy constructor.
cancellation_slot_binder(const cancellation_slot_binder& other)
: slot_(other.get_cancellation_slot()),
target_(other.get())
{
}
/// Construct a copy, but specify a different cancellation slot.
cancellation_slot_binder(const cancellation_slot_type& s,
const cancellation_slot_binder& other)
: slot_(s),
target_(other.get())
{
}
/// Construct a copy of a different cancellation slot wrapper type.
/**
* This constructor is only valid if the @c CancellationSlot type is
* constructible from type @c OtherCancellationSlot, and the type @c T is
* constructible from type @c U.
*/
template <typename U, typename OtherCancellationSlot>
cancellation_slot_binder(
const cancellation_slot_binder<U, OtherCancellationSlot>& other,
constraint_t<is_constructible<CancellationSlot,
OtherCancellationSlot>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: slot_(other.get_cancellation_slot()),
target_(other.get())
{
}
/// Construct a copy of a different cancellation slot wrapper type, but
/// specify a different cancellation slot.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U, typename OtherCancellationSlot>
cancellation_slot_binder(const cancellation_slot_type& s,
const cancellation_slot_binder<U, OtherCancellationSlot>& other,
constraint_t<is_constructible<T, U>::value> = 0)
: slot_(s),
target_(other.get())
{
}
/// Move constructor.
cancellation_slot_binder(cancellation_slot_binder&& other)
: slot_(static_cast<cancellation_slot_type&&>(
other.get_cancellation_slot())),
target_(static_cast<T&&>(other.get()))
{
}
/// Move construct the target object, but specify a different cancellation
/// slot.
cancellation_slot_binder(const cancellation_slot_type& s,
cancellation_slot_binder&& other)
: slot_(s),
target_(static_cast<T&&>(other.get()))
{
}
/// Move construct from a different cancellation slot wrapper type.
template <typename U, typename OtherCancellationSlot>
cancellation_slot_binder(
cancellation_slot_binder<U, OtherCancellationSlot>&& other,
constraint_t<is_constructible<CancellationSlot,
OtherCancellationSlot>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: slot_(static_cast<OtherCancellationSlot&&>(
other.get_cancellation_slot())),
target_(static_cast<U&&>(other.get()))
{
}
/// Move construct from a different cancellation slot wrapper type, but
/// specify a different cancellation slot.
template <typename U, typename OtherCancellationSlot>
cancellation_slot_binder(const cancellation_slot_type& s,
cancellation_slot_binder<U, OtherCancellationSlot>&& other,
constraint_t<is_constructible<T, U>::value> = 0)
: slot_(s),
target_(static_cast<U&&>(other.get()))
{
}
/// Destructor.
~cancellation_slot_binder()
{
}
/// Obtain a reference to the target object.
target_type& get() noexcept
{
return target_;
}
/// Obtain a reference to the target object.
const target_type& get() const noexcept
{
return target_;
}
/// Obtain the associated cancellation slot.
cancellation_slot_type get_cancellation_slot() const noexcept
{
return slot_;
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args)
{
return target_(static_cast<Args&&>(args)...);
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args) const
{
return target_(static_cast<Args&&>(args)...);
}
private:
CancellationSlot slot_;
T target_;
};
/// A function object type that adapts a @ref completion_token to specify that
/// the completion handler should have the supplied cancellation slot as its
/// associated cancellation slot.
/**
* May also be used directly as a completion token, in which case it adapts the
* asynchronous operation's default completion token (or boost::asio::deferred
* if no default is available).
*/
template <typename CancellationSlot>
struct partial_cancellation_slot_binder
{
/// Constructor that specifies associated cancellation slot.
explicit partial_cancellation_slot_binder(const CancellationSlot& ex)
: cancellation_slot_(ex)
{
}
/// Adapt a @ref completion_token to specify that the completion handler
/// should have the cancellation slot as its associated cancellation slot.
template <typename CompletionToken>
BOOST_ASIO_NODISCARD inline
constexpr cancellation_slot_binder<decay_t<CompletionToken>, CancellationSlot>
operator()(CompletionToken&& completion_token) const
{
return cancellation_slot_binder<decay_t<CompletionToken>, CancellationSlot>(
static_cast<CompletionToken&&>(completion_token), cancellation_slot_);
}
//private:
CancellationSlot cancellation_slot_;
};
/// Create a partial completion token that associates a cancellation slot.
template <typename CancellationSlot>
BOOST_ASIO_NODISCARD inline partial_cancellation_slot_binder<CancellationSlot>
bind_cancellation_slot(const CancellationSlot& ex)
{
return partial_cancellation_slot_binder<CancellationSlot>(ex);
}
/// Associate an object of type @c T with a cancellation slot of type
/// @c CancellationSlot.
template <typename CancellationSlot, typename T>
BOOST_ASIO_NODISCARD inline
cancellation_slot_binder<decay_t<T>, CancellationSlot>
bind_cancellation_slot(const CancellationSlot& s, T&& t)
{
return cancellation_slot_binder<decay_t<T>, CancellationSlot>(
s, static_cast<T&&>(t));
}
#if !defined(GENERATING_DOCUMENTATION)
namespace detail {
template <typename TargetAsyncResult,
typename CancellationSlot, typename = void>
class cancellation_slot_binder_completion_handler_async_result
{
public:
template <typename T>
explicit cancellation_slot_binder_completion_handler_async_result(T&)
{
}
};
template <typename TargetAsyncResult, typename CancellationSlot>
class cancellation_slot_binder_completion_handler_async_result<
TargetAsyncResult, CancellationSlot,
void_t<typename TargetAsyncResult::completion_handler_type>>
{
private:
TargetAsyncResult target_;
public:
typedef cancellation_slot_binder<
typename TargetAsyncResult::completion_handler_type, CancellationSlot>
completion_handler_type;
explicit cancellation_slot_binder_completion_handler_async_result(
typename TargetAsyncResult::completion_handler_type& handler)
: target_(handler)
{
}
auto get() -> decltype(target_.get())
{
return target_.get();
}
};
template <typename TargetAsyncResult, typename = void>
struct cancellation_slot_binder_async_result_return_type
{
};
template <typename TargetAsyncResult>
struct cancellation_slot_binder_async_result_return_type<
TargetAsyncResult, void_t<typename TargetAsyncResult::return_type>>
{
typedef typename TargetAsyncResult::return_type return_type;
};
} // namespace detail
template <typename T, typename CancellationSlot, typename Signature>
class async_result<cancellation_slot_binder<T, CancellationSlot>, Signature> :
public detail::cancellation_slot_binder_completion_handler_async_result<
async_result<T, Signature>, CancellationSlot>,
public detail::cancellation_slot_binder_async_result_return_type<
async_result<T, Signature>>
{
public:
explicit async_result(cancellation_slot_binder<T, CancellationSlot>& b)
: detail::cancellation_slot_binder_completion_handler_async_result<
async_result<T, Signature>, CancellationSlot>(b.get())
{
}
template <typename Initiation>
struct init_wrapper : detail::initiation_base<Initiation>
{
using detail::initiation_base<Initiation>::initiation_base;
template <typename Handler, typename... Args>
void operator()(Handler&& handler,
const CancellationSlot& slot, Args&&... args) &&
{
static_cast<Initiation&&>(*this)(
cancellation_slot_binder<decay_t<Handler>, CancellationSlot>(
slot, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler,
const CancellationSlot& slot, Args&&... args) const &
{
static_cast<const Initiation&>(*this)(
cancellation_slot_binder<decay_t<Handler>, CancellationSlot>(
slot, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
};
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<
conditional_t<
is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
Signature>(
declval<init_wrapper<decay_t<Initiation>>>(),
token.get(), token.get_cancellation_slot(),
static_cast<Args&&>(args)...))
{
return async_initiate<
conditional_t<
is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
Signature>(
init_wrapper<decay_t<Initiation>>(
static_cast<Initiation&&>(initiation)),
token.get(), token.get_cancellation_slot(),
static_cast<Args&&>(args)...);
}
private:
async_result(const async_result&) = delete;
async_result& operator=(const async_result&) = delete;
async_result<T, Signature> target_;
};
template <typename CancellationSlot, typename... Signatures>
struct async_result<partial_cancellation_slot_binder<CancellationSlot>,
Signatures...>
{
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
cancellation_slot_binder<
default_completion_token_t<associated_executor_t<Initiation>>,
CancellationSlot>(token.cancellation_slot_,
default_completion_token_t<associated_executor_t<Initiation>>{}),
static_cast<Args&&>(args)...))
{
return async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
cancellation_slot_binder<
default_completion_token_t<associated_executor_t<Initiation>>,
CancellationSlot>(token.cancellation_slot_,
default_completion_token_t<associated_executor_t<Initiation>>{}),
static_cast<Args&&>(args)...);
}
};
template <template <typename, typename> class Associator,
typename T, typename CancellationSlot, typename DefaultCandidate>
struct associator<Associator,
cancellation_slot_binder<T, CancellationSlot>,
DefaultCandidate>
: Associator<T, DefaultCandidate>
{
static typename Associator<T, DefaultCandidate>::type get(
const cancellation_slot_binder<T, CancellationSlot>& b) noexcept
{
return Associator<T, DefaultCandidate>::get(b.get());
}
static auto get(const cancellation_slot_binder<T, CancellationSlot>& b,
const DefaultCandidate& c) noexcept
-> decltype(Associator<T, DefaultCandidate>::get(b.get(), c))
{
return Associator<T, DefaultCandidate>::get(b.get(), c);
}
};
template <typename T, typename CancellationSlot, typename CancellationSlot1>
struct associated_cancellation_slot<
cancellation_slot_binder<T, CancellationSlot>,
CancellationSlot1>
{
typedef CancellationSlot type;
static auto get(const cancellation_slot_binder<T, CancellationSlot>& b,
const CancellationSlot1& = CancellationSlot1()) noexcept
-> decltype(b.get_cancellation_slot())
{
return b.get_cancellation_slot();
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_BIND_CANCELLATION_SLOT_HPP

View File

@ -0,0 +1,666 @@
//
// bind_executor.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BIND_EXECUTOR_HPP
#define BOOST_ASIO_BIND_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/associator.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/initiation_base.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/execution/executor.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/is_executor.hpp>
#include <boost/asio/uses_executor.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
// Helper to automatically define nested typedef result_type.
template <typename T, typename = void>
struct executor_binder_result_type
{
protected:
typedef void result_type_or_void;
};
template <typename T>
struct executor_binder_result_type<T, void_t<typename T::result_type>>
{
typedef typename T::result_type result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct executor_binder_result_type<R(*)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct executor_binder_result_type<R(&)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct executor_binder_result_type<R(*)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct executor_binder_result_type<R(&)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct executor_binder_result_type<R(*)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct executor_binder_result_type<R(&)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
// Helper to automatically define nested typedef argument_type.
template <typename T, typename = void>
struct executor_binder_argument_type {};
template <typename T>
struct executor_binder_argument_type<T, void_t<typename T::argument_type>>
{
typedef typename T::argument_type argument_type;
};
template <typename R, typename A1>
struct executor_binder_argument_type<R(*)(A1)>
{
typedef A1 argument_type;
};
template <typename R, typename A1>
struct executor_binder_argument_type<R(&)(A1)>
{
typedef A1 argument_type;
};
// Helper to automatically define nested typedefs first_argument_type and
// second_argument_type.
template <typename T, typename = void>
struct executor_binder_argument_types {};
template <typename T>
struct executor_binder_argument_types<T,
void_t<typename T::first_argument_type>>
{
typedef typename T::first_argument_type first_argument_type;
typedef typename T::second_argument_type second_argument_type;
};
template <typename R, typename A1, typename A2>
struct executor_binder_argument_type<R(*)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
template <typename R, typename A1, typename A2>
struct executor_binder_argument_type<R(&)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
// Helper to perform uses_executor construction of the target type, if
// required.
template <typename T, typename Executor, bool UsesExecutor>
class executor_binder_base;
template <typename T, typename Executor>
class executor_binder_base<T, Executor, true>
{
protected:
template <typename E, typename U>
executor_binder_base(E&& e, U&& u)
: executor_(static_cast<E&&>(e)),
target_(executor_arg_t(), executor_, static_cast<U&&>(u))
{
}
Executor executor_;
T target_;
};
template <typename T, typename Executor>
class executor_binder_base<T, Executor, false>
{
protected:
template <typename E, typename U>
executor_binder_base(E&& e, U&& u)
: executor_(static_cast<E&&>(e)),
target_(static_cast<U&&>(u))
{
}
Executor executor_;
T target_;
};
} // namespace detail
/// A call wrapper type to bind an executor of type @c Executor to an object of
/// type @c T.
template <typename T, typename Executor>
class executor_binder
#if !defined(GENERATING_DOCUMENTATION)
: public detail::executor_binder_result_type<T>,
public detail::executor_binder_argument_type<T>,
public detail::executor_binder_argument_types<T>,
private detail::executor_binder_base<
T, Executor, uses_executor<T, Executor>::value>
#endif // !defined(GENERATING_DOCUMENTATION)
{
public:
/// The type of the target object.
typedef T target_type;
/// The type of the associated executor.
typedef Executor executor_type;
#if defined(GENERATING_DOCUMENTATION)
/// The return type if a function.
/**
* The type of @c result_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to function type, @c result_type is a synonym for
* the return type of @c T;
*
* @li if @c T is a class type with a member type @c result_type, then @c
* result_type is a synonym for @c T::result_type;
*
* @li otherwise @c result_type is not defined.
*/
typedef see_below result_type;
/// The type of the function's argument.
/**
* The type of @c argument_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to a function type accepting a single argument,
* @c argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c argument_type, then @c
* argument_type is a synonym for @c T::argument_type;
*
* @li otherwise @c argument_type is not defined.
*/
typedef see_below argument_type;
/// The type of the function's first argument.
/**
* The type of @c first_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* first_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c first_argument_type is a synonym for @c T::first_argument_type;
*
* @li otherwise @c first_argument_type is not defined.
*/
typedef see_below first_argument_type;
/// The type of the function's second argument.
/**
* The type of @c second_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* second_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c second_argument_type is a synonym for @c T::second_argument_type;
*
* @li otherwise @c second_argument_type is not defined.
*/
typedef see_below second_argument_type;
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct an executor wrapper for the specified object.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U>
executor_binder(executor_arg_t, const executor_type& e,
U&& u)
: base_type(e, static_cast<U&&>(u))
{
}
/// Copy constructor.
executor_binder(const executor_binder& other)
: base_type(other.get_executor(), other.get())
{
}
/// Construct a copy, but specify a different executor.
executor_binder(executor_arg_t, const executor_type& e,
const executor_binder& other)
: base_type(e, other.get())
{
}
/// Construct a copy of a different executor wrapper type.
/**
* This constructor is only valid if the @c Executor type is constructible
* from type @c OtherExecutor, and the type @c T is constructible from type
* @c U.
*/
template <typename U, typename OtherExecutor>
executor_binder(const executor_binder<U, OtherExecutor>& other,
constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: base_type(other.get_executor(), other.get())
{
}
/// Construct a copy of a different executor wrapper type, but specify a
/// different executor.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U, typename OtherExecutor>
executor_binder(executor_arg_t, const executor_type& e,
const executor_binder<U, OtherExecutor>& other,
constraint_t<is_constructible<T, U>::value> = 0)
: base_type(e, other.get())
{
}
/// Move constructor.
executor_binder(executor_binder&& other)
: base_type(static_cast<executor_type&&>(other.get_executor()),
static_cast<T&&>(other.get()))
{
}
/// Move construct the target object, but specify a different executor.
executor_binder(executor_arg_t, const executor_type& e,
executor_binder&& other)
: base_type(e, static_cast<T&&>(other.get()))
{
}
/// Move construct from a different executor wrapper type.
template <typename U, typename OtherExecutor>
executor_binder(executor_binder<U, OtherExecutor>&& other,
constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: base_type(static_cast<OtherExecutor&&>(other.get_executor()),
static_cast<U&&>(other.get()))
{
}
/// Move construct from a different executor wrapper type, but specify a
/// different executor.
template <typename U, typename OtherExecutor>
executor_binder(executor_arg_t, const executor_type& e,
executor_binder<U, OtherExecutor>&& other,
constraint_t<is_constructible<T, U>::value> = 0)
: base_type(e, static_cast<U&&>(other.get()))
{
}
/// Destructor.
~executor_binder()
{
}
/// Obtain a reference to the target object.
target_type& get() noexcept
{
return this->target_;
}
/// Obtain a reference to the target object.
const target_type& get() const noexcept
{
return this->target_;
}
/// Obtain the associated executor.
executor_type get_executor() const noexcept
{
return this->executor_;
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args)
{
return this->target_(static_cast<Args&&>(args)...);
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args) const
{
return this->target_(static_cast<Args&&>(args)...);
}
private:
typedef detail::executor_binder_base<T, Executor,
uses_executor<T, Executor>::value> base_type;
};
/// A function object type that adapts a @ref completion_token to specify that
/// the completion handler should have the supplied executor as its associated
/// executor.
/**
* May also be used directly as a completion token, in which case it adapts the
* asynchronous operation's default completion token (or boost::asio::deferred
* if no default is available).
*/
template <typename Executor>
struct partial_executor_binder
{
/// Constructor that specifies associated executor.
explicit partial_executor_binder(const Executor& ex)
: executor_(ex)
{
}
/// Adapt a @ref completion_token to specify that the completion handler
/// should have the executor as its associated executor.
template <typename CompletionToken>
BOOST_ASIO_NODISCARD inline
constexpr executor_binder<decay_t<CompletionToken>, Executor>
operator()(CompletionToken&& completion_token) const
{
return executor_binder<decay_t<CompletionToken>, Executor>(executor_arg_t(),
static_cast<CompletionToken&&>(completion_token), executor_);
}
//private:
Executor executor_;
};
/// Create a partial completion token that associates an executor.
template <typename Executor>
BOOST_ASIO_NODISCARD inline partial_executor_binder<Executor>
bind_executor(const Executor& ex,
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0)
{
return partial_executor_binder<Executor>(ex);
}
/// Associate an object of type @c T with an executor of type @c Executor.
template <typename Executor, typename T>
BOOST_ASIO_NODISCARD inline executor_binder<decay_t<T>, Executor>
bind_executor(const Executor& ex, T&& t,
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0)
{
return executor_binder<decay_t<T>, Executor>(
executor_arg_t(), ex, static_cast<T&&>(t));
}
/// Create a partial completion token that associates an execution context's
/// executor.
template <typename ExecutionContext>
BOOST_ASIO_NODISCARD inline partial_executor_binder<
typename ExecutionContext::executor_type>
bind_executor(ExecutionContext& ctx,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
{
return partial_executor_binder<typename ExecutionContext::executor_type>(
ctx.get_executor());
}
/// Associate an object of type @c T with an execution context's executor.
template <typename ExecutionContext, typename T>
BOOST_ASIO_NODISCARD inline executor_binder<decay_t<T>,
typename ExecutionContext::executor_type>
bind_executor(ExecutionContext& ctx, T&& t,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
{
return executor_binder<decay_t<T>, typename ExecutionContext::executor_type>(
executor_arg_t(), ctx.get_executor(), static_cast<T&&>(t));
}
#if !defined(GENERATING_DOCUMENTATION)
template <typename T, typename Executor>
struct uses_executor<executor_binder<T, Executor>, Executor>
: true_type {};
namespace detail {
template <typename TargetAsyncResult, typename Executor, typename = void>
class executor_binder_completion_handler_async_result
{
public:
template <typename T>
explicit executor_binder_completion_handler_async_result(T&)
{
}
};
template <typename TargetAsyncResult, typename Executor>
class executor_binder_completion_handler_async_result<
TargetAsyncResult, Executor,
void_t<typename TargetAsyncResult::completion_handler_type >>
{
private:
TargetAsyncResult target_;
public:
typedef executor_binder<
typename TargetAsyncResult::completion_handler_type, Executor>
completion_handler_type;
explicit executor_binder_completion_handler_async_result(
typename TargetAsyncResult::completion_handler_type& handler)
: target_(handler)
{
}
auto get() -> decltype(target_.get())
{
return target_.get();
}
};
template <typename TargetAsyncResult, typename = void>
struct executor_binder_async_result_return_type
{
};
template <typename TargetAsyncResult>
struct executor_binder_async_result_return_type<TargetAsyncResult,
void_t<typename TargetAsyncResult::return_type>>
{
typedef typename TargetAsyncResult::return_type return_type;
};
} // namespace detail
template <typename T, typename Executor, typename Signature>
class async_result<executor_binder<T, Executor>, Signature> :
public detail::executor_binder_completion_handler_async_result<
async_result<T, Signature>, Executor>,
public detail::executor_binder_async_result_return_type<
async_result<T, Signature>>
{
public:
explicit async_result(executor_binder<T, Executor>& b)
: detail::executor_binder_completion_handler_async_result<
async_result<T, Signature>, Executor>(b.get())
{
}
template <typename Initiation>
struct init_wrapper : detail::initiation_base<Initiation>
{
using detail::initiation_base<Initiation>::initiation_base;
template <typename Handler, typename... Args>
void operator()(Handler&& handler, const Executor& e, Args&&... args) &&
{
static_cast<Initiation&&>(*this)(
executor_binder<decay_t<Handler>, Executor>(
executor_arg_t(), e, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler,
const Executor& e, Args&&... args) const &
{
static_cast<const Initiation&>(*this)(
executor_binder<decay_t<Handler>, Executor>(
executor_arg_t(), e, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
};
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<
conditional_t<
is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
Signature>(
declval<init_wrapper<decay_t<Initiation>>>(),
token.get(), token.get_executor(), static_cast<Args&&>(args)...))
{
return async_initiate<
conditional_t<
is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
Signature>(
init_wrapper<decay_t<Initiation>>(
static_cast<Initiation&&>(initiation)),
token.get(), token.get_executor(), static_cast<Args&&>(args)...);
}
private:
async_result(const async_result&) = delete;
async_result& operator=(const async_result&) = delete;
};
template <typename Executor, typename... Signatures>
struct async_result<partial_executor_binder<Executor>, Signatures...>
{
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
executor_binder<
default_completion_token_t<associated_executor_t<Initiation>>,
Executor>(executor_arg_t(), token.executor_,
default_completion_token_t<associated_executor_t<Initiation>>{}),
static_cast<Args&&>(args)...))
{
return async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
executor_binder<
default_completion_token_t<associated_executor_t<Initiation>>,
Executor>(executor_arg_t(), token.executor_,
default_completion_token_t<associated_executor_t<Initiation>>{}),
static_cast<Args&&>(args)...);
}
};
template <template <typename, typename> class Associator,
typename T, typename Executor, typename DefaultCandidate>
struct associator<Associator, executor_binder<T, Executor>, DefaultCandidate>
: Associator<T, DefaultCandidate>
{
static typename Associator<T, DefaultCandidate>::type get(
const executor_binder<T, Executor>& b) noexcept
{
return Associator<T, DefaultCandidate>::get(b.get());
}
static auto get(const executor_binder<T, Executor>& b,
const DefaultCandidate& c) noexcept
-> decltype(Associator<T, DefaultCandidate>::get(b.get(), c))
{
return Associator<T, DefaultCandidate>::get(b.get(), c);
}
};
template <typename T, typename Executor, typename Executor1>
struct associated_executor<executor_binder<T, Executor>, Executor1>
{
typedef Executor type;
static auto get(const executor_binder<T, Executor>& b,
const Executor1& = Executor1()) noexcept
-> decltype(b.get_executor())
{
return b.get_executor();
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_BIND_EXECUTOR_HPP

View File

@ -0,0 +1,618 @@
//
// bind_immediate_executor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BIND_IMMEDIATE_EXECUTOR_HPP
#define BOOST_ASIO_BIND_IMMEDIATE_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/associated_immediate_executor.hpp>
#include <boost/asio/associator.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/initiation_base.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
// Helper to automatically define nested typedef result_type.
template <typename T, typename = void>
struct immediate_executor_binder_result_type
{
protected:
typedef void result_type_or_void;
};
template <typename T>
struct immediate_executor_binder_result_type<T, void_t<typename T::result_type>>
{
typedef typename T::result_type result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct immediate_executor_binder_result_type<R(*)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct immediate_executor_binder_result_type<R(&)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct immediate_executor_binder_result_type<R(*)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct immediate_executor_binder_result_type<R(&)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct immediate_executor_binder_result_type<R(*)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct immediate_executor_binder_result_type<R(&)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
// Helper to automatically define nested typedef argument_type.
template <typename T, typename = void>
struct immediate_executor_binder_argument_type {};
template <typename T>
struct immediate_executor_binder_argument_type<T,
void_t<typename T::argument_type>>
{
typedef typename T::argument_type argument_type;
};
template <typename R, typename A1>
struct immediate_executor_binder_argument_type<R(*)(A1)>
{
typedef A1 argument_type;
};
template <typename R, typename A1>
struct immediate_executor_binder_argument_type<R(&)(A1)>
{
typedef A1 argument_type;
};
// Helper to automatically define nested typedefs first_argument_type and
// second_argument_type.
template <typename T, typename = void>
struct immediate_executor_binder_argument_types {};
template <typename T>
struct immediate_executor_binder_argument_types<T,
void_t<typename T::first_argument_type>>
{
typedef typename T::first_argument_type first_argument_type;
typedef typename T::second_argument_type second_argument_type;
};
template <typename R, typename A1, typename A2>
struct immediate_executor_binder_argument_type<R(*)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
template <typename R, typename A1, typename A2>
struct immediate_executor_binder_argument_type<R(&)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
} // namespace detail
/// A call wrapper type to bind a immediate executor of type @c Executor
/// to an object of type @c T.
template <typename T, typename Executor>
class immediate_executor_binder
#if !defined(GENERATING_DOCUMENTATION)
: public detail::immediate_executor_binder_result_type<T>,
public detail::immediate_executor_binder_argument_type<T>,
public detail::immediate_executor_binder_argument_types<T>
#endif // !defined(GENERATING_DOCUMENTATION)
{
public:
/// The type of the target object.
typedef T target_type;
/// The type of the associated immediate executor.
typedef Executor immediate_executor_type;
#if defined(GENERATING_DOCUMENTATION)
/// The return type if a function.
/**
* The type of @c result_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to function type, @c result_type is a synonym for
* the return type of @c T;
*
* @li if @c T is a class type with a member type @c result_type, then @c
* result_type is a synonym for @c T::result_type;
*
* @li otherwise @c result_type is not defined.
*/
typedef see_below result_type;
/// The type of the function's argument.
/**
* The type of @c argument_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to a function type accepting a single argument,
* @c argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c argument_type, then @c
* argument_type is a synonym for @c T::argument_type;
*
* @li otherwise @c argument_type is not defined.
*/
typedef see_below argument_type;
/// The type of the function's first argument.
/**
* The type of @c first_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* first_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c first_argument_type is a synonym for @c T::first_argument_type;
*
* @li otherwise @c first_argument_type is not defined.
*/
typedef see_below first_argument_type;
/// The type of the function's second argument.
/**
* The type of @c second_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* second_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c second_argument_type is a synonym for @c T::second_argument_type;
*
* @li otherwise @c second_argument_type is not defined.
*/
typedef see_below second_argument_type;
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct a immediate executor wrapper for the specified object.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U>
immediate_executor_binder(const immediate_executor_type& e,
U&& u)
: executor_(e),
target_(static_cast<U&&>(u))
{
}
/// Copy constructor.
immediate_executor_binder(const immediate_executor_binder& other)
: executor_(other.get_immediate_executor()),
target_(other.get())
{
}
/// Construct a copy, but specify a different immediate executor.
immediate_executor_binder(const immediate_executor_type& e,
const immediate_executor_binder& other)
: executor_(e),
target_(other.get())
{
}
/// Construct a copy of a different immediate executor wrapper type.
/**
* This constructor is only valid if the @c Executor type is
* constructible from type @c OtherExecutor, and the type @c T is
* constructible from type @c U.
*/
template <typename U, typename OtherExecutor>
immediate_executor_binder(
const immediate_executor_binder<U, OtherExecutor>& other,
constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: executor_(other.get_immediate_executor()),
target_(other.get())
{
}
/// Construct a copy of a different immediate executor wrapper type, but
/// specify a different immediate executor.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U, typename OtherExecutor>
immediate_executor_binder(const immediate_executor_type& e,
const immediate_executor_binder<U, OtherExecutor>& other,
constraint_t<is_constructible<T, U>::value> = 0)
: executor_(e),
target_(other.get())
{
}
/// Move constructor.
immediate_executor_binder(immediate_executor_binder&& other)
: executor_(static_cast<immediate_executor_type&&>(
other.get_immediate_executor())),
target_(static_cast<T&&>(other.get()))
{
}
/// Move construct the target object, but specify a different immediate
/// executor.
immediate_executor_binder(const immediate_executor_type& e,
immediate_executor_binder&& other)
: executor_(e),
target_(static_cast<T&&>(other.get()))
{
}
/// Move construct from a different immediate executor wrapper type.
template <typename U, typename OtherExecutor>
immediate_executor_binder(
immediate_executor_binder<U, OtherExecutor>&& other,
constraint_t<is_constructible<Executor, OtherExecutor>::value> = 0,
constraint_t<is_constructible<T, U>::value> = 0)
: executor_(static_cast<OtherExecutor&&>(
other.get_immediate_executor())),
target_(static_cast<U&&>(other.get()))
{
}
/// Move construct from a different immediate executor wrapper type, but
/// specify a different immediate executor.
template <typename U, typename OtherExecutor>
immediate_executor_binder(const immediate_executor_type& e,
immediate_executor_binder<U, OtherExecutor>&& other,
constraint_t<is_constructible<T, U>::value> = 0)
: executor_(e),
target_(static_cast<U&&>(other.get()))
{
}
/// Destructor.
~immediate_executor_binder()
{
}
/// Obtain a reference to the target object.
target_type& get() noexcept
{
return target_;
}
/// Obtain a reference to the target object.
const target_type& get() const noexcept
{
return target_;
}
/// Obtain the associated immediate executor.
immediate_executor_type get_immediate_executor() const noexcept
{
return executor_;
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args)
{
return target_(static_cast<Args&&>(args)...);
}
/// Forwarding function call operator.
template <typename... Args>
result_of_t<T(Args...)> operator()(Args&&... args) const
{
return target_(static_cast<Args&&>(args)...);
}
private:
Executor executor_;
T target_;
};
/// A function object type that adapts a @ref completion_token to specify that
/// the completion handler should have the supplied executor as its associated
/// immediate executor.
/**
* May also be used directly as a completion token, in which case it adapts the
* asynchronous operation's default completion token (or boost::asio::deferred
* if no default is available).
*/
template <typename Executor>
struct partial_immediate_executor_binder
{
/// Constructor that specifies associated executor.
explicit partial_immediate_executor_binder(const Executor& ex)
: executor_(ex)
{
}
/// Adapt a @ref completion_token to specify that the completion handler
/// should have the executor as its associated immediate executor.
template <typename CompletionToken>
BOOST_ASIO_NODISCARD inline
constexpr immediate_executor_binder<decay_t<CompletionToken>, Executor>
operator()(CompletionToken&& completion_token) const
{
return immediate_executor_binder<decay_t<CompletionToken>, Executor>(
static_cast<CompletionToken&&>(completion_token), executor_);
}
//private:
Executor executor_;
};
/// Create a partial completion token that associates an executor.
template <typename Executor>
BOOST_ASIO_NODISCARD inline partial_immediate_executor_binder<Executor>
bind_immediate_executor(const Executor& ex)
{
return partial_immediate_executor_binder<Executor>(ex);
}
/// Associate an object of type @c T with a immediate executor of type
/// @c Executor.
template <typename Executor, typename T>
BOOST_ASIO_NODISCARD inline immediate_executor_binder<decay_t<T>, Executor>
bind_immediate_executor(const Executor& e, T&& t)
{
return immediate_executor_binder<
decay_t<T>, Executor>(
e, static_cast<T&&>(t));
}
#if !defined(GENERATING_DOCUMENTATION)
namespace detail {
template <typename TargetAsyncResult, typename Executor, typename = void>
class immediate_executor_binder_completion_handler_async_result
{
public:
template <typename T>
explicit immediate_executor_binder_completion_handler_async_result(T&)
{
}
};
template <typename TargetAsyncResult, typename Executor>
class immediate_executor_binder_completion_handler_async_result<
TargetAsyncResult, Executor,
void_t<
typename TargetAsyncResult::completion_handler_type
>>
{
private:
TargetAsyncResult target_;
public:
typedef immediate_executor_binder<
typename TargetAsyncResult::completion_handler_type, Executor>
completion_handler_type;
explicit immediate_executor_binder_completion_handler_async_result(
typename TargetAsyncResult::completion_handler_type& handler)
: target_(handler)
{
}
auto get() -> decltype(target_.get())
{
return target_.get();
}
};
template <typename TargetAsyncResult, typename = void>
struct immediate_executor_binder_async_result_return_type
{
};
template <typename TargetAsyncResult>
struct immediate_executor_binder_async_result_return_type<
TargetAsyncResult,
void_t<
typename TargetAsyncResult::return_type
>>
{
typedef typename TargetAsyncResult::return_type return_type;
};
} // namespace detail
template <typename T, typename Executor, typename Signature>
class async_result<immediate_executor_binder<T, Executor>, Signature> :
public detail::immediate_executor_binder_completion_handler_async_result<
async_result<T, Signature>, Executor>,
public detail::immediate_executor_binder_async_result_return_type<
async_result<T, Signature>>
{
public:
explicit async_result(immediate_executor_binder<T, Executor>& b)
: detail::immediate_executor_binder_completion_handler_async_result<
async_result<T, Signature>, Executor>(b.get())
{
}
template <typename Initiation>
struct init_wrapper : detail::initiation_base<Initiation>
{
using detail::initiation_base<Initiation>::initiation_base;
template <typename Handler, typename... Args>
void operator()(Handler&& handler, const Executor& e, Args&&... args) &&
{
static_cast<Initiation&&>(*this)(
immediate_executor_binder<
decay_t<Handler>, Executor>(
e, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler,
const Executor& e, Args&&... args) const &
{
static_cast<const Initiation&>(*this)(
immediate_executor_binder<
decay_t<Handler>, Executor>(
e, static_cast<Handler&&>(handler)),
static_cast<Args&&>(args)...);
}
};
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<
conditional_t<
is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
Signature>(
declval<init_wrapper<decay_t<Initiation>>>(),
token.get(), token.get_immediate_executor(),
static_cast<Args&&>(args)...))
{
return async_initiate<
conditional_t<
is_const<remove_reference_t<RawCompletionToken>>::value, const T, T>,
Signature>(
init_wrapper<decay_t<Initiation>>(
static_cast<Initiation&&>(initiation)),
token.get(), token.get_immediate_executor(),
static_cast<Args&&>(args)...);
}
private:
async_result(const async_result&) = delete;
async_result& operator=(const async_result&) = delete;
async_result<T, Signature> target_;
};
template <typename Executor, typename... Signatures>
struct async_result<partial_immediate_executor_binder<Executor>, Signatures...>
{
template <typename Initiation, typename RawCompletionToken, typename... Args>
static auto initiate(Initiation&& initiation,
RawCompletionToken&& token, Args&&... args)
-> decltype(
async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
immediate_executor_binder<
default_completion_token_t<associated_executor_t<Initiation>>,
Executor>(token.executor_,
default_completion_token_t<associated_executor_t<Initiation>>{}),
static_cast<Args&&>(args)...))
{
return async_initiate<Signatures...>(
static_cast<Initiation&&>(initiation),
immediate_executor_binder<
default_completion_token_t<associated_executor_t<Initiation>>,
Executor>(token.executor_,
default_completion_token_t<associated_executor_t<Initiation>>{}),
static_cast<Args&&>(args)...);
}
};
template <template <typename, typename> class Associator,
typename T, typename Executor, typename DefaultCandidate>
struct associator<Associator,
immediate_executor_binder<T, Executor>,
DefaultCandidate>
: Associator<T, DefaultCandidate>
{
static typename Associator<T, DefaultCandidate>::type get(
const immediate_executor_binder<T, Executor>& b) noexcept
{
return Associator<T, DefaultCandidate>::get(b.get());
}
static auto get(const immediate_executor_binder<T, Executor>& b,
const DefaultCandidate& c) noexcept
-> decltype(Associator<T, DefaultCandidate>::get(b.get(), c))
{
return Associator<T, DefaultCandidate>::get(b.get(), c);
}
};
template <typename T, typename Executor, typename Executor1>
struct associated_immediate_executor<
immediate_executor_binder<T, Executor>,
Executor1>
{
typedef Executor type;
static auto get(const immediate_executor_binder<T, Executor>& b,
const Executor1& = Executor1()) noexcept
-> decltype(b.get_immediate_executor())
{
return b.get_immediate_executor();
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_BIND_IMMEDIATE_EXECUTOR_HPP

2755
extern/boost/boost/asio/buffer.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,320 @@
//
// buffer_registration.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BUFFER_REGISTRATION_HPP
#define BOOST_ASIO_BUFFER_REGISTRATION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <iterator>
#include <utility>
#include <vector>
#include <boost/asio/detail/memory.hpp>
#include <boost/asio/execution/context.hpp>
#include <boost/asio/execution/executor.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/is_executor.hpp>
#include <boost/asio/query.hpp>
#include <boost/asio/registered_buffer.hpp>
#if defined(BOOST_ASIO_HAS_IO_URING)
# include <boost/asio/detail/scheduler.hpp>
# include <boost/asio/detail/io_uring_service.hpp>
#endif // defined(BOOST_ASIO_HAS_IO_URING)
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
class buffer_registration_base
{
protected:
static mutable_registered_buffer make_buffer(const mutable_buffer& b,
const void* scope, int index) noexcept
{
return mutable_registered_buffer(b, registered_buffer_id(scope, index));
}
};
} // namespace detail
/// Automatically registers and unregistered buffers with an execution context.
/**
* For portability, applications should assume that only one registration is
* permitted per execution context.
*/
template <typename MutableBufferSequence,
typename Allocator = std::allocator<void>>
class buffer_registration
: detail::buffer_registration_base
{
public:
/// The allocator type used for allocating storage for the buffers container.
typedef Allocator allocator_type;
#if defined(GENERATING_DOCUMENTATION)
/// The type of an iterator over the registered buffers.
typedef unspecified iterator;
/// The type of a const iterator over the registered buffers.
typedef unspecified const_iterator;
#else // defined(GENERATING_DOCUMENTATION)
typedef std::vector<mutable_registered_buffer>::const_iterator iterator;
typedef std::vector<mutable_registered_buffer>::const_iterator const_iterator;
#endif // defined(GENERATING_DOCUMENTATION)
/// Register buffers with an executor's execution context.
template <typename Executor>
buffer_registration(const Executor& ex,
const MutableBufferSequence& buffer_sequence,
const allocator_type& alloc = allocator_type(),
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0)
: buffer_sequence_(buffer_sequence),
buffers_(
BOOST_ASIO_REBIND_ALLOC(allocator_type,
mutable_registered_buffer)(alloc))
{
init_buffers(buffer_registration::get_context(ex),
boost::asio::buffer_sequence_begin(buffer_sequence_),
boost::asio::buffer_sequence_end(buffer_sequence_));
}
/// Register buffers with an execution context.
template <typename ExecutionContext>
buffer_registration(ExecutionContext& ctx,
const MutableBufferSequence& buffer_sequence,
const allocator_type& alloc = allocator_type(),
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
: buffer_sequence_(buffer_sequence),
buffers_(
BOOST_ASIO_REBIND_ALLOC(allocator_type,
mutable_registered_buffer)(alloc))
{
init_buffers(ctx,
boost::asio::buffer_sequence_begin(buffer_sequence_),
boost::asio::buffer_sequence_end(buffer_sequence_));
}
/// Move constructor.
buffer_registration(buffer_registration&& other) noexcept
: buffer_sequence_(std::move(other.buffer_sequence_)),
buffers_(std::move(other.buffers_))
{
#if defined(BOOST_ASIO_HAS_IO_URING)
service_ = other.service_;
other.service_ = 0;
#endif // defined(BOOST_ASIO_HAS_IO_URING)
}
/// Unregisters the buffers.
~buffer_registration()
{
#if defined(BOOST_ASIO_HAS_IO_URING)
if (service_)
service_->unregister_buffers();
#endif // defined(BOOST_ASIO_HAS_IO_URING)
}
/// Move assignment.
buffer_registration& operator=(buffer_registration&& other) noexcept
{
if (this != &other)
{
buffer_sequence_ = std::move(other.buffer_sequence_);
buffers_ = std::move(other.buffers_);
#if defined(BOOST_ASIO_HAS_IO_URING)
if (service_)
service_->unregister_buffers();
service_ = other.service_;
other.service_ = 0;
#endif // defined(BOOST_ASIO_HAS_IO_URING)
}
return *this;
}
/// Get the number of registered buffers.
std::size_t size() const noexcept
{
return buffers_.size();
}
/// Get the begin iterator for the sequence of registered buffers.
const_iterator begin() const noexcept
{
return buffers_.begin();
}
/// Get the begin iterator for the sequence of registered buffers.
const_iterator cbegin() const noexcept
{
return buffers_.cbegin();
}
/// Get the end iterator for the sequence of registered buffers.
const_iterator end() const noexcept
{
return buffers_.end();
}
/// Get the end iterator for the sequence of registered buffers.
const_iterator cend() const noexcept
{
return buffers_.cend();
}
/// Get the buffer at the specified index.
const mutable_registered_buffer& operator[](std::size_t i) noexcept
{
return buffers_[i];
}
/// Get the buffer at the specified index.
const mutable_registered_buffer& at(std::size_t i) noexcept
{
return buffers_.at(i);
}
private:
// Disallow copying and assignment.
buffer_registration(const buffer_registration&) = delete;
buffer_registration& operator=(const buffer_registration&) = delete;
// Helper function to get an executor's context.
template <typename T>
static execution_context& get_context(const T& t,
enable_if_t<execution::is_executor<T>::value>* = 0)
{
return boost::asio::query(t, execution::context);
}
// Helper function to get an executor's context.
template <typename T>
static execution_context& get_context(const T& t,
enable_if_t<!execution::is_executor<T>::value>* = 0)
{
return t.context();
}
// Helper function to initialise the container of buffers.
template <typename Iterator>
void init_buffers(execution_context& ctx, Iterator begin, Iterator end)
{
std::size_t n = std::distance(begin, end);
buffers_.resize(n);
#if defined(BOOST_ASIO_HAS_IO_URING)
service_ = &use_service<detail::io_uring_service>(ctx);
std::vector<iovec,
BOOST_ASIO_REBIND_ALLOC(allocator_type, iovec)> iovecs(n,
BOOST_ASIO_REBIND_ALLOC(allocator_type, iovec)(
buffers_.get_allocator()));
#endif // defined(BOOST_ASIO_HAS_IO_URING)
Iterator iter = begin;
for (int index = 0; iter != end; ++index, ++iter)
{
mutable_buffer b(*iter);
std::size_t i = static_cast<std::size_t>(index);
buffers_[i] = this->make_buffer(b, &ctx, index);
#if defined(BOOST_ASIO_HAS_IO_URING)
iovecs[i].iov_base = buffers_[i].data();
iovecs[i].iov_len = buffers_[i].size();
#endif // defined(BOOST_ASIO_HAS_IO_URING)
}
#if defined(BOOST_ASIO_HAS_IO_URING)
if (n > 0)
{
service_->register_buffers(&iovecs[0],
static_cast<unsigned>(iovecs.size()));
}
#endif // defined(BOOST_ASIO_HAS_IO_URING)
}
MutableBufferSequence buffer_sequence_;
std::vector<mutable_registered_buffer,
BOOST_ASIO_REBIND_ALLOC(allocator_type,
mutable_registered_buffer)> buffers_;
#if defined(BOOST_ASIO_HAS_IO_URING)
detail::io_uring_service* service_;
#endif // defined(BOOST_ASIO_HAS_IO_URING)
};
/// Register buffers with an execution context.
template <typename Executor, typename MutableBufferSequence>
BOOST_ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence>
register_buffers(const Executor& ex,
const MutableBufferSequence& buffer_sequence,
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0)
{
return buffer_registration<MutableBufferSequence>(ex, buffer_sequence);
}
/// Register buffers with an execution context.
template <typename Executor, typename MutableBufferSequence, typename Allocator>
BOOST_ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence, Allocator>
register_buffers(const Executor& ex,
const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0)
{
return buffer_registration<MutableBufferSequence, Allocator>(
ex, buffer_sequence, alloc);
}
/// Register buffers with an execution context.
template <typename ExecutionContext, typename MutableBufferSequence>
BOOST_ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence>
register_buffers(ExecutionContext& ctx,
const MutableBufferSequence& buffer_sequence,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
{
return buffer_registration<MutableBufferSequence>(ctx, buffer_sequence);
}
/// Register buffers with an execution context.
template <typename ExecutionContext,
typename MutableBufferSequence, typename Allocator>
BOOST_ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence, Allocator>
register_buffers(ExecutionContext& ctx,
const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
{
return buffer_registration<MutableBufferSequence, Allocator>(
ctx, buffer_sequence, alloc);
}
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_BUFFER_REGISTRATION_HPP

View File

@ -0,0 +1,275 @@
//
// buffered_read_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BUFFERED_READ_STREAM_HPP
#define BOOST_ASIO_BUFFERED_READ_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <cstddef>
#include <boost/asio/async_result.hpp>
#include <boost/asio/buffered_read_stream_fwd.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffer_resize_guard.hpp>
#include <boost/asio/detail/buffered_stream_storage.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename> class initiate_async_buffered_fill;
template <typename> class initiate_async_buffered_read_some;
} // namespace detail
/// Adds buffering to the read-related operations of a stream.
/**
* The buffered_read_stream class template can be used to add buffering to the
* synchronous and asynchronous read operations of a stream.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Stream>
class buffered_read_stream
: private noncopyable
{
public:
/// The type of the next layer.
typedef remove_reference_t<Stream> next_layer_type;
/// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
/// The type of the executor associated with the object.
typedef typename lowest_layer_type::executor_type executor_type;
#if defined(GENERATING_DOCUMENTATION)
/// The default buffer size.
static const std::size_t default_buffer_size = implementation_defined;
#else
BOOST_ASIO_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
#endif
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_read_stream(Arg&& a)
: next_layer_(static_cast<Arg&&>(a)),
storage_(default_buffer_size)
{
}
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
buffered_read_stream(Arg&& a,
std::size_t buffer_size)
: next_layer_(static_cast<Arg&&>(a)),
storage_(buffer_size)
{
}
/// Get a reference to the next layer.
next_layer_type& next_layer()
{
return next_layer_;
}
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer()
{
return next_layer_.lowest_layer();
}
/// Get a const reference to the lowest layer.
const lowest_layer_type& lowest_layer() const
{
return next_layer_.lowest_layer();
}
/// Get the executor associated with the object.
executor_type get_executor() noexcept
{
return next_layer_.lowest_layer().get_executor();
}
/// Close the stream.
void close()
{
next_layer_.close();
}
/// Close the stream.
BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
{
next_layer_.close(ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Write the given data to the stream. Returns the number of bytes written.
/// Throws an exception on failure.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
return next_layer_.write_some(buffers);
}
/// Write the given data to the stream. Returns the number of bytes written,
/// or 0 if an error occurred.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
boost::system::error_code& ec)
{
return next_layer_.write_some(buffers, ec);
}
/// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation.
/**
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*/
template <typename ConstBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) WriteHandler = default_completion_token_t<executor_type>>
auto async_write_some(const ConstBufferSequence& buffers,
WriteHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
declval<conditional_t<true, Stream&, WriteHandler>>().async_write_some(
buffers, static_cast<WriteHandler&&>(handler)))
{
return next_layer_.async_write_some(buffers,
static_cast<WriteHandler&&>(handler));
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation. Throws an exception on failure.
std::size_t fill();
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation, or 0 if an error occurred.
std::size_t fill(boost::system::error_code& ec);
/// Start an asynchronous fill.
/**
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*/
template <
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) ReadHandler = default_completion_token_t<executor_type>>
auto async_fill(
ReadHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadHandler,
void (boost::system::error_code, std::size_t)>(
declval<detail::initiate_async_buffered_fill<Stream>>(),
handler, declval<detail::buffered_stream_storage*>()));
/// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers);
/// Read some data from the stream. Returns the number of bytes read or 0 if
/// an error occurred.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
boost::system::error_code& ec);
/// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation.
/**
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*/
template <typename MutableBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) ReadHandler = default_completion_token_t<executor_type>>
auto async_read_some(const MutableBufferSequence& buffers,
ReadHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<ReadHandler,
void (boost::system::error_code, std::size_t)>(
declval<detail::initiate_async_buffered_read_some<Stream>>(),
handler, declval<detail::buffered_stream_storage*>(), buffers));
/// Peek at the incoming data on the stream. Returns the number of bytes read.
/// Throws an exception on failure.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers);
/// Peek at the incoming data on the stream. Returns the number of bytes read,
/// or 0 if an error occurred.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers,
boost::system::error_code& ec);
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail()
{
return storage_.size();
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail(boost::system::error_code& ec)
{
ec = boost::system::error_code();
return storage_.size();
}
private:
/// Copy data out of the internal buffer to the specified target buffer.
/// Returns the number of bytes copied.
template <typename MutableBufferSequence>
std::size_t copy(const MutableBufferSequence& buffers)
{
std::size_t bytes_copied = boost::asio::buffer_copy(
buffers, storage_.data(), storage_.size());
storage_.consume(bytes_copied);
return bytes_copied;
}
/// Copy data from the internal buffer to the specified target buffer, without
/// removing the data from the internal buffer. Returns the number of bytes
/// copied.
template <typename MutableBufferSequence>
std::size_t peek_copy(const MutableBufferSequence& buffers)
{
return boost::asio::buffer_copy(buffers, storage_.data(), storage_.size());
}
/// The next layer.
Stream next_layer_;
// The data in the buffer.
detail::buffered_stream_storage storage_;
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/impl/buffered_read_stream.hpp>
#endif // BOOST_ASIO_BUFFERED_READ_STREAM_HPP

View File

@ -0,0 +1,27 @@
//
// buffered_read_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BUFFERED_READ_STREAM_FWD_HPP
#define BOOST_ASIO_BUFFERED_READ_STREAM_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
namespace boost {
namespace asio {
template <typename Stream>
class buffered_read_stream;
} // namespace asio
} // namespace boost
#endif // BOOST_ASIO_BUFFERED_READ_STREAM_FWD_HPP

View File

@ -0,0 +1,294 @@
//
// buffered_stream.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BUFFERED_STREAM_HPP
#define BOOST_ASIO_BUFFERED_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <cstddef>
#include <boost/asio/async_result.hpp>
#include <boost/asio/buffered_read_stream.hpp>
#include <boost/asio/buffered_write_stream.hpp>
#include <boost/asio/buffered_stream_fwd.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Adds buffering to the read- and write-related operations of a stream.
/**
* The buffered_stream class template can be used to add buffering to the
* synchronous and asynchronous read and write operations of a stream.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Stream>
class buffered_stream
: private noncopyable
{
public:
/// The type of the next layer.
typedef remove_reference_t<Stream> next_layer_type;
/// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
/// The type of the executor associated with the object.
typedef typename lowest_layer_type::executor_type executor_type;
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_stream(Arg&& a)
: inner_stream_impl_(static_cast<Arg&&>(a)),
stream_impl_(inner_stream_impl_)
{
}
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_stream(Arg&& a,
std::size_t read_buffer_size, std::size_t write_buffer_size)
: inner_stream_impl_(static_cast<Arg&&>(a), write_buffer_size),
stream_impl_(inner_stream_impl_, read_buffer_size)
{
}
/// Get a reference to the next layer.
next_layer_type& next_layer()
{
return stream_impl_.next_layer().next_layer();
}
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer()
{
return stream_impl_.lowest_layer();
}
/// Get a const reference to the lowest layer.
const lowest_layer_type& lowest_layer() const
{
return stream_impl_.lowest_layer();
}
/// Get the executor associated with the object.
executor_type get_executor() noexcept
{
return stream_impl_.lowest_layer().get_executor();
}
/// Close the stream.
void close()
{
stream_impl_.close();
}
/// Close the stream.
BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
{
stream_impl_.close(ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation. Throws an
/// exception on failure.
std::size_t flush()
{
return stream_impl_.next_layer().flush();
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation, or 0 if an
/// error occurred.
std::size_t flush(boost::system::error_code& ec)
{
return stream_impl_.next_layer().flush(ec);
}
/// Start an asynchronous flush.
/**
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*/
template <
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) WriteHandler = default_completion_token_t<executor_type>>
auto async_flush(
WriteHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
declval<buffered_write_stream<Stream>&>().async_flush(
static_cast<WriteHandler&&>(handler)))
{
return stream_impl_.next_layer().async_flush(
static_cast<WriteHandler&&>(handler));
}
/// Write the given data to the stream. Returns the number of bytes written.
/// Throws an exception on failure.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
return stream_impl_.write_some(buffers);
}
/// Write the given data to the stream. Returns the number of bytes written,
/// or 0 if an error occurred.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
boost::system::error_code& ec)
{
return stream_impl_.write_some(buffers, ec);
}
/// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation.
/**
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*/
template <typename ConstBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) WriteHandler = default_completion_token_t<executor_type>>
auto async_write_some(const ConstBufferSequence& buffers,
WriteHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
declval<Stream&>().async_write_some(buffers,
static_cast<WriteHandler&&>(handler)))
{
return stream_impl_.async_write_some(buffers,
static_cast<WriteHandler&&>(handler));
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation. Throws an exception on failure.
std::size_t fill()
{
return stream_impl_.fill();
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation, or 0 if an error occurred.
std::size_t fill(boost::system::error_code& ec)
{
return stream_impl_.fill(ec);
}
/// Start an asynchronous fill.
/**
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*/
template <
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) ReadHandler = default_completion_token_t<executor_type>>
auto async_fill(
ReadHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
declval<buffered_read_stream<
buffered_write_stream<Stream>>&>().async_fill(
static_cast<ReadHandler&&>(handler)))
{
return stream_impl_.async_fill(static_cast<ReadHandler&&>(handler));
}
/// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
return stream_impl_.read_some(buffers);
}
/// Read some data from the stream. Returns the number of bytes read or 0 if
/// an error occurred.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
boost::system::error_code& ec)
{
return stream_impl_.read_some(buffers, ec);
}
/// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation.
/**
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*/
template <typename MutableBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) ReadHandler = default_completion_token_t<executor_type>>
auto async_read_some(const MutableBufferSequence& buffers,
ReadHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
declval<Stream&>().async_read_some(buffers,
static_cast<ReadHandler&&>(handler)))
{
return stream_impl_.async_read_some(buffers,
static_cast<ReadHandler&&>(handler));
}
/// Peek at the incoming data on the stream. Returns the number of bytes read.
/// Throws an exception on failure.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers)
{
return stream_impl_.peek(buffers);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read,
/// or 0 if an error occurred.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers,
boost::system::error_code& ec)
{
return stream_impl_.peek(buffers, ec);
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail()
{
return stream_impl_.in_avail();
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail(boost::system::error_code& ec)
{
return stream_impl_.in_avail(ec);
}
private:
// The buffered write stream.
typedef buffered_write_stream<Stream> write_stream_type;
write_stream_type inner_stream_impl_;
// The buffered read stream.
typedef buffered_read_stream<write_stream_type&> read_stream_type;
read_stream_type stream_impl_;
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_BUFFERED_STREAM_HPP

View File

@ -0,0 +1,27 @@
//
// buffered_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BUFFERED_STREAM_FWD_HPP
#define BOOST_ASIO_BUFFERED_STREAM_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
namespace boost {
namespace asio {
template <typename Stream>
class buffered_stream;
} // namespace asio
} // namespace boost
#endif // BOOST_ASIO_BUFFERED_STREAM_FWD_HPP

View File

@ -0,0 +1,267 @@
//
// buffered_write_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BUFFERED_WRITE_STREAM_HPP
#define BOOST_ASIO_BUFFERED_WRITE_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <cstddef>
#include <boost/asio/buffered_write_stream_fwd.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/completion_condition.hpp>
#include <boost/asio/detail/bind_handler.hpp>
#include <boost/asio/detail/buffered_stream_storage.hpp>
#include <boost/asio/detail/noncopyable.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename> class initiate_async_buffered_flush;
template <typename> class initiate_async_buffered_write_some;
} // namespace detail
/// Adds buffering to the write-related operations of a stream.
/**
* The buffered_write_stream class template can be used to add buffering to the
* synchronous and asynchronous write operations of a stream.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Stream>
class buffered_write_stream
: private noncopyable
{
public:
/// The type of the next layer.
typedef remove_reference_t<Stream> next_layer_type;
/// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
/// The type of the executor associated with the object.
typedef typename lowest_layer_type::executor_type executor_type;
#if defined(GENERATING_DOCUMENTATION)
/// The default buffer size.
static const std::size_t default_buffer_size = implementation_defined;
#else
BOOST_ASIO_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
#endif
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_write_stream(Arg&& a)
: next_layer_(static_cast<Arg&&>(a)),
storage_(default_buffer_size)
{
}
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
buffered_write_stream(Arg&& a,
std::size_t buffer_size)
: next_layer_(static_cast<Arg&&>(a)),
storage_(buffer_size)
{
}
/// Get a reference to the next layer.
next_layer_type& next_layer()
{
return next_layer_;
}
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer()
{
return next_layer_.lowest_layer();
}
/// Get a const reference to the lowest layer.
const lowest_layer_type& lowest_layer() const
{
return next_layer_.lowest_layer();
}
/// Get the executor associated with the object.
executor_type get_executor() noexcept
{
return next_layer_.lowest_layer().get_executor();
}
/// Close the stream.
void close()
{
next_layer_.close();
}
/// Close the stream.
BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec)
{
next_layer_.close(ec);
BOOST_ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation. Throws an
/// exception on failure.
std::size_t flush();
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation, or 0 if an
/// error occurred.
std::size_t flush(boost::system::error_code& ec);
/// Start an asynchronous flush.
/**
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*/
template <
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) WriteHandler = default_completion_token_t<executor_type>>
auto async_flush(
WriteHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteHandler,
void (boost::system::error_code, std::size_t)>(
declval<detail::initiate_async_buffered_flush<Stream>>(),
handler, declval<detail::buffered_stream_storage*>()));
/// Write the given data to the stream. Returns the number of bytes written.
/// Throws an exception on failure.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers);
/// Write the given data to the stream. Returns the number of bytes written,
/// or 0 if an error occurred and the error handler did not throw.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
boost::system::error_code& ec);
/// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation.
/**
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*/
template <typename ConstBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) WriteHandler = default_completion_token_t<executor_type>>
auto async_write_some(const ConstBufferSequence& buffers,
WriteHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
async_initiate<WriteHandler,
void (boost::system::error_code, std::size_t)>(
declval<detail::initiate_async_buffered_write_some<Stream>>(),
handler, declval<detail::buffered_stream_storage*>(), buffers));
/// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
return next_layer_.read_some(buffers);
}
/// Read some data from the stream. Returns the number of bytes read or 0 if
/// an error occurred.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
boost::system::error_code& ec)
{
return next_layer_.read_some(buffers, ec);
}
/// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation.
/**
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*/
template <typename MutableBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) ReadHandler = default_completion_token_t<executor_type>>
auto async_read_some(const MutableBufferSequence& buffers,
ReadHandler&& handler = default_completion_token_t<executor_type>())
-> decltype(
declval<conditional_t<true, Stream&, ReadHandler>>().async_read_some(
buffers, static_cast<ReadHandler&&>(handler)))
{
return next_layer_.async_read_some(buffers,
static_cast<ReadHandler&&>(handler));
}
/// Peek at the incoming data on the stream. Returns the number of bytes read.
/// Throws an exception on failure.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers)
{
return next_layer_.peek(buffers);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read,
/// or 0 if an error occurred.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers,
boost::system::error_code& ec)
{
return next_layer_.peek(buffers, ec);
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail()
{
return next_layer_.in_avail();
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail(boost::system::error_code& ec)
{
return next_layer_.in_avail(ec);
}
private:
/// Copy data into the internal buffer from the specified source buffer.
/// Returns the number of bytes copied.
template <typename ConstBufferSequence>
std::size_t copy(const ConstBufferSequence& buffers);
/// The next layer.
Stream next_layer_;
// The data in the buffer.
detail::buffered_stream_storage storage_;
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/impl/buffered_write_stream.hpp>
#endif // BOOST_ASIO_BUFFERED_WRITE_STREAM_HPP

View File

@ -0,0 +1,27 @@
//
// buffered_write_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
#define BOOST_ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
namespace boost {
namespace asio {
template <typename Stream>
class buffered_write_stream;
} // namespace asio
} // namespace boost
#endif // BOOST_ASIO_BUFFERED_WRITE_STREAM_FWD_HPP

View File

@ -0,0 +1,523 @@
//
// buffers_iterator.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_BUFFERS_ITERATOR_HPP
#define BOOST_ASIO_BUFFERS_ITERATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <cstddef>
#include <iterator>
#include <boost/asio/buffer.hpp>
#include <boost/asio/detail/assert.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail
{
template <bool IsMutable>
struct buffers_iterator_types_helper;
template <>
struct buffers_iterator_types_helper<false>
{
typedef const_buffer buffer_type;
template <typename ByteType>
struct byte_type
{
typedef add_const_t<ByteType> type;
};
};
template <>
struct buffers_iterator_types_helper<true>
{
typedef mutable_buffer buffer_type;
template <typename ByteType>
struct byte_type
{
typedef ByteType type;
};
};
template <typename BufferSequence, typename ByteType>
struct buffers_iterator_types
{
enum
{
is_mutable = is_convertible<
typename BufferSequence::value_type,
mutable_buffer>::value
};
typedef buffers_iterator_types_helper<is_mutable> helper;
typedef typename helper::buffer_type buffer_type;
typedef typename helper::template byte_type<ByteType>::type byte_type;
typedef typename BufferSequence::const_iterator const_iterator;
};
template <typename ByteType>
struct buffers_iterator_types<mutable_buffer, ByteType>
{
typedef mutable_buffer buffer_type;
typedef ByteType byte_type;
typedef const mutable_buffer* const_iterator;
};
template <typename ByteType>
struct buffers_iterator_types<const_buffer, ByteType>
{
typedef const_buffer buffer_type;
typedef add_const_t<ByteType> byte_type;
typedef const const_buffer* const_iterator;
};
#if !defined(BOOST_ASIO_NO_DEPRECATED)
template <typename ByteType>
struct buffers_iterator_types<mutable_buffers_1, ByteType>
{
typedef mutable_buffer buffer_type;
typedef ByteType byte_type;
typedef const mutable_buffer* const_iterator;
};
template <typename ByteType>
struct buffers_iterator_types<const_buffers_1, ByteType>
{
typedef const_buffer buffer_type;
typedef add_const_t<ByteType> byte_type;
typedef const const_buffer* const_iterator;
};
#endif // !defined(BOOST_ASIO_NO_DEPRECATED)
}
/// A random access iterator over the bytes in a buffer sequence.
template <typename BufferSequence, typename ByteType = char>
class buffers_iterator
{
private:
typedef typename detail::buffers_iterator_types<
BufferSequence, ByteType>::buffer_type buffer_type;
typedef typename detail::buffers_iterator_types<BufferSequence,
ByteType>::const_iterator buffer_sequence_iterator_type;
public:
/// The type used for the distance between two iterators.
typedef std::ptrdiff_t difference_type;
/// The type of the value pointed to by the iterator.
typedef ByteType value_type;
#if defined(GENERATING_DOCUMENTATION)
/// The type of the result of applying operator->() to the iterator.
/**
* If the buffer sequence stores buffer objects that are convertible to
* mutable_buffer, this is a pointer to a non-const ByteType. Otherwise, a
* pointer to a const ByteType.
*/
typedef const_or_non_const_ByteType* pointer;
#else // defined(GENERATING_DOCUMENTATION)
typedef typename detail::buffers_iterator_types<
BufferSequence, ByteType>::byte_type* pointer;
#endif // defined(GENERATING_DOCUMENTATION)
#if defined(GENERATING_DOCUMENTATION)
/// The type of the result of applying operator*() to the iterator.
/**
* If the buffer sequence stores buffer objects that are convertible to
* mutable_buffer, this is a reference to a non-const ByteType. Otherwise, a
* reference to a const ByteType.
*/
typedef const_or_non_const_ByteType& reference;
#else // defined(GENERATING_DOCUMENTATION)
typedef typename detail::buffers_iterator_types<
BufferSequence, ByteType>::byte_type& reference;
#endif // defined(GENERATING_DOCUMENTATION)
/// The iterator category.
typedef std::random_access_iterator_tag iterator_category;
/// Default constructor. Creates an iterator in an undefined state.
buffers_iterator()
: current_buffer_(),
current_buffer_position_(0),
begin_(),
current_(),
end_(),
position_(0)
{
}
/// Construct an iterator representing the beginning of the buffers' data.
static buffers_iterator begin(const BufferSequence& buffers)
#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
__attribute__ ((__noinline__))
#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
{
buffers_iterator new_iter;
new_iter.begin_ = boost::asio::buffer_sequence_begin(buffers);
new_iter.current_ = boost::asio::buffer_sequence_begin(buffers);
new_iter.end_ = boost::asio::buffer_sequence_end(buffers);
while (new_iter.current_ != new_iter.end_)
{
new_iter.current_buffer_ = *new_iter.current_;
if (new_iter.current_buffer_.size() > 0)
break;
++new_iter.current_;
}
return new_iter;
}
/// Construct an iterator representing the end of the buffers' data.
static buffers_iterator end(const BufferSequence& buffers)
#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
__attribute__ ((__noinline__))
#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
{
buffers_iterator new_iter;
new_iter.begin_ = boost::asio::buffer_sequence_begin(buffers);
new_iter.current_ = boost::asio::buffer_sequence_begin(buffers);
new_iter.end_ = boost::asio::buffer_sequence_end(buffers);
while (new_iter.current_ != new_iter.end_)
{
buffer_type buffer = *new_iter.current_;
new_iter.position_ += buffer.size();
++new_iter.current_;
}
return new_iter;
}
/// Dereference an iterator.
reference operator*() const
{
return dereference();
}
/// Dereference an iterator.
pointer operator->() const
{
return &dereference();
}
/// Access an individual element.
reference operator[](std::ptrdiff_t difference) const
{
buffers_iterator tmp(*this);
tmp.advance(difference);
return *tmp;
}
/// Increment operator (prefix).
buffers_iterator& operator++()
{
increment();
return *this;
}
/// Increment operator (postfix).
buffers_iterator operator++(int)
{
buffers_iterator tmp(*this);
++*this;
return tmp;
}
/// Decrement operator (prefix).
buffers_iterator& operator--()
{
decrement();
return *this;
}
/// Decrement operator (postfix).
buffers_iterator operator--(int)
{
buffers_iterator tmp(*this);
--*this;
return tmp;
}
/// Addition operator.
buffers_iterator& operator+=(std::ptrdiff_t difference)
{
advance(difference);
return *this;
}
/// Subtraction operator.
buffers_iterator& operator-=(std::ptrdiff_t difference)
{
advance(-difference);
return *this;
}
/// Addition operator.
friend buffers_iterator operator+(const buffers_iterator& iter,
std::ptrdiff_t difference)
{
buffers_iterator tmp(iter);
tmp.advance(difference);
return tmp;
}
/// Addition operator.
friend buffers_iterator operator+(std::ptrdiff_t difference,
const buffers_iterator& iter)
{
buffers_iterator tmp(iter);
tmp.advance(difference);
return tmp;
}
/// Subtraction operator.
friend buffers_iterator operator-(const buffers_iterator& iter,
std::ptrdiff_t difference)
{
buffers_iterator tmp(iter);
tmp.advance(-difference);
return tmp;
}
/// Subtraction operator.
friend std::ptrdiff_t operator-(const buffers_iterator& a,
const buffers_iterator& b)
{
return b.distance_to(a);
}
/// Test two iterators for equality.
friend bool operator==(const buffers_iterator& a, const buffers_iterator& b)
{
return a.equal(b);
}
/// Test two iterators for inequality.
friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b)
{
return !a.equal(b);
}
/// Compare two iterators.
friend bool operator<(const buffers_iterator& a, const buffers_iterator& b)
{
return a.distance_to(b) > 0;
}
/// Compare two iterators.
friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b)
{
return !(b < a);
}
/// Compare two iterators.
friend bool operator>(const buffers_iterator& a, const buffers_iterator& b)
{
return b < a;
}
/// Compare two iterators.
friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b)
{
return !(a < b);
}
private:
// Dereference the iterator.
reference dereference() const
{
return static_cast<pointer>(
current_buffer_.data())[current_buffer_position_];
}
// Compare two iterators for equality.
bool equal(const buffers_iterator& other) const
{
return position_ == other.position_;
}
// Increment the iterator.
void increment()
{
BOOST_ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
++position_;
// Check if the increment can be satisfied by the current buffer.
++current_buffer_position_;
if (current_buffer_position_ != current_buffer_.size())
return;
// Find the next non-empty buffer.
++current_;
current_buffer_position_ = 0;
while (current_ != end_)
{
current_buffer_ = *current_;
if (current_buffer_.size() > 0)
return;
++current_;
}
}
// Decrement the iterator.
void decrement()
{
BOOST_ASIO_ASSERT(position_ > 0 && "iterator out of bounds");
--position_;
// Check if the decrement can be satisfied by the current buffer.
if (current_buffer_position_ != 0)
{
--current_buffer_position_;
return;
}
// Find the previous non-empty buffer.
buffer_sequence_iterator_type iter = current_;
while (iter != begin_)
{
--iter;
buffer_type buffer = *iter;
std::size_t buffer_size = buffer.size();
if (buffer_size > 0)
{
current_ = iter;
current_buffer_ = buffer;
current_buffer_position_ = buffer_size - 1;
return;
}
}
}
// Advance the iterator by the specified distance.
void advance(std::ptrdiff_t n)
{
if (n > 0)
{
BOOST_ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
for (;;)
{
std::ptrdiff_t current_buffer_balance
= current_buffer_.size() - current_buffer_position_;
// Check if the advance can be satisfied by the current buffer.
if (current_buffer_balance > n)
{
position_ += n;
current_buffer_position_ += n;
return;
}
// Update position.
n -= current_buffer_balance;
position_ += current_buffer_balance;
// Move to next buffer. If it is empty then it will be skipped on the
// next iteration of this loop.
if (++current_ == end_)
{
BOOST_ASIO_ASSERT(n == 0 && "iterator out of bounds");
current_buffer_ = buffer_type();
current_buffer_position_ = 0;
return;
}
current_buffer_ = *current_;
current_buffer_position_ = 0;
}
}
else if (n < 0)
{
std::size_t abs_n = -n;
BOOST_ASIO_ASSERT(position_ >= abs_n && "iterator out of bounds");
for (;;)
{
// Check if the advance can be satisfied by the current buffer.
if (current_buffer_position_ >= abs_n)
{
position_ -= abs_n;
current_buffer_position_ -= abs_n;
return;
}
// Update position.
abs_n -= current_buffer_position_;
position_ -= current_buffer_position_;
// Check if we've reached the beginning of the buffers.
if (current_ == begin_)
{
BOOST_ASIO_ASSERT(abs_n == 0 && "iterator out of bounds");
current_buffer_position_ = 0;
return;
}
// Find the previous non-empty buffer.
buffer_sequence_iterator_type iter = current_;
while (iter != begin_)
{
--iter;
buffer_type buffer = *iter;
std::size_t buffer_size = buffer.size();
if (buffer_size > 0)
{
current_ = iter;
current_buffer_ = buffer;
current_buffer_position_ = buffer_size;
break;
}
}
}
}
}
// Determine the distance between two iterators.
std::ptrdiff_t distance_to(const buffers_iterator& other) const
{
return other.position_ - position_;
}
buffer_type current_buffer_;
std::size_t current_buffer_position_;
buffer_sequence_iterator_type begin_;
buffer_sequence_iterator_type current_;
buffer_sequence_iterator_type end_;
std::size_t position_;
};
/// Construct an iterator representing the beginning of the buffers' data.
template <typename BufferSequence>
inline buffers_iterator<BufferSequence> buffers_begin(
const BufferSequence& buffers)
{
return buffers_iterator<BufferSequence>::begin(buffers);
}
/// Construct an iterator representing the end of the buffers' data.
template <typename BufferSequence>
inline buffers_iterator<BufferSequence> buffers_end(
const BufferSequence& buffers)
{
return buffers_iterator<BufferSequence>::end(buffers);
}
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_BUFFERS_ITERATOR_HPP

303
extern/boost/boost/asio/cancel_after.hpp vendored Normal file
View File

@ -0,0 +1,303 @@
//
// cancel_after.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_CANCEL_AFTER_HPP
#define BOOST_ASIO_CANCEL_AFTER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/basic_waitable_timer.hpp>
#include <boost/asio/cancellation_type.hpp>
#include <boost/asio/detail/chrono.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/wait_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// A @ref completion_token adapter that cancels an operation after a timeout.
/**
* The cancel_after_t class is used to indicate that an asynchronous operation
* should be cancelled if not complete before the specified duration has
* elapsed.
*/
template <typename CompletionToken, typename Clock,
typename WaitTraits = boost::asio::wait_traits<Clock>>
class cancel_after_t
{
public:
/// Constructor.
template <typename T>
cancel_after_t(T&& completion_token, const typename Clock::duration& timeout,
cancellation_type_t cancel_type = cancellation_type::terminal)
: token_(static_cast<T&&>(completion_token)),
timeout_(timeout),
cancel_type_(cancel_type)
{
}
//private:
CompletionToken token_;
typename Clock::duration timeout_;
cancellation_type_t cancel_type_;
};
/// A @ref completion_token adapter that cancels an operation after a timeout.
/**
* The cancel_after_timer class is used to indicate that an asynchronous
* operation should be cancelled if not complete before the specified duration
* has elapsed.
*/
template <typename CompletionToken, typename Clock,
typename WaitTraits = boost::asio::wait_traits<Clock>,
typename Executor = any_io_executor>
class cancel_after_timer
{
public:
/// Constructor.
template <typename T>
cancel_after_timer(T&& completion_token,
basic_waitable_timer<Clock, WaitTraits, Executor>& timer,
const typename Clock::duration& timeout,
cancellation_type_t cancel_type = cancellation_type::terminal)
: token_(static_cast<T&&>(completion_token)),
timer_(timer),
timeout_(timeout),
cancel_type_(cancel_type)
{
}
//private:
CompletionToken token_;
basic_waitable_timer<Clock, WaitTraits, Executor>& timer_;
typename Clock::duration timeout_;
cancellation_type_t cancel_type_;
};
/// A function object type that adapts a @ref completion_token to cancel an
/// operation after a timeout.
/**
* May also be used directly as a completion token, in which case it adapts the
* asynchronous operation's default completion token (or boost::asio::deferred
* if no default is available).
*/
template <typename Clock, typename WaitTraits = boost::asio::wait_traits<Clock>>
class partial_cancel_after
{
public:
/// Constructor that specifies the timeout duration and cancellation type.
explicit partial_cancel_after(const typename Clock::duration& timeout,
cancellation_type_t cancel_type = cancellation_type::terminal)
: timeout_(timeout),
cancel_type_(cancel_type)
{
}
/// Adapt a @ref completion_token to specify that the completion handler
/// arguments should be combined into a single tuple argument.
template <typename CompletionToken>
BOOST_ASIO_NODISCARD inline
cancel_after_t<decay_t<CompletionToken>, Clock, WaitTraits>
operator()(CompletionToken&& completion_token) const
{
return cancel_after_t<decay_t<CompletionToken>, Clock, WaitTraits>(
static_cast<CompletionToken&&>(completion_token),
timeout_, cancel_type_);
}
//private:
typename Clock::duration timeout_;
cancellation_type_t cancel_type_;
};
/// A function object type that adapts a @ref completion_token to cancel an
/// operation after a timeout.
/**
* May also be used directly as a completion token, in which case it adapts the
* asynchronous operation's default completion token (or boost::asio::deferred
* if no default is available).
*/
template <typename Clock, typename WaitTraits = boost::asio::wait_traits<Clock>,
typename Executor = any_io_executor>
class partial_cancel_after_timer
{
public:
/// Constructor that specifies the timeout duration and cancellation type.
explicit partial_cancel_after_timer(
basic_waitable_timer<Clock, WaitTraits, Executor>& timer,
const typename Clock::duration& timeout,
cancellation_type_t cancel_type = cancellation_type::terminal)
: timer_(timer),
timeout_(timeout),
cancel_type_(cancel_type)
{
}
/// Adapt a @ref completion_token to specify that the completion handler
/// arguments should be combined into a single tuple argument.
template <typename CompletionToken>
BOOST_ASIO_NODISCARD inline
cancel_after_timer<decay_t<CompletionToken>, Clock, WaitTraits, Executor>
operator()(CompletionToken&& completion_token) const
{
return cancel_after_timer<decay_t<CompletionToken>,
Clock, WaitTraits, Executor>(
static_cast<CompletionToken&&>(completion_token),
timeout_, cancel_type_);
}
//private:
basic_waitable_timer<Clock, WaitTraits, Executor>& timer_;
typename Clock::duration timeout_;
cancellation_type_t cancel_type_;
};
/// Create a partial completion token adapter that cancels an operation if not
/// complete before the specified relative timeout has elapsed.
/**
* @par Thread Safety
* When an asynchronous operation is used with cancel_after, a timer async_wait
* operation is performed in parallel to the main operation. If this parallel
* async_wait completes first, a cancellation request is emitted to cancel the
* main operation. Consequently, the application must ensure that the
* asynchronous operation is performed within an implicit or explicit strand.
*/
template <typename Rep, typename Period>
BOOST_ASIO_NODISCARD inline partial_cancel_after<chrono::steady_clock>
cancel_after(const chrono::duration<Rep, Period>& timeout,
cancellation_type_t cancel_type = cancellation_type::terminal)
{
return partial_cancel_after<chrono::steady_clock>(timeout, cancel_type);
}
/// Create a partial completion token adapter that cancels an operation if not
/// complete before the specified relative timeout has elapsed.
/**
* @par Thread Safety
* When an asynchronous operation is used with cancel_after, a timer async_wait
* operation is performed in parallel to the main operation. If this parallel
* async_wait completes first, a cancellation request is emitted to cancel the
* main operation. Consequently, the application must ensure that the
* asynchronous operation is performed within an implicit or explicit strand.
*/
template <typename Clock, typename WaitTraits,
typename Executor, typename Rep, typename Period>
BOOST_ASIO_NODISCARD inline
partial_cancel_after_timer<Clock, WaitTraits, Executor>
cancel_after(basic_waitable_timer<Clock, WaitTraits, Executor>& timer,
const chrono::duration<Rep, Period>& timeout,
cancellation_type_t cancel_type = cancellation_type::terminal)
{
return partial_cancel_after_timer<Clock, WaitTraits, Executor>(
timer, timeout, cancel_type);
}
/// Adapt a @ref completion_token to cancel an operation if not complete before
/// the specified relative timeout has elapsed.
/**
* @par Thread Safety
* When an asynchronous operation is used with cancel_after, a timer async_wait
* operation is performed in parallel to the main operation. If this parallel
* async_wait completes first, a cancellation request is emitted to cancel the
* main operation. Consequently, the application must ensure that the
* asynchronous operation is performed within an implicit or explicit strand.
*/
template <typename Rep, typename Period, typename CompletionToken>
BOOST_ASIO_NODISCARD inline
cancel_after_t<decay_t<CompletionToken>, chrono::steady_clock>
cancel_after(const chrono::duration<Rep, Period>& timeout,
CompletionToken&& completion_token)
{
return cancel_after_t<decay_t<CompletionToken>, chrono::steady_clock>(
static_cast<CompletionToken&&>(completion_token),
timeout, cancellation_type::terminal);
}
/// Adapt a @ref completion_token to cancel an operation if not complete before
/// the specified relative timeout has elapsed.
/**
* @par Thread Safety
* When an asynchronous operation is used with cancel_after, a timer async_wait
* operation is performed in parallel to the main operation. If this parallel
* async_wait completes first, a cancellation request is emitted to cancel the
* main operation. Consequently, the application must ensure that the
* asynchronous operation is performed within an implicit or explicit strand.
*/
template <typename Rep, typename Period, typename CompletionToken>
BOOST_ASIO_NODISCARD inline
cancel_after_t<decay_t<CompletionToken>, chrono::steady_clock>
cancel_after(const chrono::duration<Rep, Period>& timeout,
cancellation_type_t cancel_type, CompletionToken&& completion_token)
{
return cancel_after_t<decay_t<CompletionToken>, chrono::steady_clock>(
static_cast<CompletionToken&&>(completion_token), timeout, cancel_type);
}
/// Adapt a @ref completion_token to cancel an operation if not complete before
/// the specified relative timeout has elapsed.
/**
* @par Thread Safety
* When an asynchronous operation is used with cancel_after, a timer async_wait
* operation is performed in parallel to the main operation. If this parallel
* async_wait completes first, a cancellation request is emitted to cancel the
* main operation. Consequently, the application must ensure that the
* asynchronous operation is performed within an implicit or explicit strand.
*/
template <typename Clock, typename WaitTraits, typename Executor,
typename Rep, typename Period, typename CompletionToken>
BOOST_ASIO_NODISCARD inline
cancel_after_timer<decay_t<CompletionToken>, Clock, WaitTraits, Executor>
cancel_after(basic_waitable_timer<Clock, WaitTraits, Executor>& timer,
const chrono::duration<Rep, Period>& timeout,
CompletionToken&& completion_token)
{
return cancel_after_timer<decay_t<CompletionToken>,
Clock, WaitTraits, Executor>(
static_cast<CompletionToken&&>(completion_token),
timer, timeout, cancellation_type::terminal);
}
/// Adapt a @ref completion_token to cancel an operation if not complete before
/// the specified relative timeout has elapsed.
/**
* @par Thread Safety
* When an asynchronous operation is used with cancel_after, a timer async_wait
* operation is performed in parallel to the main operation. If this parallel
* async_wait completes first, a cancellation request is emitted to cancel the
* main operation. Consequently, the application must ensure that the
* asynchronous operation is performed within an implicit or explicit strand.
*/
template <typename Clock, typename WaitTraits, typename Executor,
typename Rep, typename Period, typename CompletionToken>
BOOST_ASIO_NODISCARD inline
cancel_after_timer<decay_t<CompletionToken>, chrono::steady_clock>
cancel_after(basic_waitable_timer<Clock, WaitTraits, Executor>& timer,
const chrono::duration<Rep, Period>& timeout,
cancellation_type_t cancel_type, CompletionToken&& completion_token)
{
return cancel_after_timer<decay_t<CompletionToken>,
Clock, WaitTraits, Executor>(
static_cast<CompletionToken&&>(completion_token),
timer, timeout, cancel_type);
}
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/impl/cancel_after.hpp>
#endif // BOOST_ASIO_CANCEL_AFTER_HPP

296
extern/boost/boost/asio/cancel_at.hpp vendored Normal file
View File

@ -0,0 +1,296 @@
//
// cancel_at.hpp
// ~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_CANCEL_AT_HPP
#define BOOST_ASIO_CANCEL_AT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/basic_waitable_timer.hpp>
#include <boost/asio/cancellation_type.hpp>
#include <boost/asio/detail/chrono.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/wait_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// A @ref completion_token adapter that cancels an operation at a given time.
/**
* The cancel_at_t class is used to indicate that an asynchronous operation
* should be cancelled if not complete at the specified absolute time.
*/
template <typename CompletionToken, typename Clock,
typename WaitTraits = boost::asio::wait_traits<Clock>>
class cancel_at_t
{
public:
/// Constructor.
template <typename T>
cancel_at_t(T&& completion_token, const typename Clock::time_point& expiry,
cancellation_type_t cancel_type = cancellation_type::terminal)
: token_(static_cast<T&&>(completion_token)),
expiry_(expiry),
cancel_type_(cancel_type)
{
}
//private:
CompletionToken token_;
typename Clock::time_point expiry_;
cancellation_type_t cancel_type_;
};
/// A @ref completion_token adapter that cancels an operation at a given time.
/**
* The cancel_at_timer class is used to indicate that an asynchronous operation
* should be cancelled if not complete at the specified absolute time.
*/
template <typename CompletionToken, typename Clock,
typename WaitTraits = boost::asio::wait_traits<Clock>,
typename Executor = any_io_executor>
class cancel_at_timer
{
public:
/// Constructor.
template <typename T>
cancel_at_timer(T&& completion_token,
basic_waitable_timer<Clock, WaitTraits, Executor>& timer,
const typename Clock::time_point& expiry,
cancellation_type_t cancel_type = cancellation_type::terminal)
: token_(static_cast<T&&>(completion_token)),
timer_(timer),
expiry_(expiry),
cancel_type_(cancel_type)
{
}
//private:
CompletionToken token_;
basic_waitable_timer<Clock, WaitTraits, Executor>& timer_;
typename Clock::time_point expiry_;
cancellation_type_t cancel_type_;
};
/// A function object type that adapts a @ref completion_token to cancel an
/// operation at a given time.
/**
* May also be used directly as a completion token, in which case it adapts the
* asynchronous operation's default completion token (or boost::asio::deferred
* if no default is available).
*/
template <typename Clock, typename WaitTraits = boost::asio::wait_traits<Clock>>
class partial_cancel_at
{
public:
/// Constructor that specifies the expiry and cancellation type.
explicit partial_cancel_at(const typename Clock::time_point& expiry,
cancellation_type_t cancel_type = cancellation_type::terminal)
: expiry_(expiry),
cancel_type_(cancel_type)
{
}
/// Adapt a @ref completion_token to specify that the completion handler
/// arguments should be combined into a single tuple argument.
template <typename CompletionToken>
BOOST_ASIO_NODISCARD inline
constexpr cancel_at_t<decay_t<CompletionToken>, Clock, WaitTraits>
operator()(CompletionToken&& completion_token) const
{
return cancel_at_t<decay_t<CompletionToken>, Clock, WaitTraits>(
static_cast<CompletionToken&&>(completion_token),
expiry_, cancel_type_);
}
//private:
typename Clock::time_point expiry_;
cancellation_type_t cancel_type_;
};
/// A function object type that adapts a @ref completion_token to cancel an
/// operation at a given time.
/**
* May also be used directly as a completion token, in which case it adapts the
* asynchronous operation's default completion token (or boost::asio::deferred
* if no default is available).
*/
template <typename Clock, typename WaitTraits = boost::asio::wait_traits<Clock>,
typename Executor = any_io_executor>
class partial_cancel_at_timer
{
public:
/// Constructor that specifies the expiry and cancellation type.
explicit partial_cancel_at_timer(
basic_waitable_timer<Clock, WaitTraits, Executor>& timer,
const typename Clock::time_point& expiry,
cancellation_type_t cancel_type = cancellation_type::terminal)
: timer_(timer),
expiry_(expiry),
cancel_type_(cancel_type)
{
}
/// Adapt a @ref completion_token to specify that the completion handler
/// arguments should be combined into a single tuple argument.
template <typename CompletionToken>
BOOST_ASIO_NODISCARD inline
cancel_at_timer<decay_t<CompletionToken>, Clock, WaitTraits, Executor>
operator()(CompletionToken&& completion_token) const
{
return cancel_at_timer<decay_t<CompletionToken>,
Clock, WaitTraits, Executor>(
static_cast<CompletionToken&&>(completion_token),
timer_, expiry_, cancel_type_);
}
//private:
basic_waitable_timer<Clock, WaitTraits, Executor>& timer_;
typename Clock::time_point expiry_;
cancellation_type_t cancel_type_;
};
/// Create a partial completion token adapter that cancels an operation if not
/// complete by the specified absolute time.
/**
* @par Thread Safety
* When an asynchronous operation is used with cancel_at, a timer async_wait
* operation is performed in parallel to the main operation. If this parallel
* async_wait completes first, a cancellation request is emitted to cancel the
* main operation. Consequently, the application must ensure that the
* asynchronous operation is performed within an implicit or explicit strand.
*/
template <typename Clock, typename Duration>
BOOST_ASIO_NODISCARD inline partial_cancel_at<Clock>
cancel_at(const chrono::time_point<Clock, Duration>& expiry,
cancellation_type_t cancel_type = cancellation_type::terminal)
{
return partial_cancel_at<Clock>(expiry, cancel_type);
}
/// Create a partial completion token adapter that cancels an operation if not
/// complete by the specified absolute time.
/**
* @par Thread Safety
* When an asynchronous operation is used with cancel_at, a timer async_wait
* operation is performed in parallel to the main operation. If this parallel
* async_wait completes first, a cancellation request is emitted to cancel the
* main operation. Consequently, the application must ensure that the
* asynchronous operation is performed within an implicit or explicit strand.
*/
template <typename Clock, typename WaitTraits,
typename Executor, typename Duration>
BOOST_ASIO_NODISCARD inline partial_cancel_at_timer<Clock, WaitTraits, Executor>
cancel_at(basic_waitable_timer<Clock, WaitTraits, Executor>& timer,
const chrono::time_point<Clock, Duration>& expiry,
cancellation_type_t cancel_type = cancellation_type::terminal)
{
return partial_cancel_at_timer<Clock, WaitTraits, Executor>(
timer, expiry, cancel_type);
}
/// Adapt a @ref completion_token to cancel an operation if not complete by the
/// specified absolute time.
/**
* @par Thread Safety
* When an asynchronous operation is used with cancel_at, a timer async_wait
* operation is performed in parallel to the main operation. If this parallel
* async_wait completes first, a cancellation request is emitted to cancel the
* main operation. Consequently, the application must ensure that the
* asynchronous operation is performed within an implicit or explicit strand.
*/
template <typename CompletionToken, typename Clock, typename Duration>
BOOST_ASIO_NODISCARD inline cancel_at_t<decay_t<CompletionToken>, Clock>
cancel_at(const chrono::time_point<Clock, Duration>& expiry,
CompletionToken&& completion_token)
{
return cancel_at_t<decay_t<CompletionToken>, Clock>(
static_cast<CompletionToken&&>(completion_token),
expiry, cancellation_type::terminal);
}
/// Adapt a @ref completion_token to cancel an operation if not complete by the
/// specified absolute time.
/**
* @par Thread Safety
* When an asynchronous operation is used with cancel_at, a timer async_wait
* operation is performed in parallel to the main operation. If this parallel
* async_wait completes first, a cancellation request is emitted to cancel the
* main operation. Consequently, the application must ensure that the
* asynchronous operation is performed within an implicit or explicit strand.
*/
template <typename CompletionToken, typename Clock, typename Duration>
BOOST_ASIO_NODISCARD inline cancel_at_t<decay_t<CompletionToken>, Clock>
cancel_at(const chrono::time_point<Clock, Duration>& expiry,
cancellation_type_t cancel_type, CompletionToken&& completion_token)
{
return cancel_at_t<decay_t<CompletionToken>, Clock>(
static_cast<CompletionToken&&>(completion_token), expiry, cancel_type);
}
/// Adapt a @ref completion_token to cancel an operation if not complete by the
/// specified absolute time.
/**
* @par Thread Safety
* When an asynchronous operation is used with cancel_at, a timer async_wait
* operation is performed in parallel to the main operation. If this parallel
* async_wait completes first, a cancellation request is emitted to cancel the
* main operation. Consequently, the application must ensure that the
* asynchronous operation is performed within an implicit or explicit strand.
*/
template <typename CompletionToken, typename Clock,
typename WaitTraits, typename Executor, typename Duration>
BOOST_ASIO_NODISCARD inline
cancel_at_timer<decay_t<CompletionToken>, Clock, WaitTraits, Executor>
cancel_at(basic_waitable_timer<Clock, WaitTraits, Executor>& timer,
const chrono::time_point<Clock, Duration>& expiry,
CompletionToken&& completion_token)
{
return cancel_at_timer<decay_t<CompletionToken>, Clock, WaitTraits, Executor>(
static_cast<CompletionToken&&>(completion_token),
timer, expiry, cancellation_type::terminal);
}
/// Adapt a @ref completion_token to cancel an operation if not complete by the
/// specified absolute time.
/**
* @par Thread Safety
* When an asynchronous operation is used with cancel_at, a timer async_wait
* operation is performed in parallel to the main operation. If this parallel
* async_wait completes first, a cancellation request is emitted to cancel the
* main operation. Consequently, the application must ensure that the
* asynchronous operation is performed within an implicit or explicit strand.
*/
template <typename CompletionToken, typename Clock,
typename WaitTraits, typename Executor, typename Duration>
BOOST_ASIO_NODISCARD inline
cancel_at_timer<decay_t<CompletionToken>, Clock, WaitTraits, Executor>
cancel_at(basic_waitable_timer<Clock, WaitTraits, Executor>& timer,
const chrono::time_point<Clock, Duration>& expiry,
cancellation_type_t cancel_type, CompletionToken&& completion_token)
{
return cancel_at_timer<decay_t<CompletionToken>, Clock, WaitTraits, Executor>(
static_cast<CompletionToken&&>(completion_token),
timer, expiry, cancel_type);
}
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/impl/cancel_at.hpp>
#endif // BOOST_ASIO_CANCEL_AT_HPP

View File

@ -0,0 +1,247 @@
//
// cancellation_signal.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_CANCELLATION_SIGNAL_HPP
#define BOOST_ASIO_CANCELLATION_SIGNAL_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <cassert>
#include <new>
#include <utility>
#include <boost/asio/cancellation_type.hpp>
#include <boost/asio/detail/cstddef.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
class cancellation_handler_base
{
public:
virtual void call(cancellation_type_t) = 0;
virtual std::pair<void*, std::size_t> destroy() noexcept = 0;
protected:
~cancellation_handler_base() {}
};
template <typename Handler>
class cancellation_handler
: public cancellation_handler_base
{
public:
template <typename... Args>
cancellation_handler(std::size_t size, Args&&... args)
: handler_(static_cast<Args&&>(args)...),
size_(size)
{
}
void call(cancellation_type_t type)
{
handler_(type);
}
std::pair<void*, std::size_t> destroy() noexcept
{
std::pair<void*, std::size_t> mem(this, size_);
this->cancellation_handler::~cancellation_handler();
return mem;
}
Handler& handler() noexcept
{
return handler_;
}
private:
~cancellation_handler()
{
}
Handler handler_;
std::size_t size_;
};
} // namespace detail
class cancellation_slot;
/// A cancellation signal with a single slot.
class cancellation_signal
{
public:
constexpr cancellation_signal()
: handler_(0)
{
}
BOOST_ASIO_DECL ~cancellation_signal();
/// Emits the signal and causes invocation of the slot's handler, if any.
void emit(cancellation_type_t type)
{
if (handler_)
handler_->call(type);
}
/// Returns the single slot associated with the signal.
/**
* The signal object must remain valid for as long the slot may be used.
* Destruction of the signal invalidates the slot.
*/
cancellation_slot slot() noexcept;
private:
cancellation_signal(const cancellation_signal&) = delete;
cancellation_signal& operator=(const cancellation_signal&) = delete;
detail::cancellation_handler_base* handler_;
};
/// A slot associated with a cancellation signal.
class cancellation_slot
{
public:
/// Creates a slot that is not connected to any cancellation signal.
constexpr cancellation_slot()
: handler_(0)
{
}
/// Installs a handler into the slot, constructing the new object directly.
/**
* Destroys any existing handler in the slot, then installs the new handler,
* constructing it with the supplied @c args.
*
* The handler is a function object to be called when the signal is emitted.
* The signature of the handler must be
* @code void handler(boost::asio::cancellation_type_t); @endcode
*
* @param args Arguments to be passed to the @c CancellationHandler object's
* constructor.
*
* @returns A reference to the newly installed handler.
*
* @note Handlers installed into the slot via @c emplace are not required to
* be copy constructible or move constructible.
*/
template <typename CancellationHandler, typename... Args>
CancellationHandler& emplace(Args&&... args)
{
typedef detail::cancellation_handler<CancellationHandler>
cancellation_handler_type;
auto_delete_helper del = { prepare_memory(
sizeof(cancellation_handler_type),
alignof(CancellationHandler)) };
cancellation_handler_type* handler_obj =
new (del.mem.first) cancellation_handler_type(
del.mem.second, static_cast<Args&&>(args)...);
del.mem.first = 0;
*handler_ = handler_obj;
return handler_obj->handler();
}
/// Installs a handler into the slot.
/**
* Destroys any existing handler in the slot, then installs the new handler,
* constructing it as a decay-copy of the supplied handler.
*
* The handler is a function object to be called when the signal is emitted.
* The signature of the handler must be
* @code void handler(boost::asio::cancellation_type_t); @endcode
*
* @param handler The handler to be installed.
*
* @returns A reference to the newly installed handler.
*/
template <typename CancellationHandler>
decay_t<CancellationHandler>& assign(CancellationHandler&& handler)
{
return this->emplace<decay_t<CancellationHandler>>(
static_cast<CancellationHandler&&>(handler));
}
/// Clears the slot.
/**
* Destroys any existing handler in the slot.
*/
BOOST_ASIO_DECL void clear();
/// Returns whether the slot is connected to a signal.
constexpr bool is_connected() const noexcept
{
return handler_ != 0;
}
/// Returns whether the slot is connected and has an installed handler.
constexpr bool has_handler() const noexcept
{
return handler_ != 0 && *handler_ != 0;
}
/// Compare two slots for equality.
friend constexpr bool operator==(const cancellation_slot& lhs,
const cancellation_slot& rhs) noexcept
{
return lhs.handler_ == rhs.handler_;
}
/// Compare two slots for inequality.
friend constexpr bool operator!=(const cancellation_slot& lhs,
const cancellation_slot& rhs) noexcept
{
return lhs.handler_ != rhs.handler_;
}
private:
friend class cancellation_signal;
constexpr cancellation_slot(int,
detail::cancellation_handler_base** handler)
: handler_(handler)
{
}
BOOST_ASIO_DECL std::pair<void*, std::size_t> prepare_memory(
std::size_t size, std::size_t align);
struct auto_delete_helper
{
std::pair<void*, std::size_t> mem;
BOOST_ASIO_DECL ~auto_delete_helper();
};
detail::cancellation_handler_base** handler_;
};
inline cancellation_slot cancellation_signal::slot() noexcept
{
return cancellation_slot(0, &handler_);
}
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#if defined(BOOST_ASIO_HEADER_ONLY)
# include <boost/asio/impl/cancellation_signal.ipp>
#endif // defined(BOOST_ASIO_HEADER_ONLY)
#endif // BOOST_ASIO_CANCELLATION_SIGNAL_HPP

View File

@ -0,0 +1,237 @@
//
// cancellation_state.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_CANCELLATION_STATE_HPP
#define BOOST_ASIO_CANCELLATION_STATE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <cassert>
#include <new>
#include <utility>
#include <boost/asio/cancellation_signal.hpp>
#include <boost/asio/detail/cstddef.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// A simple cancellation signal propagation filter.
template <cancellation_type_t Mask>
struct cancellation_filter
{
/// Returns <tt>type & Mask</tt>.
cancellation_type_t operator()(
cancellation_type_t type) const noexcept
{
return type & Mask;
}
};
/// A cancellation filter that disables cancellation.
typedef cancellation_filter<cancellation_type::none>
disable_cancellation;
/// A cancellation filter that enables terminal cancellation only.
typedef cancellation_filter<cancellation_type::terminal>
enable_terminal_cancellation;
#if defined(GENERATING_DOCUMENTATION)
/// A cancellation filter that enables terminal and partial cancellation.
typedef cancellation_filter<
cancellation_type::terminal | cancellation_type::partial>
enable_partial_cancellation;
/// A cancellation filter that enables terminal, partial and total cancellation.
typedef cancellation_filter<cancellation_type::terminal
| cancellation_type::partial | cancellation_type::total>
enable_total_cancellation;
#else // defined(GENERATING_DOCUMENTATION)
typedef cancellation_filter<
static_cast<cancellation_type_t>(
static_cast<unsigned int>(cancellation_type::terminal)
| static_cast<unsigned int>(cancellation_type::partial))>
enable_partial_cancellation;
typedef cancellation_filter<
static_cast<cancellation_type_t>(
static_cast<unsigned int>(cancellation_type::terminal)
| static_cast<unsigned int>(cancellation_type::partial)
| static_cast<unsigned int>(cancellation_type::total))>
enable_total_cancellation;
#endif // defined(GENERATING_DOCUMENTATION)
/// A cancellation state is used for chaining signals and slots in compositions.
class cancellation_state
{
public:
/// Construct a disconnected cancellation state.
constexpr cancellation_state() noexcept
: impl_(0)
{
}
/// Construct and attach to a parent slot to create a new child slot.
/**
* Initialises the cancellation state so that it allows terminal cancellation
* only. Equivalent to <tt>cancellation_state(slot,
* enable_terminal_cancellation())</tt>.
*
* @param slot The parent cancellation slot to which the state will be
* attached.
*/
template <typename CancellationSlot>
constexpr explicit cancellation_state(CancellationSlot slot)
: impl_(slot.is_connected() ? &slot.template emplace<impl<>>() : 0)
{
}
/// Construct and attach to a parent slot to create a new child slot.
/**
* @param slot The parent cancellation slot to which the state will be
* attached.
*
* @param filter A function object that is used to transform incoming
* cancellation signals as they are received from the parent slot. This
* function object must have the signature:
* @code boost::asio::cancellation_type_t filter(
* boost::asio::cancellation_type_t); @endcode
*
* The library provides the following pre-defined cancellation filters:
*
* @li boost::asio::disable_cancellation
* @li boost::asio::enable_terminal_cancellation
* @li boost::asio::enable_partial_cancellation
* @li boost::asio::enable_total_cancellation
*/
template <typename CancellationSlot, typename Filter>
constexpr cancellation_state(CancellationSlot slot, Filter filter)
: impl_(slot.is_connected()
? &slot.template emplace<impl<Filter, Filter>>(filter, filter)
: 0)
{
}
/// Construct and attach to a parent slot to create a new child slot.
/**
* @param slot The parent cancellation slot to which the state will be
* attached.
*
* @param in_filter A function object that is used to transform incoming
* cancellation signals as they are received from the parent slot. This
* function object must have the signature:
* @code boost::asio::cancellation_type_t in_filter(
* boost::asio::cancellation_type_t); @endcode
*
* @param out_filter A function object that is used to transform outcoming
* cancellation signals as they are relayed to the child slot. This function
* object must have the signature:
* @code boost::asio::cancellation_type_t out_filter(
* boost::asio::cancellation_type_t); @endcode
*
* The library provides the following pre-defined cancellation filters:
*
* @li boost::asio::disable_cancellation
* @li boost::asio::enable_terminal_cancellation
* @li boost::asio::enable_partial_cancellation
* @li boost::asio::enable_total_cancellation
*/
template <typename CancellationSlot, typename InFilter, typename OutFilter>
constexpr cancellation_state(CancellationSlot slot,
InFilter in_filter, OutFilter out_filter)
: impl_(slot.is_connected()
? &slot.template emplace<impl<InFilter, OutFilter>>(
static_cast<InFilter&&>(in_filter),
static_cast<OutFilter&&>(out_filter))
: 0)
{
}
/// Returns the single child slot associated with the state.
/**
* This sub-slot is used with the operations that are being composed.
*/
constexpr cancellation_slot slot() const noexcept
{
return impl_ ? impl_->signal_.slot() : cancellation_slot();
}
/// Returns the cancellation types that have been triggered.
cancellation_type_t cancelled() const noexcept
{
return impl_ ? impl_->cancelled_ : cancellation_type_t();
}
/// Clears the specified cancellation types, if they have been triggered.
void clear(cancellation_type_t mask = cancellation_type::all)
noexcept
{
if (impl_)
impl_->cancelled_ &= ~mask;
}
private:
struct impl_base
{
impl_base()
: cancelled_()
{
}
cancellation_signal signal_;
cancellation_type_t cancelled_;
};
template <
typename InFilter = enable_terminal_cancellation,
typename OutFilter = InFilter>
struct impl : impl_base
{
impl()
: in_filter_(),
out_filter_()
{
}
impl(InFilter in_filter, OutFilter out_filter)
: in_filter_(static_cast<InFilter&&>(in_filter)),
out_filter_(static_cast<OutFilter&&>(out_filter))
{
}
void operator()(cancellation_type_t in)
{
this->cancelled_ = in_filter_(in);
cancellation_type_t out = out_filter_(this->cancelled_);
if (out != cancellation_type::none)
this->signal_.emit(out);
}
InFilter in_filter_;
OutFilter out_filter_;
};
impl_base* impl_;
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_CANCELLATION_STATE_HPP

View File

@ -0,0 +1,159 @@
//
// cancellation_type.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_CANCELLATION_TYPE_HPP
#define BOOST_ASIO_CANCELLATION_TYPE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
# if defined(GENERATING_DOCUMENTATION)
/// Enumeration representing the different types of cancellation that may
/// be requested from or implemented by an asynchronous operation.
enum cancellation_type
{
/// Bitmask representing no types of cancellation.
none = 0,
/// Requests cancellation where, following a successful cancellation, the only
/// safe operations on the I/O object are closure or destruction.
terminal = 1,
/// Requests cancellation where a successful cancellation may result in
/// partial side effects or no side effects. Following cancellation, the I/O
/// object is in a well-known state, and may be used for further operations.
partial = 2,
/// Requests cancellation where a successful cancellation results in no
/// apparent side effects. Following cancellation, the I/O object is in the
/// same observable state as it was prior to the operation.
total = 4,
/// Bitmask representing all types of cancellation.
all = 0xFFFFFFFF
};
/// Portability typedef.
typedef cancellation_type cancellation_type_t;
#else // defined(GENERATING_DOCUMENTATION)
enum class cancellation_type : unsigned int
{
none = 0,
terminal = 1,
partial = 2,
total = 4,
all = 0xFFFFFFFF
};
typedef cancellation_type cancellation_type_t;
#endif // defined(GENERATING_DOCUMENTATION)
/// Negation operator.
/**
* @relates cancellation_type
*/
inline constexpr bool operator!(cancellation_type_t x)
{
return static_cast<unsigned int>(x) == 0;
}
/// Bitwise and operator.
/**
* @relates cancellation_type
*/
inline constexpr cancellation_type_t operator&(
cancellation_type_t x, cancellation_type_t y)
{
return static_cast<cancellation_type_t>(
static_cast<unsigned int>(x) & static_cast<unsigned int>(y));
}
/// Bitwise or operator.
/**
* @relates cancellation_type
*/
inline constexpr cancellation_type_t operator|(
cancellation_type_t x, cancellation_type_t y)
{
return static_cast<cancellation_type_t>(
static_cast<unsigned int>(x) | static_cast<unsigned int>(y));
}
/// Bitwise xor operator.
/**
* @relates cancellation_type
*/
inline constexpr cancellation_type_t operator^(
cancellation_type_t x, cancellation_type_t y)
{
return static_cast<cancellation_type_t>(
static_cast<unsigned int>(x) ^ static_cast<unsigned int>(y));
}
/// Bitwise negation operator.
/**
* @relates cancellation_type
*/
inline constexpr cancellation_type_t operator~(cancellation_type_t x)
{
return static_cast<cancellation_type_t>(~static_cast<unsigned int>(x));
}
/// Bitwise and-assignment operator.
/**
* @relates cancellation_type
*/
inline cancellation_type_t& operator&=(
cancellation_type_t& x, cancellation_type_t y)
{
x = x & y;
return x;
}
/// Bitwise or-assignment operator.
/**
* @relates cancellation_type
*/
inline cancellation_type_t& operator|=(
cancellation_type_t& x, cancellation_type_t y)
{
x = x | y;
return x;
}
/// Bitwise xor-assignment operator.
/**
* @relates cancellation_type
*/
inline cancellation_type_t& operator^=(
cancellation_type_t& x, cancellation_type_t y)
{
x = x ^ y;
return x;
}
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_CANCELLATION_TYPE_HPP

1323
extern/boost/boost/asio/co_composed.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

525
extern/boost/boost/asio/co_spawn.hpp vendored Normal file
View File

@ -0,0 +1,525 @@
//
// co_spawn.hpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_CO_SPAWN_HPP
#define BOOST_ASIO_CO_SPAWN_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
#include <boost/asio/awaitable.hpp>
#include <boost/asio/execution/executor.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/is_executor.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename T>
struct awaitable_signature;
template <typename T, typename Executor>
struct awaitable_signature<awaitable<T, Executor>>
{
typedef void type(std::exception_ptr, T);
};
template <typename Executor>
struct awaitable_signature<awaitable<void, Executor>>
{
typedef void type(std::exception_ptr);
};
} // namespace detail
/// Spawn a new coroutined-based thread of execution.
/**
* @param ex The executor that will be used to schedule the new thread of
* execution.
*
* @param a The boost::asio::awaitable object that is the result of calling the
* coroutine's entry point function.
*
* @param token The @ref completion_token that will handle the notification that
* the thread of execution has completed. The function signature of the
* completion handler must be:
* @code void handler(std::exception_ptr, T); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr, T) @endcode
*
* @par Example
* @code
* boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
* {
* std::size_t bytes_transferred = 0;
*
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* boost::asio::buffer(data), boost::asio::use_awaitable);
*
* co_await boost::asio::async_write(socket,
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
*
* bytes_transferred += n;
* }
* }
* catch (const std::exception&)
* {
* }
*
* co_return bytes_transferred;
* }
*
* // ...
*
* boost::asio::co_spawn(my_executor,
* echo(std::move(my_tcp_socket)),
* [](std::exception_ptr e, std::size_t n)
* {
* std::cout << "transferred " << n << "\n";
* });
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call boost::asio::this_coro::reset_cancellation_state.
*/
template <typename Executor, typename T, typename AwaitableExecutor,
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(std::exception_ptr, T)) CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken, void(std::exception_ptr, T))
co_spawn(const Executor& ex, awaitable<T, AwaitableExecutor> a,
CompletionToken&& token
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
constraint_t<
(is_executor<Executor>::value || execution::is_executor<Executor>::value)
&& is_convertible<Executor, AwaitableExecutor>::value
> = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ex The executor that will be used to schedule the new thread of
* execution.
*
* @param a The boost::asio::awaitable object that is the result of calling the
* coroutine's entry point function.
*
* @param token The @ref completion_token that will handle the notification that
* the thread of execution has completed. The function signature of the
* completion handler must be:
* @code void handler(std::exception_ptr); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr) @endcode
*
* @par Example
* @code
* boost::asio::awaitable<void> echo(tcp::socket socket)
* {
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* boost::asio::buffer(data), boost::asio::use_awaitable);
*
* co_await boost::asio::async_write(socket,
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
* }
* }
* catch (const std::exception& e)
* {
* std::cerr << "Exception: " << e.what() << "\n";
* }
* }
*
* // ...
*
* boost::asio::co_spawn(my_executor,
* echo(std::move(my_tcp_socket)),
* boost::asio::detached);
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call boost::asio::this_coro::reset_cancellation_state.
*/
template <typename Executor, typename AwaitableExecutor,
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(std::exception_ptr)) CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken, void(std::exception_ptr))
co_spawn(const Executor& ex, awaitable<void, AwaitableExecutor> a,
CompletionToken&& token
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
constraint_t<
(is_executor<Executor>::value || execution::is_executor<Executor>::value)
&& is_convertible<Executor, AwaitableExecutor>::value
> = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ctx An execution context that will provide the executor to be used to
* schedule the new thread of execution.
*
* @param a The boost::asio::awaitable object that is the result of calling the
* coroutine's entry point function.
*
* @param token The @ref completion_token that will handle the notification that
* the thread of execution has completed. The function signature of the
* completion handler must be:
* @code void handler(std::exception_ptr); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr, T) @endcode
*
* @par Example
* @code
* boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
* {
* std::size_t bytes_transferred = 0;
*
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* boost::asio::buffer(data), boost::asio::use_awaitable);
*
* co_await boost::asio::async_write(socket,
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
*
* bytes_transferred += n;
* }
* }
* catch (const std::exception&)
* {
* }
*
* co_return bytes_transferred;
* }
*
* // ...
*
* boost::asio::co_spawn(my_io_context,
* echo(std::move(my_tcp_socket)),
* [](std::exception_ptr e, std::size_t n)
* {
* std::cout << "transferred " << n << "\n";
* });
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call boost::asio::this_coro::reset_cancellation_state.
*/
template <typename ExecutionContext, typename T, typename AwaitableExecutor,
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(std::exception_ptr, T)) CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
typename ExecutionContext::executor_type)>
inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken, void(std::exception_ptr, T))
co_spawn(ExecutionContext& ctx, awaitable<T, AwaitableExecutor> a,
CompletionToken&& token
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
typename ExecutionContext::executor_type),
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
&& is_convertible<typename ExecutionContext::executor_type,
AwaitableExecutor>::value
> = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ctx An execution context that will provide the executor to be used to
* schedule the new thread of execution.
*
* @param a The boost::asio::awaitable object that is the result of calling the
* coroutine's entry point function.
*
* @param token The @ref completion_token that will handle the notification that
* the thread of execution has completed. The function signature of the
* completion handler must be:
* @code void handler(std::exception_ptr); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr) @endcode
*
* @par Example
* @code
* boost::asio::awaitable<void> echo(tcp::socket socket)
* {
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* boost::asio::buffer(data), boost::asio::use_awaitable);
*
* co_await boost::asio::async_write(socket,
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
* }
* }
* catch (const std::exception& e)
* {
* std::cerr << "Exception: " << e.what() << "\n";
* }
* }
*
* // ...
*
* boost::asio::co_spawn(my_io_context,
* echo(std::move(my_tcp_socket)),
* boost::asio::detached);
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call boost::asio::this_coro::reset_cancellation_state.
*/
template <typename ExecutionContext, typename AwaitableExecutor,
BOOST_ASIO_COMPLETION_TOKEN_FOR(
void(std::exception_ptr)) CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
typename ExecutionContext::executor_type)>
inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken, void(std::exception_ptr))
co_spawn(ExecutionContext& ctx, awaitable<void, AwaitableExecutor> a,
CompletionToken&& token
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
typename ExecutionContext::executor_type),
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
&& is_convertible<typename ExecutionContext::executor_type,
AwaitableExecutor>::value
> = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ex The executor that will be used to schedule the new thread of
* execution.
*
* @param f A nullary function object with a return type of the form
* @c boost::asio::awaitable<R,E> that will be used as the coroutine's entry
* point.
*
* @param token The @ref completion_token that will handle the notification
* that the thread of execution has completed. If @c R is @c void, the function
* signature of the completion handler must be:
*
* @code void handler(std::exception_ptr); @endcode
* Otherwise, the function signature of the completion handler must be:
* @code void handler(std::exception_ptr, R); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr, R) @endcode
* where @c R is the first template argument to the @c awaitable returned by the
* supplied function object @c F:
* @code boost::asio::awaitable<R, AwaitableExecutor> F() @endcode
*
* @par Example
* @code
* boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
* {
* std::size_t bytes_transferred = 0;
*
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* boost::asio::buffer(data), boost::asio::use_awaitable);
*
* co_await boost::asio::async_write(socket,
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
*
* bytes_transferred += n;
* }
* }
* catch (const std::exception&)
* {
* }
*
* co_return bytes_transferred;
* }
*
* // ...
*
* boost::asio::co_spawn(my_executor,
* [socket = std::move(my_tcp_socket)]() mutable
* -> boost::asio::awaitable<void>
* {
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* boost::asio::buffer(data), boost::asio::use_awaitable);
*
* co_await boost::asio::async_write(socket,
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
* }
* }
* catch (const std::exception& e)
* {
* std::cerr << "Exception: " << e.what() << "\n";
* }
* }, boost::asio::detached);
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call boost::asio::this_coro::reset_cancellation_state.
*/
template <typename Executor, typename F,
BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
result_of_t<F()>>::type) CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
typename detail::awaitable_signature<result_of_t<F()>>::type)
co_spawn(const Executor& ex, F&& f,
CompletionToken&& token
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
constraint_t<
is_executor<Executor>::value || execution::is_executor<Executor>::value
> = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ctx An execution context that will provide the executor to be used to
* schedule the new thread of execution.
*
* @param f A nullary function object with a return type of the form
* @c boost::asio::awaitable<R,E> that will be used as the coroutine's entry
* point.
*
* @param token The @ref completion_token that will handle the notification
* that the thread of execution has completed. If @c R is @c void, the function
* signature of the completion handler must be:
*
* @code void handler(std::exception_ptr); @endcode
* Otherwise, the function signature of the completion handler must be:
* @code void handler(std::exception_ptr, R); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr, R) @endcode
* where @c R is the first template argument to the @c awaitable returned by the
* supplied function object @c F:
* @code boost::asio::awaitable<R, AwaitableExecutor> F() @endcode
*
* @par Example
* @code
* boost::asio::awaitable<std::size_t> echo(tcp::socket socket)
* {
* std::size_t bytes_transferred = 0;
*
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* boost::asio::buffer(data), boost::asio::use_awaitable);
*
* co_await boost::asio::async_write(socket,
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
*
* bytes_transferred += n;
* }
* }
* catch (const std::exception&)
* {
* }
*
* co_return bytes_transferred;
* }
*
* // ...
*
* boost::asio::co_spawn(my_io_context,
* [socket = std::move(my_tcp_socket)]() mutable
* -> boost::asio::awaitable<void>
* {
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* boost::asio::buffer(data), boost::asio::use_awaitable);
*
* co_await boost::asio::async_write(socket,
* boost::asio::buffer(data, n), boost::asio::use_awaitable);
* }
* }
* catch (const std::exception& e)
* {
* std::cerr << "Exception: " << e.what() << "\n";
* }
* }, boost::asio::detached);
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call boost::asio::this_coro::reset_cancellation_state.
*/
template <typename ExecutionContext, typename F,
BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
result_of_t<F()>>::type) CompletionToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
typename ExecutionContext::executor_type)>
BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
typename detail::awaitable_signature<result_of_t<F()>>::type)
co_spawn(ExecutionContext& ctx, F&& f,
CompletionToken&& token
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(
typename ExecutionContext::executor_type),
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0);
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/impl/co_spawn.hpp>
#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
#endif // BOOST_ASIO_CO_SPAWN_HPP

View File

@ -0,0 +1,269 @@
//
// completion_condition.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_COMPLETION_CONDITION_HPP
#define BOOST_ASIO_COMPLETION_CONDITION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <cstddef>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/system/error_code.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
// The default maximum number of bytes to transfer in a single operation.
enum default_max_transfer_size_t { default_max_transfer_size = 65536 };
// Adapt result of old-style completion conditions (which had a bool result
// where true indicated that the operation was complete).
inline std::size_t adapt_completion_condition_result(bool result)
{
return result ? 0 : default_max_transfer_size;
}
// Adapt result of current completion conditions (which have a size_t result
// where 0 means the operation is complete, and otherwise the result is the
// maximum number of bytes to transfer on the next underlying operation).
inline std::size_t adapt_completion_condition_result(std::size_t result)
{
return result;
}
class transfer_all_t
{
public:
typedef std::size_t result_type;
template <typename Error>
std::size_t operator()(const Error& err, std::size_t)
{
return !!err ? 0 : default_max_transfer_size;
}
};
class transfer_at_least_t
{
public:
typedef std::size_t result_type;
explicit transfer_at_least_t(std::size_t minimum)
: minimum_(minimum)
{
}
template <typename Error>
std::size_t operator()(const Error& err, std::size_t bytes_transferred)
{
return (!!err || bytes_transferred >= minimum_)
? 0 : default_max_transfer_size;
}
private:
std::size_t minimum_;
};
class transfer_exactly_t
{
public:
typedef std::size_t result_type;
explicit transfer_exactly_t(std::size_t size)
: size_(size)
{
}
template <typename Error>
std::size_t operator()(const Error& err, std::size_t bytes_transferred)
{
return (!!err || bytes_transferred >= size_) ? 0 :
(size_ - bytes_transferred < default_max_transfer_size
? size_ - bytes_transferred : std::size_t(default_max_transfer_size));
}
private:
std::size_t size_;
};
template <typename T, typename = void>
struct is_completion_condition_helper : false_type
{
};
template <typename T>
struct is_completion_condition_helper<T,
enable_if_t<
is_same<
result_of_t<T(boost::system::error_code, std::size_t)>,
bool
>::value
>
> : true_type
{
};
template <typename T>
struct is_completion_condition_helper<T,
enable_if_t<
is_same<
result_of_t<T(boost::system::error_code, std::size_t)>,
std::size_t
>::value
>
> : true_type
{
};
} // namespace detail
#if defined(GENERATING_DOCUMENTATION)
/// Trait for determining whether a function object is a completion condition.
template <typename T>
struct is_completion_condition
{
static constexpr bool value = automatically_determined;
};
#else // defined(GENERATING_DOCUMENTATION)
template <typename T>
struct is_completion_condition : detail::is_completion_condition_helper<T>
{
};
#endif // defined(GENERATING_DOCUMENTATION)
/**
* @defgroup completion_condition Completion Condition Function Objects
*
* Function objects used for determining when a read or write operation should
* complete.
*/
/*@{*/
/// Return a completion condition function object that indicates that a read or
/// write operation should continue until all of the data has been transferred,
/// or until an error occurs.
/**
* This function is used to create an object, of unspecified type, that meets
* CompletionCondition requirements.
*
* @par Example
* Reading until a buffer is full:
* @code
* boost::array<char, 128> buf;
* boost::system::error_code ec;
* std::size_t n = boost::asio::read(
* sock, boost::asio::buffer(buf),
* boost::asio::transfer_all(), ec);
* if (ec)
* {
* // An error occurred.
* }
* else
* {
* // n == 128
* }
* @endcode
*/
#if defined(GENERATING_DOCUMENTATION)
unspecified transfer_all();
#else
inline detail::transfer_all_t transfer_all()
{
return detail::transfer_all_t();
}
#endif
/// Return a completion condition function object that indicates that a read or
/// write operation should continue until a minimum number of bytes has been
/// transferred, or until an error occurs.
/**
* This function is used to create an object, of unspecified type, that meets
* CompletionCondition requirements.
*
* @par Example
* Reading until a buffer is full or contains at least 64 bytes:
* @code
* boost::array<char, 128> buf;
* boost::system::error_code ec;
* std::size_t n = boost::asio::read(
* sock, boost::asio::buffer(buf),
* boost::asio::transfer_at_least(64), ec);
* if (ec)
* {
* // An error occurred.
* }
* else
* {
* // n >= 64 && n <= 128
* }
* @endcode
*/
#if defined(GENERATING_DOCUMENTATION)
unspecified transfer_at_least(std::size_t minimum);
#else
inline detail::transfer_at_least_t transfer_at_least(std::size_t minimum)
{
return detail::transfer_at_least_t(minimum);
}
#endif
/// Return a completion condition function object that indicates that a read or
/// write operation should continue until an exact number of bytes has been
/// transferred, or until an error occurs.
/**
* This function is used to create an object, of unspecified type, that meets
* CompletionCondition requirements.
*
* @par Example
* Reading until a buffer is full or contains exactly 64 bytes:
* @code
* boost::array<char, 128> buf;
* boost::system::error_code ec;
* std::size_t n = boost::asio::read(
* sock, boost::asio::buffer(buf),
* boost::asio::transfer_exactly(64), ec);
* if (ec)
* {
* // An error occurred.
* }
* else
* {
* // n == 64
* }
* @endcode
*/
#if defined(GENERATING_DOCUMENTATION)
unspecified transfer_exactly(std::size_t size);
#else
inline detail::transfer_exactly_t transfer_exactly(std::size_t size)
{
return detail::transfer_exactly_t(size);
}
#endif
/*@}*/
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_COMPLETION_CONDITION_HPP

130
extern/boost/boost/asio/compose.hpp vendored Normal file
View File

@ -0,0 +1,130 @@
//
// compose.hpp
// ~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_COMPOSE_HPP
#define BOOST_ASIO_COMPOSE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/composed.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Launch an asynchronous operation with a stateful implementation.
/**
* The async_compose function simplifies the implementation of composed
* asynchronous operations automatically wrapping a stateful function object
* with a conforming intermediate completion handler.
*
* @param implementation A function object that contains the implementation of
* the composed asynchronous operation. The first argument to the function
* object is a non-const reference to the enclosing intermediate completion
* handler. The remaining arguments are any arguments that originate from the
* completion handlers of any asynchronous operations performed by the
* implementation.
*
* @param token The completion token.
*
* @param io_objects_or_executors Zero or more I/O objects or I/O executors for
* which outstanding work must be maintained.
*
* @par Per-Operation Cancellation
* By default, terminal per-operation cancellation is enabled for
* composed operations that are implemented using @c async_compose. To
* disable cancellation for the composed operation, or to alter its
* supported cancellation types, call the @c self object's @c
* reset_cancellation_state function.
*
* @par Example:
*
* @code struct async_echo_implementation
* {
* tcp::socket& socket_;
* boost::asio::mutable_buffer buffer_;
* enum { starting, reading, writing } state_;
*
* template <typename Self>
* void operator()(Self& self,
* boost::system::error_code error = {},
* std::size_t n = 0)
* {
* switch (state_)
* {
* case starting:
* state_ = reading;
* socket_.async_read_some(
* buffer_, std::move(self));
* break;
* case reading:
* if (error)
* {
* self.complete(error, 0);
* }
* else
* {
* state_ = writing;
* boost::asio::async_write(socket_, buffer_,
* boost::asio::transfer_exactly(n),
* std::move(self));
* }
* break;
* case writing:
* self.complete(error, n);
* break;
* }
* }
* };
*
* template <typename CompletionToken>
* auto async_echo(tcp::socket& socket,
* boost::asio::mutable_buffer buffer,
* CompletionToken&& token)
* -> decltype(
* boost::asio::async_compose<CompletionToken,
* void(boost::system::error_code, std::size_t)>(
* std::declval<async_echo_implementation>(),
* token, socket))
* {
* return boost::asio::async_compose<CompletionToken,
* void(boost::system::error_code, std::size_t)>(
* async_echo_implementation{socket, buffer,
* async_echo_implementation::starting},
* token, socket);
* } @endcode
*/
template <typename CompletionToken, typename Signature,
typename Implementation, typename... IoObjectsOrExecutors>
inline auto async_compose(Implementation&& implementation,
type_identity_t<CompletionToken>& token,
IoObjectsOrExecutors&&... io_objects_or_executors)
-> decltype(
async_initiate<CompletionToken, Signature>(
composed<Signature>(static_cast<Implementation&&>(implementation),
static_cast<IoObjectsOrExecutors&&>(io_objects_or_executors)...),
token))
{
return async_initiate<CompletionToken, Signature>(
composed<Signature>(static_cast<Implementation&&>(implementation),
static_cast<IoObjectsOrExecutors&&>(io_objects_or_executors)...),
token);
}
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_COMPOSE_HPP

415
extern/boost/boost/asio/composed.hpp vendored Normal file
View File

@ -0,0 +1,415 @@
//
// composed.hpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_COMPOSED_HPP
#define BOOST_ASIO_COMPOSED_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/associated_executor.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/base_from_cancellation_state.hpp>
#include <boost/asio/detail/composed_work.hpp>
#include <boost/asio/detail/handler_cont_helpers.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename Impl, typename Work,
typename Handler, typename... Signatures>
class composed_op;
template <typename Impl, typename Work, typename Handler>
class composed_op<Impl, Work, Handler>
: public base_from_cancellation_state<Handler>
{
public:
template <typename I, typename W, typename H>
composed_op(I&& impl,
W&& work,
H&& handler)
: base_from_cancellation_state<Handler>(
handler, enable_terminal_cancellation()),
impl_(static_cast<I&&>(impl)),
work_(static_cast<W&&>(work)),
handler_(static_cast<H&&>(handler)),
invocations_(0)
{
}
composed_op(composed_op&& other)
: base_from_cancellation_state<Handler>(
static_cast<base_from_cancellation_state<Handler>&&>(other)),
impl_(static_cast<Impl&&>(other.impl_)),
work_(static_cast<Work&&>(other.work_)),
handler_(static_cast<Handler&&>(other.handler_)),
invocations_(other.invocations_)
{
}
typedef typename composed_work_guard<
typename Work::head_type>::executor_type io_executor_type;
io_executor_type get_io_executor() const noexcept
{
return work_.head_.get_executor();
}
typedef associated_executor_t<Handler, io_executor_type> executor_type;
executor_type get_executor() const noexcept
{
return (get_associated_executor)(handler_, work_.head_.get_executor());
}
typedef associated_allocator_t<Handler, std::allocator<void>> allocator_type;
allocator_type get_allocator() const noexcept
{
return (get_associated_allocator)(handler_, std::allocator<void>());
}
template <typename... T>
void operator()(T&&... t)
{
if (invocations_ < ~0u)
++invocations_;
this->get_cancellation_state().slot().clear();
impl_(*this, static_cast<T&&>(t)...);
}
template <typename... Args>
auto complete(Args&&... args)
-> decltype(declval<Handler>()(static_cast<Args&&>(args)...))
{
return static_cast<Handler&&>(this->handler_)(static_cast<Args&&>(args)...);
}
void reset_cancellation_state()
{
base_from_cancellation_state<Handler>::reset_cancellation_state(handler_);
}
template <typename Filter>
void reset_cancellation_state(Filter&& filter)
{
base_from_cancellation_state<Handler>::reset_cancellation_state(handler_,
static_cast<Filter&&>(filter));
}
template <typename InFilter, typename OutFilter>
void reset_cancellation_state(InFilter&& in_filter,
OutFilter&& out_filter)
{
base_from_cancellation_state<Handler>::reset_cancellation_state(handler_,
static_cast<InFilter&&>(in_filter),
static_cast<OutFilter&&>(out_filter));
}
cancellation_type_t cancelled() const noexcept
{
return base_from_cancellation_state<Handler>::cancelled();
}
//private:
Impl impl_;
Work work_;
Handler handler_;
unsigned invocations_;
};
template <typename Impl, typename Work, typename Handler,
typename R, typename... Args>
class composed_op<Impl, Work, Handler, R(Args...)>
: public composed_op<Impl, Work, Handler>
{
public:
using composed_op<Impl, Work, Handler>::composed_op;
template <typename... T>
void operator()(T&&... t)
{
if (this->invocations_ < ~0u)
++this->invocations_;
this->get_cancellation_state().slot().clear();
this->impl_(*this, static_cast<T&&>(t)...);
}
void complete(Args... args)
{
this->work_.reset();
static_cast<Handler&&>(this->handler_)(static_cast<Args&&>(args)...);
}
};
template <typename Impl, typename Work, typename Handler,
typename R, typename... Args, typename... Signatures>
class composed_op<Impl, Work, Handler, R(Args...), Signatures...>
: public composed_op<Impl, Work, Handler, Signatures...>
{
public:
using composed_op<Impl, Work, Handler, Signatures...>::composed_op;
template <typename... T>
void operator()(T&&... t)
{
if (this->invocations_ < ~0u)
++this->invocations_;
this->get_cancellation_state().slot().clear();
this->impl_(*this, static_cast<T&&>(t)...);
}
using composed_op<Impl, Work, Handler, Signatures...>::complete;
void complete(Args... args)
{
this->work_.reset();
static_cast<Handler&&>(this->handler_)(static_cast<Args&&>(args)...);
}
};
template <typename Impl, typename Work, typename Handler, typename Signature>
inline bool asio_handler_is_continuation(
composed_op<Impl, Work, Handler, Signature>* this_handler)
{
return this_handler->invocations_ > 1 ? true
: boost_asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Implementation, typename Executors, typename... Signatures>
class initiate_composed
{
public:
typedef typename composed_io_executors<Executors>::head_type executor_type;
template <typename I>
initiate_composed(I&& impl, composed_io_executors<Executors>&& executors)
: implementation_(std::forward<I>(impl)),
executors_(std::move(executors))
{
}
executor_type get_executor() const noexcept
{
return executors_.head_;
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args) const &
{
composed_op<decay_t<Implementation>, composed_work<Executors>,
decay_t<Handler>, Signatures...>(implementation_,
composed_work<Executors>(executors_),
static_cast<Handler&&>(handler))(static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args) &&
{
composed_op<decay_t<Implementation>, composed_work<Executors>,
decay_t<Handler>, Signatures...>(
static_cast<Implementation&&>(implementation_),
composed_work<Executors>(executors_),
static_cast<Handler&&>(handler))(static_cast<Args&&>(args)...);
}
private:
Implementation implementation_;
composed_io_executors<Executors> executors_;
};
template <typename Implementation, typename... Signatures>
class initiate_composed<Implementation, void(), Signatures...>
{
public:
template <typename I>
initiate_composed(I&& impl, composed_io_executors<void()>&&)
: implementation_(std::forward<I>(impl))
{
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args) const &
{
composed_op<decay_t<Implementation>, composed_work<void()>,
decay_t<Handler>, Signatures...>(implementation_,
composed_work<void()>(composed_io_executors<void()>()),
static_cast<Handler&&>(handler))(static_cast<Args&&>(args)...);
}
template <typename Handler, typename... Args>
void operator()(Handler&& handler, Args&&... args) &&
{
composed_op<decay_t<Implementation>, composed_work<void()>,
decay_t<Handler>, Signatures...>(
static_cast<Implementation&&>(implementation_),
composed_work<void()>(composed_io_executors<void()>()),
static_cast<Handler&&>(handler))(static_cast<Args&&>(args)...);
}
private:
Implementation implementation_;
};
template <typename... Signatures, typename Implementation, typename Executors>
inline initiate_composed<Implementation, Executors, Signatures...>
make_initiate_composed(Implementation&& implementation,
composed_io_executors<Executors>&& executors)
{
return initiate_composed<decay_t<Implementation>, Executors, Signatures...>(
static_cast<Implementation&&>(implementation),
static_cast<composed_io_executors<Executors>&&>(executors));
}
} // namespace detail
#if !defined(GENERATING_DOCUMENTATION)
template <template <typename, typename> class Associator,
typename Impl, typename Work, typename Handler,
typename Signature, typename DefaultCandidate>
struct associator<Associator,
detail::composed_op<Impl, Work, Handler, Signature>,
DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const detail::composed_op<Impl, Work, Handler, Signature>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static auto get(const detail::composed_op<Impl, Work, Handler, Signature>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Creates an initiation function object that may be used to launch an
/// asynchronous operation with a stateful implementation.
/**
* The @c composed function simplifies the implementation of composed
* asynchronous operations automatically by wrapping a stateful function object
* for use as an initiation function object.
*
* @param implementation A function object that contains the implementation of
* the composed asynchronous operation. The first argument to the function
* object is a non-const reference to the enclosing intermediate completion
* handler. The remaining arguments are any arguments that originate from the
* completion handlers of any asynchronous operations performed by the
* implementation.
*
* @param io_objects_or_executors Zero or more I/O objects or I/O executors for
* which outstanding work must be maintained.
*
* @par Per-Operation Cancellation
* By default, terminal per-operation cancellation is enabled for composed
* operations that are implemented using @c composed. To disable cancellation
* for the composed operation, or to alter its supported cancellation types,
* call the @c self object's @c reset_cancellation_state function.
*
* @par Example:
*
* @code struct async_echo_implementation
* {
* tcp::socket& socket_;
* boost::asio::mutable_buffer buffer_;
* enum { starting, reading, writing } state_;
*
* template <typename Self>
* void operator()(Self& self,
* boost::system::error_code error,
* std::size_t n)
* {
* switch (state_)
* {
* case starting:
* state_ = reading;
* socket_.async_read_some(
* buffer_, std::move(self));
* break;
* case reading:
* if (error)
* {
* self.complete(error, 0);
* }
* else
* {
* state_ = writing;
* boost::asio::async_write(socket_, buffer_,
* boost::asio::transfer_exactly(n),
* std::move(self));
* }
* break;
* case writing:
* self.complete(error, n);
* break;
* }
* }
* };
*
* template <typename CompletionToken>
* auto async_echo(tcp::socket& socket,
* boost::asio::mutable_buffer buffer,
* CompletionToken&& token)
* -> decltype(
* boost::asio::async_initiate<CompletionToken,
* void(boost::system::error_code, std::size_t)>(
* boost::asio::composed(
* async_echo_implementation{socket, buffer,
* async_echo_implementation::starting}, socket),
* token))
* {
* return boost::asio::async_initiate<CompletionToken,
* void(boost::system::error_code, std::size_t)>(
* boost::asio::composed(
* async_echo_implementation{socket, buffer,
* async_echo_implementation::starting}, socket),
* token, boost::system::error_code{}, 0);
* } @endcode
*/
template <BOOST_ASIO_COMPLETION_SIGNATURE... Signatures,
typename Implementation, typename... IoObjectsOrExecutors>
inline auto composed(Implementation&& implementation,
IoObjectsOrExecutors&&... io_objects_or_executors)
-> decltype(
detail::make_initiate_composed<Signatures...>(
static_cast<Implementation&&>(implementation),
detail::make_composed_io_executors(
detail::get_composed_io_executor(
static_cast<IoObjectsOrExecutors&&>(
io_objects_or_executors))...)))
{
return detail::make_initiate_composed<Signatures...>(
static_cast<Implementation&&>(implementation),
detail::make_composed_io_executors(
detail::get_composed_io_executor(
static_cast<IoObjectsOrExecutors&&>(
io_objects_or_executors))...));
}
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_COMPOSE_HPP

1348
extern/boost/boost/asio/connect.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,85 @@
//
// connect_pipe.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_CONNECT_PIPE_HPP
#define BOOST_ASIO_CONNECT_PIPE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_PIPE) \
|| defined(GENERATING_DOCUMENTATION)
#include <boost/asio/basic_readable_pipe.hpp>
#include <boost/asio/basic_writable_pipe.hpp>
#include <boost/asio/error.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
#if defined(BOOST_ASIO_HAS_IOCP)
typedef HANDLE native_pipe_handle;
#else // defined(BOOST_ASIO_HAS_IOCP)
typedef int native_pipe_handle;
#endif // defined(BOOST_ASIO_HAS_IOCP)
BOOST_ASIO_DECL void create_pipe(native_pipe_handle p[2],
boost::system::error_code& ec);
BOOST_ASIO_DECL void close_pipe(native_pipe_handle p);
} // namespace detail
/// Connect two pipe ends using an anonymous pipe.
/**
* @param read_end The read end of the pipe.
*
* @param write_end The write end of the pipe.
*
* @throws boost::system::system_error Thrown on failure.
*/
template <typename Executor1, typename Executor2>
void connect_pipe(basic_readable_pipe<Executor1>& read_end,
basic_writable_pipe<Executor2>& write_end);
/// Connect two pipe ends using an anonymous pipe.
/**
* @param read_end The read end of the pipe.
*
* @param write_end The write end of the pipe.
*
* @throws boost::system::system_error Thrown on failure.
*
* @param ec Set to indicate what error occurred, if any.
*/
template <typename Executor1, typename Executor2>
BOOST_ASIO_SYNC_OP_VOID connect_pipe(basic_readable_pipe<Executor1>& read_end,
basic_writable_pipe<Executor2>& write_end, boost::system::error_code& ec);
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/impl/connect_pipe.hpp>
#if defined(BOOST_ASIO_HEADER_ONLY)
# include <boost/asio/impl/connect_pipe.ipp>
#endif // defined(BOOST_ASIO_HEADER_ONLY)
#endif // defined(BOOST_ASIO_HAS_PIPE)
// || defined(GENERATING_DOCUMENTATION)
#endif // BOOST_ASIO_CONNECT_PIPE_HPP

77
extern/boost/boost/asio/consign.hpp vendored Normal file
View File

@ -0,0 +1,77 @@
//
// consign.hpp
// ~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_CONSIGN_HPP
#define BOOST_ASIO_CONSIGN_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <tuple>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Completion token type used to specify that the completion handler should
/// carry additional values along with it.
/**
* This completion token adapter is typically used to keep at least one copy of
* an object, such as a smart pointer, alive until the completion handler is
* called.
*/
template <typename CompletionToken, typename... Values>
class consign_t
{
public:
/// Constructor.
template <typename T, typename... V>
constexpr explicit consign_t(T&& completion_token, V&&... values)
: token_(static_cast<T&&>(completion_token)),
values_(static_cast<V&&>(values)...)
{
}
#if defined(GENERATING_DOCUMENTATION)
private:
#endif // defined(GENERATING_DOCUMENTATION)
CompletionToken token_;
std::tuple<Values...> values_;
};
/// Completion token adapter used to specify that the completion handler should
/// carry additional values along with it.
/**
* This completion token adapter is typically used to keep at least one copy of
* an object, such as a smart pointer, alive until the completion handler is
* called.
*/
template <typename CompletionToken, typename... Values>
BOOST_ASIO_NODISCARD inline constexpr
consign_t<decay_t<CompletionToken>, decay_t<Values>...>
consign(CompletionToken&& completion_token, Values&&... values)
{
return consign_t<decay_t<CompletionToken>, decay_t<Values>...>(
static_cast<CompletionToken&&>(completion_token),
static_cast<Values&&>(values)...);
}
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/impl/consign.hpp>
#endif // BOOST_ASIO_CONSIGN_HPP

330
extern/boost/boost/asio/coroutine.hpp vendored Normal file
View File

@ -0,0 +1,330 @@
//
// coroutine.hpp
// ~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_COROUTINE_HPP
#define BOOST_ASIO_COROUTINE_HPP
namespace boost {
namespace asio {
namespace detail {
class coroutine_ref;
} // namespace detail
/// Provides support for implementing stackless coroutines.
/**
* The @c coroutine class may be used to implement stackless coroutines. The
* class itself is used to store the current state of the coroutine.
*
* Coroutines are copy-constructible and assignable, and the space overhead is
* a single int. They can be used as a base class:
*
* @code class session : coroutine
* {
* ...
* }; @endcode
*
* or as a data member:
*
* @code class session
* {
* ...
* coroutine coro_;
* }; @endcode
*
* or even bound in as a function argument using lambdas or @c bind(). The
* important thing is that as the application maintains a copy of the object
* for as long as the coroutine must be kept alive.
*
* @par Pseudo-keywords
*
* A coroutine is used in conjunction with certain "pseudo-keywords", which
* are implemented as macros. These macros are defined by a header file:
*
* @code #include <boost/asio/yield.hpp>@endcode
*
* and may conversely be undefined as follows:
*
* @code #include <boost/asio/unyield.hpp>@endcode
*
* <b>reenter</b>
*
* The @c reenter macro is used to define the body of a coroutine. It takes a
* single argument: a pointer or reference to a coroutine object. For example,
* if the base class is a coroutine object you may write:
*
* @code reenter (this)
* {
* ... coroutine body ...
* } @endcode
*
* and if a data member or other variable you can write:
*
* @code reenter (coro_)
* {
* ... coroutine body ...
* } @endcode
*
* When @c reenter is executed at runtime, control jumps to the location of the
* last @c yield or @c fork.
*
* The coroutine body may also be a single statement, such as:
*
* @code reenter (this) for (;;)
* {
* ...
* } @endcode
*
* @b Limitation: The @c reenter macro is implemented using a switch. This
* means that you must take care when using local variables within the
* coroutine body. The local variable is not allowed in a position where
* reentering the coroutine could bypass the variable definition.
*
* <b>yield <em>statement</em></b>
*
* This form of the @c yield keyword is often used with asynchronous operations:
*
* @code yield socket_->async_read_some(buffer(*buffer_), *this); @endcode
*
* This divides into four logical steps:
*
* @li @c yield saves the current state of the coroutine.
* @li The statement initiates the asynchronous operation.
* @li The resume point is defined immediately following the statement.
* @li Control is transferred to the end of the coroutine body.
*
* When the asynchronous operation completes, the function object is invoked
* and @c reenter causes control to transfer to the resume point. It is
* important to remember to carry the coroutine state forward with the
* asynchronous operation. In the above snippet, the current class is a
* function object object with a coroutine object as base class or data member.
*
* The statement may also be a compound statement, and this permits us to
* define local variables with limited scope:
*
* @code yield
* {
* mutable_buffers_1 b = buffer(*buffer_);
* socket_->async_read_some(b, *this);
* } @endcode
*
* <b>yield return <em>expression</em> ;</b>
*
* This form of @c yield is often used in generators or coroutine-based parsers.
* For example, the function object:
*
* @code struct interleave : coroutine
* {
* istream& is1;
* istream& is2;
* char operator()(char c)
* {
* reenter (this) for (;;)
* {
* yield return is1.get();
* yield return is2.get();
* }
* }
* }; @endcode
*
* defines a trivial coroutine that interleaves the characters from two input
* streams.
*
* This type of @c yield divides into three logical steps:
*
* @li @c yield saves the current state of the coroutine.
* @li The resume point is defined immediately following the semicolon.
* @li The value of the expression is returned from the function.
*
* <b>yield ;</b>
*
* This form of @c yield is equivalent to the following steps:
*
* @li @c yield saves the current state of the coroutine.
* @li The resume point is defined immediately following the semicolon.
* @li Control is transferred to the end of the coroutine body.
*
* This form might be applied when coroutines are used for cooperative
* threading and scheduling is explicitly managed. For example:
*
* @code struct task : coroutine
* {
* ...
* void operator()()
* {
* reenter (this)
* {
* while (... not finished ...)
* {
* ... do something ...
* yield;
* ... do some more ...
* yield;
* }
* }
* }
* ...
* };
* ...
* task t1, t2;
* for (;;)
* {
* t1();
* t2();
* } @endcode
*
* <b>yield break ;</b>
*
* The final form of @c yield is used to explicitly terminate the coroutine.
* This form is comprised of two steps:
*
* @li @c yield sets the coroutine state to indicate termination.
* @li Control is transferred to the end of the coroutine body.
*
* Once terminated, calls to is_complete() return true and the coroutine cannot
* be reentered.
*
* Note that a coroutine may also be implicitly terminated if the coroutine
* body is exited without a yield, e.g. by return, throw or by running to the
* end of the body.
*
* <b>fork <em>statement</em></b>
*
* The @c fork pseudo-keyword is used when "forking" a coroutine, i.e. splitting
* it into two (or more) copies. One use of @c fork is in a server, where a new
* coroutine is created to handle each client connection:
*
* @code reenter (this)
* {
* do
* {
* socket_.reset(new tcp::socket(my_context_));
* yield acceptor->async_accept(*socket_, *this);
* fork server(*this)();
* } while (is_parent());
* ... client-specific handling follows ...
* } @endcode
*
* The logical steps involved in a @c fork are:
*
* @li @c fork saves the current state of the coroutine.
* @li The statement creates a copy of the coroutine and either executes it
* immediately or schedules it for later execution.
* @li The resume point is defined immediately following the semicolon.
* @li For the "parent", control immediately continues from the next line.
*
* The functions is_parent() and is_child() can be used to differentiate
* between parent and child. You would use these functions to alter subsequent
* control flow.
*
* Note that @c fork doesn't do the actual forking by itself. It is the
* application's responsibility to create a clone of the coroutine and call it.
* The clone can be called immediately, as above, or scheduled for delayed
* execution using something like boost::asio::post().
*
* @par Alternate macro names
*
* If preferred, an application can use macro names that follow a more typical
* naming convention, rather than the pseudo-keywords. These are:
*
* @li @c BOOST_ASIO_CORO_REENTER instead of @c reenter
* @li @c BOOST_ASIO_CORO_YIELD instead of @c yield
* @li @c BOOST_ASIO_CORO_FORK instead of @c fork
*/
class coroutine
{
public:
/// Constructs a coroutine in its initial state.
coroutine() : value_(0) {}
/// Returns true if the coroutine is the child of a fork.
bool is_child() const { return value_ < 0; }
/// Returns true if the coroutine is the parent of a fork.
bool is_parent() const { return !is_child(); }
/// Returns true if the coroutine has reached its terminal state.
bool is_complete() const { return value_ == -1; }
private:
friend class detail::coroutine_ref;
int value_;
};
namespace detail {
class coroutine_ref
{
public:
coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {}
coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {}
coroutine_ref(const coroutine_ref&) = default;
~coroutine_ref() { if (!modified_) value_ = -1; }
operator int() const { return value_; }
int& operator=(int v) { modified_ = true; return value_ = v; }
private:
void operator=(const coroutine_ref&);
int& value_;
bool modified_;
};
} // namespace detail
} // namespace asio
} // namespace boost
#define BOOST_ASIO_CORO_REENTER(c) \
switch (::boost::asio::detail::coroutine_ref _coro_value = c) \
case -1: if (_coro_value) \
{ \
goto terminate_coroutine; \
terminate_coroutine: \
_coro_value = -1; \
goto bail_out_of_coroutine; \
bail_out_of_coroutine: \
break; \
} \
else /* fall-through */ case 0:
#define BOOST_ASIO_CORO_YIELD_IMPL(n) \
for (_coro_value = (n);;) \
if (_coro_value == 0) \
{ \
case (n): ; \
break; \
} \
else \
switch (_coro_value ? 0 : 1) \
for (;;) \
/* fall-through */ case -1: if (_coro_value) \
goto terminate_coroutine; \
else for (;;) \
/* fall-through */ case 1: if (_coro_value) \
goto bail_out_of_coroutine; \
else /* fall-through */ case 0:
#define BOOST_ASIO_CORO_FORK_IMPL(n) \
for (_coro_value = -(n);; _coro_value = (n)) \
if (_coro_value == (n)) \
{ \
case -(n): ; \
break; \
} \
else
#if defined(_MSC_VER)
# define BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD_IMPL(__COUNTER__ + 1)
# define BOOST_ASIO_CORO_FORK BOOST_ASIO_CORO_FORK_IMPL(__COUNTER__ + 1)
#else // defined(_MSC_VER)
# define BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD_IMPL(__LINE__)
# define BOOST_ASIO_CORO_FORK BOOST_ASIO_CORO_FORK_IMPL(__LINE__)
#endif // defined(_MSC_VER)
#endif // BOOST_ASIO_COROUTINE_HPP

View File

@ -0,0 +1,40 @@
//
// deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_DEADLINE_TIMER_HPP
#define BOOST_ASIO_DEADLINE_TIMER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \
|| defined(GENERATING_DOCUMENTATION)
#include <boost/asio/detail/socket_types.hpp> // Must come before posix_time.
#include <boost/asio/basic_deadline_timer.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
namespace boost {
namespace asio {
/// Typedef for the typical usage of timer. Uses a UTC clock.
typedef basic_deadline_timer<boost::posix_time::ptime> deadline_timer;
} // namespace asio
} // namespace boost
#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME)
// || defined(GENERATING_DOCUMENTATION)
#endif // BOOST_ASIO_DEADLINE_TIMER_HPP

View File

@ -0,0 +1,91 @@
//
// default_completion_token.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_HPP
#define BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
class deferred_t;
namespace detail {
template <typename T, typename = void>
struct default_completion_token_impl
{
typedef deferred_t type;
};
template <typename T>
struct default_completion_token_impl<T,
void_t<typename T::default_completion_token_type>
>
{
typedef typename T::default_completion_token_type type;
};
} // namespace detail
#if defined(GENERATING_DOCUMENTATION)
/// Traits type used to determine the default completion token type associated
/// with a type (such as an executor).
/**
* A program may specialise this traits type if the @c T template parameter in
* the specialisation is a user-defined type.
*
* Specialisations of this trait may provide a nested typedef @c type, which is
* a default-constructible completion token type.
*
* If not otherwise specialised, the default completion token type is
* boost::asio::deferred_t.
*/
template <typename T>
struct default_completion_token
{
/// If @c T has a nested type @c default_completion_token_type,
/// <tt>T::default_completion_token_type</tt>. Otherwise the typedef @c type
/// is boost::asio::deferred_t.
typedef see_below type;
};
#else
template <typename T>
struct default_completion_token
: detail::default_completion_token_impl<T>
{
};
#endif
template <typename T>
using default_completion_token_t = typename default_completion_token<T>::type;
#define BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(e) \
= typename ::boost::asio::default_completion_token<e>::type
#define BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(e) \
= typename ::boost::asio::default_completion_token<e>::type()
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/deferred.hpp>
#endif // BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_HPP

220
extern/boost/boost/asio/defer.hpp vendored Normal file
View File

@ -0,0 +1,220 @@
//
// defer.hpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_DEFER_HPP
#define BOOST_ASIO_DEFER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/initiate_defer.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/execution_context.hpp>
#include <boost/asio/execution/blocking.hpp>
#include <boost/asio/execution/executor.hpp>
#include <boost/asio/is_executor.hpp>
#include <boost/asio/require.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Submits a completion token or function object for execution.
/**
* This function submits an object for execution using the object's associated
* executor. The function object is queued for execution, and is never called
* from the current thread prior to returning from <tt>defer()</tt>.
*
* The use of @c defer(), rather than @ref post(), indicates the caller's
* preference that the executor defer the queueing of the function object. This
* may allow the executor to optimise queueing for cases when the function
* object represents a continuation of the current call context.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler. The function signature of the completion handler must be:
* @code void handler(); @endcode
*
* @returns This function returns <tt>async_initiate<NullaryToken,
* void()>(Init{}, token)</tt>, where @c Init is a function object type defined
* as:
*
* @code class Init
* {
* public:
* template <typename CompletionHandler>
* void operator()(CompletionHandler&& completion_handler) const;
* }; @endcode
*
* The function call operator of @c Init:
*
* @li Obtains the handler's associated executor object @c ex of type @c Ex by
* performing @code auto ex = get_associated_executor(handler); @endcode
*
* @li Obtains the handler's associated allocator object @c alloc by performing
* @code auto alloc = get_associated_allocator(handler); @endcode
*
* @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs
* @code prefer(
* require(ex, execution::blocking.never),
* execution::relationship.continuation,
* execution::allocator(alloc)
* ).execute(std::forward<CompletionHandler>(completion_handler)); @endcode
*
* @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs
* @code ex.defer(
* std::forward<CompletionHandler>(completion_handler),
* alloc); @endcode
*
* @par Completion Signature
* @code void() @endcode
*/
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken>
auto defer(NullaryToken&& token)
-> decltype(
async_initiate<NullaryToken, void()>(
declval<detail::initiate_defer>(), token))
{
return async_initiate<NullaryToken, void()>(
detail::initiate_defer(), token);
}
/// Submits a completion token or function object for execution.
/**
* This function submits an object for execution using the specified executor.
* The function object is queued for execution, and is never called from the
* current thread prior to returning from <tt>defer()</tt>.
*
* The use of @c defer(), rather than @ref post(), indicates the caller's
* preference that the executor defer the queueing of the function object. This
* may allow the executor to optimise queueing for cases when the function
* object represents a continuation of the current call context.
*
* @param ex The target executor.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler. The function signature of the completion handler must be:
* @code void handler(); @endcode
*
* @returns This function returns <tt>async_initiate<NullaryToken,
* void()>(Init{ex}, token)</tt>, where @c Init is a function object type
* defined as:
*
* @code class Init
* {
* public:
* using executor_type = Executor;
* explicit Init(const Executor& ex) : ex_(ex) {}
* executor_type get_executor() const noexcept { return ex_; }
* template <typename CompletionHandler>
* void operator()(CompletionHandler&& completion_handler) const;
* private:
* Executor ex_; // exposition only
* }; @endcode
*
* The function call operator of @c Init:
*
* @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by
* performing @code auto ex1 = get_associated_executor(handler, ex); @endcode
*
* @li Obtains the handler's associated allocator object @c alloc by performing
* @code auto alloc = get_associated_allocator(handler); @endcode
*
* @li If <tt>execution::is_executor<Ex1>::value</tt> is true, constructs a
* function object @c f with a member @c executor_ that is initialised with
* <tt>prefer(ex1, execution::outstanding_work.tracked)</tt>, a member @c
* handler_ that is a decay-copy of @c completion_handler, and a function call
* operator that performs:
* @code auto a = get_associated_allocator(handler_);
* prefer(executor_, execution::allocator(a)).execute(std::move(handler_));
* @endcode
*
* @li If <tt>execution::is_executor<Ex1>::value</tt> is false, constructs a
* function object @c f with a member @c work_ that is initialised with
* <tt>make_work_guard(ex1)</tt>, a member @c handler_ that is a decay-copy of
* @c completion_handler, and a function call operator that performs:
* @code auto a = get_associated_allocator(handler_);
* work_.get_executor().dispatch(std::move(handler_), a);
* work_.reset(); @endcode
*
* @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs
* @code prefer(
* require(ex, execution::blocking.never),
* execution::relationship.continuation,
* execution::allocator(alloc)
* ).execute(std::move(f)); @endcode
*
* @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs
* @code ex.defer(std::move(f), alloc); @endcode
*
* @par Completion Signature
* @code void() @endcode
*/
template <typename Executor,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken
= default_completion_token_t<Executor>>
auto defer(const Executor& ex,
NullaryToken&& token
= default_completion_token_t<Executor>(),
constraint_t<
(execution::is_executor<Executor>::value
&& can_require<Executor, execution::blocking_t::never_t>::value)
|| is_executor<Executor>::value
> = 0)
-> decltype(
async_initiate<NullaryToken, void()>(
declval<detail::initiate_defer_with_executor<Executor>>(), token))
{
return async_initiate<NullaryToken, void()>(
detail::initiate_defer_with_executor<Executor>(ex), token);
}
/// Submits a completion token or function object for execution.
/**
* @param ctx An execution context, from which the target executor is obtained.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler. The function signature of the completion handler must be:
* @code void handler(); @endcode
*
* @returns <tt>defer(ctx.get_executor(), forward<NullaryToken>(token))</tt>.
*
* @par Completion Signature
* @code void() @endcode
*/
template <typename ExecutionContext,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken
= default_completion_token_t<typename ExecutionContext::executor_type>>
auto defer(ExecutionContext& ctx,
NullaryToken&& token
= default_completion_token_t<typename ExecutionContext::executor_type>(),
constraint_t<
is_convertible<ExecutionContext&, execution_context&>::value
> = 0)
-> decltype(
async_initiate<NullaryToken, void()>(
declval<detail::initiate_defer_with_executor<
typename ExecutionContext::executor_type>>(), token))
{
return async_initiate<NullaryToken, void()>(
detail::initiate_defer_with_executor<
typename ExecutionContext::executor_type>(
ctx.get_executor()), token);
}
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DEFER_HPP

721
extern/boost/boost/asio/deferred.hpp vendored Normal file
View File

@ -0,0 +1,721 @@
//
// deferred.hpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_DEFERRED_HPP
#define BOOST_ASIO_DEFERRED_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <tuple>
#include <boost/asio/associator.hpp>
#include <boost/asio/async_result.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/utility.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// Trait for detecting objects that are usable as deferred operations.
template <typename T>
struct is_deferred : false_type
{
};
/// Helper type to wrap multiple completion signatures.
template <typename... Signatures>
struct deferred_signatures
{
};
namespace detail {
// Helper trait for getting the completion signatures of the tail in a sequence
// when invoked with the specified arguments.
template <typename Tail, typename... Signatures>
struct deferred_sequence_signatures;
template <typename Tail, typename R, typename... Args, typename... Signatures>
struct deferred_sequence_signatures<Tail, R(Args...), Signatures...>
: completion_signature_of<decltype(declval<Tail>()(declval<Args>()...))>
{
static_assert(
!is_same<decltype(declval<Tail>()(declval<Args>()...)), void>::value,
"deferred functions must produce a deferred return type");
};
// Completion handler for the head component of a deferred sequence.
template <typename Handler, typename Tail>
class deferred_sequence_handler
{
public:
template <typename H, typename T>
explicit deferred_sequence_handler(H&& handler, T&& tail)
: handler_(static_cast<H&&>(handler)),
tail_(static_cast<T&&>(tail))
{
}
template <typename... Args>
void operator()(Args&&... args)
{
static_cast<Tail&&>(tail_)(
static_cast<Args&&>(args)...)(
static_cast<Handler&&>(handler_));
}
//private:
Handler handler_;
Tail tail_;
};
template <typename Head, typename Tail, typename... Signatures>
class deferred_sequence_base
{
private:
struct initiate
{
template <typename Handler>
void operator()(Handler&& handler, Head head, Tail&& tail)
{
static_cast<Head&&>(head)(
deferred_sequence_handler<decay_t<Handler>, decay_t<Tail>>(
static_cast<Handler&&>(handler), static_cast<Tail&&>(tail)));
}
};
Head head_;
Tail tail_;
public:
template <typename H, typename T>
constexpr explicit deferred_sequence_base(H&& head, T&& tail)
: head_(static_cast<H&&>(head)),
tail_(static_cast<T&&>(tail))
{
}
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken>
auto operator()(CompletionToken&& token) &&
-> decltype(
async_initiate<CompletionToken, Signatures...>(
initiate(), token, static_cast<Head&&>(this->head_),
static_cast<Tail&&>(this->tail_)))
{
return async_initiate<CompletionToken, Signatures...>(initiate(),
token, static_cast<Head&&>(head_), static_cast<Tail&&>(tail_));
}
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken>
auto operator()(CompletionToken&& token) const &
-> decltype(
async_initiate<CompletionToken, Signatures...>(
initiate(), token, this->head_, this->tail_))
{
return async_initiate<CompletionToken, Signatures...>(
initiate(), token, head_, tail_);
}
};
// Two-step application of variadic Signatures to determine correct base type.
template <typename Head, typename Tail>
struct deferred_sequence_types
{
template <typename... Signatures>
struct op1
{
typedef deferred_sequence_base<Head, Tail, Signatures...> type;
};
template <typename... Signatures>
struct op2
{
typedef typename deferred_sequence_signatures<Tail, Signatures...>::template
apply<op1>::type::type type;
};
typedef typename completion_signature_of<Head>::template
apply<op2>::type::type base;
};
} // namespace detail
/// Used to represent an empty deferred action.
struct deferred_noop
{
/// No effect.
template <typename... Args>
void operator()(Args&&...) &&
{
}
/// No effect.
template <typename... Args>
void operator()(Args&&...) const &
{
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <>
struct is_deferred<deferred_noop> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Tag type to disambiguate deferred constructors.
struct deferred_init_tag {};
/// Wraps a function object so that it may be used as an element in a deferred
/// composition.
template <typename Function>
class deferred_function
{
public:
/// Constructor.
template <typename F>
constexpr explicit deferred_function(deferred_init_tag, F&& function)
: function_(static_cast<F&&>(function))
{
}
//private:
Function function_;
public:
template <typename... Args>
auto operator()(Args&&... args) &&
-> decltype(
static_cast<Function&&>(this->function_)(static_cast<Args&&>(args)...))
{
return static_cast<Function&&>(function_)(static_cast<Args&&>(args)...);
}
template <typename... Args>
auto operator()(Args&&... args) const &
-> decltype(Function(function_)(static_cast<Args&&>(args)...))
{
return Function(function_)(static_cast<Args&&>(args)...);
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename Function>
struct is_deferred<deferred_function<Function>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Encapsulates deferred values.
template <typename... Values>
class BOOST_ASIO_NODISCARD deferred_values
{
private:
std::tuple<Values...> values_;
struct initiate
{
template <typename Handler, typename... V>
void operator()(Handler handler, V&&... values)
{
static_cast<Handler&&>(handler)(static_cast<V&&>(values)...);
}
};
template <typename CompletionToken, std::size_t... I>
auto invoke_helper(CompletionToken&& token, detail::index_sequence<I...>)
-> decltype(
async_initiate<CompletionToken, void(Values...)>(initiate(), token,
std::get<I>(static_cast<std::tuple<Values...>&&>(this->values_))...))
{
return async_initiate<CompletionToken, void(Values...)>(initiate(), token,
std::get<I>(static_cast<std::tuple<Values...>&&>(values_))...);
}
template <typename CompletionToken, std::size_t... I>
auto const_invoke_helper(CompletionToken&& token,
detail::index_sequence<I...>)
-> decltype(
async_initiate<CompletionToken, void(Values...)>(
initiate(), token, std::get<I>(values_)...))
{
return async_initiate<CompletionToken, void(Values...)>(
initiate(), token, std::get<I>(values_)...);
}
public:
/// Construct a deferred asynchronous operation from the arguments to an
/// initiation function object.
template <typename... V>
constexpr explicit deferred_values(
deferred_init_tag, V&&... values)
: values_(static_cast<V&&>(values)...)
{
}
/// Initiate the deferred operation using the supplied completion token.
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(Values...)) CompletionToken>
auto operator()(CompletionToken&& token) &&
-> decltype(
this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<Values...>()))
{
return this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<Values...>());
}
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(Values...)) CompletionToken>
auto operator()(CompletionToken&& token) const &
-> decltype(
this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<Values...>()))
{
return this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<Values...>());
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename... Values>
struct is_deferred<deferred_values<Values...>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Encapsulates a deferred asynchronous operation.
template <typename Signature, typename Initiation, typename... InitArgs>
class BOOST_ASIO_NODISCARD deferred_async_operation
{
private:
typedef decay_t<Initiation> initiation_t;
initiation_t initiation_;
typedef std::tuple<decay_t<InitArgs>...> init_args_t;
init_args_t init_args_;
template <typename CompletionToken, std::size_t... I>
auto invoke_helper(CompletionToken&& token, detail::index_sequence<I...>)
-> decltype(
async_initiate<CompletionToken, Signature>(
static_cast<initiation_t&&>(initiation_), token,
std::get<I>(static_cast<init_args_t&&>(init_args_))...))
{
return async_initiate<CompletionToken, Signature>(
static_cast<initiation_t&&>(initiation_), token,
std::get<I>(static_cast<init_args_t&&>(init_args_))...);
}
template <typename CompletionToken, std::size_t... I>
auto const_invoke_helper(CompletionToken&& token,
detail::index_sequence<I...>) const &
-> decltype(
async_initiate<CompletionToken, Signature>(
conditional_t<true, initiation_t, CompletionToken>(initiation_),
token, std::get<I>(init_args_)...))
{
return async_initiate<CompletionToken, Signature>(
initiation_t(initiation_), token, std::get<I>(init_args_)...);
}
public:
/// Construct a deferred asynchronous operation from the arguments to an
/// initiation function object.
template <typename I, typename... A>
constexpr explicit deferred_async_operation(
deferred_init_tag, I&& initiation, A&&... init_args)
: initiation_(static_cast<I&&>(initiation)),
init_args_(static_cast<A&&>(init_args)...)
{
}
/// Initiate the asynchronous operation using the supplied completion token.
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signature) CompletionToken>
auto operator()(CompletionToken&& token) &&
-> decltype(
this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>()))
{
return this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>());
}
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signature) CompletionToken>
auto operator()(CompletionToken&& token) const &
-> decltype(
this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>()))
{
return this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>());
}
};
/// Encapsulates a deferred asynchronous operation thas has multiple completion
/// signatures.
template <typename... Signatures, typename Initiation, typename... InitArgs>
class BOOST_ASIO_NODISCARD deferred_async_operation<
deferred_signatures<Signatures...>, Initiation, InitArgs...>
{
private:
typedef decay_t<Initiation> initiation_t;
initiation_t initiation_;
typedef std::tuple<decay_t<InitArgs>...> init_args_t;
init_args_t init_args_;
template <typename CompletionToken, std::size_t... I>
auto invoke_helper(CompletionToken&& token, detail::index_sequence<I...>)
-> decltype(
async_initiate<CompletionToken, Signatures...>(
static_cast<initiation_t&&>(initiation_), token,
std::get<I>(static_cast<init_args_t&&>(init_args_))...))
{
return async_initiate<CompletionToken, Signatures...>(
static_cast<initiation_t&&>(initiation_), token,
std::get<I>(static_cast<init_args_t&&>(init_args_))...);
}
template <typename CompletionToken, std::size_t... I>
auto const_invoke_helper(CompletionToken&& token,
detail::index_sequence<I...>) const &
-> decltype(
async_initiate<CompletionToken, Signatures...>(
initiation_t(initiation_), token, std::get<I>(init_args_)...))
{
return async_initiate<CompletionToken, Signatures...>(
initiation_t(initiation_), token, std::get<I>(init_args_)...);
}
public:
/// Construct a deferred asynchronous operation from the arguments to an
/// initiation function object.
template <typename I, typename... A>
constexpr explicit deferred_async_operation(
deferred_init_tag, I&& initiation, A&&... init_args)
: initiation_(static_cast<I&&>(initiation)),
init_args_(static_cast<A&&>(init_args)...)
{
}
/// Initiate the asynchronous operation using the supplied completion token.
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken>
auto operator()(CompletionToken&& token) &&
-> decltype(
this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>()))
{
return this->invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>());
}
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(Signatures...) CompletionToken>
auto operator()(CompletionToken&& token) const &
-> decltype(
this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>()))
{
return this->const_invoke_helper(
static_cast<CompletionToken&&>(token),
detail::index_sequence_for<InitArgs...>());
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename Signature, typename Initiation, typename... InitArgs>
struct is_deferred<
deferred_async_operation<Signature, Initiation, InitArgs...>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Defines a link between two consecutive operations in a sequence.
template <typename Head, typename Tail>
class BOOST_ASIO_NODISCARD deferred_sequence :
public detail::deferred_sequence_types<Head, Tail>::base
{
public:
template <typename H, typename T>
constexpr explicit deferred_sequence(deferred_init_tag, H&& head, T&& tail)
: detail::deferred_sequence_types<Head, Tail>::base(
static_cast<H&&>(head), static_cast<T&&>(tail))
{
}
#if defined(GENERATING_DOCUMENTATION)
template <typename CompletionToken>
auto operator()(CompletionToken&& token) &&;
template <typename CompletionToken>
auto operator()(CompletionToken&& token) const &;
#endif // defined(GENERATING_DOCUMENTATION)
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename Head, typename Tail>
struct is_deferred<deferred_sequence<Head, Tail>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Used to represent a deferred conditional branch.
template <typename OnTrue = deferred_noop, typename OnFalse = deferred_noop>
class BOOST_ASIO_NODISCARD deferred_conditional
{
private:
template <typename T, typename F> friend class deferred_conditional;
// Helper constructor.
template <typename T, typename F>
explicit deferred_conditional(bool b, T&& on_true, F&& on_false)
: on_true_(static_cast<T&&>(on_true)),
on_false_(static_cast<F&&>(on_false)),
bool_(b)
{
}
OnTrue on_true_;
OnFalse on_false_;
bool bool_;
public:
/// Construct a deferred conditional with the value to determine which branch
/// will be executed.
constexpr explicit deferred_conditional(bool b)
: on_true_(),
on_false_(),
bool_(b)
{
}
/// Invoke the conditional branch bsaed on the stored value.
template <typename... Args>
auto operator()(Args&&... args) &&
-> decltype(static_cast<OnTrue&&>(on_true_)(static_cast<Args&&>(args)...))
{
if (bool_)
{
return static_cast<OnTrue&&>(on_true_)(static_cast<Args&&>(args)...);
}
else
{
return static_cast<OnFalse&&>(on_false_)(static_cast<Args&&>(args)...);
}
}
template <typename... Args>
auto operator()(Args&&... args) const &
-> decltype(on_true_(static_cast<Args&&>(args)...))
{
if (bool_)
{
return on_true_(static_cast<Args&&>(args)...);
}
else
{
return on_false_(static_cast<Args&&>(args)...);
}
}
/// Set the true branch of the conditional.
template <typename T>
deferred_conditional<T, OnFalse> then(T on_true,
constraint_t<
is_deferred<T>::value
>* = 0,
constraint_t<
is_same<
conditional_t<true, OnTrue, T>,
deferred_noop
>::value
>* = 0) &&
{
return deferred_conditional<T, OnFalse>(
bool_, static_cast<T&&>(on_true),
static_cast<OnFalse&&>(on_false_));
}
/// Set the false branch of the conditional.
template <typename T>
deferred_conditional<OnTrue, T> otherwise(T on_false,
constraint_t<
is_deferred<T>::value
>* = 0,
constraint_t<
!is_same<
conditional_t<true, OnTrue, T>,
deferred_noop
>::value
>* = 0,
constraint_t<
is_same<
conditional_t<true, OnFalse, T>,
deferred_noop
>::value
>* = 0) &&
{
return deferred_conditional<OnTrue, T>(
bool_, static_cast<OnTrue&&>(on_true_),
static_cast<T&&>(on_false));
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <typename OnTrue, typename OnFalse>
struct is_deferred<deferred_conditional<OnTrue, OnFalse>> : true_type
{
};
#endif // !defined(GENERATING_DOCUMENTATION)
/// Class used to specify that an asynchronous operation should return a
/// function object to lazily launch the operation.
/**
* The deferred_t class is used to indicate that an asynchronous operation
* should return a function object which is itself an initiation function. A
* deferred_t object may be passed as a completion token to an asynchronous
* operation, typically as the default completion token:
*
* @code auto my_deferred_op = my_socket.async_read_some(my_buffer); @endcode
*
* or by explicitly passing the special value @c boost::asio::deferred:
*
* @code auto my_deferred_op
* = my_socket.async_read_some(my_buffer,
* boost::asio::deferred); @endcode
*
* The initiating function (async_read_some in the above example) returns a
* function object that will lazily initiate the operation.
*/
class deferred_t
{
public:
/// Default constructor.
constexpr deferred_t()
{
}
/// Adapts an executor to add the @c deferred_t completion token as the
/// default.
template <typename InnerExecutor>
struct executor_with_default : InnerExecutor
{
/// Specify @c deferred_t as the default completion token type.
typedef deferred_t default_completion_token_type;
/// Construct the adapted executor from the inner executor type.
template <typename InnerExecutor1>
executor_with_default(const InnerExecutor1& ex,
constraint_t<
conditional_t<
!is_same<InnerExecutor1, executor_with_default>::value,
is_convertible<InnerExecutor1, InnerExecutor>,
false_type
>::value
> = 0) noexcept
: InnerExecutor(ex)
{
}
};
/// Type alias to adapt an I/O object to use @c deferred_t as its
/// default completion token type.
template <typename T>
using as_default_on_t = typename T::template rebind_executor<
executor_with_default<typename T::executor_type>>::other;
/// Function helper to adapt an I/O object to use @c deferred_t as its
/// default completion token type.
template <typename T>
static typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other
as_default_on(T&& object)
{
return typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other(static_cast<T&&>(object));
}
/// Creates a new deferred from a function.
template <typename Function>
constraint_t<
!is_deferred<decay_t<Function>>::value,
deferred_function<decay_t<Function>>
> operator()(Function&& function) const
{
return deferred_function<decay_t<Function>>(
deferred_init_tag{}, static_cast<Function&&>(function));
}
/// Passes through anything that is already deferred.
template <typename T>
constraint_t<
is_deferred<decay_t<T>>::value,
decay_t<T>
> operator()(T&& t) const
{
return static_cast<T&&>(t);
}
/// Returns a deferred operation that returns the provided values.
template <typename... Args>
static constexpr deferred_values<decay_t<Args>...> values(Args&&... args)
{
return deferred_values<decay_t<Args>...>(
deferred_init_tag{}, static_cast<Args&&>(args)...);
}
/// Creates a conditional object for branching deferred operations.
static constexpr deferred_conditional<> when(bool b)
{
return deferred_conditional<>(b);
}
};
/// Pipe operator used to chain deferred operations.
template <typename Head, typename Tail>
inline auto operator|(Head head, Tail&& tail)
-> constraint_t<
is_deferred<Head>::value,
decltype(static_cast<Head&&>(head)(static_cast<Tail&&>(tail)))
>
{
return static_cast<Head&&>(head)(static_cast<Tail&&>(tail));
}
/// A @ref completion_token object used to specify that an asynchronous
/// operation should return a function object to lazily launch the operation.
/**
* See the documentation for boost::asio::deferred_t for a usage example.
*/
BOOST_ASIO_INLINE_VARIABLE constexpr deferred_t deferred;
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/impl/deferred.hpp>
#endif // BOOST_ASIO_DEFERRED_HPP

107
extern/boost/boost/asio/detached.hpp vendored Normal file
View File

@ -0,0 +1,107 @@
//
// detached.hpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_DETACHED_HPP
#define BOOST_ASIO_DETACHED_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <memory>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
/// A @ref completion_token type used to specify that an asynchronous operation
/// is detached.
/**
* The detached_t class is used to indicate that an asynchronous operation is
* detached. That is, there is no completion handler waiting for the
* operation's result. A detached_t object may be passed as a handler to an
* asynchronous operation, typically using the special value
* @c boost::asio::detached. For example:
*
* @code my_socket.async_send(my_buffer, boost::asio::detached);
* @endcode
*/
class detached_t
{
public:
/// Constructor.
constexpr detached_t()
{
}
/// Adapts an executor to add the @c detached_t completion token as the
/// default.
template <typename InnerExecutor>
struct executor_with_default : InnerExecutor
{
/// Specify @c detached_t as the default completion token type.
typedef detached_t default_completion_token_type;
/// Construct the adapted executor from the inner executor type.
executor_with_default(const InnerExecutor& ex) noexcept
: InnerExecutor(ex)
{
}
/// Convert the specified executor to the inner executor type, then use
/// that to construct the adapted executor.
template <typename OtherExecutor>
executor_with_default(const OtherExecutor& ex,
constraint_t<
is_convertible<OtherExecutor, InnerExecutor>::value
> = 0) noexcept
: InnerExecutor(ex)
{
}
};
/// Type alias to adapt an I/O object to use @c detached_t as its
/// default completion token type.
template <typename T>
using as_default_on_t = typename T::template rebind_executor<
executor_with_default<typename T::executor_type>>::other;
/// Function helper to adapt an I/O object to use @c detached_t as its
/// default completion token type.
template <typename T>
static typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other
as_default_on(T&& object)
{
return typename decay_t<T>::template rebind_executor<
executor_with_default<typename decay_t<T>::executor_type>
>::other(static_cast<T&&>(object));
}
};
/// A @ref completion_token object used to specify that an asynchronous
/// operation is detached.
/**
* See the documentation for boost::asio::detached_t for a usage example.
*/
BOOST_ASIO_INLINE_VARIABLE constexpr detached_t detached;
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#include <boost/asio/impl/detached.hpp>
#endif // BOOST_ASIO_DETACHED_HPP

View File

@ -0,0 +1,32 @@
//
// detail/array.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_DETAIL_ARRAY_HPP
#define BOOST_ASIO_DETAIL_ARRAY_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <array>
namespace boost {
namespace asio {
namespace detail {
using std::array;
} // namespace detail
} // namespace asio
} // namespace boost
#endif // BOOST_ASIO_DETAIL_ARRAY_HPP

View File

@ -0,0 +1,32 @@
//
// detail/array_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_DETAIL_ARRAY_FWD_HPP
#define BOOST_ASIO_DETAIL_ARRAY_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
namespace boost {
template<class T, std::size_t N>
class array;
} // namespace boost
// Standard library components can't be forward declared, so we'll have to
// include the array header. Fortunately, it's fairly lightweight and doesn't
// add significantly to the compile time.
#include <array>
#endif // BOOST_ASIO_DETAIL_ARRAY_FWD_HPP

View File

@ -0,0 +1,32 @@
//
// detail/assert.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_DETAIL_ASSERT_HPP
#define BOOST_ASIO_DETAIL_ASSERT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if defined(BOOST_ASIO_HAS_BOOST_ASSERT)
# include <boost/assert.hpp>
#else // defined(BOOST_ASIO_HAS_BOOST_ASSERT)
# include <cassert>
#endif // defined(BOOST_ASIO_HAS_BOOST_ASSERT)
#if defined(BOOST_ASIO_HAS_BOOST_ASSERT)
# define BOOST_ASIO_ASSERT(expr) BOOST_ASSERT(expr)
#else // defined(BOOST_ASIO_HAS_BOOST_ASSERT)
# define BOOST_ASIO_ASSERT(expr) assert(expr)
#endif // defined(BOOST_ASIO_HAS_BOOST_ASSERT)
#endif // BOOST_ASIO_DETAIL_ASSERT_HPP

View File

@ -0,0 +1,61 @@
//
// detail/atomic_count.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_DETAIL_ATOMIC_COUNT_HPP
#define BOOST_ASIO_DETAIL_ATOMIC_COUNT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#if !defined(BOOST_ASIO_HAS_THREADS)
// Nothing to include.
#else // !defined(BOOST_ASIO_HAS_THREADS)
# include <atomic>
#endif // !defined(BOOST_ASIO_HAS_THREADS)
namespace boost {
namespace asio {
namespace detail {
#if !defined(BOOST_ASIO_HAS_THREADS)
typedef long atomic_count;
inline void increment(atomic_count& a, long b) { a += b; }
inline void decrement(atomic_count& a, long b) { a -= b; }
inline void ref_count_up(atomic_count& a) { ++a; }
inline bool ref_count_down(atomic_count& a) { return --a == 0; }
#else // !defined(BOOST_ASIO_HAS_THREADS)
typedef std::atomic<long> atomic_count;
inline void increment(atomic_count& a, long b) { a += b; }
inline void decrement(atomic_count& a, long b) { a -= b; }
inline void ref_count_up(atomic_count& a)
{
a.fetch_add(1, std::memory_order_relaxed);
}
inline bool ref_count_down(atomic_count& a)
{
if (a.fetch_sub(1, std::memory_order_release) == 1)
{
std::atomic_thread_fence(std::memory_order_acquire);
return true;
}
return false;
}
#endif // !defined(BOOST_ASIO_HAS_THREADS)
} // namespace detail
} // namespace asio
} // namespace boost
#endif // BOOST_ASIO_DETAIL_ATOMIC_COUNT_HPP

View File

@ -0,0 +1,166 @@
//
// detail/base_from_cancellation_state.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_DETAIL_BASE_FROM_CANCELLATION_STATE_HPP
#define BOOST_ASIO_DETAIL_BASE_FROM_CANCELLATION_STATE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/associated_cancellation_slot.hpp>
#include <boost/asio/cancellation_state.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename Handler, typename = void>
class base_from_cancellation_state
{
public:
typedef cancellation_slot cancellation_slot_type;
cancellation_slot_type get_cancellation_slot() const noexcept
{
return cancellation_state_.slot();
}
cancellation_state get_cancellation_state() const noexcept
{
return cancellation_state_;
}
protected:
explicit base_from_cancellation_state(const Handler& handler)
: cancellation_state_(
boost::asio::get_associated_cancellation_slot(handler))
{
}
template <typename Filter>
base_from_cancellation_state(const Handler& handler, Filter filter)
: cancellation_state_(
boost::asio::get_associated_cancellation_slot(handler), filter, filter)
{
}
template <typename InFilter, typename OutFilter>
base_from_cancellation_state(const Handler& handler,
InFilter&& in_filter,
OutFilter&& out_filter)
: cancellation_state_(
boost::asio::get_associated_cancellation_slot(handler),
static_cast<InFilter&&>(in_filter),
static_cast<OutFilter&&>(out_filter))
{
}
void reset_cancellation_state(const Handler& handler)
{
cancellation_state_ = cancellation_state(
boost::asio::get_associated_cancellation_slot(handler));
}
template <typename Filter>
void reset_cancellation_state(const Handler& handler, Filter filter)
{
cancellation_state_ = cancellation_state(
boost::asio::get_associated_cancellation_slot(handler), filter, filter);
}
template <typename InFilter, typename OutFilter>
void reset_cancellation_state(const Handler& handler,
InFilter&& in_filter,
OutFilter&& out_filter)
{
cancellation_state_ = cancellation_state(
boost::asio::get_associated_cancellation_slot(handler),
static_cast<InFilter&&>(in_filter),
static_cast<OutFilter&&>(out_filter));
}
cancellation_type_t cancelled() const noexcept
{
return cancellation_state_.cancelled();
}
private:
cancellation_state cancellation_state_;
};
template <typename Handler>
class base_from_cancellation_state<Handler,
enable_if_t<
is_same<
typename associated_cancellation_slot<
Handler, cancellation_slot
>::asio_associated_cancellation_slot_is_unspecialised,
void
>::value
>
>
{
public:
cancellation_state get_cancellation_state() const noexcept
{
return cancellation_state();
}
protected:
explicit base_from_cancellation_state(const Handler&)
{
}
template <typename Filter>
base_from_cancellation_state(const Handler&, Filter)
{
}
template <typename InFilter, typename OutFilter>
base_from_cancellation_state(const Handler&,
InFilter&&,
OutFilter&&)
{
}
void reset_cancellation_state(const Handler&)
{
}
template <typename Filter>
void reset_cancellation_state(const Handler&, Filter)
{
}
template <typename InFilter, typename OutFilter>
void reset_cancellation_state(const Handler&,
InFilter&&,
OutFilter&&)
{
}
constexpr cancellation_type_t cancelled() const noexcept
{
return cancellation_type::none;
}
};
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_BASE_FROM_CANCELLATION_STATE_HPP

View File

@ -0,0 +1,71 @@
//
// detail/base_from_completion_cond.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP
#define BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/completion_condition.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename CompletionCondition>
class base_from_completion_cond
{
protected:
explicit base_from_completion_cond(CompletionCondition& completion_condition)
: completion_condition_(
static_cast<CompletionCondition&&>(completion_condition))
{
}
std::size_t check_for_completion(
const boost::system::error_code& ec,
std::size_t total_transferred)
{
return detail::adapt_completion_condition_result(
completion_condition_(ec, total_transferred));
}
private:
CompletionCondition completion_condition_;
};
template <>
class base_from_completion_cond<transfer_all_t>
{
protected:
explicit base_from_completion_cond(transfer_all_t)
{
}
static std::size_t check_for_completion(
const boost::system::error_code& ec,
std::size_t total_transferred)
{
return transfer_all_t()(ec, total_transferred);
}
};
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP

View File

@ -0,0 +1,713 @@
//
// detail/bind_handler.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_DETAIL_BIND_HANDLER_HPP
#define BOOST_ASIO_DETAIL_BIND_HANDLER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/associator.hpp>
#include <boost/asio/detail/handler_cont_helpers.hpp>
#include <boost/asio/detail/type_traits.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename Handler>
class binder0
{
public:
template <typename T>
binder0(int, T&& handler)
: handler_(static_cast<T&&>(handler))
{
}
binder0(Handler& handler)
: handler_(static_cast<Handler&&>(handler))
{
}
binder0(const binder0& other)
: handler_(other.handler_)
{
}
binder0(binder0&& other)
: handler_(static_cast<Handler&&>(other.handler_))
{
}
void operator()()
{
static_cast<Handler&&>(handler_)();
}
void operator()() const
{
handler_();
}
//private:
Handler handler_;
};
template <typename Handler>
inline bool asio_handler_is_continuation(
binder0<Handler>* this_handler)
{
return boost_asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Handler>
inline binder0<decay_t<Handler>> bind_handler(
Handler&& handler)
{
return binder0<decay_t<Handler>>(
0, static_cast<Handler&&>(handler));
}
template <typename Handler, typename Arg1>
class binder1
{
public:
template <typename T>
binder1(int, T&& handler, const Arg1& arg1)
: handler_(static_cast<T&&>(handler)),
arg1_(arg1)
{
}
binder1(Handler& handler, const Arg1& arg1)
: handler_(static_cast<Handler&&>(handler)),
arg1_(arg1)
{
}
binder1(const binder1& other)
: handler_(other.handler_),
arg1_(other.arg1_)
{
}
binder1(binder1&& other)
: handler_(static_cast<Handler&&>(other.handler_)),
arg1_(static_cast<Arg1&&>(other.arg1_))
{
}
void operator()()
{
static_cast<Handler&&>(handler_)(
static_cast<const Arg1&>(arg1_));
}
void operator()() const
{
handler_(arg1_);
}
//private:
Handler handler_;
Arg1 arg1_;
};
template <typename Handler, typename Arg1>
inline bool asio_handler_is_continuation(
binder1<Handler, Arg1>* this_handler)
{
return boost_asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Handler, typename Arg1>
inline binder1<decay_t<Handler>, Arg1> bind_handler(
Handler&& handler, const Arg1& arg1)
{
return binder1<decay_t<Handler>, Arg1>(0,
static_cast<Handler&&>(handler), arg1);
}
template <typename Handler, typename Arg1, typename Arg2>
class binder2
{
public:
template <typename T>
binder2(int, T&& handler,
const Arg1& arg1, const Arg2& arg2)
: handler_(static_cast<T&&>(handler)),
arg1_(arg1),
arg2_(arg2)
{
}
binder2(Handler& handler, const Arg1& arg1, const Arg2& arg2)
: handler_(static_cast<Handler&&>(handler)),
arg1_(arg1),
arg2_(arg2)
{
}
binder2(const binder2& other)
: handler_(other.handler_),
arg1_(other.arg1_),
arg2_(other.arg2_)
{
}
binder2(binder2&& other)
: handler_(static_cast<Handler&&>(other.handler_)),
arg1_(static_cast<Arg1&&>(other.arg1_)),
arg2_(static_cast<Arg2&&>(other.arg2_))
{
}
void operator()()
{
static_cast<Handler&&>(handler_)(
static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_));
}
void operator()() const
{
handler_(arg1_, arg2_);
}
//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
};
template <typename Handler, typename Arg1, typename Arg2>
inline bool asio_handler_is_continuation(
binder2<Handler, Arg1, Arg2>* this_handler)
{
return boost_asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2>
inline binder2<decay_t<Handler>, Arg1, Arg2> bind_handler(
Handler&& handler, const Arg1& arg1, const Arg2& arg2)
{
return binder2<decay_t<Handler>, Arg1, Arg2>(0,
static_cast<Handler&&>(handler), arg1, arg2);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
class binder3
{
public:
template <typename T>
binder3(int, T&& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3)
: handler_(static_cast<T&&>(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3)
{
}
binder3(Handler& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3)
: handler_(static_cast<Handler&&>(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3)
{
}
binder3(const binder3& other)
: handler_(other.handler_),
arg1_(other.arg1_),
arg2_(other.arg2_),
arg3_(other.arg3_)
{
}
binder3(binder3&& other)
: handler_(static_cast<Handler&&>(other.handler_)),
arg1_(static_cast<Arg1&&>(other.arg1_)),
arg2_(static_cast<Arg2&&>(other.arg2_)),
arg3_(static_cast<Arg3&&>(other.arg3_))
{
}
void operator()()
{
static_cast<Handler&&>(handler_)(
static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_),
static_cast<const Arg3&>(arg3_));
}
void operator()() const
{
handler_(arg1_, arg2_, arg3_);
}
//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
};
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline bool asio_handler_is_continuation(
binder3<Handler, Arg1, Arg2, Arg3>* this_handler)
{
return boost_asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2, typename Arg3>
inline binder3<decay_t<Handler>, Arg1, Arg2, Arg3> bind_handler(
Handler&& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3)
{
return binder3<decay_t<Handler>, Arg1, Arg2, Arg3>(0,
static_cast<Handler&&>(handler), arg1, arg2, arg3);
}
template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
class binder4
{
public:
template <typename T>
binder4(int, T&& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
: handler_(static_cast<T&&>(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4)
{
}
binder4(Handler& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
: handler_(static_cast<Handler&&>(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4)
{
}
binder4(const binder4& other)
: handler_(other.handler_),
arg1_(other.arg1_),
arg2_(other.arg2_),
arg3_(other.arg3_),
arg4_(other.arg4_)
{
}
binder4(binder4&& other)
: handler_(static_cast<Handler&&>(other.handler_)),
arg1_(static_cast<Arg1&&>(other.arg1_)),
arg2_(static_cast<Arg2&&>(other.arg2_)),
arg3_(static_cast<Arg3&&>(other.arg3_)),
arg4_(static_cast<Arg4&&>(other.arg4_))
{
}
void operator()()
{
static_cast<Handler&&>(handler_)(
static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_),
static_cast<const Arg3&>(arg3_),
static_cast<const Arg4&>(arg4_));
}
void operator()() const
{
handler_(arg1_, arg2_, arg3_, arg4_);
}
//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
Arg4 arg4_;
};
template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline bool asio_handler_is_continuation(
binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler)
{
return boost_asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Handler, typename Arg1,
typename Arg2, typename Arg3, typename Arg4>
inline binder4<decay_t<Handler>, Arg1, Arg2, Arg3, Arg4>
bind_handler(Handler&& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4)
{
return binder4<decay_t<Handler>, Arg1, Arg2, Arg3, Arg4>(0,
static_cast<Handler&&>(handler), arg1, arg2, arg3, arg4);
}
template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5>
class binder5
{
public:
template <typename T>
binder5(int, T&& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
: handler_(static_cast<T&&>(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4),
arg5_(arg5)
{
}
binder5(Handler& handler, const Arg1& arg1, const Arg2& arg2,
const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
: handler_(static_cast<Handler&&>(handler)),
arg1_(arg1),
arg2_(arg2),
arg3_(arg3),
arg4_(arg4),
arg5_(arg5)
{
}
binder5(const binder5& other)
: handler_(other.handler_),
arg1_(other.arg1_),
arg2_(other.arg2_),
arg3_(other.arg3_),
arg4_(other.arg4_),
arg5_(other.arg5_)
{
}
binder5(binder5&& other)
: handler_(static_cast<Handler&&>(other.handler_)),
arg1_(static_cast<Arg1&&>(other.arg1_)),
arg2_(static_cast<Arg2&&>(other.arg2_)),
arg3_(static_cast<Arg3&&>(other.arg3_)),
arg4_(static_cast<Arg4&&>(other.arg4_)),
arg5_(static_cast<Arg5&&>(other.arg5_))
{
}
void operator()()
{
static_cast<Handler&&>(handler_)(
static_cast<const Arg1&>(arg1_),
static_cast<const Arg2&>(arg2_),
static_cast<const Arg3&>(arg3_),
static_cast<const Arg4&>(arg4_),
static_cast<const Arg5&>(arg5_));
}
void operator()() const
{
handler_(arg1_, arg2_, arg3_, arg4_, arg5_);
}
//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
Arg3 arg3_;
Arg4 arg4_;
Arg5 arg5_;
};
template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5>
inline bool asio_handler_is_continuation(
binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler)
{
return boost_asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2,
typename Arg3, typename Arg4, typename Arg5>
inline binder5<decay_t<Handler>, Arg1, Arg2, Arg3, Arg4, Arg5>
bind_handler(Handler&& handler, const Arg1& arg1,
const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5)
{
return binder5<decay_t<Handler>, Arg1, Arg2, Arg3, Arg4, Arg5>(0,
static_cast<Handler&&>(handler), arg1, arg2, arg3, arg4, arg5);
}
template <typename Handler, typename Arg1>
class move_binder1
{
public:
move_binder1(int, Handler&& handler,
Arg1&& arg1)
: handler_(static_cast<Handler&&>(handler)),
arg1_(static_cast<Arg1&&>(arg1))
{
}
move_binder1(move_binder1&& other)
: handler_(static_cast<Handler&&>(other.handler_)),
arg1_(static_cast<Arg1&&>(other.arg1_))
{
}
void operator()()
{
static_cast<Handler&&>(handler_)(
static_cast<Arg1&&>(arg1_));
}
//private:
Handler handler_;
Arg1 arg1_;
};
template <typename Handler, typename Arg1>
inline bool asio_handler_is_continuation(
move_binder1<Handler, Arg1>* this_handler)
{
return boost_asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
template <typename Handler, typename Arg1, typename Arg2>
class move_binder2
{
public:
move_binder2(int, Handler&& handler,
const Arg1& arg1, Arg2&& arg2)
: handler_(static_cast<Handler&&>(handler)),
arg1_(arg1),
arg2_(static_cast<Arg2&&>(arg2))
{
}
move_binder2(move_binder2&& other)
: handler_(static_cast<Handler&&>(other.handler_)),
arg1_(static_cast<Arg1&&>(other.arg1_)),
arg2_(static_cast<Arg2&&>(other.arg2_))
{
}
void operator()()
{
static_cast<Handler&&>(handler_)(
static_cast<const Arg1&>(arg1_),
static_cast<Arg2&&>(arg2_));
}
//private:
Handler handler_;
Arg1 arg1_;
Arg2 arg2_;
};
template <typename Handler, typename Arg1, typename Arg2>
inline bool asio_handler_is_continuation(
move_binder2<Handler, Arg1, Arg2>* this_handler)
{
return boost_asio_handler_cont_helpers::is_continuation(
this_handler->handler_);
}
} // namespace detail
template <template <typename, typename> class Associator,
typename Handler, typename DefaultCandidate>
struct associator<Associator,
detail::binder0<Handler>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const detail::binder0<Handler>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static auto get(const detail::binder0<Handler>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename DefaultCandidate>
struct associator<Associator,
detail::binder1<Handler, Arg1>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const detail::binder1<Handler, Arg1>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static auto get(const detail::binder1<Handler, Arg1>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename Arg2,
typename DefaultCandidate>
struct associator<Associator,
detail::binder2<Handler, Arg1, Arg2>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const detail::binder2<Handler, Arg1, Arg2>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static auto get(const detail::binder2<Handler, Arg1, Arg2>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename DefaultCandidate>
struct associator<Associator,
detail::binder3<Handler, Arg1, Arg2, Arg3>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const detail::binder3<Handler, Arg1, Arg2, Arg3>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static auto get(const detail::binder3<Handler, Arg1, Arg2, Arg3>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename DefaultCandidate>
struct associator<Associator,
detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static auto get(const detail::binder4<Handler, Arg1, Arg2, Arg3, Arg4>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename Arg2, typename Arg3,
typename Arg4, typename Arg5, typename DefaultCandidate>
struct associator<Associator,
detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static auto get(
const detail::binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename DefaultCandidate>
struct associator<Associator,
detail::move_binder1<Handler, Arg1>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const detail::move_binder1<Handler, Arg1>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static auto get(const detail::move_binder1<Handler, Arg1>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
template <template <typename, typename> class Associator,
typename Handler, typename Arg1, typename Arg2, typename DefaultCandidate>
struct associator<Associator,
detail::move_binder2<Handler, Arg1, Arg2>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const detail::move_binder2<Handler, Arg1, Arg2>& h) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_);
}
static auto get(const detail::move_binder2<Handler, Arg1, Arg2>& h,
const DefaultCandidate& c) noexcept
-> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_BIND_HANDLER_HPP

View File

@ -0,0 +1,109 @@
//
// detail/blocking_executor_op.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 BOOST_ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP
#define BOOST_ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include <boost/asio/detail/config.hpp>
#include <boost/asio/detail/event.hpp>
#include <boost/asio/detail/fenced_block.hpp>
#include <boost/asio/detail/mutex.hpp>
#include <boost/asio/detail/scheduler_operation.hpp>
#include <boost/asio/detail/push_options.hpp>
namespace boost {
namespace asio {
namespace detail {
template <typename Operation = scheduler_operation>
class blocking_executor_op_base : public Operation
{
public:
blocking_executor_op_base(typename Operation::func_type complete_func)
: Operation(complete_func),
is_complete_(false)
{
}
void wait()
{
boost::asio::detail::mutex::scoped_lock lock(mutex_);
while (!is_complete_)
event_.wait(lock);
}
protected:
struct do_complete_cleanup
{
~do_complete_cleanup()
{
boost::asio::detail::mutex::scoped_lock lock(op_->mutex_);
op_->is_complete_ = true;
op_->event_.unlock_and_signal_one_for_destruction(lock);
}
blocking_executor_op_base* op_;
};
private:
boost::asio::detail::mutex mutex_;
boost::asio::detail::event event_;
bool is_complete_;
};
template <typename Handler, typename Operation = scheduler_operation>
class blocking_executor_op : public blocking_executor_op_base<Operation>
{
public:
blocking_executor_op(Handler& h)
: blocking_executor_op_base<Operation>(&blocking_executor_op::do_complete),
handler_(h)
{
}
static void do_complete(void* owner, Operation* base,
const boost::system::error_code& /*ec*/,
std::size_t /*bytes_transferred*/)
{
BOOST_ASIO_ASSUME(base != 0);
blocking_executor_op* o(static_cast<blocking_executor_op*>(base));
typename blocking_executor_op_base<Operation>::do_complete_cleanup
on_exit = { o };
(void)on_exit;
BOOST_ASIO_HANDLER_COMPLETION((*o));
// Make the upcall if required.
if (owner)
{
fenced_block b(fenced_block::half);
BOOST_ASIO_HANDLER_INVOCATION_BEGIN(());
static_cast<Handler&&>(o->handler_)();
BOOST_ASIO_HANDLER_INVOCATION_END;
}
}
private:
Handler& handler_;
};
} // namespace detail
} // namespace asio
} // namespace boost
#include <boost/asio/detail/pop_options.hpp>
#endif // BOOST_ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP

Some files were not shown because too many files have changed in this diff Show More