From 2812bddd81f8a1b804c7460f4e14cd0aa393d129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Mon, 1 Jun 2009 10:48:42 +0200 Subject: Import. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8364ba9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +*.dep +*.gcda +*.gcno +*.app +*.o +*.a +*.swp +*.exe +*.dll +*.moc +*~ +*.manifest +moc_* +qrc_* +ui_* +checker +aclocal.m4 +autom4te.cache +config.log +config.status +configure +Makefile.config +Swiften/Examples/TuneBot/TuneBot +Swiften/QA/ClientTest/ClientTest +Swiften/config.h +Swiften/config.h.in +UI/Qt/Makefile +UI/Qt/swift +UI/Qt/DefaultTheme.qrc +UI/Qt/*/Makefile +tools/coverage/results diff --git a/3rdParty/Boost/Makefile.inc b/3rdParty/Boost/Makefile.inc new file mode 100644 index 0000000..718d91a --- /dev/null +++ b/3rdParty/Boost/Makefile.inc @@ -0,0 +1,47 @@ +CPPFLAGS += -DBOOST_ALL_NO_LIB +CXXFLAGS += -isystem 3rdParty/Boost -DBOOST_SIGNALS_NAMESPACE=bsignals + +BOOST_SOURCES += \ + 3rdParty/Boost/libs/date_time/src/gregorian/date_generators.cpp \ + 3rdParty/Boost/libs/date_time/src/gregorian/greg_month.cpp \ + 3rdParty/Boost/libs/date_time/src/gregorian/greg_weekday.cpp \ + 3rdParty/Boost/libs/date_time/src/gregorian/gregorian_types.cpp \ + 3rdParty/Boost/libs/date_time/src/posix_time/posix_time_types.cpp \ + 3rdParty/Boost/libs/system/src/error_code.cpp \ + 3rdParty/Boost/libs/thread/src/tss_null.cpp \ + 3rdParty/Boost/libs/signals/src/connection.cpp \ + 3rdParty/Boost/libs/signals/src/named_slot_map.cpp \ + 3rdParty/Boost/libs/signals/src/signal_base.cpp \ + 3rdParty/Boost/libs/signals/src/slot.cpp \ + 3rdParty/Boost/libs/signals/src/trackable.cpp \ + 3rdParty/Boost/libs/filesystem/src/operations.cpp \ + 3rdParty/Boost/libs/filesystem/src/path.cpp \ + 3rdParty/Boost/libs/filesystem/src/portability.cpp \ + 3rdParty/Boost/libs/filesystem/src/utf8_codecvt_facet.cpp + +ifeq ($(WIN32),1) +# The WINNT flag is the boost default (Windows XP Target) +CXXFLAGS += -D_WIN32_WINNT=0x0501 +# Only needed for CygWin +CXXFLAGS += -D__USE_W32_SOCKETS +BOOST_SOURCES += \ + 3rdParty/Boost/win32_stubs.cpp \ + 3rdParty/Boost/libs/thread/src/win32/exceptions.cpp \ + 3rdParty/Boost/libs/thread/src/win32/thread.cpp \ + 3rdParty/Boost/libs/thread/src/win32/tss_dll.cpp \ + 3rdParty/Boost/libs/thread/src/win32/tss_pe.cpp +else +LIBS += -lpthread +BOOST_SOURCES += \ + 3rdParty/Boost/libs/thread/src/pthread/exceptions.cpp \ + 3rdParty/Boost/libs/thread/src/pthread/once.cpp \ + 3rdParty/Boost/libs/thread/src/pthread/thread.cpp +endif + +BOOST_OBJECTS = \ + $(BOOST_SOURCES:.cpp=.o) + +CLEANFILES += \ + $(BOOST_SOURCES:.cpp=.gcda) \ + $(BOOST_SOURCES:.cpp=.gcno) \ + $(BOOST_OBJECTS) diff --git a/3rdParty/Boost/boost/algorithm/string/case_conv.hpp b/3rdParty/Boost/boost/algorithm/string/case_conv.hpp new file mode 100644 index 0000000..536c022 --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/case_conv.hpp @@ -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 +#include +#include +#include + +#include +#include +#include +#include + +#include + +/*! \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 + inline OutputIteratorT + to_lower_copy( + OutputIteratorT Output, + const RangeT& Input, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::detail::transform_range_copy( + Output, + as_literal(Input), + ::boost::algorithm::detail::to_lowerF< + typename range_value::type >(Loc)); + } + + //! Convert to lower case + /*! + \overload + */ + template + inline SequenceT to_lower_copy( + const SequenceT& Input, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::detail::transform_range_copy( + Input, + ::boost::algorithm::detail::to_lowerF< + typename range_value::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 + inline void to_lower( + WritableRangeT& Input, + const std::locale& Loc=std::locale()) + { + ::boost::algorithm::detail::transform_range( + as_literal(Input), + ::boost::algorithm::detail::to_lowerF< + typename range_value::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 + inline OutputIteratorT + to_upper_copy( + OutputIteratorT Output, + const RangeT& Input, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::detail::transform_range_copy( + Output, + as_literal(Input), + ::boost::algorithm::detail::to_upperF< + typename range_value::type >(Loc)); + } + + //! Convert to upper case + /*! + \overload + */ + template + inline SequenceT to_upper_copy( + const SequenceT& Input, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::detail::transform_range_copy( + Input, + ::boost::algorithm::detail::to_upperF< + typename range_value::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 + inline void to_upper( + WritableRangeT& Input, + const std::locale& Loc=std::locale()) + { + ::boost::algorithm::detail::transform_range( + as_literal(Input), + ::boost::algorithm::detail::to_upperF< + typename range_value::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 diff --git a/3rdParty/Boost/boost/algorithm/string/compare.hpp b/3rdParty/Boost/boost/algorithm/string/compare.hpp new file mode 100644 index 0000000..734303a --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/compare.hpp @@ -0,0 +1,199 @@ +// Boost string_algo library compare.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_COMPARE_HPP +#define BOOST_STRING_COMPARE_HPP + +#include +#include + +/*! \file + Defines element comparison predicates. Many algorithms in this library can + take an additional argument with a predicate used to compare elements. + This makes it possible, for instance, to have case insensitive versions + of the algorithms. +*/ + +namespace boost { + namespace algorithm { + + // is_equal functor -----------------------------------------------// + + //! is_equal functor + /*! + Standard STL equal_to only handle comparison between arguments + of the same type. This is a less restrictive version which wraps operator ==. + */ + struct is_equal + { + //! Function operator + /*! + Compare two operands for equality + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + return Arg1==Arg2; + } + }; + + //! case insensitive version of is_equal + /*! + Case insensitive comparison predicate. Comparison is done using + specified locales. + */ + struct is_iequal + { + //! Constructor + /*! + \param Loc locales used for comparison + */ + is_iequal( const std::locale& Loc=std::locale() ) : + m_Loc( Loc ) {} + + //! Function operator + /*! + Compare two operands. Case is ignored. + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::toupper(Arg1)==std::toupper(Arg2); + #else + return std::toupper(Arg1,m_Loc)==std::toupper(Arg2,m_Loc); + #endif + } + + private: + std::locale m_Loc; + }; + + // is_less functor -----------------------------------------------// + + //! is_less functor + /*! + Convenient version of standard std::less. Operation is templated, therefore it is + not required to specify the exact types upon the construction + */ + struct is_less + { + //! Functor operation + /*! + Compare two operands using > operator + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + return Arg1 + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::toupper(Arg1)(Arg1,m_Loc)(Arg2,m_Loc); + #endif + } + + private: + std::locale m_Loc; + }; + + // is_not_greater functor -----------------------------------------------// + + //! is_not_greater functor + /*! + Convenient version of standard std::not_greater_to. Operation is templated, therefore it is + not required to specify the exact types upon the construction + */ + struct is_not_greater + { + //! Functor operation + /*! + Compare two operands using > operator + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + return Arg1<=Arg2; + } + }; + + + //! case insensitive version of is_not_greater + /*! + Case insensitive comparison predicate. Comparison is done using + specified locales. + */ + struct is_not_igreater + { + //! Constructor + /*! + \param Loc locales used for comparison + */ + is_not_igreater( const std::locale& Loc=std::locale() ) : + m_Loc( Loc ) {} + + //! Function operator + /*! + Compare two operands. Case is ignored. + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::toupper(Arg1)<=std::toupper(Arg2); + #else + return std::toupper(Arg1,m_Loc)<=std::toupper(Arg2,m_Loc); + #endif + } + + private: + std::locale m_Loc; + }; + + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::is_equal; + using algorithm::is_iequal; + using algorithm::is_less; + using algorithm::is_iless; + using algorithm::is_not_greater; + using algorithm::is_not_igreater; + +} // namespace boost + + +#endif // BOOST_STRING_COMPARE_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/concept.hpp b/3rdParty/Boost/boost/algorithm/string/concept.hpp new file mode 100644 index 0000000..9876e98 --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/concept.hpp @@ -0,0 +1,83 @@ +// Boost string_algo library concept.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_CONCEPT_HPP +#define BOOST_STRING_CONCEPT_HPP + +#include +#include +#include +#include + +/*! \file + Defines concepts used in string_algo library +*/ + +namespace boost { + namespace algorithm { + + //! Finder concept + /*! + Defines the Finder concept. Finder is a functor which selects + an arbitrary part of a string. Search is performed on + the range specified by starting and ending iterators. + + Result of the find operation must be convertible to iterator_range. + */ + template + struct FinderConcept + { + private: + typedef iterator_range range; + public: + void constraints() + { + // Operation + r=(*pF)(i,i); + } + private: + range r; + IteratorT i; + FinderT* pF; + }; // Finder_concept + + + //! Formatter concept + /*! + Defines the Formatter concept. Formatter is a functor, which + takes a result from a finder operation and transforms it + in a specific way. + + Result must be a container supported by container_traits, + or a reference to it. + */ + template + struct FormatterConcept + { + public: + void constraints() + { + // Operation + ::boost::begin((*pFo)( (*pF)(i,i) )); + ::boost::end((*pFo)( (*pF)(i,i) )); + } + private: + IteratorT i; + FinderT* pF; + FormatterT *pFo; + }; // FormatterConcept; + + } // namespace algorithm +} // namespace boost + + + + +#endif // BOOST_STRING_CONCEPT_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/config.hpp b/3rdParty/Boost/boost/algorithm/string/config.hpp new file mode 100644 index 0000000..559750a --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/config.hpp @@ -0,0 +1,28 @@ +// Boost string_algo library config.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_CONFIG_HPP +#define BOOST_STRING_CONFIG_HPP + +#include +#include + +#ifdef BOOST_STRING_DEDUCED_TYPENAME +# error "macro already defined!" +#endif + +#define BOOST_STRING_TYPENAME BOOST_DEDUCED_TYPENAME + +// Metrowerks workaround +#if BOOST_WORKAROUND(__MWERKS__, <= 0x3003) // 8.x +#pragma parse_func_templ off +#endif + +#endif // BOOST_STRING_CONFIG_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/constants.hpp b/3rdParty/Boost/boost/algorithm/string/constants.hpp new file mode 100644 index 0000000..6ed70ef --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/constants.hpp @@ -0,0 +1,36 @@ +// Boost string_algo library constants.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_CONSTANTS_HPP +#define BOOST_STRING_CONSTANTS_HPP + +namespace boost { + namespace algorithm { + + //! Token compression mode + /*! + Specifies token compression mode for the token_finder. + */ + enum token_compress_mode_type + { + token_compress_on, //!< Compress adjacent tokens + token_compress_off //!< Do not compress adjacent tokens + }; + + } // namespace algorithm + + // pull the names to the boost namespace + using algorithm::token_compress_on; + using algorithm::token_compress_off; + +} // namespace boost + +#endif // BOOST_STRING_CONSTANTS_HPP + diff --git a/3rdParty/Boost/boost/algorithm/string/detail/case_conv.hpp b/3rdParty/Boost/boost/algorithm/string/detail/case_conv.hpp new file mode 100644 index 0000000..5253454 --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/detail/case_conv.hpp @@ -0,0 +1,121 @@ +// 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 +#include +#include + +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 + struct to_lowerF : public std::unary_function + { + // Constructor + to_lowerF( const std::locale& Loc ) : m_Loc( Loc ) {} + + // Operation + CharT operator ()( CharT Ch ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::tolower( Ch); + #else + return std::tolower( Ch, m_Loc ); + #endif + } + private: + const std::locale& m_Loc; + }; + + // a toupper functor + template + struct to_upperF : public std::unary_function + { + // Constructor + to_upperF( const std::locale& Loc ) : m_Loc( Loc ) {} + + // Operation + CharT operator ()( CharT Ch ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::toupper( Ch); + #else + return std::toupper( 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 + 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 + void transform_range( + const RangeT& Input, + FunctorT Functor) + { + std::transform( + ::boost::begin(Input), + ::boost::end(Input), + ::boost::begin(Input), + Functor); + } + + template + inline SequenceT transform_range_copy( + const RangeT& Input, + FunctorT Functor) + { + return SequenceT( + make_transform_iterator( + ::boost::begin(Input), + Functor), + make_transform_iterator( + ::boost::end(Input), + Functor)); + } + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_CASE_CONV_DETAIL_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/detail/find_format.hpp b/3rdParty/Boost/boost/algorithm/string/detail/find_format.hpp new file mode 100644 index 0000000..8fb625e --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/detail/find_format.hpp @@ -0,0 +1,193 @@ +// 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 +#include +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// find_format_copy (iterator variant) implementation -------------------------------// + + 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 ) + { + return find_format_copy_impl2( + Output, + Input, + Formatter, + FindResult, + Formatter(FindResult) ); + } + + 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::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 + std::copy( ::boost::begin(Input), ::boost::end(Input), Output ); + return Output; + } + + // Copy the beginning of the sequence + std::copy( ::boost::begin(Input), ::boost::begin(M), Output ); + // Format find result + // Copy formated result + std::copy( ::boost::begin(M.format_result()), ::boost::end(M.format_result()), Output ); + // Copy the rest of the sequence + std::copy( M.end(), ::boost::end(Input), Output ); + + return Output; + } + +// find_format_copy implementation --------------------------------------------------// + + template< + typename InputT, + typename FormatterT, + typename FindResultT > + inline InputT find_format_copy_impl( + const InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult) + { + return find_format_copy_impl2( + Input, + Formatter, + FindResult, + Formatter(FindResult) ); + } + + 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::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 + insert( Output, ::boost::end(Output), ::boost::begin(Input), M.begin() ); + // Copy formated result + insert( Output, ::boost::end(Output), M.format_result() ); + // Copy the rest of the sequence + insert( Output, ::boost::end(Output), M.end(), ::boost::end(Input) ); + + return Output; + } + +// replace implementation ----------------------------------------------------// + + template< + typename InputT, + typename FormatterT, + typename FindResultT > + inline void find_format_impl( + InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult) + { + find_format_impl2( + Input, + Formatter, + FindResult, + Formatter(FindResult) ); + } + + 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::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 + replace( Input, M.begin(), M.end(), M.format_result() ); + } + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FIND_FORMAT_DETAIL_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/detail/find_format_all.hpp b/3rdParty/Boost/boost/algorithm/string/detail/find_format_all.hpp new file mode 100644 index 0000000..9533be6 --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/detail/find_format_all.hpp @@ -0,0 +1,263 @@ +// 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 +#include +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// find_format_all_copy (iterator variant) implementation ---------------------------// + + 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 ) + { + return find_format_all_copy_impl2( + Output, + Input, + Finder, + Formatter, + FindResult, + Formatter(FindResult) ); + } + + 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::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 + std::copy( LastMatch, M.begin(), Output ); + // Copy formated result + 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 + std::copy( LastMatch, ::boost::end(Input), Output ); + + return Output; + } + +// find_format_all_copy implementation ----------------------------------------------// + + 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) + { + return find_format_all_copy_impl2( + Input, + Finder, + Formatter, + FindResult, + Formatter(FindResult) ); + } + + 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::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 + insert( Output, ::boost::end(Output), LastMatch, M.begin() ); + // Copy formated result + 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 + insert( Output, ::boost::end(Output), LastMatch, ::boost::end(Input) ); + + return Output; + } + +// find_format_all implementation ------------------------------------------------// + + template< + typename InputT, + typename FinderT, + typename FormatterT, + typename FindResultT > + inline void find_format_all_impl( + InputT& Input, + FinderT Finder, + FormatterT Formatter, + FindResultT FindResult) + { + find_format_all_impl2( + Input, + Finder, + Formatter, + FindResult, + Formatter(FindResult) ); + } + + 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::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::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 formated replace to the storage + copy_to_storage( Storage, M.format_result() ); + + // Find range for a next match + M=Finder( SearchIt, ::boost::end(Input) ); + } + + // process the last segment + InsertIt=process_segment( + Storage, + Input, + InsertIt, + SearchIt, + ::boost::end(Input) ); + + if ( Storage.empty() ) + { + // Truncate input + erase( Input, InsertIt, ::boost::end(Input) ); + } + else + { + // Copy remaining data to the end of input + insert( Input, ::boost::end(Input), Storage.begin(), Storage.end() ); + } + } + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FIND_FORMAT_ALL_DETAIL_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/detail/find_format_store.hpp b/3rdParty/Boost/boost/algorithm/string/detail/find_format_store.hpp new file mode 100644 index 0000000..2260fc2e --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/detail/find_format_store.hpp @@ -0,0 +1,78 @@ +// 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 +#include + +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 + { + public: + // typedefs + typedef iterator_range 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::operator=(FindResult); + 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; + }; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FIND_FORMAT_STORE_DETAIL_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/detail/finder.hpp b/3rdParty/Boost/boost/algorithm/string/detail/finder.hpp new file mode 100644 index 0000000..c6d0752 --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/detail/finder.hpp @@ -0,0 +1,646 @@ +// Boost string_algo library finder.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_FINDER_DETAIL_HPP +#define BOOST_STRING_FINDER_DETAIL_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + + +// find first functor -----------------------------------------------// + + // find a subsequence in the sequence ( functor ) + /* + Returns a pair marking the subsequence in the sequence. + If the find fails, functor returns + */ + template + struct first_finderF + { + typedef SearchIteratorT search_iterator_type; + + // Construction + template< typename SearchT > + first_finderF( const SearchT& Search, PredicateT Comp ) : + m_Search(::boost::begin(Search), ::boost::end(Search)), m_Comp(Comp) {} + first_finderF( + search_iterator_type SearchBegin, + search_iterator_type SearchEnd, + PredicateT Comp ) : + m_Search(SearchBegin, SearchEnd), m_Comp(Comp) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + typedef iterator_range result_type; + typedef ForwardIteratorT input_iterator_type; + + // Outer loop + for(input_iterator_type OuterIt=Begin; + OuterIt!=End; + ++OuterIt) + { + // Sanity check + if( boost::empty(m_Search) ) + return result_type( End, End ); + + input_iterator_type InnerIt=OuterIt; + search_iterator_type SubstrIt=m_Search.begin(); + for(; + InnerIt!=End && SubstrIt!=m_Search.end(); + ++InnerIt,++SubstrIt) + { + if( !( m_Comp(*InnerIt,*SubstrIt) ) ) + break; + } + + // Substring matching succeeded + if ( SubstrIt==m_Search.end() ) + return result_type( OuterIt, InnerIt ); + } + + return result_type( End, End ); + } + + private: + iterator_range m_Search; + PredicateT m_Comp; + }; + +// find last functor -----------------------------------------------// + + // find the last match a subseqeunce in the sequence ( functor ) + /* + Returns a pair marking the subsequence in the sequence. + If the find fails, returns + */ + template + struct last_finderF + { + typedef SearchIteratorT search_iterator_type; + typedef first_finderF< + search_iterator_type, + PredicateT> first_finder_type; + + // Construction + template< typename SearchT > + last_finderF( const SearchT& Search, PredicateT Comp ) : + m_Search(::boost::begin(Search), ::boost::end(Search)), m_Comp(Comp) {} + last_finderF( + search_iterator_type SearchBegin, + search_iterator_type SearchEnd, + PredicateT Comp ) : + m_Search(SearchBegin, SearchEnd), m_Comp(Comp) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + typedef iterator_range result_type; + + if( boost::empty(m_Search) ) + return result_type( End, End ); + + typedef BOOST_STRING_TYPENAME boost::detail:: + iterator_traits::iterator_category category; + + return findit( Begin, End, category() ); + } + + private: + // forward iterator + template< typename ForwardIteratorT > + iterator_range + findit( + ForwardIteratorT Begin, + ForwardIteratorT End, + std::forward_iterator_tag ) const + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + first_finder_type first_finder( + m_Search.begin(), m_Search.end(), m_Comp ); + + result_type M=first_finder( Begin, End ); + result_type Last=M; + + while( M ) + { + Last=M; + M=first_finder( ::boost::end(M), End ); + } + + return Last; + } + + // bidirectional iterator + template< typename ForwardIteratorT > + iterator_range + findit( + ForwardIteratorT Begin, + ForwardIteratorT End, + std::bidirectional_iterator_tag ) const + { + typedef iterator_range result_type; + typedef ForwardIteratorT input_iterator_type; + + // Outer loop + for(input_iterator_type OuterIt=End; + OuterIt!=Begin; ) + { + input_iterator_type OuterIt2=--OuterIt; + + input_iterator_type InnerIt=OuterIt2; + search_iterator_type SubstrIt=m_Search.begin(); + for(; + InnerIt!=End && SubstrIt!=m_Search.end(); + ++InnerIt,++SubstrIt) + { + if( !( m_Comp(*InnerIt,*SubstrIt) ) ) + break; + } + + // Substring matching succeeded + if( SubstrIt==m_Search.end() ) + return result_type( OuterIt2, InnerIt ); + } + + return result_type( End, End ); + } + + private: + iterator_range m_Search; + PredicateT m_Comp; + }; + +// find n-th functor -----------------------------------------------// + + // find the n-th match of a subsequence in the sequence ( functor ) + /* + Returns a pair marking the subsequence in the sequence. + If the find fails, returns + */ + template + struct nth_finderF + { + typedef SearchIteratorT search_iterator_type; + typedef first_finderF< + search_iterator_type, + PredicateT> first_finder_type; + typedef last_finderF< + search_iterator_type, + PredicateT> last_finder_type; + + // Construction + template< typename SearchT > + nth_finderF( + const SearchT& Search, + int Nth, + PredicateT Comp) : + m_Search(::boost::begin(Search), ::boost::end(Search)), + m_Nth(Nth), + m_Comp(Comp) {} + nth_finderF( + search_iterator_type SearchBegin, + search_iterator_type SearchEnd, + int Nth, + PredicateT Comp) : + m_Search(SearchBegin, SearchEnd), + m_Nth(Nth), + m_Comp(Comp) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + if(m_Nth>=0) + { + return find_forward(Begin, End, m_Nth); + } + else + { + return find_backward(Begin, End, -m_Nth); + } + + } + + private: + // Implementation helpers + template< typename ForwardIteratorT > + iterator_range + find_forward( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N) const + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + // Sanity check + if( boost::empty(m_Search) ) + return result_type( End, End ); + + // Instantiate find functor + first_finder_type first_finder( + m_Search.begin(), m_Search.end(), m_Comp ); + + result_type M( Begin, Begin ); + + for( unsigned int n=0; n<=N; ++n ) + { + // find next match + M=first_finder( ::boost::end(M), End ); + + if ( !M ) + { + // Subsequence not found, return + return M; + } + } + + return M; + } + + template< typename ForwardIteratorT > + iterator_range + find_backward( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N) const + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + // Sanity check + if( boost::empty(m_Search) ) + return result_type( End, End ); + + // Instantiate find functor + last_finder_type last_finder( + m_Search.begin(), m_Search.end(), m_Comp ); + + result_type M( End, End ); + + for( unsigned int n=1; n<=N; ++n ) + { + // find next match + M=last_finder( Begin, ::boost::begin(M) ); + + if ( !M ) + { + // Subsequence not found, return + return M; + } + } + + return M; + } + + + private: + iterator_range m_Search; + int m_Nth; + PredicateT m_Comp; + }; + +// find head/tail implementation helpers ---------------------------// + + template + iterator_range + find_head_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::forward_iterator_tag ) + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + input_iterator_type It=Begin; + for( + unsigned int Index=0; + Index + iterator_range + find_head_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::random_access_iterator_tag ) + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + if ( (End<=Begin) || ( static_cast(End-Begin) < N ) ) + return result_type( Begin, End ); + + return result_type(Begin,Begin+N); + } + + // Find head implementation + template + iterator_range + find_head_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N ) + { + typedef BOOST_STRING_TYPENAME boost::detail:: + iterator_traits::iterator_category category; + + return find_head_impl( Begin, End, N, category() ); + } + + template< typename ForwardIteratorT > + iterator_range + find_tail_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::forward_iterator_tag ) + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + unsigned int Index=0; + input_iterator_type It=Begin; + input_iterator_type It2=Begin; + + // Advance It2 by N increments + for( Index=0; Index + iterator_range + find_tail_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::bidirectional_iterator_tag ) + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + input_iterator_type It=End; + for( + unsigned int Index=0; + Index + iterator_range + find_tail_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::random_access_iterator_tag ) + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + if ( (End<=Begin) || ( static_cast(End-Begin) < N ) ) + return result_type( Begin, End ); + + return result_type( End-N, End ); + } + + // Operation + template< typename ForwardIteratorT > + iterator_range + find_tail_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N ) + { + typedef BOOST_STRING_TYPENAME boost::detail:: + iterator_traits::iterator_category category; + + return find_tail_impl( Begin, End, N, category() ); + } + + + +// find head functor -----------------------------------------------// + + + // find a head in the sequence ( functor ) + /* + This functor find a head of the specified range. For + a specified N, the head is a subsequence of N starting + elements of the range. + */ + struct head_finderF + { + // Construction + head_finderF( int N ) : m_N(N) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + if(m_N>=0) + { + return find_head_impl( Begin, End, m_N ); + } + else + { + iterator_range Res= + find_tail_impl( Begin, End, -m_N ); + + return make_iterator_range(Begin, Res.begin()); + } + } + + private: + int m_N; + }; + +// find tail functor -----------------------------------------------// + + + // find a tail in the sequence ( functor ) + /* + This functor find a tail of the specified range. For + a specified N, the head is a subsequence of N starting + elements of the range. + */ + struct tail_finderF + { + // Construction + tail_finderF( int N ) : m_N(N) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + if(m_N>=0) + { + return find_tail_impl( Begin, End, m_N ); + } + else + { + iterator_range Res= + find_head_impl( Begin, End, -m_N ); + + return make_iterator_range(Res.end(), End); + } + } + + private: + int m_N; + }; + +// find token functor -----------------------------------------------// + + // find a token in a sequence ( functor ) + /* + This find functor finds a token specified be a predicate + in a sequence. It is equivalent of std::find algorithm, + with an exception that it return range instead of a single + iterator. + + If bCompress is set to true, adjacent matching tokens are + concatenated into one match. + */ + template< typename PredicateT > + struct token_finderF + { + // Construction + token_finderF( + PredicateT Pred, + token_compress_mode_type eCompress=token_compress_off ) : + m_Pred(Pred), m_eCompress(eCompress) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + typedef iterator_range result_type; + + ForwardIteratorT It=std::find_if( Begin, End, m_Pred ); + + if( It==End ) + { + return result_type( End, End ); + } + else + { + ForwardIteratorT It2=It; + + if( m_eCompress==token_compress_on ) + { + // Find first non-matching character + while( It2!=End && m_Pred(*It2) ) ++It2; + } + else + { + // Advance by one position + ++It2; + } + + return result_type( It, It2 ); + } + } + + private: + PredicateT m_Pred; + token_compress_mode_type m_eCompress; + }; + +// find range functor -----------------------------------------------// + + // find a range in the sequence ( functor ) + /* + This functor actually does not perform any find operation. + It always returns given iterator range as a result. + */ + template + struct range_finderF + { + typedef ForwardIterator1T input_iterator_type; + typedef iterator_range result_type; + + // Construction + range_finderF( + input_iterator_type Begin, + input_iterator_type End ) : m_Range(Begin, End) {} + + range_finderF(const iterator_range& Range) : + m_Range(Range) {} + + // Operation + template< typename ForwardIterator2T > + iterator_range + operator()( + ForwardIterator2T, + ForwardIterator2T ) const + { +#if BOOST_WORKAROUND( __MWERKS__, <= 0x3003 ) + return iterator_range(this->m_Range); +#elif BOOST_WORKAROUND(BOOST_MSVC, <= 1300) + return iterator_range(m_Range.begin(), m_Range.end()); +#else + return m_Range; +#endif + } + + private: + iterator_range m_Range; + }; + + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FINDER_DETAIL_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/detail/formatter.hpp b/3rdParty/Boost/boost/algorithm/string/detail/formatter.hpp new file mode 100644 index 0000000..bd6a780 --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/detail/formatter.hpp @@ -0,0 +1,94 @@ +// 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 +#include +#include +#include + +#include + +// generic replace functors -----------------------------------------------// + +namespace boost { + namespace algorithm { + namespace detail { + +// const format functor ----------------------------------------------------// + + // constant format functor + template + struct const_formatF + { + private: + typedef BOOST_STRING_TYPENAME + range_const_iterator::type format_iterator; + typedef iterator_range result_type; + + public: + // Construction + const_formatF(const RangeT& Format) : + m_Format(::boost::begin(Format), ::boost::end(Format)) {} + + // Operation +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + template + result_type& operator()(const Range2T&) + { + return m_Format; + } +#endif + + template + const result_type& operator()(const Range2T&) const + { + return m_Format; + } + + private: + result_type m_Format; + }; + +// identity format functor ----------------------------------------------------// + + // identity format functor + template + 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 operator()(const ReplaceT&) const + { + return empty_container(); + } + }; + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FORMATTER_DETAIL_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/detail/replace_storage.hpp b/3rdParty/Boost/boost/algorithm/string/detail/replace_storage.hpp new file mode 100644 index 0000000..7aff247 --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/detail/replace_storage.hpp @@ -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 +#include +#include +#include +#include + +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=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 + 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::value>()( + Storage, Input, InsertIt, SegmentBegin, SegmentEnd ); + } + + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_REPLACE_STORAGE_DETAIL_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/detail/sequence.hpp b/3rdParty/Boost/boost/algorithm/string/detail/sequence.hpp new file mode 100644 index 0000000..de01350 --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/detail/sequence.hpp @@ -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 +#include +#include +#include +#include + +#include + +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 ) + { + 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, + has_const_time_erase >::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::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) + { + replace( Input, From, To, ::boost::begin(Insert), ::boost::end(Insert) ); + } + else + { + insert( Input, From, ::boost::begin(Insert), ::boost::end(Insert) ); + } + } + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_DETAIL_SEQUENCE_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/detail/util.hpp b/3rdParty/Boost/boost/algorithm/string/detail/util.hpp new file mode 100644 index 0000000..7e8471f --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/detail/util.hpp @@ -0,0 +1,106 @@ +// Boost string_algo library util.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_UTIL_DETAIL_HPP +#define BOOST_STRING_UTIL_DETAIL_HPP + +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// empty container -----------------------------------------------// + + // empty_container + /* + This class represents always empty container, + containing elements of type CharT. + + It is supposed to be used in a const version only + */ + template< typename CharT > + struct empty_container + { + typedef empty_container type; + typedef CharT value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef const value_type& reference; + typedef const value_type& const_reference; + typedef const value_type* iterator; + typedef const value_type* const_iterator; + + + // Operations + const_iterator begin() const + { + return reinterpret_cast(0); + } + + const_iterator end() const + { + return reinterpret_cast(0); + } + + bool empty() const + { + return false; + } + + size_type size() const + { + return 0; + } + }; + +// bounded copy algorithm -----------------------------------------------// + + // Bounded version of the std::copy algorithm + template + inline OutputIteratorT bounded_copy( + InputIteratorT First, + InputIteratorT Last, + OutputIteratorT DestFirst, + OutputIteratorT DestLast ) + { + InputIteratorT InputIt=First; + OutputIteratorT OutputIt=DestFirst; + for(; InputIt!=Last && OutputIt!=DestLast; InputIt++, OutputIt++ ) + { + *OutputIt=*InputIt; + } + + return OutputIt; + } + +// iterator range utilities -----------------------------------------// + + // copy range functor + template< + typename SeqT, + typename IteratorT=BOOST_STRING_TYPENAME SeqT::const_iterator > + struct copy_iterator_rangeF : + public std::unary_function< iterator_range, SeqT > + { + SeqT operator()( const iterator_range& Range ) const + { + return copy_range(Range); + } + }; + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_UTIL_DETAIL_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/erase.hpp b/3rdParty/Boost/boost/algorithm/string/erase.hpp new file mode 100644 index 0000000..b50323b --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/erase.hpp @@ -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 + +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \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 + inline OutputIteratorT erase_range_copy( + OutputIteratorT Output, + const RangeT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_const_iterator::type>& SearchRange ) + { + return find_format_copy( + Output, + Input, + range_finder(SearchRange), + empty_formatter(Input) ); + } + + //! Erase range algorithm + /*! + \overload + */ + template + inline SequenceT erase_range_copy( + const SequenceT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_const_iterator::type>& SearchRange ) + { + return find_format_copy( + Input, + range_finder(SearchRange), + 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 + inline void erase_range( + SequenceT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_iterator::type>& SearchRange ) + { + find_format( + Input, + range_finder(SearchRange), + 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 find_format_copy( + Output, + Input, + first_finder(Search), + empty_formatter(Input) ); + } + + //! Erase first algorithm + /*! + \overload + */ + template + inline SequenceT erase_first_copy( + const SequenceT& Input, + const RangeT& Search ) + { + return find_format_copy( + Input, + first_finder(Search), + 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 + inline void erase_first( + SequenceT& Input, + const RangeT& Search ) + { + find_format( + Input, + first_finder(Search), + 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 find_format_copy( + Output, + Input, + first_finder(Search, is_iequal(Loc)), + empty_formatter(Input) ); + } + + //! Erase first algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ierase_first_copy( + const SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + return find_format_copy( + Input, + first_finder(Search, is_iequal(Loc)), + 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 + inline void ierase_first( + SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + find_format( + Input, + first_finder(Search, is_iequal(Loc)), + 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 find_format_copy( + Output, + Input, + last_finder(Search), + empty_formatter(Input) ); + } + + //! Erase last algorithm + /*! + \overload + */ + template + inline SequenceT erase_last_copy( + const SequenceT& Input, + const RangeT& Search ) + { + return find_format_copy( + Input, + last_finder(Search), + 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 + inline void erase_last( + SequenceT& Input, + const RangeT& Search ) + { + find_format( + Input, + last_finder(Search), + 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 find_format_copy( + Output, + Input, + last_finder(Search, is_iequal(Loc)), + empty_formatter(Input) ); + } + + //! Erase last algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ierase_last_copy( + const SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + return find_format_copy( + Input, + last_finder(Search, is_iequal(Loc)), + 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 + inline void ierase_last( + SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + find_format( + Input, + last_finder(Search, is_iequal(Loc)), + 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 find_format_copy( + Output, + Input, + nth_finder(Search, Nth), + empty_formatter(Input) ); + } + + //! Erase nth algorithm + /*! + \overload + */ + template + inline SequenceT erase_nth_copy( + const SequenceT& Input, + const RangeT& Search, + int Nth ) + { + return find_format_copy( + Input, + nth_finder(Search, Nth), + 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 + inline void erase_nth( + SequenceT& Input, + const RangeT& Search, + int Nth ) + { + find_format( + Input, + nth_finder(Search, Nth), + 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 find_format_copy( + Output, + Input, + nth_finder(Search, Nth, is_iequal(Loc)), + empty_formatter(Input) ); + } + + //! Erase nth algorithm + /*! + \overload + */ + template + inline SequenceT ierase_nth_copy( + const SequenceT& Input, + const RangeT& Search, + int Nth, + const std::locale& Loc=std::locale() ) + { + return find_format_copy( + Input, + 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 + inline void ierase_nth( + SequenceT& Input, + const RangeT& Search, + int Nth, + const std::locale& Loc=std::locale() ) + { + find_format( + Input, + nth_finder(Search, Nth, is_iequal(Loc)), + 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 find_format_all_copy( + Output, + Input, + first_finder(Search), + empty_formatter(Input) ); + } + + //! Erase all algorithm + /*! + \overload + */ + template + inline SequenceT erase_all_copy( + const SequenceT& Input, + const RangeT& Search ) + { + return find_format_all_copy( + Input, + first_finder(Search), + 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 + inline void erase_all( + SequenceT& Input, + const RangeT& Search ) + { + find_format_all( + Input, + first_finder(Search), + 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 find_format_all_copy( + Output, + Input, + first_finder(Search, is_iequal(Loc)), + empty_formatter(Input) ); + } + + //! Erase all algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ierase_all_copy( + const SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + return find_format_all_copy( + Input, + first_finder(Search, is_iequal(Loc)), + 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 + inline void ierase_all( + SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + find_format_all( + Input, + first_finder(Search, is_iequal(Loc)), + 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 find_format_copy( + Output, + Input, + head_finder(N), + empty_formatter( Input ) ); + } + + //! Erase head algorithm + /*! + \overload + */ + template + inline SequenceT erase_head_copy( + const SequenceT& Input, + int N ) + { + return find_format_copy( + Input, + head_finder(N), + 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 + inline void erase_head( + SequenceT& Input, + int N ) + { + find_format( + Input, + head_finder(N), + 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 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_tail_copy( + OutputIteratorT Output, + const RangeT& Input, + int N ) + { + return find_format_copy( + Output, + Input, + tail_finder(N), + empty_formatter( Input ) ); + } + + //! Erase tail algorithm + /*! + \overload + */ + template + inline SequenceT erase_tail_copy( + const SequenceT& Input, + int N ) + { + return find_format_copy( + Input, + tail_finder(N), + 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 head + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + */ + template + inline void erase_tail( + SequenceT& Input, + int N ) + { + find_format( + Input, + tail_finder(N), + 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 diff --git a/3rdParty/Boost/boost/algorithm/string/find_format.hpp b/3rdParty/Boost/boost/algorithm/string/find_format.hpp new file mode 100644 index 0000000..7cbaf34 --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/find_format.hpp @@ -0,0 +1,269 @@ +// 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \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 + function_requires< + FinderConcept::type> >(); + function_requires< + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> >(); + + iterator_range::type> lit_input(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 + function_requires< + FinderConcept::type> >(); + function_requires< + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::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 + function_requires< + FinderConcept::type> >(); + function_requires< + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::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 + function_requires< + FinderConcept::type> >(); + function_requires< + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> >(); + + iterator_range::type> lit_input(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 + function_requires< + FinderConcept::type> >(); + function_requires< + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::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 + function_requires< + FinderConcept::type> >(); + function_requires< + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::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 diff --git a/3rdParty/Boost/boost/algorithm/string/finder.hpp b/3rdParty/Boost/boost/algorithm/string/finder.hpp new file mode 100644 index 0000000..c936ddb --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/finder.hpp @@ -0,0 +1,270 @@ +// Boost string_algo library finder.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_FINDER_HPP +#define BOOST_STRING_FINDER_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file + Defines Finder generators. Finder object is a functor which is able to + find a substring matching a specific criteria in the input. + Finders are used as a pluggable components for replace, find + and split facilities. This header contains generator functions + for finders provided in this library. +*/ + +namespace boost { + namespace algorithm { + +// Finder generators ------------------------------------------// + + //! "First" finder + /*! + Construct the \c first_finder. The finder searches for the first + occurrence of the string in a given input. + The result is given as an \c iterator_range delimiting the match. + + \param Search A substring to be searched for. + \param Comp An element comparison predicate + \return An instance of the \c first_finder object + */ + template + inline detail::first_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + is_equal> + first_finder( const RangeT& Search ) + { + return + detail::first_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + is_equal>( as_literal(Search), is_equal() ) ; + } + + //! "First" finder + /*! + \overload + */ + template + inline detail::first_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + PredicateT> + first_finder( + const RangeT& Search, PredicateT Comp ) + { + return + detail::first_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + PredicateT>( as_literal(Search), Comp ); + } + + //! "Last" finder + /*! + Construct the \c last_finder. The finder searches for the last + occurrence of the string in a given input. + The result is given as an \c iterator_range delimiting the match. + + \param Search A substring to be searched for. + \param Comp An element comparison predicate + \return An instance of the \c last_finder object + */ + template + inline detail::last_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + is_equal> + last_finder( const RangeT& Search ) + { + return + detail::last_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + is_equal>( as_literal(Search), is_equal() ); + } + //! "Last" finder + /*! + \overload + */ + template + inline detail::last_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + PredicateT> + last_finder( const RangeT& Search, PredicateT Comp ) + { + return + detail::last_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + PredicateT>( as_literal(Search), Comp ) ; + } + + //! "Nth" finder + /*! + Construct the \c nth_finder. The finder searches for the n-th (zero-indexed) + occurrence of the string in a given input. + The result is given as an \c iterator_range delimiting the match. + + \param Search A substring to be searched for. + \param Nth An index of the match to be find + \param Comp An element comparison predicate + \return An instance of the \c nth_finder object + */ + template + inline detail::nth_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + is_equal> + nth_finder( + const RangeT& Search, + int Nth) + { + return + detail::nth_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + is_equal>( as_literal(Search), Nth, is_equal() ) ; + } + //! "Nth" finder + /*! + \overload + */ + template + inline detail::nth_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + PredicateT> + nth_finder( + const RangeT& Search, + int Nth, + PredicateT Comp ) + { + return + detail::nth_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + PredicateT>( as_literal(Search), Nth, Comp ); + } + + //! "Head" finder + /*! + Construct the \c head_finder. The finder returns a head of a given + input. The head is a prefix of a string up to n elements in + size. If an input has less then n elements, whole input is + considered a head. + The result is given as an \c iterator_range delimiting the match. + + \param N The size of the head + \return An instance of the \c head_finder object + */ + inline detail::head_finderF + head_finder( int N ) + { + return detail::head_finderF(N); + } + + //! "Tail" finder + /*! + Construct the \c tail_finder. The finder returns a tail of a given + input. The tail is a suffix of a string up to n elements in + size. If an input has less then n elements, whole input is + considered a head. + The result is given as an \c iterator_range delimiting the match. + + \param N The size of the head + \return An instance of the \c tail_finder object + */ + inline detail::tail_finderF + tail_finder( int N ) + { + return detail::tail_finderF(N); + } + + //! "Token" finder + /*! + Construct the \c token_finder. The finder searches for a token + specified by a predicate. It is similar to std::find_if + algorithm, with an exception that it return a range of + instead of a single iterator. + + If "compress token mode" is enabled, adjacent matching tokens are + concatenated into one match. Thus the finder can be used to + search for continuous segments of characters satisfying the + given predicate. + + The result is given as an \c iterator_range delimiting the match. + + \param Pred An element selection predicate + \param eCompress Compress flag + \return An instance of the \c token_finder object + */ + template< typename PredicateT > + inline detail::token_finderF + token_finder( + PredicateT Pred, + token_compress_mode_type eCompress=token_compress_off ) + { + return detail::token_finderF( Pred, eCompress ); + } + + //! "Range" finder + /*! + Construct the \c range_finder. The finder does not perform + any operation. It simply returns the given range for + any input. + + \param Begin Beginning of the range + \param End End of the range + \param Range The range. + \return An instance of the \c range_finger object + */ + template< typename ForwardIteratorT > + inline detail::range_finderF + range_finder( + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + return detail::range_finderF( Begin, End ); + } + + //! "Range" finder + /*! + \overload + */ + template< typename ForwardIteratorT > + inline detail::range_finderF + range_finder( iterator_range Range ) + { + return detail::range_finderF( Range ); + } + + } // namespace algorithm + + // pull the names to the boost namespace + using algorithm::first_finder; + using algorithm::last_finder; + using algorithm::nth_finder; + using algorithm::head_finder; + using algorithm::tail_finder; + using algorithm::token_finder; + using algorithm::range_finder; + +} // namespace boost + + +#endif // BOOST_STRING_FINDER_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/formatter.hpp b/3rdParty/Boost/boost/algorithm/string/formatter.hpp new file mode 100644 index 0000000..e04a50f --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/formatter.hpp @@ -0,0 +1,103 @@ +// 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 +#include +#include +#include + +#include + +/*! \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 + /*! + Construct the \c const_formatter. Const formatter always returns + the same value, regardless of the parameter. + + \param Format A predefined value used as a result for formating + \return An instance of the \c const_formatter object. + */ + template + inline detail::const_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> > + const_formatter(const RangeT& Format) + { + return detail::const_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> >(as_literal(Format)); + } + + //! Identity formatter + /*! + Construct the \c identity_formatter. Identity formatter always returns + the parameter. + + \return An instance of the \c identity_formatter object. + */ + template + inline detail::identity_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> > + identity_formatter() + { + return detail::identity_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> >(); + } + + //! Empty formatter + /*! + Construct the \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 + inline detail::empty_formatF< + BOOST_STRING_TYPENAME range_value::type> + empty_formatter(const RangeT&) + { + return detail::empty_formatF< + BOOST_STRING_TYPENAME range_value::type>(); + } + + + } // namespace algorithm + + // pull the names to the boost namespace + using algorithm::const_formatter; + using algorithm::identity_formatter; + using algorithm::empty_formatter; + +} // namespace boost + + +#endif // BOOST_FORMATTER_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/replace.hpp b/3rdParty/Boost/boost/algorithm/string/replace.hpp new file mode 100644 index 0000000..1c59ec7 --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/replace.hpp @@ -0,0 +1,928 @@ +// 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 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/*! \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::type>& SearchRange, + const Range2T& Format) + { + return find_format_copy( + Output, + Input, + range_finder(SearchRange), + const_formatter(Format)); + } + + //! Replace range algorithm + /*! + \overload + */ + template + inline SequenceT replace_range_copy( + const SequenceT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_const_iterator::type>& SearchRange, + const RangeT& Format) + { + return find_format_copy( + Input, + range_finder(SearchRange), + 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 + inline void replace_range( + SequenceT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_iterator::type>& SearchRange, + const RangeT& Format) + { + find_format( + Input, + range_finder(SearchRange), + 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 find_format_copy( + Output, + Input, + first_finder(Search), + const_formatter(Format) ); + } + + //! Replace first algorithm + /*! + \overload + */ + template + inline SequenceT replace_first_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + return find_format_copy( + Input, + first_finder(Search), + 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 + inline void replace_first( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + find_format( + Input, + first_finder(Search), + 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 find_format_copy( + Output, + Input, + first_finder(Search, is_iequal(Loc)), + const_formatter(Format) ); + } + + //! Replace first algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ireplace_first_copy( + const SequenceT& Input, + const Range2T& Search, + const Range1T& Format, + const std::locale& Loc=std::locale() ) + { + return find_format_copy( + Input, + first_finder(Search, is_iequal(Loc)), + 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 + inline void ireplace_first( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + find_format( + Input, + first_finder(Search, is_iequal(Loc)), + 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 find_format_copy( + Output, + Input, + last_finder(Search), + const_formatter(Format) ); + } + + //! Replace last algorithm + /*! + \overload + */ + template + inline SequenceT replace_last_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + return find_format_copy( + Input, + last_finder(Search), + 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 + inline void replace_last( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + find_format( + Input, + last_finder(Search), + 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 find_format_copy( + Output, + Input, + last_finder(Search, is_iequal(Loc)), + const_formatter(Format) ); + } + + //! Replace last algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ireplace_last_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + return find_format_copy( + Input, + last_finder(Search, is_iequal(Loc)), + 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 + \return A reference to the modified input + */ + template + inline void ireplace_last( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + find_format( + Input, + last_finder(Search, is_iequal(Loc)), + 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 find_format_copy( + Output, + Input, + nth_finder(Search, Nth), + const_formatter(Format) ); + } + + //! Replace nth algorithm + /*! + \overload + */ + template + inline SequenceT replace_nth_copy( + const SequenceT& Input, + const Range1T& Search, + int Nth, + const Range2T& Format ) + { + return find_format_copy( + Input, + nth_finder(Search, Nth), + 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 + inline void replace_nth( + SequenceT& Input, + const Range1T& Search, + int Nth, + const Range2T& Format ) + { + find_format( + Input, + nth_finder(Search, Nth), + 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 find_format_copy( + Output, + Input, + nth_finder(Search, Nth, is_iequal(Loc) ), + const_formatter(Format) ); + } + + //! Replace nth algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ireplace_nth_copy( + const SequenceT& Input, + const Range1T& Search, + int Nth, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + return find_format_copy( + Input, + nth_finder(Search, Nth, is_iequal(Loc)), + 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 + inline void ireplace_nth( + SequenceT& Input, + const Range1T& Search, + int Nth, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + find_format( + Input, + nth_finder(Search, Nth, is_iequal(Loc)), + 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 find_format_all_copy( + Output, + Input, + first_finder(Search), + const_formatter(Format) ); + } + + //! Replace all algorithm + /*! + \overload + */ + template + inline SequenceT replace_all_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + return find_format_all_copy( + Input, + first_finder(Search), + 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 + \return A reference to the modified input + */ + template + inline void replace_all( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + find_format_all( + Input, + first_finder(Search), + 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 find_format_all_copy( + Output, + Input, + first_finder(Search, is_iequal(Loc)), + const_formatter(Format) ); + } + + //! Replace all algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ireplace_all_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + return find_format_all_copy( + Input, + first_finder(Search, is_iequal(Loc)), + 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 + inline void ireplace_all( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + find_format_all( + Input, + first_finder(Search, is_iequal(Loc)), + 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 find_format_copy( + Output, + Input, + head_finder(N), + const_formatter(Format) ); + } + + //! Replace head algorithm + /*! + \overload + */ + template + inline SequenceT replace_head_copy( + const SequenceT& Input, + int N, + const RangeT& Format ) + { + return find_format_copy( + Input, + head_finder(N), + 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 + inline void replace_head( + SequenceT& Input, + int N, + const RangeT& Format ) + { + find_format( + Input, + head_finder(N), + 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 find_format_copy( + Output, + Input, + tail_finder(N), + const_formatter(Format) ); + } + + //! Replace tail algorithm + /*! + \overload + */ + template + inline SequenceT replace_tail_copy( + const SequenceT& Input, + int N, + const RangeT& Format ) + { + return find_format_copy( + Input, + tail_finder(N), + 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 + inline void replace_tail( + SequenceT& Input, + int N, + const RangeT& Format ) + { + find_format( + Input, + tail_finder(N), + 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 diff --git a/3rdParty/Boost/boost/algorithm/string/sequence_traits.hpp b/3rdParty/Boost/boost/algorithm/string/sequence_traits.hpp new file mode 100644 index 0000000..b1ac67e --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/sequence_traits.hpp @@ -0,0 +1,193 @@ +// 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 +#include +#include + +/*! \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 -----------------------------------------------// + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + + //! Native replace tester + /*! + Declare an override of this tester function with return + type boost::string_algo::yes_type for a sequence with this property. + + \return yes_type if the container has basic_string like native replace + method. + */ + no_type has_native_replace_tester(...); + + //! Stable iterators tester + /*! + Declare an override of this tester function with return + type boost::string_algo::yes_type for a sequence with this property. + + \return yes_type if the sequence's insert/replace/erase methods do not invalidate + existing iterators. + */ + no_type has_stable_iterators_tester(...); + + //! const time insert tester + /*! + Declare an override of this tester function with return + type boost::string_algo::yes_type for a sequence with this property. + + \return yes_type if the sequence's insert method is working in constant time + */ + no_type has_const_time_insert_tester(...); + + //! const time erase tester + /*! + Declare an override of this tester function with return + type boost::string_algo::yes_type for a sequence with this property. + + \return yes_type if the sequence's erase method is working in constant time + */ + no_type has_const_time_erase_tester(...); + +#endif //BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + + //! Native replace trait + /*! + This trait specifies that the sequence has \c std::string like replace method + */ + template< typename T > + class has_native_replace + { + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + private: + static T* t; + public: + BOOST_STATIC_CONSTANT(bool, value=( + sizeof(has_native_replace_tester(t))==sizeof(yes_type) ) ); +#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + public: +# if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = false }; +# else + BOOST_STATIC_CONSTANT(bool, value=false); +# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) +#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + + + typedef mpl::bool_::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 + { +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + private: + static T* t; + public: + BOOST_STATIC_CONSTANT(bool, value=( + sizeof(has_stable_iterators_tester(t))==sizeof(yes_type) ) ); +#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + public: +# if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = false }; +# else + BOOST_STATIC_CONSTANT(bool, value=false); +# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) +#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + + typedef mpl::bool_::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 + { +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + private: + static T* t; + public: + BOOST_STATIC_CONSTANT(bool, value=( + sizeof(has_const_time_insert_tester(t))==sizeof(yes_type) ) ); +#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + public: +# if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = false }; +# else + BOOST_STATIC_CONSTANT(bool, value=false); +# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) +#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + + typedef mpl::bool_::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 + { +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + private: + static T* t; + public: + BOOST_STATIC_CONSTANT(bool, value=( + sizeof(has_const_time_erase_tester(t))==sizeof(yes_type) ) ); +#else // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + public: +# if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = false }; +# else + BOOST_STATIC_CONSTANT(bool, value=false); +# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) +#endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + + typedef mpl::bool_::value> type; + }; + + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_SEQUENCE_TRAITS_HPP diff --git a/3rdParty/Boost/boost/algorithm/string/yes_no_type.hpp b/3rdParty/Boost/boost/algorithm/string/yes_no_type.hpp new file mode 100644 index 0000000..b76cc6c --- /dev/null +++ b/3rdParty/Boost/boost/algorithm/string/yes_no_type.hpp @@ -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 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 diff --git a/3rdParty/Boost/boost/aligned_storage.hpp b/3rdParty/Boost/boost/aligned_storage.hpp new file mode 100644 index 0000000..cfaf787 --- /dev/null +++ b/3rdParty/Boost/boost/aligned_storage.hpp @@ -0,0 +1,170 @@ +//----------------------------------------------------------------------------- +// boost aligned_storage.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002-2003 +// Eric Friedman, Itay Maman +// +// 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_ALIGNED_STORAGE_HPP +#define BOOST_ALIGNED_STORAGE_HPP + +#include // for std::size_t + +#include "boost/config.hpp" +#include "boost/detail/workaround.hpp" +#include "boost/type_traits/alignment_of.hpp" +#include "boost/type_traits/type_with_alignment.hpp" +#include "boost/type_traits/is_pod.hpp" + +#include "boost/mpl/eval_if.hpp" +#include "boost/mpl/identity.hpp" + +#include "boost/type_traits/detail/bool_trait_def.hpp" + +namespace boost { + +namespace detail { namespace aligned_storage { + +BOOST_STATIC_CONSTANT( + std::size_t + , alignment_of_max_align = ::boost::alignment_of::value + ); + +// +// To be TR1 conforming this must be a POD type: +// +template < + std::size_t size_ + , std::size_t alignment_ +> +struct aligned_storage_imp +{ + union data_t + { + char buf[size_]; + + typename mpl::eval_if_c< + alignment_ == std::size_t(-1) + , mpl::identity + , type_with_alignment + >::type align_; + } data_; +}; + +}} // namespace detail::aligned_storage + +template < + std::size_t size_ + , std::size_t alignment_ = std::size_t(-1) +> +class aligned_storage +{ +private: // representation + + detail::aligned_storage::aligned_storage_imp data_; + +public: // constants + + typedef detail::aligned_storage::aligned_storage_imp type; + + BOOST_STATIC_CONSTANT( + std::size_t + , size = size_ + ); + BOOST_STATIC_CONSTANT( + std::size_t + , alignment = ( + alignment_ == std::size_t(-1) + ? ::boost::detail::aligned_storage::alignment_of_max_align + : alignment_ + ) + ); + +#if defined(__GNUC__) &&\ + (__GNUC__ > 3) ||\ + (__GNUC__ == 3 && (__GNUC_MINOR__ > 2 ||\ + (__GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ >=3))) + +private: // noncopyable + + aligned_storage(const aligned_storage&); + aligned_storage& operator=(const aligned_storage&); + +#else // gcc less than 3.2.3 + +public: // _should_ be noncopyable, but GCC compiler emits error + + aligned_storage(const aligned_storage&); + aligned_storage& operator=(const aligned_storage&); + +#endif // gcc < 3.2.3 workaround + +public: // structors + + aligned_storage() + { + } + + ~aligned_storage() + { + } + +public: // accessors + + void* address() + { + return this; + } + +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) + + const void* address() const + { + return this; + } + +#else // MSVC6 + + const void* address() const; + +#endif // MSVC6 workaround + +}; + +#if BOOST_WORKAROUND(BOOST_MSVC, < 1300) + +// MSVC6 seems not to like inline functions with const void* returns, so we +// declare the following here: + +template +const void* aligned_storage::address() const +{ + return const_cast< aligned_storage* >(this)->address(); +} + +#endif // MSVC6 workaround + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +// +// Make sure that is_pod recognises aligned_storage<>::type +// as a POD (Note that aligned_storage<> itself is not a POD): +// +template +struct is_pod > + BOOST_TT_AUX_BOOL_C_BASE(true) +{ + BOOST_TT_AUX_BOOL_TRAIT_VALUE_DECL(true) +}; +#endif + + +} // namespace boost + +#include "boost/type_traits/detail/bool_trait_undef.hpp" + +#endif // BOOST_ALIGNED_STORAGE_HPP diff --git a/3rdParty/Boost/boost/any.hpp b/3rdParty/Boost/boost/any.hpp new file mode 100644 index 0000000..47773dc --- /dev/null +++ b/3rdParty/Boost/boost/any.hpp @@ -0,0 +1,237 @@ +// See http://www.boost.org/libs/any for Documentation. + +#ifndef BOOST_ANY_INCLUDED +#define BOOST_ANY_INCLUDED + +// what: variant type boost::any +// who: contributed by Kevlin Henney, +// with features contributed and bugs found by +// Ed Brey, Mark Rodgers, Peter Dimov, and James Curran +// when: July 2001 +// where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95 + +#include +#include + +#include "boost/config.hpp" +#include +#include +#include +#include + +namespace boost +{ + class any + { + public: // structors + + any() + : content(0) + { + } + + template + any(const ValueType & value) + : content(new holder(value)) + { + } + + any(const any & other) + : content(other.content ? other.content->clone() : 0) + { + } + + ~any() + { + delete content; + } + + public: // modifiers + + any & swap(any & rhs) + { + std::swap(content, rhs.content); + return *this; + } + + template + any & operator=(const ValueType & rhs) + { + any(rhs).swap(*this); + return *this; + } + + any & operator=(any rhs) + { + rhs.swap(*this); + return *this; + } + + public: // queries + + bool empty() const + { + return !content; + } + + const std::type_info & type() const + { + return content ? content->type() : typeid(void); + } + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + private: // types +#else + public: // types (public so any_cast can be non-friend) +#endif + + class placeholder + { + public: // structors + + virtual ~placeholder() + { + } + + public: // queries + + virtual const std::type_info & type() const = 0; + + virtual placeholder * clone() const = 0; + + }; + + template + class holder : public placeholder + { + public: // structors + + holder(const ValueType & value) + : held(value) + { + } + + public: // queries + + virtual const std::type_info & type() const + { + return typeid(ValueType); + } + + virtual placeholder * clone() const + { + return new holder(held); + } + + public: // representation + + ValueType held; + + private: // intentionally left unimplemented + holder & operator=(const holder &); + }; + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + + private: // representation + + template + friend ValueType * any_cast(any *); + + template + friend ValueType * unsafe_any_cast(any *); + +#else + + public: // representation (public so any_cast can be non-friend) + +#endif + + placeholder * content; + + }; + + class bad_any_cast : public std::bad_cast + { + public: + virtual const char * what() const throw() + { + return "boost::bad_any_cast: " + "failed conversion using boost::any_cast"; + } + }; + + template + ValueType * any_cast(any * operand) + { + return operand && operand->type() == typeid(ValueType) + ? &static_cast *>(operand->content)->held + : 0; + } + + template + inline const ValueType * any_cast(const any * operand) + { + return any_cast(const_cast(operand)); + } + + template + ValueType any_cast(any & operand) + { + typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + // If 'nonref' is still reference type, it means the user has not + // specialized 'remove_reference'. + + // Please use BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION macro + // to generate specialization of remove_reference for your class + // See type traits library documentation for details + BOOST_STATIC_ASSERT(!is_reference::value); +#endif + + nonref * result = any_cast(&operand); + if(!result) + boost::throw_exception(bad_any_cast()); + return *result; + } + + template + inline ValueType any_cast(const any & operand) + { + typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + // The comment in the above version of 'any_cast' explains when this + // assert is fired and what to do. + BOOST_STATIC_ASSERT(!is_reference::value); +#endif + + return any_cast(const_cast(operand)); + } + + // Note: The "unsafe" versions of any_cast are not part of the + // public interface and may be removed at any time. They are + // required where we know what type is stored in the any and can't + // use typeid() comparison, e.g., when our types may travel across + // different shared libraries. + template + inline ValueType * unsafe_any_cast(any * operand) + { + return &static_cast *>(operand->content)->held; + } + + template + inline const ValueType * unsafe_any_cast(const any * operand) + { + return unsafe_any_cast(const_cast(operand)); + } +} + +// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. +// +// 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) + +#endif diff --git a/3rdParty/Boost/boost/array.hpp b/3rdParty/Boost/boost/array.hpp new file mode 100644 index 0000000..52218aa --- /dev/null +++ b/3rdParty/Boost/boost/array.hpp @@ -0,0 +1,321 @@ +/* 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) + * + * 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 +#include +#include + +// Handles broken standard libraries better than +#include +#include +#include + +// FIXES for broken compilers +#include + + +namespace boost { + + template + 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; } + iterator end() { return elems+N; } + const_iterator end() const { return elems+N; } + + // reverse iterator support +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS) + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#elif defined(_MSC_VER) && (_MSC_VER == 1300) && defined(BOOST_DINKUMWARE_STDLIB) && (BOOST_DINKUMWARE_STDLIB == 310) + // workaround for broken reverse_iterator in VC7 + typedef std::reverse_iterator > reverse_iterator; + typedef std::reverse_iterator > const_reverse_iterator; +#else + // workaround for broken reverse_iterator implementations + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#endif + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + + // operator[] + reference operator[](size_type i) + { + BOOST_ASSERT( i < N && "out of range" ); + return elems[i]; + } + + const_reference operator[](size_type i) const + { + BOOST_ASSERT( i < N && "out of range" ); + return elems[i]; + } + + // at() with range check + reference at(size_type i) { rangecheck(i); return elems[i]; } + const_reference at(size_type i) const { rangecheck(i); return elems[i]; } + + // front() and back() + reference front() + { + return elems[0]; + } + + const_reference front() const + { + return elems[0]; + } + + reference back() + { + return elems[N-1]; + } + + const_reference back() const + { + return elems[N-1]; + } + + // size is constant + static size_type size() { return N; } + static bool empty() { return false; } + static size_type max_size() { return N; } + enum { static_size = N }; + + // swap (note: linear complexity) + void swap (array& y) { + std::swap_ranges(begin(),end(),y.begin()); + } + + // 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 + array& operator= (const array& rhs) { + std::copy(rhs.begin(),rhs.end(), begin()); + return *this; + } + + // assign one value to all elements + void assign (const T& value) + { + std::fill_n(begin(),size(),value); + } + + // check range (may be private because it is static) + static void rangecheck (size_type i) { + if (i >= size()) { + throw std::out_of_range("array<>: index out of range"); + } + } + + }; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + 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 ) ); } + iterator end() { return begin(); } + const_iterator end() const { return begin(); } + + // reverse iterator support +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS) + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#elif defined(_MSC_VER) && (_MSC_VER == 1300) && defined(BOOST_DINKUMWARE_STDLIB) && (BOOST_DINKUMWARE_STDLIB == 310) + // workaround for broken reverse_iterator in VC7 + typedef std::reverse_iterator > reverse_iterator; + typedef std::reverse_iterator > const_reverse_iterator; +#else + // workaround for broken reverse_iterator implementations + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#endif + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + + // operator[] + reference operator[](size_type i) + { + return failed_rangecheck(); + } + + const_reference operator[](size_type i) const + { + return failed_rangecheck(); + } + + // at() with range check + reference at(size_type i) { return failed_rangecheck(); } + const_reference at(size_type i) const { return failed_rangecheck(); } + + // front() and back() + reference front() + { + return failed_rangecheck(); + } + + const_reference front() const + { + return failed_rangecheck(); + } + + reference back() + { + return failed_rangecheck(); + } + + const_reference back() const + { + return failed_rangecheck(); + } + + // size is constant + static size_type size() { return 0; } + static bool empty() { return true; } + static size_type max_size() { return 0; } + enum { static_size = 0 }; + + void swap (array& 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 + array& operator= (const array& ) { + return *this; + } + + // assign one value to all elements + void assign (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); + // + // 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 + bool operator== (const array& x, const array& y) { + return std::equal(x.begin(), x.end(), y.begin()); + } + template + bool operator< (const array& x, const array& y) { + return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end()); + } + template + bool operator!= (const array& x, const array& y) { + return !(x==y); + } + template + bool operator> (const array& x, const array& y) { + return y + bool operator<= (const array& x, const array& y) { + return !(y + bool operator>= (const array& x, const array& y) { + return !(x + inline void swap (array& x, array& y) { + x.swap(y); + } + +} /* namespace boost */ + +#endif /*BOOST_ARRAY_HPP*/ diff --git a/3rdParty/Boost/boost/asio.hpp b/3rdParty/Boost/boost/asio.hpp new file mode 100644 index 0000000..5d8b43b --- /dev/null +++ b/3rdParty/Boost/boost/asio.hpp @@ -0,0 +1,100 @@ +// +// asio.hpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2008 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // BOOST_ASIO_HPP diff --git a/3rdParty/Boost/boost/asio/basic_datagram_socket.hpp b/3rdParty/Boost/boost/asio/basic_datagram_socket.hpp new file mode 100644 index 0000000..8fa870b --- /dev/null +++ b/3rdParty/Boost/boost/asio/basic_datagram_socket.hpp @@ -0,0 +1,805 @@ +// +// basic_datagram_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_DATAGRAM_SOCKET_HPP +#define BOOST_ASIO_BASIC_DATAGRAM_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace boost { +namespace asio { + +/// Provides datagram-oriented socket functionality. +/** + * The basic_datagram_socket class template provides asynchronous and blocking + * datagram-oriented socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template > +class basic_datagram_socket + : public basic_socket +{ +public: + /// The native representation of a socket. + typedef typename DatagramSocketService::native_type native_type; + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_datagram_socket without opening it. + /** + * This constructor creates a datagram socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param io_service The io_service object that the datagram socket will use + * to dispatch handlers for any asynchronous operations performed on the + * socket. + */ + explicit basic_datagram_socket(boost::asio::io_service& io_service) + : basic_socket(io_service) + { + } + + /// Construct and open a basic_datagram_socket. + /** + * This constructor creates and opens a datagram socket. + * + * @param io_service The io_service object that the datagram socket will use + * 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_datagram_socket(boost::asio::io_service& io_service, + const protocol_type& protocol) + : basic_socket(io_service, protocol) + { + } + + /// Construct a basic_datagram_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a datagram 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 io_service The io_service object that the datagram socket will use + * to dispatch handlers for any asynchronous operations performed on the + * socket. + * + * @param endpoint An endpoint on the local machine to which the datagram + * socket will be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_datagram_socket(boost::asio::io_service& io_service, + const endpoint_type& endpoint) + : basic_socket(io_service, endpoint) + { + } + + /// Construct a basic_datagram_socket on an existing native socket. + /** + * This constructor creates a datagram socket object to hold an existing + * native socket. + * + * @param io_service The io_service object that the datagram socket will use + * 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_datagram_socket(boost::asio::io_service& io_service, + const protocol_type& protocol, const native_type& native_socket) + : basic_socket( + io_service, protocol, native_socket) + { + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an error + * occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected datagram socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code socket.send(boost::asio::buffer(data, size)); @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 + std::size_t send(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->service.send(this->implementation, buffers, 0, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an error + * occurs. + * + * @param buffers One ore 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. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected datagram socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->service.send( + this->implementation, buffers, flags, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an 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. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected datagram socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return this->service.send(this->implementation, buffers, flags, ec); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an error + * occurs. + * + * @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 handler is called. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected datagram + * socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(boost::asio::buffer(data, size), 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. + */ + template + void async_send(const ConstBufferSequence& buffers, WriteHandler handler) + { + this->service.async_send(this->implementation, buffers, 0, handler); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an error + * occurs. + * + * @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 handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected datagram + * socket. + */ + template + void async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, WriteHandler handler) + { + this->service.async_send(this->implementation, buffers, flags, handler); + } + + /// Send a datagram to the specified endpoint. + /** + * This function is used to send a datagram to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @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 + * boost::asio::ip::udp::endpoint destination( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.send_to(boost::asio::buffer(data, size), destination); + * @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 + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination) + { + boost::system::error_code ec; + std::size_t s = this->service.send_to( + this->implementation, buffers, destination, 0, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Send a datagram to the specified endpoint. + /** + * This function is used to send a datagram to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @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. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->service.send_to( + this->implementation, buffers, destination, flags, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Send a datagram to the specified endpoint. + /** + * This function is used to send a datagram to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @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. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + boost::system::error_code& ec) + { + return this->service.send_to(this->implementation, + buffers, destination, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send a datagram to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * 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 handler is called. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * boost::asio::ip::udp::endpoint destination( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.async_send_to( + * boost::asio::buffer(data, size), destination, 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. + */ + template + void async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, WriteHandler handler) + { + this->service.async_send_to(this->implementation, buffers, destination, 0, + handler); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send a datagram to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * 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 handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + */ + template + void async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + WriteHandler handler) + { + this->service.async_send_to(this->implementation, buffers, destination, + flags, handler); + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the datagram socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected datagram + * socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.receive(boost::asio::buffer(data, size)); @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 + std::size_t receive(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->service.receive( + this->implementation, buffers, 0, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the datagram socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected datagram + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->service.receive( + this->implementation, buffers, flags, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the datagram socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected datagram + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return this->service.receive(this->implementation, buffers, flags, ec); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the datagram + * socket. The function call 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 handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * datagram socket. + * + * @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), 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. + */ + template + void async_receive(const MutableBufferSequence& buffers, ReadHandler handler) + { + this->service.async_receive(this->implementation, buffers, 0, handler); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the datagram + * socket. The function call 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 handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * datagram socket. + */ + template + void async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, ReadHandler handler) + { + this->service.async_receive(this->implementation, buffers, flags, handler); + } + + /// Receive a datagram with the endpoint of the sender. + /** + * This function is used to receive a datagram. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * boost::asio::ip::udp::endpoint sender_endpoint; + * socket.receive_from( + * boost::asio::buffer(data, size), sender_endpoint); + * @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 + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint) + { + boost::system::error_code ec; + std::size_t s = this->service.receive_from( + this->implementation, buffers, sender_endpoint, 0, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Receive a datagram with the endpoint of the sender. + /** + * This function is used to receive a datagram. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->service.receive_from( + this->implementation, buffers, sender_endpoint, flags, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Receive a datagram with the endpoint of the sender. + /** + * This function is used to receive a datagram. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + boost::system::error_code& ec) + { + return this->service.receive_from(this->implementation, buffers, + sender_endpoint, flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive a datagram. The function + * call 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 handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.async_receive_from( + * boost::asio::buffer(data, size), 0, sender_endpoint, 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. + */ + template + void async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, ReadHandler handler) + { + this->service.async_receive_from(this->implementation, buffers, + sender_endpoint, 0, handler); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive a datagram. The function + * call 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 handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + */ + template + void async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + ReadHandler handler) + { + this->service.async_receive_from(this->implementation, buffers, + sender_endpoint, flags, handler); + } +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_DATAGRAM_SOCKET_HPP diff --git a/3rdParty/Boost/boost/asio/basic_deadline_timer.hpp b/3rdParty/Boost/boost/asio/basic_deadline_timer.hpp new file mode 100644 index 0000000..65256b8 --- /dev/null +++ b/3rdParty/Boost/boost/asio/basic_deadline_timer.hpp @@ -0,0 +1,383 @@ +// +// basic_deadline_timer.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 + +#include +#include +#include +#include + +#include +#include +#include +#include + +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. + * + * 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(io_service); + * + * // 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(io_service, + * 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 TimerService = deadline_timer_service > +class basic_deadline_timer + : public basic_io_object +{ +public: + /// 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 io_service The io_service object that the timer will use to dispatch + * handlers for any asynchronous operations performed on the timer. + */ + explicit basic_deadline_timer(boost::asio::io_service& io_service) + : basic_io_object(io_service) + { + } + + /// Constructor to set a particular expiry time as an absolute time. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param io_service The io_service object that the timer will use 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(boost::asio::io_service& io_service, + const time_type& expiry_time) + : basic_io_object(io_service) + { + boost::system::error_code ec; + this->service.expires_at(this->implementation, expiry_time, ec); + boost::asio::detail::throw_error(ec); + } + + /// Constructor to set a particular expiry time relative to now. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param io_service The io_service object that the timer will use 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(boost::asio::io_service& io_service, + const duration_type& expiry_time) + : basic_io_object(io_service) + { + boost::system::error_code ec; + this->service.expires_from_now(this->implementation, expiry_time, ec); + boost::asio::detail::throw_error(ec); + } + + /// 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. + */ + std::size_t cancel() + { + boost::system::error_code ec; + std::size_t s = this->service.cancel(this->implementation, ec); + boost::asio::detail::throw_error(ec); + 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. + */ + std::size_t cancel(boost::system::error_code& ec) + { + return this->service.cancel(this->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 this->service.expires_at(this->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. + */ + std::size_t expires_at(const time_type& expiry_time) + { + boost::system::error_code ec; + std::size_t s = this->service.expires_at( + this->implementation, expiry_time, ec); + boost::asio::detail::throw_error(ec); + 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. + */ + std::size_t expires_at(const time_type& expiry_time, + boost::system::error_code& ec) + { + return this->service.expires_at(this->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 this->service.expires_from_now(this->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. + */ + std::size_t expires_from_now(const duration_type& expiry_time) + { + boost::system::error_code ec; + std::size_t s = this->service.expires_from_now( + this->implementation, expiry_time, ec); + boost::asio::detail::throw_error(ec); + 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. + */ + std::size_t expires_from_now(const duration_type& expiry_time, + boost::system::error_code& ec) + { + return this->service.expires_from_now( + this->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; + this->service.wait(this->implementation, ec); + boost::asio::detail::throw_error(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. + * + * @param ec Set to indicate what error occurred, if any. + */ + void wait(boost::system::error_code& ec) + { + this->service.wait(this->implementation, ec); + } + + /// Start an asynchronous wait on the timer. + /** + * This function may be used to initiate an asynchronous wait against the + * timer. It always returns immediately. + * + * For each call to async_wait(), the supplied handler will be called exactly + * once. The 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 handler The handler to be called when the timer expires. Copies + * will be made of the handler as required. The function signature of the + * 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + */ + template + void async_wait(WaitHandler handler) + { + this->service.async_wait(this->implementation, handler); + } +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_DEADLINE_TIMER_HPP diff --git a/3rdParty/Boost/boost/asio/basic_io_object.hpp b/3rdParty/Boost/boost/asio/basic_io_object.hpp new file mode 100644 index 0000000..1cbf9bb --- /dev/null +++ b/3rdParty/Boost/boost/asio/basic_io_object.hpp @@ -0,0 +1,99 @@ +// +// basic_io_object.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 + +#include +#include + +namespace boost { +namespace asio { + +/// Base class for all I/O objects. +template +class basic_io_object + : private noncopyable +{ +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; + + /// (Deprecated: use get_io_service().) Get the io_service associated with + /// the object. + /** + * This function may be used to obtain the io_service object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_service object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_service& io_service() + { + return service.get_io_service(); + } + + /// Get the io_service associated with the object. + /** + * This function may be used to obtain the io_service object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_service object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_service& get_io_service() + { + return service.get_io_service(); + } + +protected: + /// Construct a basic_io_object. + /** + * Performs: + * @code service.construct(implementation); @endcode + */ + explicit basic_io_object(boost::asio::io_service& io_service) + : service(boost::asio::use_service(io_service)) + { + service.construct(implementation); + } + + /// Protected destructor to prevent deletion through this type. + /** + * Performs: + * @code service.destroy(implementation); @endcode + */ + ~basic_io_object() + { + service.destroy(implementation); + } + + /// The service associated with the I/O object. + service_type& service; + + /// The underlying implementation of the I/O object. + implementation_type implementation; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_IO_OBJECT_HPP diff --git a/3rdParty/Boost/boost/asio/basic_raw_socket.hpp b/3rdParty/Boost/boost/asio/basic_raw_socket.hpp new file mode 100644 index 0000000..1ba5558 --- /dev/null +++ b/3rdParty/Boost/boost/asio/basic_raw_socket.hpp @@ -0,0 +1,800 @@ +// +// basic_raw_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_RAW_SOCKET_HPP +#define BOOST_ASIO_BASIC_RAW_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace boost { +namespace asio { + +/// Provides raw-oriented socket functionality. +/** + * The basic_raw_socket class template provides asynchronous and blocking + * raw-oriented socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template > +class basic_raw_socket + : public basic_socket +{ +public: + /// The native representation of a socket. + typedef typename RawSocketService::native_type native_type; + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_raw_socket without opening it. + /** + * This constructor creates a raw socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param io_service The io_service object that the raw socket will use + * to dispatch handlers for any asynchronous operations performed on the + * socket. + */ + explicit basic_raw_socket(boost::asio::io_service& io_service) + : basic_socket(io_service) + { + } + + /// Construct and open a basic_raw_socket. + /** + * This constructor creates and opens a raw socket. + * + * @param io_service The io_service object that the raw socket will use + * 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_raw_socket(boost::asio::io_service& io_service, + const protocol_type& protocol) + : basic_socket(io_service, protocol) + { + } + + /// Construct a basic_raw_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a raw 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 io_service The io_service object that the raw socket will use + * to dispatch handlers for any asynchronous operations performed on the + * socket. + * + * @param endpoint An endpoint on the local machine to which the raw + * socket will be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_raw_socket(boost::asio::io_service& io_service, + const endpoint_type& endpoint) + : basic_socket(io_service, endpoint) + { + } + + /// Construct a basic_raw_socket on an existing native socket. + /** + * This constructor creates a raw socket object to hold an existing + * native socket. + * + * @param io_service The io_service object that the raw socket will use + * 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_raw_socket(boost::asio::io_service& io_service, + const protocol_type& protocol, const native_type& native_socket) + : basic_socket( + io_service, protocol, native_socket) + { + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected raw socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code socket.send(boost::asio::buffer(data, size)); @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 + std::size_t send(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->service.send(this->implementation, buffers, 0, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One ore 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. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected raw socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->service.send( + this->implementation, buffers, flags, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an 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. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected raw socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return this->service.send(this->implementation, buffers, flags, ec); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @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 handler is called. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected raw + * socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(boost::asio::buffer(data, size), 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. + */ + template + void async_send(const ConstBufferSequence& buffers, WriteHandler handler) + { + this->service.async_send(this->implementation, buffers, 0, handler); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @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 handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected raw + * socket. + */ + template + void async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, WriteHandler handler) + { + this->service.async_send(this->implementation, buffers, flags, handler); + } + + /// Send raw data to the specified endpoint. + /** + * This function is used to send raw data to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @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 + * boost::asio::ip::udp::endpoint destination( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.send_to(boost::asio::buffer(data, size), destination); + * @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 + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination) + { + boost::system::error_code ec; + std::size_t s = this->service.send_to( + this->implementation, buffers, destination, 0, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Send raw data to the specified endpoint. + /** + * This function is used to send raw data to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @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. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->service.send_to( + this->implementation, buffers, destination, flags, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Send raw data to the specified endpoint. + /** + * This function is used to send raw data to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @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. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + boost::system::error_code& ec) + { + return this->service.send_to(this->implementation, + buffers, destination, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send raw data to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * 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 handler is called. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * boost::asio::ip::udp::endpoint destination( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.async_send_to( + * boost::asio::buffer(data, size), destination, 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. + */ + template + void async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, WriteHandler handler) + { + this->service.async_send_to(this->implementation, buffers, destination, 0, + handler); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send raw data to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * 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 handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + */ + template + void async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + WriteHandler handler) + { + this->service.async_send_to(this->implementation, buffers, destination, + flags, handler); + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the raw socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected raw + * socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.receive(boost::asio::buffer(data, size)); @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 + std::size_t receive(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->service.receive( + this->implementation, buffers, 0, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the raw socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected raw + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->service.receive( + this->implementation, buffers, flags, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the raw socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected raw + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return this->service.receive(this->implementation, buffers, flags, ec); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the raw + * socket. The function call 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 handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * raw socket. + * + * @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), 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. + */ + template + void async_receive(const MutableBufferSequence& buffers, ReadHandler handler) + { + this->service.async_receive(this->implementation, buffers, 0, handler); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the raw + * socket. The function call 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 handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * raw socket. + */ + template + void async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, ReadHandler handler) + { + this->service.async_receive(this->implementation, buffers, flags, handler); + } + + /// Receive raw data with the endpoint of the sender. + /** + * This function is used to receive raw data. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * boost::asio::ip::udp::endpoint sender_endpoint; + * socket.receive_from( + * boost::asio::buffer(data, size), sender_endpoint); + * @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 + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint) + { + boost::system::error_code ec; + std::size_t s = this->service.receive_from( + this->implementation, buffers, sender_endpoint, 0, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Receive raw data with the endpoint of the sender. + /** + * This function is used to receive raw data. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->service.receive_from( + this->implementation, buffers, sender_endpoint, flags, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Receive raw data with the endpoint of the sender. + /** + * This function is used to receive raw data. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + boost::system::error_code& ec) + { + return this->service.receive_from(this->implementation, buffers, + sender_endpoint, flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive raw data. The function + * call 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 handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.async_receive_from( + * boost::asio::buffer(data, size), 0, sender_endpoint, 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. + */ + template + void async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, ReadHandler handler) + { + this->service.async_receive_from(this->implementation, buffers, + sender_endpoint, 0, handler); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive raw data. The function + * call 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 handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + */ + template + void async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + ReadHandler handler) + { + this->service.async_receive_from(this->implementation, buffers, + sender_endpoint, flags, handler); + } +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_RAW_SOCKET_HPP diff --git a/3rdParty/Boost/boost/asio/basic_serial_port.hpp b/3rdParty/Boost/boost/asio/basic_serial_port.hpp new file mode 100644 index 0000000..339d5df --- /dev/null +++ b/3rdParty/Boost/boost/asio/basic_serial_port.hpp @@ -0,0 +1,624 @@ +// +// basic_serial_port.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ + || defined(GENERATING_DOCUMENTATION) + +namespace boost { +namespace asio { + +/// Provides serial port functionality. +/** + * The basic_serial_port class template provides functionality that is common + * to all serial ports. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_serial_port + : public basic_io_object, + public serial_port_base +{ +public: + /// The native representation of a serial port. + typedef typename SerialPortService::native_type native_type; + + /// A 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 io_service The io_service object that the serial port will use to + * dispatch handlers for any asynchronous operations performed on the port. + */ + explicit basic_serial_port(boost::asio::io_service& io_service) + : basic_io_object(io_service) + { + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param io_service The io_service object that the serial port will use to + * dispatch handlers for any asynchronous operations performed on the port. + * + * @param device The platform-specific device name for this serial + * port. + */ + explicit basic_serial_port(boost::asio::io_service& io_service, + const char* device) + : basic_io_object(io_service) + { + boost::system::error_code ec; + this->service.open(this->implementation, device, ec); + boost::asio::detail::throw_error(ec); + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param io_service The io_service object that the serial port will use to + * dispatch handlers for any asynchronous operations performed on the port. + * + * @param device The platform-specific device name for this serial + * port. + */ + explicit basic_serial_port(boost::asio::io_service& io_service, + const std::string& device) + : basic_io_object(io_service) + { + boost::system::error_code ec; + this->service.open(this->implementation, device, ec); + boost::asio::detail::throw_error(ec); + } + + /// 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 io_service The io_service object that the serial port will use to + * dispatch handlers for any asynchronous operations performed on the port. + * + * @param native_serial_port A native serial port. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_serial_port(boost::asio::io_service& io_service, + const native_type& native_serial_port) + : basic_io_object(io_service) + { + boost::system::error_code ec; + this->service.assign(this->implementation, native_serial_port, ec); + boost::asio::detail::throw_error(ec); + } + + /// 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; + this->service.open(this->implementation, device, ec); + boost::asio::detail::throw_error(ec); + } + + /// 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::system::error_code open(const std::string& device, + boost::system::error_code& ec) + { + return this->service.open(this->implementation, device, 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_type& native_serial_port) + { + boost::system::error_code ec; + this->service.assign(this->implementation, native_serial_port, ec); + boost::asio::detail::throw_error(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. + * + * @param ec Set to indicate what error occurred, if any. + */ + boost::system::error_code assign(const native_type& native_serial_port, + boost::system::error_code& ec) + { + return this->service.assign(this->implementation, native_serial_port, ec); + } + + /// Determine whether the serial port is open. + bool is_open() const + { + return this->service.is_open(this->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; + this->service.close(this->implementation, ec); + boost::asio::detail::throw_error(ec); + } + + /// 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::system::error_code close(boost::system::error_code& ec) + { + return this->service.close(this->implementation, 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_type native() + { + return this->service.native(this->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; + this->service.cancel(this->implementation, ec); + boost::asio::detail::throw_error(ec); + } + + /// 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::system::error_code cancel(boost::system::error_code& ec) + { + return this->service.cancel(this->implementation, 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; + this->service.send_break(this->implementation, ec); + boost::asio::detail::throw_error(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. + * + * @param ec Set to indicate what error occurred, if any. + */ + boost::system::error_code send_break(boost::system::error_code& ec) + { + return this->service.send_break(this->implementation, 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 + void set_option(const SettableSerialPortOption& option) + { + boost::system::error_code ec; + this->service.set_option(this->implementation, option, ec); + boost::asio::detail::throw_error(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. + * + * @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 + boost::system::error_code set_option(const SettableSerialPortOption& option, + boost::system::error_code& ec) + { + return this->service.set_option(this->implementation, option, 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 + void get_option(GettableSerialPortOption& option) + { + boost::system::error_code ec; + this->service.get_option(this->implementation, option, ec); + boost::asio::detail::throw_error(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. + * + * @param ec Set to indicate what error occured, 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 + boost::system::error_code get_option(GettableSerialPortOption& option, + boost::system::error_code& ec) + { + return this->service.get_option(this->implementation, option, 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 + * 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 + std::size_t write_some(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->service.write_some(this->implementation, buffers, ec); + boost::asio::detail::throw_error(ec); + 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 + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->service.write_some(this->implementation, buffers, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the serial port. + * The function call 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 handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @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 + * 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. + */ + template + void async_write_some(const ConstBufferSequence& buffers, + WriteHandler handler) + { + this->service.async_write_some(this->implementation, buffers, handler); + } + + /// 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 + * 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 + std::size_t read_some(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->service.read_some(this->implementation, buffers, ec); + boost::asio::detail::throw_error(ec); + 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 + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->service.read_some(this->implementation, buffers, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the serial port. + * The function call 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 handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @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 + * 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. + */ + template + void async_read_some(const MutableBufferSequence& buffers, + ReadHandler handler) + { + this->service.async_read_some(this->implementation, buffers, handler); + } +}; + +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + // || defined(GENERATING_DOCUMENTATION) + +#include + +#endif // BOOST_ASIO_BASIC_SERIAL_PORT_HPP diff --git a/3rdParty/Boost/boost/asio/basic_socket.hpp b/3rdParty/Boost/boost/asio/basic_socket.hpp new file mode 100644 index 0000000..c991132 --- /dev/null +++ b/3rdParty/Boost/boost/asio/basic_socket.hpp @@ -0,0 +1,1065 @@ +// +// basic_socket.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_HPP +#define BOOST_ASIO_BASIC_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace boost { +namespace asio { + +/// Provides socket functionality. +/** + * The basic_socket class template provides functionality that is common to both + * stream-oriented and datagram-oriented sockets. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_socket + : public basic_io_object, + public socket_base +{ +public: + /// The native representation of a socket. + typedef typename SocketService::native_type native_type; + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// A basic_socket is always the lowest layer. + typedef basic_socket lowest_layer_type; + + /// Construct a basic_socket without opening it. + /** + * This constructor creates a socket without opening it. + * + * @param io_service The io_service object that the socket will use to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_socket(boost::asio::io_service& io_service) + : basic_io_object(io_service) + { + } + + /// Construct and open a basic_socket. + /** + * This constructor creates and opens a socket. + * + * @param io_service The io_service object that the socket will use 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_socket(boost::asio::io_service& io_service, + const protocol_type& protocol) + : basic_io_object(io_service) + { + boost::system::error_code ec; + this->service.open(this->implementation, protocol, ec); + boost::asio::detail::throw_error(ec); + } + + /// Construct a basic_socket, opening it and binding it to the given local + /// endpoint. + /** + * This constructor creates a 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 io_service The io_service object that the socket will use to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_socket(boost::asio::io_service& io_service, + const endpoint_type& endpoint) + : basic_io_object(io_service) + { + boost::system::error_code ec; + this->service.open(this->implementation, endpoint.protocol(), ec); + boost::asio::detail::throw_error(ec); + this->service.bind(this->implementation, endpoint, ec); + boost::asio::detail::throw_error(ec); + } + + /// Construct a basic_socket on an existing native socket. + /** + * This constructor creates a socket object to hold an existing native socket. + * + * @param io_service The io_service object that the socket will use to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket A native socket. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_socket(boost::asio::io_service& io_service, + const protocol_type& protocol, const native_type& native_socket) + : basic_io_object(io_service) + { + boost::system::error_code ec; + this->service.assign(this->implementation, protocol, native_socket, ec); + boost::asio::detail::throw_error(ec); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since a basic_socket 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_socket 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 socket using the specified protocol. + /** + * This function opens the socket so that it will use the specified protocol. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * socket.open(boost::asio::ip::tcp::v4()); + * @endcode + */ + void open(const protocol_type& protocol = protocol_type()) + { + boost::system::error_code ec; + this->service.open(this->implementation, protocol, ec); + boost::asio::detail::throw_error(ec); + } + + /// Open the socket using the specified protocol. + /** + * This function opens the socket so that it will use the specified protocol. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * boost::system::error_code ec; + * socket.open(boost::asio::ip::tcp::v4(), ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + boost::system::error_code open(const protocol_type& protocol, + boost::system::error_code& ec) + { + return this->service.open(this->implementation, protocol, ec); + } + + /// Assign an existing native socket to the socket. + /* + * This function opens the socket to hold an existing native socket. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_socket A native socket. + * + * @throws boost::system::system_error Thrown on failure. + */ + void assign(const protocol_type& protocol, const native_type& native_socket) + { + boost::system::error_code ec; + this->service.assign(this->implementation, protocol, native_socket, ec); + boost::asio::detail::throw_error(ec); + } + + /// Assign an existing native socket to the socket. + /* + * This function opens the socket to hold an existing native socket. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_socket A native socket. + * + * @param ec Set to indicate what error occurred, if any. + */ + boost::system::error_code assign(const protocol_type& protocol, + const native_type& native_socket, boost::system::error_code& ec) + { + return this->service.assign(this->implementation, + protocol, native_socket, ec); + } + + /// Determine whether the socket is open. + bool is_open() const + { + return this->service.is_open(this->implementation); + } + + /// Close the socket. + /** + * This function is used to close the socket. Any asynchronous send, receive + * or connect 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 For portable behaviour with respect to graceful closure of a + * connected socket, call shutdown() before closing the socket. + */ + void close() + { + boost::system::error_code ec; + this->service.close(this->implementation, ec); + boost::asio::detail::throw_error(ec); + } + + /// Close the socket. + /** + * This function is used to close the socket. Any asynchronous send, receive + * or connect 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. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * ... + * boost::system::error_code ec; + * socket.close(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + * + * @note For portable behaviour with respect to graceful closure of a + * connected socket, call shutdown() before closing the socket. + */ + boost::system::error_code close(boost::system::error_code& ec) + { + return this->service.close(this->implementation, ec); + } + + /// Get the native socket representation. + /** + * This function may be used to obtain the underlying representation of the + * socket. This is intended to allow access to native socket functionality + * that is not otherwise provided. + */ + native_type native() + { + return this->service.native(this->implementation); + } + + /// Cancel all asynchronous operations associated with the socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * 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 one of the following + * alternatives: + * + * @li Disable asio's I/O completion port backend by defining + * BOOST_ASIO_DISABLE_IOCP. + * + * @li Use the close() function to simultaneously cancel the outstanding + * operations and close the socket. + * + * 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_MSVC) && (BOOST_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; + this->service.cancel(this->implementation, ec); + boost::asio::detail::throw_error(ec); + } + + /// Cancel all asynchronous operations associated with the socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * 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 one of the following + * alternatives: + * + * @li Disable asio's I/O completion port backend by defining + * BOOST_ASIO_DISABLE_IOCP. + * + * @li Use the close() function to simultaneously cancel the outstanding + * operations and close the socket. + * + * 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_MSVC) && (BOOST_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::system::error_code cancel(boost::system::error_code& ec) + { + return this->service.cancel(this->implementation, ec); + } + + /// Determine whether the socket is at the out-of-band data mark. + /** + * This function is used to check whether the socket input is currently + * positioned at the out-of-band data mark. + * + * @return A bool indicating whether the socket is at the out-of-band data + * mark. + * + * @throws boost::system::system_error Thrown on failure. + */ + bool at_mark() const + { + boost::system::error_code ec; + bool b = this->service.at_mark(this->implementation, ec); + boost::asio::detail::throw_error(ec); + return b; + } + + /// Determine whether the socket is at the out-of-band data mark. + /** + * This function is used to check whether the socket input is currently + * positioned at the out-of-band data mark. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return A bool indicating whether the socket is at the out-of-band data + * mark. + */ + bool at_mark(boost::system::error_code& ec) const + { + return this->service.at_mark(this->implementation, ec); + } + + /// Determine the number of bytes available for reading. + /** + * This function is used to determine the number of bytes that may be read + * without blocking. + * + * @return The number of bytes that may be read without blocking, or 0 if an + * error occurs. + * + * @throws boost::system::system_error Thrown on failure. + */ + std::size_t available() const + { + boost::system::error_code ec; + std::size_t s = this->service.available(this->implementation, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Determine the number of bytes available for reading. + /** + * This function is used to determine the number of bytes that may be read + * without blocking. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of bytes that may be read without blocking, or 0 if an + * error occurs. + */ + std::size_t available(boost::system::error_code& ec) const + { + return this->service.available(this->implementation, ec); + } + + /// Bind the socket to the given local endpoint. + /** + * This function binds the socket to the specified endpoint on the local + * machine. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * socket.open(boost::asio::ip::tcp::v4()); + * socket.bind(boost::asio::ip::tcp::endpoint( + * boost::asio::ip::tcp::v4(), 12345)); + * @endcode + */ + void bind(const endpoint_type& endpoint) + { + boost::system::error_code ec; + this->service.bind(this->implementation, endpoint, ec); + boost::asio::detail::throw_error(ec); + } + + /// Bind the socket to the given local endpoint. + /** + * This function binds the socket to the specified endpoint on the local + * machine. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * socket.open(boost::asio::ip::tcp::v4()); + * boost::system::error_code ec; + * socket.bind(boost::asio::ip::tcp::endpoint( + * boost::asio::ip::tcp::v4(), 12345), ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + boost::system::error_code bind(const endpoint_type& endpoint, + boost::system::error_code& ec) + { + return this->service.bind(this->implementation, endpoint, ec); + } + + /// Connect the socket to the specified endpoint. + /** + * This function is used to connect a socket to the specified remote endpoint. + * The function call will block until the connection is successfully made or + * an error occurs. + * + * The socket is automatically opened if it is not already open. If the + * connect fails, and the socket was automatically opened, the socket is + * not returned to the closed state. + * + * @param peer_endpoint The remote endpoint to which the socket will be + * connected. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::endpoint endpoint( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.connect(endpoint); + * @endcode + */ + void connect(const endpoint_type& peer_endpoint) + { + boost::system::error_code ec; + if (!is_open()) + { + this->service.open(this->implementation, peer_endpoint.protocol(), ec); + boost::asio::detail::throw_error(ec); + } + this->service.connect(this->implementation, peer_endpoint, ec); + boost::asio::detail::throw_error(ec); + } + + /// Connect the socket to the specified endpoint. + /** + * This function is used to connect a socket to the specified remote endpoint. + * The function call will block until the connection is successfully made or + * an error occurs. + * + * The socket is automatically opened if it is not already open. If the + * connect fails, and the socket was automatically opened, the socket is + * not returned to the closed state. + * + * @param peer_endpoint The remote endpoint to which the socket will be + * connected. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::endpoint endpoint( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * boost::system::error_code ec; + * socket.connect(endpoint, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + boost::system::error_code connect(const endpoint_type& peer_endpoint, + boost::system::error_code& ec) + { + if (!is_open()) + { + if (this->service.open(this->implementation, + peer_endpoint.protocol(), ec)) + { + return ec; + } + } + + return this->service.connect(this->implementation, peer_endpoint, ec); + } + + /// Start an asynchronous connect. + /** + * This function is used to asynchronously connect a socket to the specified + * remote endpoint. The function call always returns immediately. + * + * The socket is automatically opened if it is not already open. If the + * connect fails, and the socket was automatically opened, the socket is + * not returned to the closed state. + * + * @param peer_endpoint The remote endpoint to which the socket will be + * connected. Copies will be made of the endpoint object as required. + * + * @param handler The handler to be called when the connection operation + * completes. Copies will be made of the handler as required. The function + * signature of the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @par Example + * @code + * void connect_handler(const boost::system::error_code& error) + * { + * if (!error) + * { + * // Connect succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::endpoint endpoint( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.async_connect(endpoint, connect_handler); + * @endcode + */ + template + void async_connect(const endpoint_type& peer_endpoint, ConnectHandler handler) + { + if (!is_open()) + { + boost::system::error_code ec; + if (this->service.open(this->implementation, + peer_endpoint.protocol(), ec)) + { + this->get_io_service().post( + boost::asio::detail::bind_handler(handler, ec)); + return; + } + } + + this->service.async_connect(this->implementation, peer_endpoint, handler); + } + + /// Set an option on the socket. + /** + * This function is used to set an option on the socket. + * + * @param option The new option value to be set on the socket. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa SettableSocketOption @n + * boost::asio::socket_base::broadcast @n + * boost::asio::socket_base::do_not_route @n + * boost::asio::socket_base::keep_alive @n + * boost::asio::socket_base::linger @n + * boost::asio::socket_base::receive_buffer_size @n + * boost::asio::socket_base::receive_low_watermark @n + * boost::asio::socket_base::reuse_address @n + * boost::asio::socket_base::send_buffer_size @n + * boost::asio::socket_base::send_low_watermark @n + * boost::asio::ip::multicast::join_group @n + * boost::asio::ip::multicast::leave_group @n + * boost::asio::ip::multicast::enable_loopback @n + * boost::asio::ip::multicast::outbound_interface @n + * boost::asio::ip::multicast::hops @n + * boost::asio::ip::tcp::no_delay + * + * @par Example + * Setting the IPPROTO_TCP/TCP_NODELAY option: + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * ... + * boost::asio::ip::tcp::no_delay option(true); + * socket.set_option(option); + * @endcode + */ + template + void set_option(const SettableSocketOption& option) + { + boost::system::error_code ec; + this->service.set_option(this->implementation, option, ec); + boost::asio::detail::throw_error(ec); + } + + /// Set an option on the socket. + /** + * This function is used to set an option on the socket. + * + * @param option The new option value to be set on the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa SettableSocketOption @n + * boost::asio::socket_base::broadcast @n + * boost::asio::socket_base::do_not_route @n + * boost::asio::socket_base::keep_alive @n + * boost::asio::socket_base::linger @n + * boost::asio::socket_base::receive_buffer_size @n + * boost::asio::socket_base::receive_low_watermark @n + * boost::asio::socket_base::reuse_address @n + * boost::asio::socket_base::send_buffer_size @n + * boost::asio::socket_base::send_low_watermark @n + * boost::asio::ip::multicast::join_group @n + * boost::asio::ip::multicast::leave_group @n + * boost::asio::ip::multicast::enable_loopback @n + * boost::asio::ip::multicast::outbound_interface @n + * boost::asio::ip::multicast::hops @n + * boost::asio::ip::tcp::no_delay + * + * @par Example + * Setting the IPPROTO_TCP/TCP_NODELAY option: + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * ... + * boost::asio::ip::tcp::no_delay option(true); + * boost::system::error_code ec; + * socket.set_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + boost::system::error_code set_option(const SettableSocketOption& option, + boost::system::error_code& ec) + { + return this->service.set_option(this->implementation, option, ec); + } + + /// Get an option from the socket. + /** + * This function is used to get the current value of an option on the socket. + * + * @param option The option value to be obtained from the socket. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa GettableSocketOption @n + * boost::asio::socket_base::broadcast @n + * boost::asio::socket_base::do_not_route @n + * boost::asio::socket_base::keep_alive @n + * boost::asio::socket_base::linger @n + * boost::asio::socket_base::receive_buffer_size @n + * boost::asio::socket_base::receive_low_watermark @n + * boost::asio::socket_base::reuse_address @n + * boost::asio::socket_base::send_buffer_size @n + * boost::asio::socket_base::send_low_watermark @n + * boost::asio::ip::multicast::join_group @n + * boost::asio::ip::multicast::leave_group @n + * boost::asio::ip::multicast::enable_loopback @n + * boost::asio::ip::multicast::outbound_interface @n + * boost::asio::ip::multicast::hops @n + * boost::asio::ip::tcp::no_delay + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * ... + * boost::asio::ip::tcp::socket::keep_alive option; + * socket.get_option(option); + * bool is_set = option.get(); + * @endcode + */ + template + void get_option(GettableSocketOption& option) const + { + boost::system::error_code ec; + this->service.get_option(this->implementation, option, ec); + boost::asio::detail::throw_error(ec); + } + + /// Get an option from the socket. + /** + * This function is used to get the current value of an option on the socket. + * + * @param option The option value to be obtained from the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa GettableSocketOption @n + * boost::asio::socket_base::broadcast @n + * boost::asio::socket_base::do_not_route @n + * boost::asio::socket_base::keep_alive @n + * boost::asio::socket_base::linger @n + * boost::asio::socket_base::receive_buffer_size @n + * boost::asio::socket_base::receive_low_watermark @n + * boost::asio::socket_base::reuse_address @n + * boost::asio::socket_base::send_buffer_size @n + * boost::asio::socket_base::send_low_watermark @n + * boost::asio::ip::multicast::join_group @n + * boost::asio::ip::multicast::leave_group @n + * boost::asio::ip::multicast::enable_loopback @n + * boost::asio::ip::multicast::outbound_interface @n + * boost::asio::ip::multicast::hops @n + * boost::asio::ip::tcp::no_delay + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * ... + * boost::asio::ip::tcp::socket::keep_alive option; + * boost::system::error_code ec; + * socket.get_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * bool is_set = option.get(); + * @endcode + */ + template + boost::system::error_code get_option(GettableSocketOption& option, + boost::system::error_code& ec) const + { + return this->service.get_option(this->implementation, option, ec); + } + + /// Perform an IO control command on the socket. + /** + * This function is used to execute an IO control command on the socket. + * + * @param command The IO control command to be performed on the socket. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa IoControlCommand @n + * boost::asio::socket_base::bytes_readable @n + * boost::asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * ... + * boost::asio::ip::tcp::socket::bytes_readable command; + * socket.io_control(command); + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template + void io_control(IoControlCommand& command) + { + boost::system::error_code ec; + this->service.io_control(this->implementation, command, ec); + boost::asio::detail::throw_error(ec); + } + + /// Perform an IO control command on the socket. + /** + * This function is used to execute an IO control command on the socket. + * + * @param command The IO control command to be performed on the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa IoControlCommand @n + * boost::asio::socket_base::bytes_readable @n + * boost::asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * ... + * boost::asio::ip::tcp::socket::bytes_readable command; + * boost::system::error_code ec; + * socket.io_control(command, ec); + * if (ec) + * { + * // An error occurred. + * } + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template + boost::system::error_code io_control(IoControlCommand& command, + boost::system::error_code& ec) + { + return this->service.io_control(this->implementation, command, ec); + } + + /// Get the local endpoint of the socket. + /** + * This function is used to obtain the locally bound endpoint of the socket. + * + * @returns An object that represents the local endpoint of the socket. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * ... + * boost::asio::ip::tcp::endpoint endpoint = socket.local_endpoint(); + * @endcode + */ + endpoint_type local_endpoint() const + { + boost::system::error_code ec; + endpoint_type ep = this->service.local_endpoint(this->implementation, ec); + boost::asio::detail::throw_error(ec); + return ep; + } + + /// Get the local endpoint of the socket. + /** + * This function is used to obtain the locally bound endpoint of the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns An object that represents the local endpoint of the socket. + * Returns a default-constructed endpoint object if an error occurred. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * ... + * boost::system::error_code ec; + * boost::asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + endpoint_type local_endpoint(boost::system::error_code& ec) const + { + return this->service.local_endpoint(this->implementation, ec); + } + + /// Get the remote endpoint of the socket. + /** + * This function is used to obtain the remote endpoint of the socket. + * + * @returns An object that represents the remote endpoint of the socket. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * ... + * boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(); + * @endcode + */ + endpoint_type remote_endpoint() const + { + boost::system::error_code ec; + endpoint_type ep = this->service.remote_endpoint(this->implementation, ec); + boost::asio::detail::throw_error(ec); + return ep; + } + + /// Get the remote endpoint of the socket. + /** + * This function is used to obtain the remote endpoint of the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns An object that represents the remote endpoint of the socket. + * Returns a default-constructed endpoint object if an error occurred. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * ... + * boost::system::error_code ec; + * boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + endpoint_type remote_endpoint(boost::system::error_code& ec) const + { + return this->service.remote_endpoint(this->implementation, ec); + } + + /// Disable sends or receives on the socket. + /** + * This function is used to disable send operations, receive operations, or + * both. + * + * @param what Determines what types of operation will no longer be allowed. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * Shutting down the send side of the socket: + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * ... + * socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send); + * @endcode + */ + void shutdown(shutdown_type what) + { + boost::system::error_code ec; + this->service.shutdown(this->implementation, what, ec); + boost::asio::detail::throw_error(ec); + } + + /// Disable sends or receives on the socket. + /** + * This function is used to disable send operations, receive operations, or + * both. + * + * @param what Determines what types of operation will no longer be allowed. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * Shutting down the send side of the socket: + * @code + * boost::asio::ip::tcp::socket socket(io_service); + * ... + * boost::system::error_code ec; + * socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + boost::system::error_code shutdown(shutdown_type what, + boost::system::error_code& ec) + { + return this->service.shutdown(this->implementation, what, ec); + } + +protected: + /// Protected destructor to prevent deletion through this type. + ~basic_socket() + { + } +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_SOCKET_HPP diff --git a/3rdParty/Boost/boost/asio/basic_socket_acceptor.hpp b/3rdParty/Boost/boost/asio/basic_socket_acceptor.hpp new file mode 100644 index 0000000..afa0d63 --- /dev/null +++ b/3rdParty/Boost/boost/asio/basic_socket_acceptor.hpp @@ -0,0 +1,826 @@ +// +// basic_socket_acceptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_ACCEPTOR_HPP +#define BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { + +/// Provides the ability to accept new connections. +/** + * The basic_socket_acceptor class template is used for accepting new socket + * connections. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Example + * Opening a socket acceptor with the SO_REUSEADDR option enabled: + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port); + * acceptor.open(endpoint.protocol()); + * acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + * acceptor.bind(endpoint); + * acceptor.listen(); + * @endcode + */ +template > +class basic_socket_acceptor + : public basic_io_object, + public socket_base +{ +public: + /// The native representation of an acceptor. + typedef typename SocketAcceptorService::native_type native_type; + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct an acceptor without opening it. + /** + * This constructor creates an acceptor without opening it to listen for new + * connections. The open() function must be called before the acceptor can + * accept new socket connections. + * + * @param io_service The io_service object that the acceptor will use to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + */ + explicit basic_socket_acceptor(boost::asio::io_service& io_service) + : basic_io_object(io_service) + { + } + + /// Construct an open acceptor. + /** + * This constructor creates an acceptor and automatically opens it. + * + * @param io_service The io_service object that the acceptor will use to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_socket_acceptor(boost::asio::io_service& io_service, + const protocol_type& protocol) + : basic_io_object(io_service) + { + boost::system::error_code ec; + this->service.open(this->implementation, protocol, ec); + boost::asio::detail::throw_error(ec); + } + + /// Construct an acceptor opened on the given endpoint. + /** + * This constructor creates an acceptor and automatically opens it to listen + * for new connections on the specified endpoint. + * + * @param io_service The io_service object that the acceptor will use to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + * + * @param endpoint An endpoint on the local machine on which the acceptor + * will listen for new connections. + * + * @param reuse_addr Whether the constructor should set the socket option + * socket_base::reuse_address. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This constructor is equivalent to the following code: + * @code + * basic_socket_acceptor acceptor(io_service); + * acceptor.open(endpoint.protocol()); + * if (reuse_addr) + * acceptor.set_option(socket_base::reuse_address(true)); + * acceptor.bind(endpoint); + * acceptor.listen(listen_backlog); + * @endcode + */ + basic_socket_acceptor(boost::asio::io_service& io_service, + const endpoint_type& endpoint, bool reuse_addr = true) + : basic_io_object(io_service) + { + boost::system::error_code ec; + this->service.open(this->implementation, endpoint.protocol(), ec); + boost::asio::detail::throw_error(ec); + if (reuse_addr) + { + this->service.set_option(this->implementation, + socket_base::reuse_address(true), ec); + boost::asio::detail::throw_error(ec); + } + this->service.bind(this->implementation, endpoint, ec); + boost::asio::detail::throw_error(ec); + this->service.listen(this->implementation, + socket_base::max_connections, ec); + boost::asio::detail::throw_error(ec); + } + + /// Construct a basic_socket_acceptor on an existing native acceptor. + /** + * This constructor creates an acceptor object to hold an existing native + * acceptor. + * + * @param io_service The io_service object that the acceptor will use to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_acceptor A native acceptor. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_socket_acceptor(boost::asio::io_service& io_service, + const protocol_type& protocol, const native_type& native_acceptor) + : basic_io_object(io_service) + { + boost::system::error_code ec; + this->service.assign(this->implementation, protocol, native_acceptor, ec); + boost::asio::detail::throw_error(ec); + } + + /// Open the acceptor using the specified protocol. + /** + * This function opens the socket acceptor so that it will use the specified + * protocol. + * + * @param protocol An object specifying which protocol is to be used. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * acceptor.open(boost::asio::ip::tcp::v4()); + * @endcode + */ + void open(const protocol_type& protocol = protocol_type()) + { + boost::system::error_code ec; + this->service.open(this->implementation, protocol, ec); + boost::asio::detail::throw_error(ec); + } + + /// Open the acceptor using the specified protocol. + /** + * This function opens the socket acceptor so that it will use the specified + * protocol. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * boost::system::error_code ec; + * acceptor.open(boost::asio::ip::tcp::v4(), ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + boost::system::error_code open(const protocol_type& protocol, + boost::system::error_code& ec) + { + return this->service.open(this->implementation, protocol, ec); + } + + /// Assigns an existing native acceptor to the acceptor. + /* + * This function opens the acceptor to hold an existing native acceptor. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_acceptor A native acceptor. + * + * @throws boost::system::system_error Thrown on failure. + */ + void assign(const protocol_type& protocol, const native_type& native_acceptor) + { + boost::system::error_code ec; + this->service.assign(this->implementation, protocol, native_acceptor, ec); + boost::asio::detail::throw_error(ec); + } + + /// Assigns an existing native acceptor to the acceptor. + /* + * This function opens the acceptor to hold an existing native acceptor. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_acceptor A native acceptor. + * + * @param ec Set to indicate what error occurred, if any. + */ + boost::system::error_code assign(const protocol_type& protocol, + const native_type& native_acceptor, boost::system::error_code& ec) + { + return this->service.assign(this->implementation, + protocol, native_acceptor, ec); + } + + /// Determine whether the acceptor is open. + bool is_open() const + { + return this->service.is_open(this->implementation); + } + + /// Bind the acceptor to the given local endpoint. + /** + * This function binds the socket acceptor to the specified endpoint on the + * local machine. + * + * @param endpoint An endpoint on the local machine to which the socket + * acceptor will be bound. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * acceptor.open(boost::asio::ip::tcp::v4()); + * acceptor.bind(boost::asio::ip::tcp::endpoint(12345)); + * @endcode + */ + void bind(const endpoint_type& endpoint) + { + boost::system::error_code ec; + this->service.bind(this->implementation, endpoint, ec); + boost::asio::detail::throw_error(ec); + } + + /// Bind the acceptor to the given local endpoint. + /** + * This function binds the socket acceptor to the specified endpoint on the + * local machine. + * + * @param endpoint An endpoint on the local machine to which the socket + * acceptor will be bound. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * acceptor.open(boost::asio::ip::tcp::v4()); + * boost::system::error_code ec; + * acceptor.bind(boost::asio::ip::tcp::endpoint(12345), ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + boost::system::error_code bind(const endpoint_type& endpoint, + boost::system::error_code& ec) + { + return this->service.bind(this->implementation, endpoint, ec); + } + + /// Place the acceptor into the state where it will listen for new + /// connections. + /** + * This function puts the socket acceptor into the state where it may accept + * new connections. + * + * @param backlog The maximum length of the queue of pending connections. + * + * @throws boost::system::system_error Thrown on failure. + */ + void listen(int backlog = socket_base::max_connections) + { + boost::system::error_code ec; + this->service.listen(this->implementation, backlog, ec); + boost::asio::detail::throw_error(ec); + } + + /// Place the acceptor into the state where it will listen for new + /// connections. + /** + * This function puts the socket acceptor into the state where it may accept + * new connections. + * + * @param backlog The maximum length of the queue of pending connections. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * ... + * boost::system::error_code ec; + * acceptor.listen(boost::asio::socket_base::max_connections, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + boost::system::error_code listen(int backlog, boost::system::error_code& ec) + { + return this->service.listen(this->implementation, backlog, ec); + } + + /// Close the acceptor. + /** + * This function is used to close the acceptor. Any asynchronous accept + * operations will be cancelled immediately. + * + * A subsequent call to open() is required before the acceptor can again be + * used to again perform socket accept operations. + * + * @throws boost::system::system_error Thrown on failure. + */ + void close() + { + boost::system::error_code ec; + this->service.close(this->implementation, ec); + boost::asio::detail::throw_error(ec); + } + + /// Close the acceptor. + /** + * This function is used to close the acceptor. Any asynchronous accept + * operations will be cancelled immediately. + * + * A subsequent call to open() is required before the acceptor can again be + * used to again perform socket accept operations. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * ... + * boost::system::error_code ec; + * acceptor.close(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + boost::system::error_code close(boost::system::error_code& ec) + { + return this->service.close(this->implementation, ec); + } + + /// Get the native acceptor representation. + /** + * This function may be used to obtain the underlying representation of the + * acceptor. This is intended to allow access to native acceptor functionality + * that is not otherwise provided. + */ + native_type native() + { + return this->service.native(this->implementation); + } + + /// Cancel all asynchronous operations associated with the acceptor. + /** + * This function causes all outstanding asynchronous connect, send and receive + * 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; + this->service.cancel(this->implementation, ec); + boost::asio::detail::throw_error(ec); + } + + /// Cancel all asynchronous operations associated with the acceptor. + /** + * This function causes all outstanding asynchronous connect, send and receive + * 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::system::error_code cancel(boost::system::error_code& ec) + { + return this->service.cancel(this->implementation, ec); + } + + /// Set an option on the acceptor. + /** + * This function is used to set an option on the acceptor. + * + * @param option The new option value to be set on the acceptor. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa SettableSocketOption @n + * boost::asio::socket_base::reuse_address + * boost::asio::socket_base::enable_connection_aborted + * + * @par Example + * Setting the SOL_SOCKET/SO_REUSEADDR option: + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * ... + * boost::asio::ip::tcp::acceptor::reuse_address option(true); + * acceptor.set_option(option); + * @endcode + */ + template + void set_option(const SettableSocketOption& option) + { + boost::system::error_code ec; + this->service.set_option(this->implementation, option, ec); + boost::asio::detail::throw_error(ec); + } + + /// Set an option on the acceptor. + /** + * This function is used to set an option on the acceptor. + * + * @param option The new option value to be set on the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa SettableSocketOption @n + * boost::asio::socket_base::reuse_address + * boost::asio::socket_base::enable_connection_aborted + * + * @par Example + * Setting the SOL_SOCKET/SO_REUSEADDR option: + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * ... + * boost::asio::ip::tcp::acceptor::reuse_address option(true); + * boost::system::error_code ec; + * acceptor.set_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + boost::system::error_code set_option(const SettableSocketOption& option, + boost::system::error_code& ec) + { + return this->service.set_option(this->implementation, option, ec); + } + + /// Get an option from the acceptor. + /** + * This function is used to get the current value of an option on the + * acceptor. + * + * @param option The option value to be obtained from the acceptor. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa GettableSocketOption @n + * boost::asio::socket_base::reuse_address + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * ... + * boost::asio::ip::tcp::acceptor::reuse_address option; + * acceptor.get_option(option); + * bool is_set = option.get(); + * @endcode + */ + template + void get_option(GettableSocketOption& option) + { + boost::system::error_code ec; + this->service.get_option(this->implementation, option, ec); + boost::asio::detail::throw_error(ec); + } + + /// Get an option from the acceptor. + /** + * This function is used to get the current value of an option on the + * acceptor. + * + * @param option The option value to be obtained from the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa GettableSocketOption @n + * boost::asio::socket_base::reuse_address + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * ... + * boost::asio::ip::tcp::acceptor::reuse_address option; + * boost::system::error_code ec; + * acceptor.get_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * bool is_set = option.get(); + * @endcode + */ + template + boost::system::error_code get_option(GettableSocketOption& option, + boost::system::error_code& ec) + { + return this->service.get_option(this->implementation, option, ec); + } + + /// Get the local endpoint of the acceptor. + /** + * This function is used to obtain the locally bound endpoint of the acceptor. + * + * @returns An object that represents the local endpoint of the acceptor. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * ... + * boost::asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(); + * @endcode + */ + endpoint_type local_endpoint() const + { + boost::system::error_code ec; + endpoint_type ep = this->service.local_endpoint(this->implementation, ec); + boost::asio::detail::throw_error(ec); + return ep; + } + + /// Get the local endpoint of the acceptor. + /** + * This function is used to obtain the locally bound endpoint of the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns An object that represents the local endpoint of the acceptor. + * Returns a default-constructed endpoint object if an error occurred and the + * error handler did not throw an exception. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * ... + * boost::system::error_code ec; + * boost::asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + endpoint_type local_endpoint(boost::system::error_code& ec) const + { + return this->service.local_endpoint(this->implementation, ec); + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer into the + * given socket. The function call will block until a new connection has been + * accepted successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * ... + * boost::asio::ip::tcp::socket socket(io_service); + * acceptor.accept(socket); + * @endcode + */ + template + void accept(basic_socket& peer) + { + boost::system::error_code ec; + this->service.accept(this->implementation, peer, 0, ec); + boost::asio::detail::throw_error(ec); + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer into the + * given socket. The function call will block until a new connection has been + * accepted successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * ... + * boost::asio::ip::tcp::soocket socket(io_service); + * boost::system::error_code ec; + * acceptor.accept(socket, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + boost::system::error_code accept( + basic_socket& peer, + boost::system::error_code& ec) + { + return this->service.accept(this->implementation, peer, 0, ec); + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection into a + * socket. The function call always returns immediately. + * + * @param peer The socket into which the new connection will be accepted. + * Ownership of the peer object is retained by the caller, which must + * guarantee that it is valid until the handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @par Example + * @code + * void accept_handler(const boost::system::error_code& error) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * ... + * boost::asio::ip::tcp::socket socket(io_service); + * acceptor.async_accept(socket, accept_handler); + * @endcode + */ + template + void async_accept(basic_socket& peer, + AcceptHandler handler) + { + this->service.async_accept(this->implementation, peer, 0, handler); + } + + /// Accept a new connection and obtain the endpoint of the peer + /** + * This function is used to accept a new connection from a peer into the + * given socket, and additionally provide the endpoint of the remote peer. + * The function call will block until a new connection has been accepted + * successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @param peer_endpoint An endpoint object which will receive the endpoint of + * the remote peer. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * ... + * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::endpoint endpoint; + * acceptor.accept(socket, endpoint); + * @endcode + */ + template + void accept(basic_socket& peer, + endpoint_type& peer_endpoint) + { + boost::system::error_code ec; + this->service.accept(this->implementation, peer, &peer_endpoint, ec); + boost::asio::detail::throw_error(ec); + } + + /// Accept a new connection and obtain the endpoint of the peer + /** + * This function is used to accept a new connection from a peer into the + * given socket, and additionally provide the endpoint of the remote peer. + * The function call will block until a new connection has been accepted + * successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @param peer_endpoint An endpoint object which will receive the endpoint of + * the remote peer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(io_service); + * ... + * boost::asio::ip::tcp::socket socket(io_service); + * boost::asio::ip::tcp::endpoint endpoint; + * boost::system::error_code ec; + * acceptor.accept(socket, endpoint, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + boost::system::error_code accept( + basic_socket& peer, + endpoint_type& peer_endpoint, boost::system::error_code& ec) + { + return this->service.accept(this->implementation, peer, &peer_endpoint, ec); + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection into a + * socket, and additionally obtain the endpoint of the remote peer. The + * function call always returns immediately. + * + * @param peer The socket into which the new connection will be accepted. + * Ownership of the peer object is retained by the caller, which must + * guarantee that it is valid until the handler is called. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. Ownership of the peer_endpoint object is + * retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + */ + template + void async_accept(basic_socket& peer, + endpoint_type& peer_endpoint, AcceptHandler handler) + { + this->service.async_accept(this->implementation, + peer, &peer_endpoint, handler); + } +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_HPP diff --git a/3rdParty/Boost/boost/asio/basic_socket_iostream.hpp b/3rdParty/Boost/boost/asio/basic_socket_iostream.hpp new file mode 100644 index 0000000..b0ae259 --- /dev/null +++ b/3rdParty/Boost/boost/asio/basic_socket_iostream.hpp @@ -0,0 +1,150 @@ +// +// basic_socket_iostream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if !defined(BOOST_ASIO_SOCKET_IOSTREAM_MAX_ARITY) +#define BOOST_ASIO_SOCKET_IOSTREAM_MAX_ARITY 5 +#endif // !defined(BOOST_ASIO_SOCKET_IOSTREAM_MAX_ARITY) + +// A macro that should expand to: +// template +// explicit basic_socket_iostream(T1 x1, ..., Tn xn) +// : basic_iostream(&this->boost::base_from_member< +// basic_socket_streambuf >::member) +// { +// if (rdbuf()->connect(x1, ..., xn) == 0) +// this->setstate(std::ios_base::failbit); +// } +// This macro should only persist within this file. + +#define BOOST_ASIO_PRIVATE_CTR_DEF(z, n, data) \ + template \ + explicit basic_socket_iostream(BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \ + : std::basic_iostream(&this->boost::base_from_member< \ + basic_socket_streambuf >::member) \ + { \ + tie(this); \ + if (rdbuf()->connect(BOOST_PP_ENUM_PARAMS(n, x)) == 0) \ + this->setstate(std::ios_base::failbit); \ + } \ + /**/ + +// A macro that should expand to: +// template +// void connect(T1 x1, ..., Tn xn) +// { +// if (rdbuf()->connect(x1, ..., xn) == 0) +// this->setstate(std::ios_base::failbit); +// } +// This macro should only persist within this file. + +#define BOOST_ASIO_PRIVATE_CONNECT_DEF(z, n, data) \ + template \ + void connect(BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \ + { \ + if (rdbuf()->connect(BOOST_PP_ENUM_PARAMS(n, x)) == 0) \ + this->setstate(std::ios_base::failbit); \ + } \ + /**/ + +namespace boost { +namespace asio { + +/// Iostream interface for a socket. +template > +class basic_socket_iostream + : public boost::base_from_member< + basic_socket_streambuf >, + public std::basic_iostream +{ +public: + /// Construct a basic_socket_iostream without establishing a connection. + basic_socket_iostream() + : std::basic_iostream(&this->boost::base_from_member< + basic_socket_streambuf >::member) + { + tie(this); + } + +#if defined(GENERATING_DOCUMENTATION) + /// 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 + explicit basic_socket_iostream(T1 t1, ..., TN tn); +#else + BOOST_PP_REPEAT_FROM_TO( + 1, BOOST_PP_INC(BOOST_ASIO_SOCKET_IOSTREAM_MAX_ARITY), + BOOST_ASIO_PRIVATE_CTR_DEF, _ ) +#endif + +#if defined(GENERATING_DOCUMENTATION) + /// 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 + void connect(T1 t1, ..., TN tn); +#else + BOOST_PP_REPEAT_FROM_TO( + 1, BOOST_PP_INC(BOOST_ASIO_SOCKET_IOSTREAM_MAX_ARITY), + BOOST_ASIO_PRIVATE_CONNECT_DEF, _ ) +#endif + + /// 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* rdbuf() const + { + return const_cast*>( + &this->boost::base_from_member< + basic_socket_streambuf >::member); + } +}; + +} // namespace asio +} // namespace boost + +#undef BOOST_ASIO_PRIVATE_CTR_DEF +#undef BOOST_ASIO_PRIVATE_CONNECT_DEF + +#include + +#endif // BOOST_ASIO_BASIC_SOCKET_IOSTREAM_HPP diff --git a/3rdParty/Boost/boost/asio/basic_socket_streambuf.hpp b/3rdParty/Boost/boost/asio/basic_socket_streambuf.hpp new file mode 100644 index 0000000..9977be6 --- /dev/null +++ b/3rdParty/Boost/boost/asio/basic_socket_streambuf.hpp @@ -0,0 +1,287 @@ +// +// basic_socket_streambuf.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY) +#define BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY 5 +#endif // !defined(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY) + +// A macro that should expand to: +// template +// basic_socket_streambuf* connect( +// T1 x1, ..., Tn xn) +// { +// init_buffers(); +// boost::system::error_code ec; +// this->basic_socket::close(ec); +// typedef typename Protocol::resolver_query resolver_query; +// resolver_query query(x1, ..., xn); +// resolve_and_connect(query, ec); +// return !ec ? this : 0; +// } +// This macro should only persist within this file. + +#define BOOST_ASIO_PRIVATE_CONNECT_DEF( z, n, data ) \ + template \ + basic_socket_streambuf* connect( \ + BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \ + { \ + init_buffers(); \ + boost::system::error_code ec; \ + this->basic_socket::close(ec); \ + typedef typename Protocol::resolver_query resolver_query; \ + resolver_query query(BOOST_PP_ENUM_PARAMS(n, x)); \ + resolve_and_connect(query, ec); \ + return !ec ? this : 0; \ + } \ + /**/ + +namespace boost { +namespace asio { + +/// Iostream streambuf for a socket. +template > +class basic_socket_streambuf + : public std::streambuf, + private boost::base_from_member, + public basic_socket +{ +public: + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_socket_streambuf without establishing a connection. + basic_socket_streambuf() + : basic_socket( + boost::base_from_member::member), + unbuffered_(false) + { + init_buffers(); + } + + /// 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(); + boost::system::error_code ec; + this->basic_socket::close(ec); + this->basic_socket::connect(endpoint, ec); + return !ec ? this : 0; + } + +#if defined(GENERATING_DOCUMENTATION) + /// 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 + basic_socket_streambuf* connect( + T1 t1, ..., TN tn); +#else + BOOST_PP_REPEAT_FROM_TO( + 1, BOOST_PP_INC(BOOST_ASIO_SOCKET_STREAMBUF_MAX_ARITY), + BOOST_ASIO_PRIVATE_CONNECT_DEF, _ ) +#endif + + /// Close the connection. + /** + * @return \c this if a connection was successfully established, a null + * pointer otherwise. + */ + basic_socket_streambuf* close() + { + boost::system::error_code ec; + sync(); + this->basic_socket::close(ec); + if (!ec) + init_buffers(); + return !ec ? this : 0; + } + +protected: + int_type underflow() + { + if (gptr() == egptr()) + { + boost::system::error_code ec; + std::size_t bytes_transferred = this->service.receive( + this->implementation, + boost::asio::buffer(boost::asio::buffer(get_buffer_) + putback_max), + 0, ec); + if (ec) + return traits_type::eof(); + setg(get_buffer_.begin(), get_buffer_.begin() + putback_max, + get_buffer_.begin() + putback_max + bytes_transferred); + return traits_type::to_int_type(*gptr()); + } + else + { + return traits_type::eof(); + } + } + + int_type overflow(int_type c) + { + if (unbuffered_) + { + if (traits_type::eq_int_type(c, traits_type::eof())) + { + // Nothing to do. + return traits_type::not_eof(c); + } + else + { + // Send the single character immediately. + boost::system::error_code ec; + char_type ch = traits_type::to_char_type(c); + this->service.send(this->implementation, + boost::asio::buffer(&ch, sizeof(char_type)), 0, ec); + if (ec) + return traits_type::eof(); + return c; + } + } + else + { + // Send all data in the output buffer. + boost::asio::const_buffer buffer = + boost::asio::buffer(pbase(), pptr() - pbase()); + while (boost::asio::buffer_size(buffer) > 0) + { + boost::system::error_code ec; + std::size_t bytes_transferred = this->service.send( + this->implementation, boost::asio::buffer(buffer), + 0, ec); + if (ec) + return traits_type::eof(); + buffer = buffer + bytes_transferred; + } + setp(put_buffer_.begin(), put_buffer_.end()); + + // 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() = traits_type::to_char_type(c); + pbump(1); + return c; + } + } + + int sync() + { + return overflow(traits_type::eof()); + } + + std::streambuf* setbuf(char_type* s, std::streamsize n) + { + if (pptr() == pbase() && s == 0 && n == 0) + { + unbuffered_ = true; + setp(0, 0); + return this; + } + + return 0; + } + +private: + void init_buffers() + { + setg(get_buffer_.begin(), + get_buffer_.begin() + putback_max, + get_buffer_.begin() + putback_max); + if (unbuffered_) + setp(0, 0); + else + setp(put_buffer_.begin(), put_buffer_.end()); + } + + template + void resolve_and_connect(const ResolverQuery& query, + boost::system::error_code& ec) + { + typedef typename Protocol::resolver resolver_type; + typedef typename Protocol::resolver_iterator iterator_type; + resolver_type resolver( + boost::base_from_member::member); + iterator_type i = resolver.resolve(query, ec); + if (!ec) + { + iterator_type end; + ec = boost::asio::error::host_not_found; + while (ec && i != end) + { + this->basic_socket::close(); + this->basic_socket::connect(*i, ec); + ++i; + } + } + } + + enum { putback_max = 8 }; + enum { buffer_size = 512 }; + boost::array get_buffer_; + boost::array put_buffer_; + bool unbuffered_; +}; + +} // namespace asio +} // namespace boost + +#undef BOOST_ASIO_PRIVATE_CONNECT_DEF + +#include + +#endif // BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP diff --git a/3rdParty/Boost/boost/asio/basic_stream_socket.hpp b/3rdParty/Boost/boost/asio/basic_stream_socket.hpp new file mode 100644 index 0000000..c020369 --- /dev/null +++ b/3rdParty/Boost/boost/asio/basic_stream_socket.hpp @@ -0,0 +1,720 @@ +// +// basic_stream_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SOCKET_HPP +#define BOOST_ASIO_BASIC_STREAM_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace boost { +namespace asio { + +/// Provides stream-oriented socket functionality. +/** + * The basic_stream_socket class template provides asynchronous and blocking + * stream-oriented socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template > +class basic_stream_socket + : public basic_socket +{ +public: + /// The native representation of a socket. + typedef typename StreamSocketService::native_type native_type; + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_stream_socket without opening it. + /** + * This constructor creates a stream 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 io_service The io_service object that the stream socket will use to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_stream_socket(boost::asio::io_service& io_service) + : basic_socket(io_service) + { + } + + /// Construct and open a basic_stream_socket. + /** + * This constructor creates and opens a stream socket. The socket needs to be + * connected or accepted before data can be sent or received on it. + * + * @param io_service The io_service object that the stream socket will use 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_stream_socket(boost::asio::io_service& io_service, + const protocol_type& protocol) + : basic_socket(io_service, protocol) + { + } + + /// Construct a basic_stream_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a stream 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 io_service The io_service object that the stream socket will use to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the stream + * socket will be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_stream_socket(boost::asio::io_service& io_service, + const endpoint_type& endpoint) + : basic_socket(io_service, endpoint) + { + } + + /// Construct a basic_stream_socket on an existing native socket. + /** + * This constructor creates a stream socket object to hold an existing native + * socket. + * + * @param io_service The io_service object that the stream socket will use 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_stream_socket(boost::asio::io_service& io_service, + const protocol_type& protocol, const native_type& native_socket) + : basic_socket( + io_service, protocol, native_socket) + { + } + + /// Send some data on the socket. + /** + * This function is used to send data on the stream socket. The function + * call will block until one or more bytes of the data has been sent + * successfully, or an until error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + * + * @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. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.send(boost::asio::buffer(data, size)); + * @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 + std::size_t send(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->service.send( + this->implementation, buffers, 0, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Send some data on the socket. + /** + * This function is used to send data on the stream socket. The function + * call will block until one or more bytes of 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. + * + * @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. + * + * @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 + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->service.send( + this->implementation, buffers, flags, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Send some data on the socket. + /** + * This function is used to send data on the stream socket. The function + * call will block until one or more bytes of 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 + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return this->service.send(this->implementation, buffers, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send data on the stream socket. + * The function call 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 handler is called. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @note The send 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 send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(boost::asio::buffer(data, size), 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. + */ + template + void async_send(const ConstBufferSequence& buffers, WriteHandler handler) + { + this->service.async_send(this->implementation, buffers, 0, handler); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send data on the stream socket. + * The function call 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 handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @note The send 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 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. + */ + template + void async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, WriteHandler handler) + { + this->service.async_send(this->implementation, buffers, flags, handler); + } + + /// Receive some data on the socket. + /** + * This function is used to receive data on the stream socket. The function + * call will block until one or more bytes of data has been received + * successfully, or until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @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)); + * @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 + std::size_t receive(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->service.receive(this->implementation, buffers, 0, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Receive some data on the socket. + /** + * This function is used to receive data on the stream socket. The function + * call will block until one or more bytes of data has been received + * successfully, or until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @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); + * @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 + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->service.receive( + this->implementation, buffers, flags, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the stream socket. The function + * call will block until one or more bytes of data has been received + * successfully, or until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @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 + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return this->service.receive(this->implementation, buffers, flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive data from the stream + * socket. The function call 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 handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @note The receive operation may not receive 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 received before the asynchronous + * operation completes. + * + * @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), 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. + */ + template + void async_receive(const MutableBufferSequence& buffers, ReadHandler handler) + { + this->service.async_receive(this->implementation, buffers, 0, handler); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive data from the stream + * socket. The function call 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 handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @note The receive operation may not receive 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 received before the asynchronous + * operation completes. + * + * @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, 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. + */ + template + void async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, ReadHandler handler) + { + this->service.async_receive(this->implementation, buffers, flags, handler); + } + + /// Write some data to the socket. + /** + * This function is used to write data to the stream socket. 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 socket. + * + * @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 + * socket.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 + std::size_t write_some(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->service.send(this->implementation, buffers, 0, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Write some data to the socket. + /** + * This function is used to write data to the stream socket. 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 socket. + * + * @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 + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->service.send(this->implementation, buffers, 0, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the stream socket. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be written to 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 handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @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 + * socket.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 + void async_write_some(const ConstBufferSequence& buffers, + WriteHandler handler) + { + this->service.async_send(this->implementation, buffers, 0, handler); + } + + /// Read some data from the socket. + /** + * This function is used to read data from the stream socket. 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 + * socket.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 + std::size_t read_some(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->service.receive(this->implementation, buffers, 0, ec); + boost::asio::detail::throw_error(ec); + return s; + } + + /// Read some data from the socket. + /** + * This function is used to read data from the stream socket. 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 + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->service.receive(this->implementation, buffers, 0, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the stream socket. + * The function call 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 handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the 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 handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * boost::asio::io_service::post(). + * + * @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 + * socket.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 + void async_read_some(const MutableBufferSequence& buffers, + ReadHandler handler) + { + this->service.async_receive(this->implementation, buffers, 0, handler); + } +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_STREAM_SOCKET_HPP diff --git a/3rdParty/Boost/boost/asio/basic_streambuf.hpp b/3rdParty/Boost/boost/asio/basic_streambuf.hpp new file mode 100644 index 0000000..db0e0c5 --- /dev/null +++ b/3rdParty/Boost/boost/asio/basic_streambuf.hpp @@ -0,0 +1,340 @@ +// +// basic_streambuf.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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::const_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 + */ +template > +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_buffers_1 const_buffers_type; + typedef boost::asio::mutable_buffers_1 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 max_size = (std::numeric_limits::max)(), + const Allocator& allocator = Allocator()) + : max_size_(max_size), + buffer_(allocator) + { + std::size_t pend = (std::min)(max_size_, buffer_delta); + buffer_.resize((std::max)(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 += buffer_size(buf); + * } + * @endcode + */ + std::size_t size() const + { + 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 + { + return max_size_; + } + + /// 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 + { + 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 size() + n > max_size(). + * + * @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 prepare(x) where x >= n, and + * no intervening operations that modify the input or output sequence. + * + * @throws std::length_error If @c n is greater than the size of the output + * sequence. + */ + void commit(std::size_t n) + { + if (pptr() + n > epptr()) + n = epptr() - pptr(); + pbump(static_cast(n)); + setg(eback(), gptr(), pptr()); + } + + /// Remove characters from the input sequence. + /** + * Removes @c n characters from the beginning of the input sequence. + * + * @throws std::length_error If n > size(). + */ + void consume(std::size_t n) + { + if (gptr() + n > pptr()) + n = pptr() - gptr(); + gbump(static_cast(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 + * size() > max_size() 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)(pend, 1)); + } + else + { + throw std::length_error("boost::asio::streambuf too long"); + } + } + + // 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 buffer_; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_STREAMBUF_HPP diff --git a/3rdParty/Boost/boost/asio/buffer.hpp b/3rdParty/Boost/boost/asio/buffer.hpp new file mode 100644 index 0000000..056d712 --- /dev/null +++ b/3rdParty/Boost/boost/asio/buffer.hpp @@ -0,0 +1,1042 @@ +// +// buffer.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_HPP +#define BOOST_ASIO_BUFFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_MSVC) +# if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0) +# if !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING) +# define BOOST_ASIO_ENABLE_BUFFER_DEBUGGING +# endif // !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING) +# endif // defined(_HAS_ITERATOR_DEBUGGING) +#endif // defined(BOOST_MSVC) + +#if defined(__GNUC__) +# if defined(_GLIBCXX_DEBUG) +# if !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING) +# define BOOST_ASIO_ENABLE_BUFFER_DEBUGGING +# endif // !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING) +# endif // defined(_GLIBCXX_DEBUG) +#endif // defined(__GNUC__) + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) +# include +# include +# include +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + +namespace boost { +namespace asio { + +class mutable_buffer; +class const_buffer; + +namespace detail { +void* buffer_cast_helper(const mutable_buffer&); +const void* buffer_cast_helper(const const_buffer&); +std::size_t buffer_size_helper(const mutable_buffer&); +std::size_t buffer_size_helper(const const_buffer&); +} // namespace detail + +/// Holds a buffer that can be modified. +/** + * The mutable_buffer class provides a safe representation of a buffer that can + * be modified. It does not own the underlying data, and so is cheap to copy or + * assign. + */ +class mutable_buffer +{ +public: + /// Construct an empty buffer. + mutable_buffer() + : data_(0), + size_(0) + { + } + + /// Construct a buffer to represent a given memory range. + mutable_buffer(void* data, std::size_t size) + : data_(data), + size_(size) + { + } + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + mutable_buffer(void* data, std::size_t size, + boost::function debug_check) + : data_(data), + size_(size), + debug_check_(debug_check) + { + } + + const boost::function& get_debug_check() const + { + return debug_check_; + } +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + +private: + friend void* boost::asio::detail::buffer_cast_helper( + const mutable_buffer& b); + friend std::size_t boost::asio::detail::buffer_size_helper( + const mutable_buffer& b); + + void* data_; + std::size_t size_; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + boost::function debug_check_; +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING +}; + +namespace detail { + +inline void* buffer_cast_helper(const mutable_buffer& b) +{ +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + if (b.size_ && b.debug_check_) + b.debug_check_(); +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + return b.data_; +} + +inline std::size_t buffer_size_helper(const mutable_buffer& b) +{ + return b.size_; +} + +} // namespace detail + +/// Cast a non-modifiable buffer to a specified pointer to POD type. +/** + * @relates mutable_buffer + */ +template +inline PointerToPodType buffer_cast(const mutable_buffer& b) +{ + return static_cast(detail::buffer_cast_helper(b)); +} + +/// Get the number of bytes in a non-modifiable buffer. +/** + * @relates mutable_buffer + */ +inline std::size_t buffer_size(const mutable_buffer& b) +{ + return detail::buffer_size_helper(b); +} + +/// Create a new modifiable buffer that is offset from the start of another. +/** + * @relates mutable_buffer + */ +inline mutable_buffer operator+(const mutable_buffer& b, std::size_t start) +{ + if (start > buffer_size(b)) + return mutable_buffer(); + char* new_data = buffer_cast(b) + start; + std::size_t new_size = buffer_size(b) - start; + return mutable_buffer(new_data, new_size +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new modifiable buffer that is offset from the start of another. +/** + * @relates mutable_buffer + */ +inline mutable_buffer operator+(std::size_t start, const mutable_buffer& b) +{ + if (start > buffer_size(b)) + return mutable_buffer(); + char* new_data = buffer_cast(b) + start; + std::size_t new_size = buffer_size(b) - start; + return mutable_buffer(new_data, new_size +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Adapts a single modifiable buffer so that it meets the requirements of the +/// MutableBufferSequence concept. +class mutable_buffers_1 + : public mutable_buffer +{ +public: + /// The type for each element in the list of buffers. + typedef mutable_buffer value_type; + + /// A random-access iterator type that may be used to read elements. + typedef const mutable_buffer* const_iterator; + + /// Construct to represent a given memory range. + mutable_buffers_1(void* data, std::size_t size) + : mutable_buffer(data, size) + { + } + + /// Construct to represent a single modifiable buffer. + explicit mutable_buffers_1(const mutable_buffer& b) + : mutable_buffer(b) + { + } + + /// Get a random-access iterator to the first element. + const_iterator begin() const + { + return this; + } + + /// Get a random-access iterator for one past the last element. + const_iterator end() const + { + return begin() + 1; + } +}; + +/// Holds a buffer that cannot be modified. +/** + * The const_buffer class provides a safe representation of a buffer that cannot + * be modified. It does not own the underlying data, and so is cheap to copy or + * assign. + */ +class const_buffer +{ +public: + /// Construct an empty buffer. + const_buffer() + : data_(0), + size_(0) + { + } + + /// Construct a buffer to represent a given memory range. + const_buffer(const void* data, std::size_t size) + : data_(data), + size_(size) + { + } + + /// Construct a non-modifiable buffer from a modifiable one. + const_buffer(const mutable_buffer& b) + : data_(boost::asio::detail::buffer_cast_helper(b)), + size_(boost::asio::detail::buffer_size_helper(b)) +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , debug_check_(b.get_debug_check()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + { + } + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + const_buffer(const void* data, std::size_t size, + boost::function debug_check) + : data_(data), + size_(size), + debug_check_(debug_check) + { + } + + const boost::function& get_debug_check() const + { + return debug_check_; + } +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + +private: + friend const void* boost::asio::detail::buffer_cast_helper( + const const_buffer& b); + friend std::size_t boost::asio::detail::buffer_size_helper( + const const_buffer& b); + + const void* data_; + std::size_t size_; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + boost::function debug_check_; +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING +}; + +namespace detail { + +inline const void* buffer_cast_helper(const const_buffer& b) +{ +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + if (b.size_ && b.debug_check_) + b.debug_check_(); +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + return b.data_; +} + +inline std::size_t buffer_size_helper(const const_buffer& b) +{ + return b.size_; +} + +} // namespace detail + +/// Cast a non-modifiable buffer to a specified pointer to POD type. +/** + * @relates const_buffer + */ +template +inline PointerToPodType buffer_cast(const const_buffer& b) +{ + return static_cast(detail::buffer_cast_helper(b)); +} + +/// Get the number of bytes in a non-modifiable buffer. +/** + * @relates const_buffer + */ +inline std::size_t buffer_size(const const_buffer& b) +{ + return detail::buffer_size_helper(b); +} + +/// Create a new non-modifiable buffer that is offset from the start of another. +/** + * @relates const_buffer + */ +inline const_buffer operator+(const const_buffer& b, std::size_t start) +{ + if (start > buffer_size(b)) + return const_buffer(); + const char* new_data = buffer_cast(b) + start; + std::size_t new_size = buffer_size(b) - start; + return const_buffer(new_data, new_size +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new non-modifiable buffer that is offset from the start of another. +/** + * @relates const_buffer + */ +inline const_buffer operator+(std::size_t start, const const_buffer& b) +{ + if (start > buffer_size(b)) + return const_buffer(); + const char* new_data = buffer_cast(b) + start; + std::size_t new_size = buffer_size(b) - start; + return const_buffer(new_data, new_size +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Adapts a single non-modifiable buffer so that it meets the requirements of +/// the ConstBufferSequence concept. +class const_buffers_1 + : public const_buffer +{ +public: + /// The type for each element in the list of buffers. + typedef const_buffer value_type; + + /// A random-access iterator type that may be used to read elements. + typedef const const_buffer* const_iterator; + + /// Construct to represent a given memory range. + const_buffers_1(const void* data, std::size_t size) + : const_buffer(data, size) + { + } + + /// Construct to represent a single non-modifiable buffer. + explicit const_buffers_1(const const_buffer& b) + : const_buffer(b) + { + } + + /// Get a random-access iterator to the first element. + const_iterator begin() const + { + return this; + } + + /// Get a random-access iterator for one past the last element. + const_iterator end() const + { + return begin() + 1; + } +}; + +/// An implementation of both the ConstBufferSequence and MutableBufferSequence +/// concepts to represent a null buffer sequence. +class null_buffers +{ +public: + /// The type for each element in the list of buffers. + typedef mutable_buffer value_type; + + /// A random-access iterator type that may be used to read elements. + typedef const mutable_buffer* const_iterator; + + /// Get a random-access iterator to the first element. + const_iterator begin() const + { + return &buf_; + } + + /// Get a random-access iterator for one past the last element. + const_iterator end() const + { + return &buf_; + } + +private: + mutable_buffer buf_; +}; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) +namespace detail { + +template +class buffer_debug_check +{ +public: + buffer_debug_check(Iterator iter) + : iter_(iter) + { + } + + ~buffer_debug_check() + { +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) + // MSVC's string iterator checking may crash in a std::string::iterator + // object's destructor when the iterator points to an already-destroyed + // std::string object, unless the iterator is cleared first. + iter_ = Iterator(); +#endif // BOOST_WORKAROUND(BOOST_MSVC, >= 1400) + } + + void operator()() + { + *iter_; + } + +private: + Iterator iter_; +}; + +} // namespace detail +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + +/** @defgroup buffer boost::asio::buffer + * + * @brief The boost::asio::buffer function is used to create a buffer object to + * represent raw memory, an array of POD elements, a vector of POD elements, + * or a std::string. + * + * A buffer object represents a contiguous region of memory as a 2-tuple + * consisting of a pointer and size in bytes. A tuple of the form {void*, + * size_t} specifies a mutable (modifiable) region of memory. Similarly, a + * tuple of the form {const void*, size_t} specifies a const + * (non-modifiable) region of memory. These two forms correspond to the classes + * mutable_buffer and const_buffer, respectively. To mirror C++'s conversion + * rules, a mutable_buffer is implicitly convertible to a const_buffer, and the + * opposite conversion is not permitted. + * + * The simplest use case involves reading or writing a single buffer of a + * specified size: + * + * @code sock.send(boost::asio::buffer(data, size)); @endcode + * + * In the above example, the return value of boost::asio::buffer meets the + * requirements of the ConstBufferSequence concept so that it may be directly + * passed to the socket's write function. A buffer created for modifiable + * memory also meets the requirements of the MutableBufferSequence concept. + * + * An individual buffer may be created from a builtin array, std::vector or + * boost::array of POD elements. This helps prevent buffer overruns by + * automatically determining the size of the buffer: + * + * @code char d1[128]; + * size_t bytes_transferred = sock.receive(boost::asio::buffer(d1)); + * + * std::vector d2(128); + * bytes_transferred = sock.receive(boost::asio::buffer(d2)); + * + * boost::array d3; + * bytes_transferred = sock.receive(boost::asio::buffer(d3)); @endcode + * + * In all three cases above, the buffers created are exactly 128 bytes long. + * Note that a vector is @e never automatically resized when creating or using + * a buffer. The buffer size is determined using the vector's size() + * member function, and not its capacity. + * + * @par Accessing Buffer Contents + * + * The contents of a buffer may be accessed using the boost::asio::buffer_size + * and boost::asio::buffer_cast functions: + * + * @code boost::asio::mutable_buffer b1 = ...; + * std::size_t s1 = boost::asio::buffer_size(b1); + * unsigned char* p1 = boost::asio::buffer_cast(b1); + * + * boost::asio::const_buffer b2 = ...; + * std::size_t s2 = boost::asio::buffer_size(b2); + * const void* p2 = boost::asio::buffer_cast(b2); @endcode + * + * The boost::asio::buffer_cast function permits violations of type safety, so + * uses of it in application code should be carefully considered. + * + * @par Buffer Invalidation + * + * A buffer object does not have any ownership of the memory it refers to. It + * is the responsibility of the application to ensure the memory region remains + * valid until it is no longer required for an I/O operation. When the memory + * is no longer available, the buffer is said to have been invalidated. + * + * For the boost::asio::buffer overloads that accept an argument of type + * std::vector, the buffer objects returned are invalidated by any vector + * operation that also invalidates all references, pointers and iterators + * referring to the elements in the sequence (C++ Std, 23.2.4) + * + * For the boost::asio::buffer overloads that accept an argument of type + * std::string, the buffer objects returned are invalidated according to the + * rules defined for invalidation of references, pointers and iterators + * referring to elements of the sequence (C++ Std, 21.3). + * + * @par Buffer Arithmetic + * + * Buffer objects may be manipulated using simple arithmetic in a safe way + * which helps prevent buffer overruns. Consider an array initialised as + * follows: + * + * @code boost::array a = { 'a', 'b', 'c', 'd', 'e' }; @endcode + * + * A buffer object @c b1 created using: + * + * @code b1 = boost::asio::buffer(a); @endcode + * + * represents the entire array, { 'a', 'b', 'c', 'd', 'e' }. An + * optional second argument to the boost::asio::buffer function may be used to + * limit the size, in bytes, of the buffer: + * + * @code b2 = boost::asio::buffer(a, 3); @endcode + * + * such that @c b2 represents the data { 'a', 'b', 'c' }. Even if the + * size argument exceeds the actual size of the array, the size of the buffer + * object created will be limited to the array size. + * + * An offset may be applied to an existing buffer to create a new one: + * + * @code b3 = b1 + 2; @endcode + * + * where @c b3 will set to represent { 'c', 'd', 'e' }. If the offset + * exceeds the size of the existing buffer, the newly created buffer will be + * empty. + * + * Both an offset and size may be specified to create a buffer that corresponds + * to a specific range of bytes within an existing buffer: + * + * @code b4 = boost::asio::buffer(b1 + 1, 3); @endcode + * + * so that @c b4 will refer to the bytes { 'b', 'c', 'd' }. + * + * @par Buffers and Scatter-Gather I/O + * + * To read or write using multiple buffers (i.e. scatter-gather I/O), multiple + * buffer objects may be assigned into a container that supports the + * MutableBufferSequence (for read) or ConstBufferSequence (for write) concepts: + * + * @code + * char d1[128]; + * std::vector d2(128); + * boost::array d3; + * + * boost::array bufs1 = { + * boost::asio::buffer(d1), + * boost::asio::buffer(d2), + * boost::asio::buffer(d3) }; + * bytes_transferred = sock.receive(bufs1); + * + * std::vector bufs2; + * bufs2.push_back(boost::asio::buffer(d1)); + * bufs2.push_back(boost::asio::buffer(d2)); + * bufs2.push_back(boost::asio::buffer(d3)); + * bytes_transferred = sock.send(bufs2); @endcode + */ +/*@{*/ + +/// Create a new modifiable buffer from an existing buffer. +/** + * @returns mutable_buffers_1(b). + */ +inline mutable_buffers_1 buffer(const mutable_buffer& b) +{ + return mutable_buffers_1(b); +} + +/// Create a new modifiable buffer from an existing buffer. +/** + * @returns A mutable_buffers_1 value equivalent to: + * @code mutable_buffers_1( + * buffer_cast(b), + * min(buffer_size(b), max_size_in_bytes)); @endcode + */ +inline mutable_buffers_1 buffer(const mutable_buffer& b, + std::size_t max_size_in_bytes) +{ + return mutable_buffers_1( + mutable_buffer(buffer_cast(b), + buffer_size(b) < max_size_in_bytes + ? buffer_size(b) : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + )); +} + +/// Create a new non-modifiable buffer from an existing buffer. +/** + * @returns const_buffers_1(b). + */ +inline const_buffers_1 buffer(const const_buffer& b) +{ + return const_buffers_1(b); +} + +/// Create a new non-modifiable buffer from an existing buffer. +/** + * @returns A const_buffers_1 value equivalent to: + * @code const_buffers_1( + * buffer_cast(b), + * min(buffer_size(b), max_size_in_bytes)); @endcode + */ +inline const_buffers_1 buffer(const const_buffer& b, + std::size_t max_size_in_bytes) +{ + return const_buffers_1( + const_buffer(buffer_cast(b), + buffer_size(b) < max_size_in_bytes + ? buffer_size(b) : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + )); +} + +/// Create a new modifiable buffer that represents the given memory range. +/** + * @returns mutable_buffers_1(data, size_in_bytes). + */ +inline mutable_buffers_1 buffer(void* data, std::size_t size_in_bytes) +{ + return mutable_buffers_1(mutable_buffer(data, size_in_bytes)); +} + +/// Create a new non-modifiable buffer that represents the given memory range. +/** + * @returns const_buffers_1(data, size_in_bytes). + */ +inline const_buffers_1 buffer(const void* data, + std::size_t size_in_bytes) +{ + return const_buffers_1(const_buffer(data, size_in_bytes)); +} + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffers_1 value equivalent to: + * @code mutable_buffers_1( + * static_cast(data), + * N * sizeof(PodType)); @endcode + */ +template +inline mutable_buffers_1 buffer(PodType (&data)[N]) +{ + return mutable_buffers_1(mutable_buffer(data, N * sizeof(PodType))); +} + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffers_1 value equivalent to: + * @code mutable_buffers_1( + * static_cast(data), + * min(N * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline mutable_buffers_1 buffer(PodType (&data)[N], + std::size_t max_size_in_bytes) +{ + return mutable_buffers_1( + mutable_buffer(data, + N * sizeof(PodType) < max_size_in_bytes + ? N * sizeof(PodType) : max_size_in_bytes)); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffers_1 value equivalent to: + * @code const_buffers_1( + * static_cast(data), + * N * sizeof(PodType)); @endcode + */ +template +inline const_buffers_1 buffer(const PodType (&data)[N]) +{ + return const_buffers_1(const_buffer(data, N * sizeof(PodType))); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffers_1 value equivalent to: + * @code const_buffers_1( + * static_cast(data), + * min(N * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline const_buffers_1 buffer(const PodType (&data)[N], + std::size_t max_size_in_bytes) +{ + return const_buffers_1( + const_buffer(data, + N * sizeof(PodType) < max_size_in_bytes + ? N * sizeof(PodType) : max_size_in_bytes)); +} + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \ + || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) + +// Borland C++ and Sun Studio think the overloads: +// +// unspecified buffer(boost::array& array ...); +// +// and +// +// unspecified buffer(boost::array& array ...); +// +// are ambiguous. This will be worked around by using a buffer_types traits +// class that contains typedefs for the appropriate buffer and container +// classes, based on whether PodType is const or non-const. + +namespace detail { + +template +struct buffer_types_base; + +template <> +struct buffer_types_base +{ + typedef mutable_buffer buffer_type; + typedef mutable_buffers_1 container_type; +}; + +template <> +struct buffer_types_base +{ + typedef const_buffer buffer_type; + typedef const_buffers_1 container_type; +}; + +template +struct buffer_types + : public buffer_types_base::value> +{ +}; + +} // namespace detail + +template +inline typename detail::buffer_types::container_type +buffer(boost::array& data) +{ + typedef typename boost::asio::detail::buffer_types::buffer_type + buffer_type; + typedef typename boost::asio::detail::buffer_types::container_type + container_type; + return container_type( + buffer_type(data.c_array(), data.size() * sizeof(PodType))); +} + +template +inline typename detail::buffer_types::container_type +buffer(boost::array& data, std::size_t max_size_in_bytes) +{ + typedef typename boost::asio::detail::buffer_types::buffer_type + buffer_type; + typedef typename boost::asio::detail::buffer_types::container_type + container_type; + return container_type( + buffer_type(data.c_array(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes)); +} + +#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffers_1 value equivalent to: + * @code mutable_buffers_1( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline mutable_buffers_1 buffer(boost::array& data) +{ + return mutable_buffers_1( + mutable_buffer(data.c_array(), data.size() * sizeof(PodType))); +} + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffers_1 value equivalent to: + * @code mutable_buffers_1( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline mutable_buffers_1 buffer(boost::array& data, + std::size_t max_size_in_bytes) +{ + return mutable_buffers_1( + mutable_buffer(data.c_array(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes)); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffers_1 value equivalent to: + * @code const_buffers_1( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline const_buffers_1 buffer(boost::array& data) +{ + return const_buffers_1( + const_buffer(data.data(), data.size() * sizeof(PodType))); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffers_1 value equivalent to: + * @code const_buffers_1( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline const_buffers_1 buffer(boost::array& data, + std::size_t max_size_in_bytes) +{ + return const_buffers_1( + const_buffer(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes)); +} + +#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffers_1 value equivalent to: + * @code const_buffers_1( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline const_buffers_1 buffer(const boost::array& data) +{ + return const_buffers_1( + const_buffer(data.data(), data.size() * sizeof(PodType))); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffers_1 value equivalent to: + * @code const_buffers_1( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline const_buffers_1 buffer(const boost::array& data, + std::size_t max_size_in_bytes) +{ + return const_buffers_1( + const_buffer(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes)); +} + +/// Create a new modifiable buffer that represents the given POD vector. +/** + * @returns A mutable_buffers_1 value equivalent to: + * @code mutable_buffers_1( + * data.size() ? &data[0] : 0, + * data.size() * sizeof(PodType)); @endcode + * + * @note The buffer is invalidated by any vector operation that would also + * invalidate iterators. + */ +template +inline mutable_buffers_1 buffer(std::vector& data) +{ + return mutable_buffers_1( + mutable_buffer(data.size() ? &data[0] : 0, data.size() * sizeof(PodType) +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + )); +} + +/// Create a new modifiable buffer that represents the given POD vector. +/** + * @returns A mutable_buffers_1 value equivalent to: + * @code mutable_buffers_1( + * data.size() ? &data[0] : 0, + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + * + * @note The buffer is invalidated by any vector operation that would also + * invalidate iterators. + */ +template +inline mutable_buffers_1 buffer(std::vector& data, + std::size_t max_size_in_bytes) +{ + return mutable_buffers_1( + mutable_buffer(data.size() ? &data[0] : 0, + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + )); +} + +/// Create a new non-modifiable buffer that represents the given POD vector. +/** + * @returns A const_buffers_1 value equivalent to: + * @code const_buffers_1( + * data.size() ? &data[0] : 0, + * data.size() * sizeof(PodType)); @endcode + * + * @note The buffer is invalidated by any vector operation that would also + * invalidate iterators. + */ +template +inline const_buffers_1 buffer( + const std::vector& data) +{ + return const_buffers_1( + const_buffer(data.size() ? &data[0] : 0, data.size() * sizeof(PodType) +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::const_iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + )); +} + +/// Create a new non-modifiable buffer that represents the given POD vector. +/** + * @returns A const_buffers_1 value equivalent to: + * @code const_buffers_1( + * data.size() ? &data[0] : 0, + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + * + * @note The buffer is invalidated by any vector operation that would also + * invalidate iterators. + */ +template +inline const_buffers_1 buffer( + const std::vector& data, std::size_t max_size_in_bytes) +{ + return const_buffers_1( + const_buffer(data.size() ? &data[0] : 0, + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::const_iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + )); +} + +/// Create a new non-modifiable buffer that represents the given string. +/** + * @returns const_buffers_1(data.data(), data.size()). + * + * @note The buffer is invalidated by any non-const operation called on the + * given string object. + */ +inline const_buffers_1 buffer(const std::string& data) +{ + return const_buffers_1(const_buffer(data.data(), data.size() +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + )); +} + +/// Create a new non-modifiable buffer that represents the given string. +/** + * @returns A const_buffers_1 value equivalent to: + * @code const_buffers_1( + * data.data(), + * min(data.size(), max_size_in_bytes)); @endcode + * + * @note The buffer is invalidated by any non-const operation called on the + * given string object. + */ +inline const_buffers_1 buffer(const std::string& data, + std::size_t max_size_in_bytes) +{ + return const_buffers_1( + const_buffer(data.data(), + data.size() < max_size_in_bytes + ? data.size() : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + )); +} + +/*@}*/ + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BUFFER_HPP diff --git a/3rdParty/Boost/boost/asio/buffered_read_stream.hpp b/3rdParty/Boost/boost/asio/buffered_read_stream.hpp new file mode 100644 index 0000000..742123b --- /dev/null +++ b/3rdParty/Boost/boost/asio/buffered_read_stream.hpp @@ -0,0 +1,422 @@ +// +// buffered_read_stream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { + +/// 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, Sync_Read_Stream, SyncWriteStream. + */ +template +class buffered_read_stream + : private noncopyable +{ +public: + /// The type of the next layer. + typedef typename boost::remove_reference::type next_layer_type; + + /// The type of the lowest layer. + typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The default buffer size. + static const std::size_t default_buffer_size = implementation_defined; +#else + BOOST_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024); +#endif + + /// Construct, passing the specified argument to initialise the next layer. + template + explicit buffered_read_stream(Arg& a) + : next_layer_(a), + storage_(default_buffer_size) + { + } + + /// Construct, passing the specified argument to initialise the next layer. + template + buffered_read_stream(Arg& a, std::size_t buffer_size) + : next_layer_(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(); + } + + /// (Deprecated: use get_io_service().) Get the io_service associated with + /// the object. + boost::asio::io_service& io_service() + { + return next_layer_.get_io_service(); + } + + /// Get the io_service associated with the object. + boost::asio::io_service& get_io_service() + { + return next_layer_.get_io_service(); + } + + /// Close the stream. + void close() + { + next_layer_.close(); + } + + /// Close the stream. + boost::system::error_code close(boost::system::error_code& ec) + { + return next_layer_.close(ec); + } + + /// Write the given data to the stream. Returns the number of bytes written. + /// Throws an exception on failure. + template + 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 + 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. + template + void async_write_some(const ConstBufferSequence& buffers, + WriteHandler handler) + { + next_layer_.async_write_some(buffers, 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() + { + detail::buffer_resize_guard + resize_guard(storage_); + std::size_t previous_size = storage_.size(); + storage_.resize(storage_.capacity()); + storage_.resize(previous_size + next_layer_.read_some(buffer( + storage_.data() + previous_size, + storage_.size() - previous_size))); + resize_guard.commit(); + return storage_.size() - previous_size; + } + + /// 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) + { + detail::buffer_resize_guard + resize_guard(storage_); + std::size_t previous_size = storage_.size(); + storage_.resize(storage_.capacity()); + storage_.resize(previous_size + next_layer_.read_some(buffer( + storage_.data() + previous_size, + storage_.size() - previous_size), + ec)); + resize_guard.commit(); + return storage_.size() - previous_size; + } + + template + class fill_handler + { + public: + fill_handler(boost::asio::io_service& io_service, + detail::buffered_stream_storage& storage, + std::size_t previous_size, ReadHandler handler) + : io_service_(io_service), + storage_(storage), + previous_size_(previous_size), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + storage_.resize(previous_size_ + bytes_transferred); + io_service_.dispatch(detail::bind_handler( + handler_, ec, bytes_transferred)); + } + + private: + boost::asio::io_service& io_service_; + detail::buffered_stream_storage& storage_; + std::size_t previous_size_; + ReadHandler handler_; + }; + + /// Start an asynchronous fill. + template + void async_fill(ReadHandler handler) + { + std::size_t previous_size = storage_.size(); + storage_.resize(storage_.capacity()); + next_layer_.async_read_some( + buffer( + storage_.data() + previous_size, + storage_.size() - previous_size), + fill_handler(get_io_service(), + storage_, previous_size, handler)); + } + + /// Read some data from the stream. Returns the number of bytes read. Throws + /// an exception on failure. + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + if (storage_.empty()) + fill(); + return copy(buffers); + } + + /// Read some data from the stream. Returns the number of bytes read or 0 if + /// an error occurred. + template + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + ec = boost::system::error_code(); + if (storage_.empty() && !fill(ec)) + return 0; + return copy(buffers); + } + + template + class read_some_handler + { + public: + read_some_handler(boost::asio::io_service& io_service, + detail::buffered_stream_storage& storage, + const MutableBufferSequence& buffers, ReadHandler handler) + : io_service_(io_service), + storage_(storage), + buffers_(buffers), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, std::size_t) + { + if (ec || storage_.empty()) + { + std::size_t length = 0; + io_service_.dispatch(detail::bind_handler(handler_, ec, length)); + } + else + { + using namespace std; // For memcpy. + + std::size_t bytes_avail = storage_.size(); + std::size_t bytes_copied = 0; + + typename MutableBufferSequence::const_iterator iter = buffers_.begin(); + typename MutableBufferSequence::const_iterator end = buffers_.end(); + for (; iter != end && bytes_avail > 0; ++iter) + { + std::size_t max_length = buffer_size(*iter); + std::size_t length = (max_length < bytes_avail) + ? max_length : bytes_avail; + memcpy(buffer_cast(*iter), + storage_.data() + bytes_copied, length); + bytes_copied += length; + bytes_avail -= length; + } + + storage_.consume(bytes_copied); + io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied)); + } + } + + private: + boost::asio::io_service& io_service_; + detail::buffered_stream_storage& storage_; + MutableBufferSequence buffers_; + ReadHandler handler_; + }; + + /// Start an asynchronous read. The buffer into which the data will be read + /// must be valid for the lifetime of the asynchronous operation. + template + void async_read_some(const MutableBufferSequence& buffers, + ReadHandler handler) + { + if (storage_.empty()) + { + async_fill(read_some_handler( + get_io_service(), storage_, buffers, handler)); + } + else + { + std::size_t length = copy(buffers); + get_io_service().post(detail::bind_handler( + handler, boost::system::error_code(), length)); + } + } + + /// Peek at the incoming data on the stream. Returns the number of bytes read. + /// Throws an exception on failure. + template + std::size_t peek(const MutableBufferSequence& buffers) + { + if (storage_.empty()) + fill(); + return peek_copy(buffers); + } + + /// Peek at the incoming data on the stream. Returns the number of bytes read, + /// or 0 if an error occurred. + template + std::size_t peek(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + ec = boost::system::error_code(); + if (storage_.empty() && !fill(ec)) + return 0; + return peek_copy(buffers); + } + + /// 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 + std::size_t copy(const MutableBufferSequence& buffers) + { + using namespace std; // For memcpy. + + std::size_t bytes_avail = storage_.size(); + std::size_t bytes_copied = 0; + + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); + for (; iter != end && bytes_avail > 0; ++iter) + { + std::size_t max_length = buffer_size(*iter); + std::size_t length = (max_length < bytes_avail) + ? max_length : bytes_avail; + memcpy(buffer_cast(*iter), storage_.data() + bytes_copied, length); + bytes_copied += length; + bytes_avail -= length; + } + + 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 + std::size_t peek_copy(const MutableBufferSequence& buffers) + { + using namespace std; // For memcpy. + + std::size_t bytes_avail = storage_.size(); + std::size_t bytes_copied = 0; + + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); + for (; iter != end && bytes_avail > 0; ++iter) + { + std::size_t max_length = buffer_size(*iter); + std::size_t length = (max_length < bytes_avail) + ? max_length : bytes_avail; + memcpy(buffer_cast(*iter), storage_.data() + bytes_copied, length); + bytes_copied += length; + bytes_avail -= length; + } + + return bytes_copied; + } + + /// The next layer. + Stream next_layer_; + + // The data in the buffer. + detail::buffered_stream_storage storage_; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BUFFERED_READ_STREAM_HPP diff --git a/3rdParty/Boost/boost/asio/buffered_read_stream_fwd.hpp b/3rdParty/Boost/boost/asio/buffered_read_stream_fwd.hpp new file mode 100644 index 0000000..da9765e --- /dev/null +++ b/3rdParty/Boost/boost/asio/buffered_read_stream_fwd.hpp @@ -0,0 +1,31 @@ +// +// buffered_read_stream_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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) + +#include + +namespace boost { +namespace asio { + +template +class buffered_read_stream; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BUFFERED_READ_STREAM_FWD_HPP diff --git a/3rdParty/Boost/boost/asio/buffered_stream.hpp b/3rdParty/Boost/boost/asio/buffered_stream.hpp new file mode 100644 index 0000000..e1b8d38 --- /dev/null +++ b/3rdParty/Boost/boost/asio/buffered_stream.hpp @@ -0,0 +1,258 @@ +// +// buffered_stream.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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 +class buffered_stream + : private noncopyable +{ +public: + /// The type of the next layer. + typedef typename boost::remove_reference::type next_layer_type; + + /// The type of the lowest layer. + typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + + /// Construct, passing the specified argument to initialise the next layer. + template + explicit buffered_stream(Arg& a) + : inner_stream_impl_(a), + stream_impl_(inner_stream_impl_) + { + } + + /// Construct, passing the specified argument to initialise the next layer. + template + explicit buffered_stream(Arg& a, std::size_t read_buffer_size, + std::size_t write_buffer_size) + : inner_stream_impl_(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(); + } + + /// (Deprecated: use get_io_service().) Get the io_service associated with + /// the object. + boost::asio::io_service& io_service() + { + return stream_impl_.get_io_service(); + } + + /// Get the io_service associated with the object. + boost::asio::io_service& get_io_service() + { + return stream_impl_.get_io_service(); + } + + /// Close the stream. + void close() + { + stream_impl_.close(); + } + + /// Close the stream. + boost::system::error_code close(boost::system::error_code& ec) + { + return stream_impl_.close(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. + template + void async_flush(WriteHandler handler) + { + return stream_impl_.next_layer().async_flush(handler); + } + + /// Write the given data to the stream. Returns the number of bytes written. + /// Throws an exception on failure. + template + 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 + 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. + template + void async_write_some(const ConstBufferSequence& buffers, + WriteHandler handler) + { + stream_impl_.async_write_some(buffers, 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. + template + void async_fill(ReadHandler handler) + { + stream_impl_.async_fill(handler); + } + + /// Read some data from the stream. Returns the number of bytes read. Throws + /// an exception on failure. + template + 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 + 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. + template + void async_read_some(const MutableBufferSequence& buffers, + ReadHandler handler) + { + stream_impl_.async_read_some(buffers, handler); + } + + /// Peek at the incoming data on the stream. Returns the number of bytes read. + /// Throws an exception on failure. + template + 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 + 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 write_stream_type; + write_stream_type inner_stream_impl_; + + // The buffered read stream. + typedef buffered_read_stream read_stream_type; + read_stream_type stream_impl_; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BUFFERED_STREAM_HPP diff --git a/3rdParty/Boost/boost/asio/buffered_stream_fwd.hpp b/3rdParty/Boost/boost/asio/buffered_stream_fwd.hpp new file mode 100644 index 0000000..7641235 --- /dev/null +++ b/3rdParty/Boost/boost/asio/buffered_stream_fwd.hpp @@ -0,0 +1,31 @@ +// +// buffered_stream_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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) + +#include + +namespace boost { +namespace asio { + +template +class buffered_stream; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BUFFERED_STREAM_FWD_HPP diff --git a/3rdParty/Boost/boost/asio/buffered_write_stream.hpp b/3rdParty/Boost/boost/asio/buffered_write_stream.hpp new file mode 100644 index 0000000..1d06541 --- /dev/null +++ b/3rdParty/Boost/boost/asio/buffered_write_stream.hpp @@ -0,0 +1,376 @@ +// +// buffered_write_stream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { + +/// 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 +class buffered_write_stream + : private noncopyable +{ +public: + /// The type of the next layer. + typedef typename boost::remove_reference::type next_layer_type; + + /// The type of the lowest layer. + typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The default buffer size. + static const std::size_t default_buffer_size = implementation_defined; +#else + BOOST_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024); +#endif + + /// Construct, passing the specified argument to initialise the next layer. + template + explicit buffered_write_stream(Arg& a) + : next_layer_(a), + storage_(default_buffer_size) + { + } + + /// Construct, passing the specified argument to initialise the next layer. + template + buffered_write_stream(Arg& a, std::size_t buffer_size) + : next_layer_(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(); + } + + /// (Deprecated: use get_io_service().) Get the io_service associated with + /// the object. + boost::asio::io_service& io_service() + { + return next_layer_.get_io_service(); + } + + /// Get the io_service associated with the object. + boost::asio::io_service& get_io_service() + { + return next_layer_.get_io_service(); + } + + /// Close the stream. + void close() + { + next_layer_.close(); + } + + /// Close the stream. + boost::system::error_code close(boost::system::error_code& ec) + { + return next_layer_.close(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() + { + std::size_t bytes_written = write(next_layer_, + buffer(storage_.data(), storage_.size())); + storage_.consume(bytes_written); + return bytes_written; + } + + /// 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) + { + std::size_t bytes_written = write(next_layer_, + buffer(storage_.data(), storage_.size()), + transfer_all(), ec); + storage_.consume(bytes_written); + return bytes_written; + } + + template + class flush_handler + { + public: + flush_handler(boost::asio::io_service& io_service, + detail::buffered_stream_storage& storage, WriteHandler handler) + : io_service_(io_service), + storage_(storage), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_written) + { + storage_.consume(bytes_written); + io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_written)); + } + + private: + boost::asio::io_service& io_service_; + detail::buffered_stream_storage& storage_; + WriteHandler handler_; + }; + + /// Start an asynchronous flush. + template + void async_flush(WriteHandler handler) + { + async_write(next_layer_, buffer(storage_.data(), storage_.size()), + flush_handler(get_io_service(), storage_, handler)); + } + + /// Write the given data to the stream. Returns the number of bytes written. + /// Throws an exception on failure. + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + if (storage_.size() == storage_.capacity()) + flush(); + return copy(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 + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec) + { + ec = boost::system::error_code(); + if (storage_.size() == storage_.capacity() && !flush(ec)) + return 0; + return copy(buffers); + } + + template + class write_some_handler + { + public: + write_some_handler(boost::asio::io_service& io_service, + detail::buffered_stream_storage& storage, + const ConstBufferSequence& buffers, WriteHandler handler) + : io_service_(io_service), + storage_(storage), + buffers_(buffers), + handler_(handler) + { + } + + void operator()(const boost::system::error_code& ec, std::size_t) + { + if (ec) + { + std::size_t length = 0; + io_service_.dispatch(detail::bind_handler(handler_, ec, length)); + } + else + { + using namespace std; // For memcpy. + + std::size_t orig_size = storage_.size(); + std::size_t space_avail = storage_.capacity() - orig_size; + std::size_t bytes_copied = 0; + + typename ConstBufferSequence::const_iterator iter = buffers_.begin(); + typename ConstBufferSequence::const_iterator end = buffers_.end(); + for (; iter != end && space_avail > 0; ++iter) + { + std::size_t bytes_avail = buffer_size(*iter); + std::size_t length = (bytes_avail < space_avail) + ? bytes_avail : space_avail; + storage_.resize(orig_size + bytes_copied + length); + memcpy(storage_.data() + orig_size + bytes_copied, + buffer_cast(*iter), length); + bytes_copied += length; + space_avail -= length; + } + + io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied)); + } + } + + private: + boost::asio::io_service& io_service_; + detail::buffered_stream_storage& storage_; + ConstBufferSequence buffers_; + WriteHandler handler_; + }; + + /// Start an asynchronous write. The data being written must be valid for the + /// lifetime of the asynchronous operation. + template + void async_write_some(const ConstBufferSequence& buffers, + WriteHandler handler) + { + if (storage_.size() == storage_.capacity()) + { + async_flush(write_some_handler( + get_io_service(), storage_, buffers, handler)); + } + else + { + std::size_t bytes_copied = copy(buffers); + get_io_service().post(detail::bind_handler( + handler, boost::system::error_code(), bytes_copied)); + } + } + + /// Read some data from the stream. Returns the number of bytes read. Throws + /// an exception on failure. + template + 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 + 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. + template + void async_read_some(const MutableBufferSequence& buffers, + ReadHandler handler) + { + next_layer_.async_read_some(buffers, handler); + } + + /// Peek at the incoming data on the stream. Returns the number of bytes read. + /// Throws an exception on failure. + template + 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 + 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 + std::size_t copy(const ConstBufferSequence& buffers) + { + using namespace std; // For memcpy. + + std::size_t orig_size = storage_.size(); + std::size_t space_avail = storage_.capacity() - orig_size; + std::size_t bytes_copied = 0; + + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); + for (; iter != end && space_avail > 0; ++iter) + { + std::size_t bytes_avail = buffer_size(*iter); + std::size_t length = (bytes_avail < space_avail) + ? bytes_avail : space_avail; + storage_.resize(orig_size + bytes_copied + length); + memcpy(storage_.data() + orig_size + bytes_copied, + buffer_cast(*iter), length); + bytes_copied += length; + space_avail -= length; + } + + return bytes_copied; + } + + /// The next layer. + Stream next_layer_; + + // The data in the buffer. + detail::buffered_stream_storage storage_; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BUFFERED_WRITE_STREAM_HPP diff --git a/3rdParty/Boost/boost/asio/buffered_write_stream_fwd.hpp b/3rdParty/Boost/boost/asio/buffered_write_stream_fwd.hpp new file mode 100644 index 0000000..4774e89 --- /dev/null +++ b/3rdParty/Boost/boost/asio/buffered_write_stream_fwd.hpp @@ -0,0 +1,31 @@ +// +// buffered_write_stream_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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) + +#include + +namespace boost { +namespace asio { + +template +class buffered_write_stream; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BUFFERED_WRITE_STREAM_FWD_HPP diff --git a/3rdParty/Boost/boost/asio/buffers_iterator.hpp b/3rdParty/Boost/boost/asio/buffers_iterator.hpp new file mode 100644 index 0000000..f9d61da --- /dev/null +++ b/3rdParty/Boost/boost/asio/buffers_iterator.hpp @@ -0,0 +1,327 @@ +// +// buffers_iterator.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +namespace detail +{ + template + struct buffers_iterator_types_helper; + + template <> + struct buffers_iterator_types_helper + { + typedef const_buffer buffer_type; + template + struct byte_type + { + typedef typename boost::add_const::type type; + }; + }; + + template <> + struct buffers_iterator_types_helper + { + typedef mutable_buffer buffer_type; + template + struct byte_type + { + typedef ByteType type; + }; + }; + + template + struct buffers_iterator_types + { + enum + { + is_mutable = boost::is_convertible< + typename BufferSequence::value_type, mutable_buffer>::value + }; + typedef buffers_iterator_types_helper helper; + typedef typename helper::buffer_type buffer_type; + typedef typename helper::template byte_type::type byte_type; + }; +} + +/// A random access iterator over the bytes in a buffer sequence. +template +class buffers_iterator + : public boost::iterator_facade< + buffers_iterator, + typename detail::buffers_iterator_types< + BufferSequence, ByteType>::byte_type, + boost::random_access_traversal_tag> +{ +private: + typedef typename detail::buffers_iterator_types< + BufferSequence, ByteType>::buffer_type buffer_type; + typedef typename detail::buffers_iterator_types< + BufferSequence, ByteType>::byte_type byte_type; + +public: + /// 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 BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3) + __attribute__ ((noinline)) +#endif + { + buffers_iterator new_iter; + new_iter.begin_ = buffers.begin(); + new_iter.current_ = buffers.begin(); + new_iter.end_ = buffers.end(); + while (new_iter.current_ != new_iter.end_) + { + new_iter.current_buffer_ = *new_iter.current_; + if (boost::asio::buffer_size(new_iter.current_buffer_) > 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 BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3) + __attribute__ ((noinline)) +#endif + { + buffers_iterator new_iter; + new_iter.begin_ = buffers.begin(); + new_iter.current_ = buffers.begin(); + new_iter.end_ = buffers.end(); + while (new_iter.current_ != new_iter.end_) + { + buffer_type buffer = *new_iter.current_; + new_iter.position_ += boost::asio::buffer_size(buffer); + ++new_iter.current_; + } + return new_iter; + } + +private: + friend class boost::iterator_core_access; + + // Dereference the iterator. + byte_type& dereference() const + { + return buffer_cast(current_buffer_)[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_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_ != boost::asio::buffer_size(current_buffer_)) + return; + + // Find the next non-empty buffer. + ++current_; + current_buffer_position_ = 0; + while (current_ != end_) + { + current_buffer_ = *current_; + if (boost::asio::buffer_size(current_buffer_) > 0) + return; + ++current_; + } + } + + // Decrement the iterator. + void decrement() + { + BOOST_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. + typename BufferSequence::const_iterator iter = current_; + while (iter != begin_) + { + --iter; + buffer_type buffer = *iter; + std::size_t buffer_size = boost::asio::buffer_size(buffer); + 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_ASSERT(current_ != end_ && "iterator out of bounds"); + for (;;) + { + std::ptrdiff_t current_buffer_balance + = boost::asio::buffer_size(current_buffer_) + - 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_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_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_ASSERT(abs_n == 0 && "iterator out of bounds"); + current_buffer_position_ = 0; + return; + } + + // Find the previous non-empty buffer. + typename BufferSequence::const_iterator iter = current_; + while (iter != begin_) + { + --iter; + buffer_type buffer = *iter; + std::size_t buffer_size = boost::asio::buffer_size(buffer); + 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_; + typename BufferSequence::const_iterator begin_; + typename BufferSequence::const_iterator current_; + typename BufferSequence::const_iterator end_; + std::size_t position_; +}; + +/// Construct an iterator representing the beginning of the buffers' data. +template +inline buffers_iterator buffers_begin( + const BufferSequence& buffers) +{ + return buffers_iterator::begin(buffers); +} + +/// Construct an iterator representing the end of the buffers' data. +template +inline buffers_iterator buffers_end( + const BufferSequence& buffers) +{ + return buffers_iterator::end(buffers); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BUFFERS_ITERATOR_HPP diff --git a/3rdParty/Boost/boost/asio/completion_condition.hpp b/3rdParty/Boost/boost/asio/completion_condition.hpp new file mode 100644 index 0000000..c317c02 --- /dev/null +++ b/3rdParty/Boost/boost/asio/completion_condition.hpp @@ -0,0 +1,166 @@ +// +// completion_condition.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 + +#include +#include +#include +#include + +namespace boost { +namespace asio { + +namespace detail { + +// The default maximum number of bytes to transfer in a single operation. +enum { 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 + 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 + 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_; +}; + +} // namespace detail + +/** + * @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 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 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 + +/*@}*/ + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_COMPLETION_CONDITION_HPP diff --git a/3rdParty/Boost/boost/asio/datagram_socket_service.hpp b/3rdParty/Boost/boost/asio/datagram_socket_service.hpp new file mode 100644 index 0000000..8cc6617 --- /dev/null +++ b/3rdParty/Boost/boost/asio/datagram_socket_service.hpp @@ -0,0 +1,325 @@ +// +// datagram_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_DATAGRAM_SOCKET_SERVICE_HPP +#define BOOST_ASIO_DATAGRAM_SOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { + +/// Default service implementation for a datagram socket. +template +class datagram_socket_service +#if defined(GENERATING_DOCUMENTATION) + : public boost::asio::io_service::service +#else + : public boost::asio::detail::service_base > +#endif +{ +public: +#if defined(GENERATING_DOCUMENTATION) + /// The unique service identifier. + static boost::asio::io_service::id id; +#endif + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + +private: + // The type of the platform-specific implementation. +#if defined(BOOST_ASIO_HAS_IOCP) + typedef detail::win_iocp_socket_service service_impl_type; +#elif defined(BOOST_ASIO_HAS_EPOLL) + typedef detail::reactive_socket_service< + Protocol, detail::epoll_reactor > service_impl_type; +#elif defined(BOOST_ASIO_HAS_KQUEUE) + typedef detail::reactive_socket_service< + Protocol, detail::kqueue_reactor > service_impl_type; +#elif defined(BOOST_ASIO_HAS_DEV_POLL) + typedef detail::reactive_socket_service< + Protocol, detail::dev_poll_reactor > service_impl_type; +#else + typedef detail::reactive_socket_service< + Protocol, detail::select_reactor > service_impl_type; +#endif + +public: + /// The type of a datagram socket. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined implementation_type; +#else + typedef typename service_impl_type::implementation_type implementation_type; +#endif + + /// The native socket type. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_type; +#else + typedef typename service_impl_type::native_type native_type; +#endif + + /// Construct a new datagram socket service for the specified io_service. + explicit datagram_socket_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base< + datagram_socket_service >(io_service), + service_impl_(boost::asio::use_service(io_service)) + { + } + + /// Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + } + + /// Construct a new datagram socket implementation. + void construct(implementation_type& impl) + { + service_impl_.construct(impl); + } + + /// Destroy a datagram socket implementation. + void destroy(implementation_type& impl) + { + service_impl_.destroy(impl); + } + + // Open a new datagram socket implementation. + boost::system::error_code open(implementation_type& impl, + const protocol_type& protocol, boost::system::error_code& ec) + { + if (protocol.type() == SOCK_DGRAM) + service_impl_.open(impl, protocol, ec); + else + ec = boost::asio::error::invalid_argument; + return ec; + } + + /// Assign an existing native socket to a datagram socket. + boost::system::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_type& native_socket, + boost::system::error_code& ec) + { + return service_impl_.assign(impl, protocol, native_socket, ec); + } + + /// Determine whether the socket is open. + bool is_open(const implementation_type& impl) const + { + return service_impl_.is_open(impl); + } + + /// Close a datagram socket implementation. + boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec) + { + return service_impl_.close(impl, ec); + } + + /// Get the native socket implementation. + native_type native(implementation_type& impl) + { + return service_impl_.native(impl); + } + + /// Cancel all asynchronous operations associated with the socket. + boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec) + { + return service_impl_.cancel(impl, ec); + } + + /// Determine whether the socket is at the out-of-band data mark. + bool at_mark(const implementation_type& impl, + boost::system::error_code& ec) const + { + return service_impl_.at_mark(impl, ec); + } + + /// Determine the number of bytes available for reading. + std::size_t available(const implementation_type& impl, + boost::system::error_code& ec) const + { + return service_impl_.available(impl, ec); + } + + // Bind the datagram socket to the specified local endpoint. + boost::system::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, boost::system::error_code& ec) + { + return service_impl_.bind(impl, endpoint, ec); + } + + /// Connect the datagram socket to the specified endpoint. + boost::system::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, boost::system::error_code& ec) + { + return service_impl_.connect(impl, peer_endpoint, ec); + } + + /// Start an asynchronous connect. + template + void async_connect(implementation_type& impl, + const endpoint_type& peer_endpoint, ConnectHandler handler) + { + service_impl_.async_connect(impl, peer_endpoint, handler); + } + + /// Set a socket option. + template + boost::system::error_code set_option(implementation_type& impl, + const SettableSocketOption& option, boost::system::error_code& ec) + { + return service_impl_.set_option(impl, option, ec); + } + + /// Get a socket option. + template + boost::system::error_code get_option(const implementation_type& impl, + GettableSocketOption& option, boost::system::error_code& ec) const + { + return service_impl_.get_option(impl, option, ec); + } + + /// Perform an IO control command on the socket. + template + boost::system::error_code io_control(implementation_type& impl, + IoControlCommand& command, boost::system::error_code& ec) + { + return service_impl_.io_control(impl, command, ec); + } + + /// Get the local endpoint. + endpoint_type local_endpoint(const implementation_type& impl, + boost::system::error_code& ec) const + { + return service_impl_.local_endpoint(impl, ec); + } + + /// Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type& impl, + boost::system::error_code& ec) const + { + return service_impl_.remote_endpoint(impl, ec); + } + + /// Disable sends or receives on the socket. + boost::system::error_code shutdown(implementation_type& impl, + socket_base::shutdown_type what, boost::system::error_code& ec) + { + return service_impl_.shutdown(impl, what, ec); + } + + /// Send the given data to the peer. + template + std::size_t send(implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return service_impl_.send(impl, buffers, flags, ec); + } + + /// Start an asynchronous send. + template + void async_send(implementation_type& impl, const ConstBufferSequence& buffers, + socket_base::message_flags flags, WriteHandler handler) + { + service_impl_.async_send(impl, buffers, flags, handler); + } + + /// Send a datagram to the specified endpoint. + template + std::size_t send_to(implementation_type& impl, + const ConstBufferSequence& buffers, const endpoint_type& destination, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return service_impl_.send_to(impl, buffers, destination, flags, ec); + } + + /// Start an asynchronous send. + template + void async_send_to(implementation_type& impl, + const ConstBufferSequence& buffers, const endpoint_type& destination, + socket_base::message_flags flags, WriteHandler handler) + { + service_impl_.async_send_to(impl, buffers, destination, flags, handler); + } + + /// Receive some data from the peer. + template + std::size_t receive(implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return service_impl_.receive(impl, buffers, flags, ec); + } + + /// Start an asynchronous receive. + template + void async_receive(implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, ReadHandler handler) + { + service_impl_.async_receive(impl, buffers, flags, handler); + } + + /// Receive a datagram with the endpoint of the sender. + template + std::size_t receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return service_impl_.receive_from(impl, buffers, sender_endpoint, flags, + ec); + } + + /// Start an asynchronous receive that will get the endpoint of the sender. + template + void async_receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, + socket_base::message_flags flags, ReadHandler handler) + { + service_impl_.async_receive_from(impl, buffers, sender_endpoint, flags, + handler); + } + +private: + // The service that provides the platform-specific implementation. + service_impl_type& service_impl_; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DATAGRAM_SOCKET_SERVICE_HPP diff --git a/3rdParty/Boost/boost/asio/deadline_timer.hpp b/3rdParty/Boost/boost/asio/deadline_timer.hpp new file mode 100644 index 0000000..a62a2ce --- /dev/null +++ b/3rdParty/Boost/boost/asio/deadline_timer.hpp @@ -0,0 +1,39 @@ +// +// deadline_timer.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 + +#include // Must come before posix_time. + +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Typedef for the typical usage of timer. +typedef basic_deadline_timer deadline_timer; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DEADLINE_TIMER_HPP diff --git a/3rdParty/Boost/boost/asio/deadline_timer_service.hpp b/3rdParty/Boost/boost/asio/deadline_timer_service.hpp new file mode 100644 index 0000000..dccd139 --- /dev/null +++ b/3rdParty/Boost/boost/asio/deadline_timer_service.hpp @@ -0,0 +1,170 @@ +// +// deadline_timer_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SERVICE_HPP +#define BOOST_ASIO_DEADLINE_TIMER_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { + +/// Default service implementation for a timer. +template > +class deadline_timer_service +#if defined(GENERATING_DOCUMENTATION) + : public boost::asio::io_service::service +#else + : public boost::asio::detail::service_base< + deadline_timer_service > +#endif +{ +public: +#if defined(GENERATING_DOCUMENTATION) + /// The unique service identifier. + static boost::asio::io_service::id id; +#endif + + /// 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; + +private: + // The type of the platform-specific implementation. +#if defined(BOOST_ASIO_HAS_IOCP) + typedef detail::deadline_timer_service< + traits_type, detail::win_iocp_io_service> service_impl_type; +#elif defined(BOOST_ASIO_HAS_EPOLL) + typedef detail::deadline_timer_service< + traits_type, detail::epoll_reactor > service_impl_type; +#elif defined(BOOST_ASIO_HAS_KQUEUE) + typedef detail::deadline_timer_service< + traits_type, detail::kqueue_reactor > service_impl_type; +#elif defined(BOOST_ASIO_HAS_DEV_POLL) + typedef detail::deadline_timer_service< + traits_type, detail::dev_poll_reactor > service_impl_type; +#else + typedef detail::deadline_timer_service< + traits_type, detail::select_reactor > service_impl_type; +#endif + +public: + /// The implementation type of the deadline timer. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined implementation_type; +#else + typedef typename service_impl_type::implementation_type implementation_type; +#endif + + /// Construct a new timer service for the specified io_service. + explicit deadline_timer_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base< + deadline_timer_service >(io_service), + service_impl_(boost::asio::use_service(io_service)) + { + } + + /// Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + } + + /// Construct a new timer implementation. + void construct(implementation_type& impl) + { + service_impl_.construct(impl); + } + + /// Destroy a timer implementation. + void destroy(implementation_type& impl) + { + service_impl_.destroy(impl); + } + + /// Cancel any asynchronous wait operations associated with the timer. + std::size_t cancel(implementation_type& impl, boost::system::error_code& ec) + { + return service_impl_.cancel(impl, ec); + } + + /// Get the expiry time for the timer as an absolute time. + time_type expires_at(const implementation_type& impl) const + { + return service_impl_.expires_at(impl); + } + + /// Set the expiry time for the timer as an absolute time. + std::size_t expires_at(implementation_type& impl, + const time_type& expiry_time, boost::system::error_code& ec) + { + return service_impl_.expires_at(impl, expiry_time, ec); + } + + /// Get the expiry time for the timer relative to now. + duration_type expires_from_now(const implementation_type& impl) const + { + return service_impl_.expires_from_now(impl); + } + + /// Set the expiry time for the timer relative to now. + std::size_t expires_from_now(implementation_type& impl, + const duration_type& expiry_time, boost::system::error_code& ec) + { + return service_impl_.expires_from_now(impl, expiry_time, ec); + } + + // Perform a blocking wait on the timer. + void wait(implementation_type& impl, boost::system::error_code& ec) + { + service_impl_.wait(impl, ec); + } + + // Start an asynchronous wait on the timer. + template + void async_wait(implementation_type& impl, WaitHandler handler) + { + service_impl_.async_wait(impl, handler); + } + +private: + // The service that provides the platform-specific implementation. + service_impl_type& service_impl_; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DEADLINE_TIMER_SERVICE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/bind_handler.hpp b/3rdParty/Boost/boost/asio/detail/bind_handler.hpp new file mode 100644 index 0000000..3a9ad01 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/bind_handler.hpp @@ -0,0 +1,351 @@ +// +// bind_handler.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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 + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class binder1 +{ +public: + binder1(const Handler& handler, const Arg1& arg1) + : handler_(handler), + arg1_(arg1) + { + } + + void operator()() + { + handler_(arg1_); + } + + void operator()() const + { + handler_(arg1_); + } + +//private: + Handler handler_; + Arg1 arg1_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + binder1* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, &this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder1* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, &this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + binder1* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, &this_handler->handler_); +} + +template +inline binder1 bind_handler(const Handler& handler, + const Arg1& arg1) +{ + return binder1(handler, arg1); +} + +template +class binder2 +{ +public: + binder2(const Handler& handler, const Arg1& arg1, const Arg2& arg2) + : handler_(handler), + arg1_(arg1), + arg2_(arg2) + { + } + + void operator()() + { + handler_(arg1_, arg2_); + } + + void operator()() const + { + handler_(arg1_, arg2_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + binder2* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, &this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder2* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, &this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + binder2* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, &this_handler->handler_); +} + +template +inline binder2 bind_handler(const Handler& handler, + const Arg1& arg1, const Arg2& arg2) +{ + return binder2(handler, arg1, arg2); +} + +template +class binder3 +{ +public: + binder3(const Handler& handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3) + : handler_(handler), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3) + { + } + + void operator()() + { + handler_(arg1_, arg2_, arg3_); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + binder3* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, &this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder3* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, &this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + binder3* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, &this_handler->handler_); +} + +template +inline binder3 bind_handler(const Handler& handler, + const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) +{ + return binder3(handler, arg1, arg2, arg3); +} + +template +class binder4 +{ +public: + binder4(const Handler& handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3, const Arg4& arg4) + : handler_(handler), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4) + { + } + + void operator()() + { + handler_(arg1_, arg2_, arg3_, arg4_); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_, arg4_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; + Arg4 arg4_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + binder4* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, &this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder4* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, &this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + binder4* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, &this_handler->handler_); +} + +template +inline binder4 bind_handler( + const Handler& handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3, const Arg4& arg4) +{ + return binder4(handler, arg1, arg2, arg3, + arg4); +} + +template +class binder5 +{ +public: + binder5(const Handler& handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) + : handler_(handler), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4), + arg5_(arg5) + { + } + + void operator()() + { + handler_(arg1_, arg2_, arg3_, arg4_, arg5_); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_, arg4_, arg5_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; + Arg4 arg4_; + Arg5 arg5_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + binder5* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, &this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder5* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, &this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + binder5* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, &this_handler->handler_); +} + +template +inline binder5 bind_handler( + const Handler& handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) +{ + return binder5(handler, arg1, arg2, + arg3, arg4, arg5); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_BIND_HANDLER_HPP diff --git a/3rdParty/Boost/boost/asio/detail/buffer_resize_guard.hpp b/3rdParty/Boost/boost/asio/detail/buffer_resize_guard.hpp new file mode 100644 index 0000000..63d957c --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/buffer_resize_guard.hpp @@ -0,0 +1,72 @@ +// +// buffer_resize_guard.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_BUFFER_RESIZE_GUARD_HPP +#define BOOST_ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +// Helper class to manage buffer resizing in an exception safe way. +template +class buffer_resize_guard +{ +public: + // Constructor. + buffer_resize_guard(Buffer& buffer) + : buffer_(buffer), + old_size_(buffer.size()) + { + } + + // Destructor rolls back the buffer resize unless commit was called. + ~buffer_resize_guard() + { + if (old_size_ + != std::numeric_limits::max BOOST_PREVENT_MACRO_SUBSTITUTION()) + { + buffer_.resize(old_size_); + } + } + + // Commit the resize transaction. + void commit() + { + old_size_ + = std::numeric_limits::max BOOST_PREVENT_MACRO_SUBSTITUTION(); + } + +private: + // The buffer being managed. + Buffer& buffer_; + + // The size of the buffer at the time the guard was constructed. + size_t old_size_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP diff --git a/3rdParty/Boost/boost/asio/detail/buffered_stream_storage.hpp b/3rdParty/Boost/boost/asio/detail/buffered_stream_storage.hpp new file mode 100644 index 0000000..f20bf27 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/buffered_stream_storage.hpp @@ -0,0 +1,129 @@ +// +// buffered_stream_storage.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_BUFFERED_STREAM_STORAGE_HPP +#define BOOST_ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class buffered_stream_storage +{ +public: + // The type of the bytes stored in the buffer. + typedef unsigned char byte_type; + + // The type used for offsets into the buffer. + typedef std::size_t size_type; + + // Constructor. + explicit buffered_stream_storage(std::size_t capacity) + : begin_offset_(0), + end_offset_(0), + buffer_(capacity) + { + } + + /// Clear the buffer. + void clear() + { + begin_offset_ = 0; + end_offset_ = 0; + } + + // Return a pointer to the beginning of the unread data. + byte_type* data() + { + return &buffer_[0] + begin_offset_; + } + + // Return a pointer to the beginning of the unread data. + const byte_type* data() const + { + return &buffer_[0] + begin_offset_; + } + + // Is there no unread data in the buffer. + bool empty() const + { + return begin_offset_ == end_offset_; + } + + // Return the amount of unread data the is in the buffer. + size_type size() const + { + return end_offset_ - begin_offset_; + } + + // Resize the buffer to the specified length. + void resize(size_type length) + { + assert(length <= capacity()); + if (begin_offset_ + length <= capacity()) + { + end_offset_ = begin_offset_ + length; + } + else + { + using namespace std; // For memmove. + memmove(&buffer_[0], &buffer_[0] + begin_offset_, size()); + end_offset_ = length; + begin_offset_ = 0; + } + } + + // Return the maximum size for data in the buffer. + size_type capacity() const + { + return buffer_.size(); + } + + // Consume multiple bytes from the beginning of the buffer. + void consume(size_type count) + { + assert(begin_offset_ + count <= end_offset_); + begin_offset_ += count; + if (empty()) + clear(); + } + +private: + // The offset to the beginning of the unread data. + size_type begin_offset_; + + // The offset to the end of the unread data. + size_type end_offset_; + + // The data in the buffer. + std::vector buffer_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/call_stack.hpp b/3rdParty/Boost/boost/asio/detail/call_stack.hpp new file mode 100644 index 0000000..0096741 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/call_stack.hpp @@ -0,0 +1,92 @@ +// +// call_stack.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_CALL_STACK_HPP +#define BOOST_ASIO_DETAIL_CALL_STACK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +// Helper class to determine whether or not the current thread is inside an +// invocation of io_service::run() for a specified io_service object. +template +class call_stack +{ +public: + // Context class automatically pushes an owner on to the stack. + class context + : private noncopyable + { + public: + // Push the owner on to the stack. + explicit context(Owner* d) + : owner_(d), + next_(call_stack::top_) + { + call_stack::top_ = this; + } + + // Pop the owner from the stack. + ~context() + { + call_stack::top_ = next_; + } + + private: + friend class call_stack; + + // The owner associated with the context. + Owner* owner_; + + // The next element in the stack. + context* next_; + }; + + friend class context; + + // Determine whether the specified owner is on the stack. + static bool contains(Owner* d) + { + context* elem = top_; + while (elem) + { + if (elem->owner_ == d) + return true; + elem = elem->next_; + } + return false; + } + +private: + // The top of the stack of calls for the current thread. + static tss_ptr top_; +}; + +template +tss_ptr::context> +call_stack::top_; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_CALL_STACK_HPP diff --git a/3rdParty/Boost/boost/asio/detail/consuming_buffers.hpp b/3rdParty/Boost/boost/asio/detail/consuming_buffers.hpp new file mode 100644 index 0000000..0ed811d --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/consuming_buffers.hpp @@ -0,0 +1,246 @@ +// +// consuming_buffers.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_CONSUMING_BUFFERS_HPP +#define BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +// A proxy iterator for a sub-range in a list of buffers. +template +class consuming_buffers_iterator + : public boost::iterator_facade< + consuming_buffers_iterator, + const Buffer, boost::forward_traversal_tag> +{ +public: + // Default constructor creates an end iterator. + consuming_buffers_iterator() + : at_end_(true) + { + } + + // Construct with a buffer for the first entry and an iterator + // range for the remaining entries. + consuming_buffers_iterator(bool at_end, const Buffer& first, + Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder, + std::size_t max_size) + : at_end_(max_size > 0 ? at_end : true), + first_(buffer(first, max_size)), + begin_remainder_(begin_remainder), + end_remainder_(end_remainder), + offset_(0), + max_size_(max_size) + { + } + +private: + friend class boost::iterator_core_access; + + void increment() + { + if (!at_end_) + { + if (begin_remainder_ == end_remainder_ + || offset_ + buffer_size(first_) >= max_size_) + { + at_end_ = true; + } + else + { + offset_ += buffer_size(first_); + first_ = buffer(*begin_remainder_++, max_size_ - offset_); + } + } + } + + bool equal(const consuming_buffers_iterator& other) const + { + if (at_end_ && other.at_end_) + return true; + return !at_end_ && !other.at_end_ + && buffer_cast(first_) + == buffer_cast(other.first_) + && buffer_size(first_) == buffer_size(other.first_) + && begin_remainder_ == other.begin_remainder_ + && end_remainder_ == other.end_remainder_; + } + + const Buffer& dereference() const + { + return first_; + } + + bool at_end_; + Buffer first_; + Buffer_Iterator begin_remainder_; + Buffer_Iterator end_remainder_; + std::size_t offset_; + std::size_t max_size_; +}; + +// A proxy for a sub-range in a list of buffers. +template +class consuming_buffers +{ +public: + // The type for each element in the list of buffers. + typedef Buffer value_type; + + // A forward-only iterator type that may be used to read elements. + typedef consuming_buffers_iterator + const_iterator; + + // Construct to represent the entire list of buffers. + consuming_buffers(const Buffers& buffers) + : buffers_(buffers), + at_end_(buffers_.begin() == buffers_.end()), + first_(*buffers_.begin()), + begin_remainder_(buffers_.begin()), + max_size_((std::numeric_limits::max)()) + { + if (!at_end_) + ++begin_remainder_; + } + + // Copy constructor. + consuming_buffers(const consuming_buffers& other) + : buffers_(other.buffers_), + at_end_(other.at_end_), + first_(other.first_), + begin_remainder_(buffers_.begin()), + max_size_(other.max_size_) + { + typename Buffers::const_iterator first = other.buffers_.begin(); + typename Buffers::const_iterator second = other.begin_remainder_; + std::advance(begin_remainder_, std::distance(first, second)); + } + + // Assignment operator. + consuming_buffers& operator=(const consuming_buffers& other) + { + buffers_ = other.buffers_; + at_end_ = other.at_end_; + first_ = other.first_; + begin_remainder_ = buffers_.begin(); + typename Buffers::const_iterator first = other.buffers_.begin(); + typename Buffers::const_iterator second = other.begin_remainder_; + std::advance(begin_remainder_, std::distance(first, second)); + max_size_ = other.max_size_; + return *this; + } + + // Get a forward-only iterator to the first element. + const_iterator begin() const + { + return const_iterator(at_end_, first_, + begin_remainder_, buffers_.end(), max_size_); + } + + // Get a forward-only iterator for one past the last element. + const_iterator end() const + { + return const_iterator(); + } + + // Set the maximum size for a single transfer. + void set_max_size(std::size_t max_size) + { + max_size_ = max_size; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + // Remove buffers from the start until the specified size is reached. + while (size > 0 && !at_end_) + { + if (buffer_size(first_) <= size) + { + size -= buffer_size(first_); + if (begin_remainder_ == buffers_.end()) + at_end_ = true; + else + first_ = *begin_remainder_++; + } + else + { + first_ = first_ + size; + size = 0; + } + } + + // Remove any more empty buffers at the start. + while (!at_end_ && buffer_size(first_) == 0) + { + if (begin_remainder_ == buffers_.end()) + at_end_ = true; + else + first_ = *begin_remainder_++; + } + } + +private: + Buffers buffers_; + bool at_end_; + Buffer first_; + typename Buffers::const_iterator begin_remainder_; + std::size_t max_size_; +}; + +// Specialisation for null_buffers to ensure that the null_buffers type is +// always passed through to the underlying read or write operation. +template +class consuming_buffers + : public boost::asio::null_buffers +{ +public: + consuming_buffers(const boost::asio::null_buffers&) + { + // No-op. + } + + void set_max_size(std::size_t) + { + // No-op. + } + + void consume(std::size_t) + { + // No-op. + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP diff --git a/3rdParty/Boost/boost/asio/detail/deadline_timer_service.hpp b/3rdParty/Boost/boost/asio/detail/deadline_timer_service.hpp new file mode 100644 index 0000000..16206a7 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/deadline_timer_service.hpp @@ -0,0 +1,203 @@ +// +// deadline_timer_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_DEADLINE_TIMER_SERVICE_HPP +#define BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class deadline_timer_service + : public boost::asio::detail::service_base< + deadline_timer_service > +{ +public: + // The time type. + typedef typename Time_Traits::time_type time_type; + + // The duration type. + typedef typename Time_Traits::duration_type duration_type; + + // The implementation type of the timer. This type is dependent on the + // underlying implementation of the timer service. + struct implementation_type + : private boost::asio::detail::noncopyable + { + time_type expiry; + bool might_have_pending_waits; + }; + + // Constructor. + deadline_timer_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base< + deadline_timer_service >(io_service), + scheduler_(boost::asio::use_service(io_service)) + { + scheduler_.init_task(); + scheduler_.add_timer_queue(timer_queue_); + } + + // Destructor. + ~deadline_timer_service() + { + scheduler_.remove_timer_queue(timer_queue_); + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + } + + // Construct a new timer implementation. + void construct(implementation_type& impl) + { + impl.expiry = time_type(); + impl.might_have_pending_waits = false; + } + + // Destroy a timer implementation. + void destroy(implementation_type& impl) + { + boost::system::error_code ec; + cancel(impl, ec); + } + + // Cancel any asynchronous wait operations associated with the timer. + std::size_t cancel(implementation_type& impl, boost::system::error_code& ec) + { + if (!impl.might_have_pending_waits) + { + ec = boost::system::error_code(); + return 0; + } + std::size_t count = scheduler_.cancel_timer(timer_queue_, &impl); + impl.might_have_pending_waits = false; + ec = boost::system::error_code(); + return count; + } + + // Get the expiry time for the timer as an absolute time. + time_type expires_at(const implementation_type& impl) const + { + return impl.expiry; + } + + // Set the expiry time for the timer as an absolute time. + std::size_t expires_at(implementation_type& impl, + const time_type& expiry_time, boost::system::error_code& ec) + { + std::size_t count = cancel(impl, ec); + impl.expiry = expiry_time; + ec = boost::system::error_code(); + return count; + } + + // Get the expiry time for the timer relative to now. + duration_type expires_from_now(const implementation_type& impl) const + { + return Time_Traits::subtract(expires_at(impl), Time_Traits::now()); + } + + // Set the expiry time for the timer relative to now. + std::size_t expires_from_now(implementation_type& impl, + const duration_type& expiry_time, boost::system::error_code& ec) + { + return expires_at(impl, + Time_Traits::add(Time_Traits::now(), expiry_time), ec); + } + + // Perform a blocking wait on the timer. + void wait(implementation_type& impl, boost::system::error_code& ec) + { + time_type now = Time_Traits::now(); + while (Time_Traits::less_than(now, impl.expiry)) + { + boost::posix_time::time_duration timeout = + Time_Traits::to_posix_duration(Time_Traits::subtract(impl.expiry, now)); + ::timeval tv; + tv.tv_sec = timeout.total_seconds(); + tv.tv_usec = timeout.total_microseconds() % 1000000; + boost::system::error_code ec; + socket_ops::select(0, 0, 0, 0, &tv, ec); + now = Time_Traits::now(); + } + ec = boost::system::error_code(); + } + + template + class wait_handler : + public handler_base_from_member + { + public: + wait_handler(boost::asio::io_service& io_service, Handler handler) + : handler_base_from_member(handler), + io_service_(io_service), + work_(io_service) + { + } + + void operator()(const boost::system::error_code& result) + { + io_service_.post(detail::bind_handler(this->handler_, result)); + } + + private: + boost::asio::io_service& io_service_; + boost::asio::io_service::work work_; + }; + + // Start an asynchronous wait on the timer. + template + void async_wait(implementation_type& impl, Handler handler) + { + impl.might_have_pending_waits = true; + scheduler_.schedule_timer(timer_queue_, impl.expiry, + wait_handler(this->get_io_service(), handler), &impl); + } + +private: + // The queue of timers. + timer_queue timer_queue_; + + // The object that schedules and executes timers. Usually a reactor. + Timer_Scheduler& scheduler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/descriptor_ops.hpp b/3rdParty/Boost/boost/asio/detail/descriptor_ops.hpp new file mode 100644 index 0000000..2ee1988 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/descriptor_ops.hpp @@ -0,0 +1,178 @@ +// +// descriptor_ops.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_DESCRIPTOR_OPS_HPP +#define BOOST_ASIO_DETAIL_DESCRIPTOR_OPS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#include +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +namespace boost { +namespace asio { +namespace detail { +namespace descriptor_ops { + +inline void clear_error(boost::system::error_code& ec) +{ + errno = 0; + ec = boost::system::error_code(); +} + +template +inline ReturnType error_wrapper(ReturnType return_value, + boost::system::error_code& ec) +{ + ec = boost::system::error_code(errno, + boost::asio::error::get_system_category()); + return return_value; +} + +inline int open(const char* path, int flags, boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(::open(path, flags), ec); + if (result >= 0) + clear_error(ec); + return result; +} + +inline int close(int d, boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(::close(d), ec); + if (result == 0) + clear_error(ec); + return result; +} + +inline void init_buf_iov_base(void*& base, void* addr) +{ + base = addr; +} + +template +inline void init_buf_iov_base(T& base, void* addr) +{ + base = static_cast(addr); +} + +typedef iovec buf; + +inline void init_buf(buf& b, void* data, size_t size) +{ + init_buf_iov_base(b.iov_base, data); + b.iov_len = size; +} + +inline void init_buf(buf& b, const void* data, size_t size) +{ + init_buf_iov_base(b.iov_base, const_cast(data)); + b.iov_len = size; +} + +inline int scatter_read(int d, buf* bufs, size_t count, + boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(::readv(d, bufs, static_cast(count)), ec); + if (result >= 0) + clear_error(ec); + return result; +} + +inline int gather_write(int d, const buf* bufs, size_t count, + boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(::writev(d, bufs, static_cast(count)), ec); + if (result >= 0) + clear_error(ec); + return result; +} + +inline int ioctl(int d, long cmd, ioctl_arg_type* arg, + boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(::ioctl(d, cmd, arg), ec); + if (result >= 0) + clear_error(ec); + return result; +} + +inline int fcntl(int d, long cmd, boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(::fcntl(d, cmd), ec); + if (result != -1) + clear_error(ec); + return result; +} + +inline int fcntl(int d, long cmd, long arg, boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(::fcntl(d, cmd, arg), ec); + if (result != -1) + clear_error(ec); + return result; +} + +inline int poll_read(int d, boost::system::error_code& ec) +{ + clear_error(ec); + pollfd fds; + fds.fd = d; + fds.events = POLLIN; + fds.revents = 0; + clear_error(ec); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + clear_error(ec); + return result; +} + +inline int poll_write(int d, boost::system::error_code& ec) +{ + clear_error(ec); + pollfd fds; + fds.fd = d; + fds.events = POLLOUT; + fds.revents = 0; + clear_error(ec); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + clear_error(ec); + return result; +} + +} // namespace descriptor_ops +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include + +#endif // BOOST_ASIO_DETAIL_DESCRIPTOR_OPS_HPP diff --git a/3rdParty/Boost/boost/asio/detail/dev_poll_reactor.hpp b/3rdParty/Boost/boost/asio/detail/dev_poll_reactor.hpp new file mode 100644 index 0000000..8739085 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/dev_poll_reactor.hpp @@ -0,0 +1,678 @@ +// +// dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_DEV_POLL_REACTOR_HPP +#define BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if defined(BOOST_ASIO_HAS_DEV_POLL) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class dev_poll_reactor + : public boost::asio::detail::service_base > +{ +public: + // Per-descriptor data. + struct per_descriptor_data + { + }; + + // Constructor. + dev_poll_reactor(boost::asio::io_service& io_service) + : boost::asio::detail::service_base< + dev_poll_reactor >(io_service), + mutex_(), + dev_poll_fd_(do_dev_poll_create()), + wait_in_progress_(false), + interrupter_(), + read_op_queue_(), + write_op_queue_(), + except_op_queue_(), + pending_cancellations_(), + stop_thread_(false), + thread_(0), + shutdown_(false) + { + // Start the reactor's internal thread only if needed. + if (Own_Thread) + { + boost::asio::detail::signal_blocker sb; + thread_ = new boost::asio::detail::thread( + bind_handler(&dev_poll_reactor::call_run_thread, this)); + } + + // Add the interrupter's descriptor to /dev/poll. + ::pollfd ev = { 0 }; + ev.fd = interrupter_.read_descriptor(); + ev.events = POLLIN | POLLERR; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + } + + // Destructor. + ~dev_poll_reactor() + { + shutdown_service(); + ::close(dev_poll_fd_); + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + stop_thread_ = true; + lock.unlock(); + + if (thread_) + { + interrupter_.interrupt(); + thread_->join(); + delete thread_; + thread_ = 0; + } + + read_op_queue_.destroy_operations(); + write_op_queue_.destroy_operations(); + except_op_queue_.destroy_operations(); + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + timer_queues_[i]->destroy_timers(); + timer_queues_.clear(); + } + + // Initialise the task, but only if the reactor is not in its own thread. + void init_task() + { + if (!Own_Thread) + { + typedef task_io_service > + task_io_service_type; + use_service(this->get_io_service()).init_task(); + } + } + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + int register_descriptor(socket_type, per_descriptor_data&) + { + return 0; + } + + // Start a new read operation. The handler object will be invoked when the + // given descriptor is ready to be read, or an error has occurred. + template + void start_read_op(socket_type descriptor, per_descriptor_data&, + Handler handler, bool allow_speculative_read = true) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (allow_speculative_read) + { + if (!read_op_queue_.has_operation(descriptor)) + { + boost::system::error_code ec; + std::size_t bytes_transferred = 0; + if (handler.perform(ec, bytes_transferred)) + { + handler.complete(ec, bytes_transferred); + return; + } + } + } + + if (read_op_queue_.enqueue_operation(descriptor, handler)) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLIN | POLLERR | POLLHUP; + if (write_op_queue_.has_operation(descriptor)) + ev.events |= POLLOUT; + if (except_op_queue_.has_operation(descriptor)) + ev.events |= POLLPRI; + interrupter_.interrupt(); + } + } + + // Start a new write operation. The handler object will be invoked when the + // given descriptor is ready to be written, or an error has occurred. + template + void start_write_op(socket_type descriptor, per_descriptor_data&, + Handler handler, bool allow_speculative_write = true) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (allow_speculative_write) + { + if (!write_op_queue_.has_operation(descriptor)) + { + boost::system::error_code ec; + std::size_t bytes_transferred = 0; + if (handler.perform(ec, bytes_transferred)) + { + handler.complete(ec, bytes_transferred); + return; + } + } + } + + if (write_op_queue_.enqueue_operation(descriptor, handler)) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLOUT | POLLERR | POLLHUP; + if (read_op_queue_.has_operation(descriptor)) + ev.events |= POLLIN; + if (except_op_queue_.has_operation(descriptor)) + ev.events |= POLLPRI; + interrupter_.interrupt(); + } + } + + // Start a new exception operation. The handler object will be invoked when + // the given descriptor has exception information, or an error has occurred. + template + void start_except_op(socket_type descriptor, + per_descriptor_data&, Handler handler) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (except_op_queue_.enqueue_operation(descriptor, handler)) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLPRI | POLLERR | POLLHUP; + if (read_op_queue_.has_operation(descriptor)) + ev.events |= POLLIN; + if (write_op_queue_.has_operation(descriptor)) + ev.events |= POLLOUT; + interrupter_.interrupt(); + } + } + + // Start a new write operation. The handler object will be invoked when the + // information available, or an error has occurred. + template + void start_connect_op(socket_type descriptor, + per_descriptor_data&, Handler handler) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (write_op_queue_.enqueue_operation(descriptor, handler)) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLOUT | POLLERR | POLLHUP; + if (read_op_queue_.has_operation(descriptor)) + ev.events |= POLLIN; + if (except_op_queue_.has_operation(descriptor)) + ev.events |= POLLPRI; + interrupter_.interrupt(); + } + } + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + void cancel_ops(socket_type descriptor, per_descriptor_data&) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor); + } + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. + void close_descriptor(socket_type descriptor, per_descriptor_data&) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Remove the descriptor from /dev/poll. + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLREMOVE; + interrupter_.interrupt(); + + // Cancel any outstanding operations associated with the descriptor. + cancel_ops_unlocked(descriptor); + } + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& timer_queue) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + timer_queues_.push_back(&timer_queue); + } + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& timer_queue) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + if (timer_queues_[i] == &timer_queue) + { + timer_queues_.erase(timer_queues_.begin() + i); + return; + } + } + } + + // Schedule a timer in the given timer queue to expire at the specified + // absolute time. The handler object will be invoked when the timer expires. + template + void schedule_timer(timer_queue& timer_queue, + const typename Time_Traits::time_type& time, Handler handler, void* token) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + if (timer_queue.enqueue_timer(time, handler, token)) + interrupter_.interrupt(); + } + + // Cancel the timer associated with the given token. Returns the number of + // handlers that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& timer_queue, void* token) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + std::size_t n = timer_queue.cancel_timer(token); + if (n > 0) + interrupter_.interrupt(); + return n; + } + +private: + friend class task_io_service >; + + // Run /dev/poll once until interrupted or events are ready to be dispatched. + void run(bool block) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Dispatch any operation cancellations that were made while the select + // loop was not running. + read_op_queue_.perform_cancellations(); + write_op_queue_.perform_cancellations(); + except_op_queue_.perform_cancellations(); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + timer_queues_[i]->dispatch_cancellations(); + + // Check if the thread is supposed to stop. + if (stop_thread_) + { + complete_operations_and_timers(lock); + return; + } + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (!block && read_op_queue_.empty() && write_op_queue_.empty() + && except_op_queue_.empty() && all_timer_queues_are_empty()) + { + complete_operations_and_timers(lock); + return; + } + + // Write the pending event registration changes to the /dev/poll descriptor. + std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); + errno = 0; + int result = ::write(dev_poll_fd_, + &pending_event_changes_[0], events_size); + if (result != static_cast(events_size)) + { + for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) + { + int descriptor = pending_event_changes_[i].fd; + boost::system::error_code ec = boost::system::error_code( + errno, boost::asio::error::get_system_category()); + read_op_queue_.perform_all_operations(descriptor, ec); + write_op_queue_.perform_all_operations(descriptor, ec); + except_op_queue_.perform_all_operations(descriptor, ec); + } + } + pending_event_changes_.clear(); + pending_event_change_index_.clear(); + + int timeout = block ? get_timeout() : 0; + wait_in_progress_ = true; + lock.unlock(); + + // Block on the /dev/poll descriptor. + ::pollfd events[128] = { { 0 } }; + ::dvpoll dp = { 0 }; + dp.dp_fds = events; + dp.dp_nfds = 128; + dp.dp_timeout = timeout; + int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp); + + lock.lock(); + wait_in_progress_ = false; + + // Block signals while performing operations. + boost::asio::detail::signal_blocker sb; + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + int descriptor = events[i].fd; + if (descriptor == interrupter_.read_descriptor()) + { + interrupter_.reset(); + } + else + { + bool more_reads = false; + bool more_writes = false; + bool more_except = false; + boost::system::error_code ec; + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + if (events[i].events & (POLLPRI | POLLERR | POLLHUP)) + more_except = except_op_queue_.perform_operation(descriptor, ec); + else + more_except = except_op_queue_.has_operation(descriptor); + + if (events[i].events & (POLLIN | POLLERR | POLLHUP)) + more_reads = read_op_queue_.perform_operation(descriptor, ec); + else + more_reads = read_op_queue_.has_operation(descriptor); + + if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) + more_writes = write_op_queue_.perform_operation(descriptor, ec); + else + more_writes = write_op_queue_.has_operation(descriptor); + + if ((events[i].events & (POLLERR | POLLHUP)) != 0 + && (events[i].events & ~(POLLERR | POLLHUP)) == 0 + && !more_except && !more_reads && !more_writes) + { + // If we have an event and no operations associated with the + // descriptor then we need to delete the descriptor from /dev/poll. + // The poll operation can produce POLLHUP or POLLERR events when there + // is no operation pending, so if we do not remove the descriptor we + // can end up in a tight polling loop. + ::pollfd ev = { 0 }; + ev.fd = descriptor; + ev.events = POLLREMOVE; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + } + else + { + ::pollfd ev = { 0 }; + ev.fd = descriptor; + ev.events = POLLERR | POLLHUP; + if (more_reads) + ev.events |= POLLIN; + if (more_writes) + ev.events |= POLLOUT; + if (more_except) + ev.events |= POLLPRI; + ev.revents = 0; + int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); + if (result != sizeof(ev)) + { + ec = boost::system::error_code(errno, + boost::asio::error::get_system_category()); + read_op_queue_.perform_all_operations(descriptor, ec); + write_op_queue_.perform_all_operations(descriptor, ec); + except_op_queue_.perform_all_operations(descriptor, ec); + } + } + } + } + read_op_queue_.perform_cancellations(); + write_op_queue_.perform_cancellations(); + except_op_queue_.perform_cancellations(); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + timer_queues_[i]->dispatch_timers(); + timer_queues_[i]->dispatch_cancellations(); + } + + // Issue any pending cancellations. + for (size_t i = 0; i < pending_cancellations_.size(); ++i) + cancel_ops_unlocked(pending_cancellations_[i]); + pending_cancellations_.clear(); + + complete_operations_and_timers(lock); + } + + // Run the select loop in the thread. + void run_thread() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + lock.unlock(); + run(true); + lock.lock(); + } + } + + // Entry point for the select loop thread. + static void call_run_thread(dev_poll_reactor* reactor) + { + reactor->run_thread(); + } + + // Interrupt the select loop. + void interrupt() + { + interrupter_.interrupt(); + } + + // Create the /dev/poll file descriptor. Throws an exception if the descriptor + // cannot be created. + static int do_dev_poll_create() + { + int fd = ::open("/dev/poll", O_RDWR); + if (fd == -1) + { + boost::throw_exception( + boost::system::system_error( + boost::system::error_code(errno, + boost::asio::error::get_system_category()), + "/dev/poll")); + } + return fd; + } + + // Check if all timer queues are empty. + bool all_timer_queues_are_empty() const + { + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + if (!timer_queues_[i]->empty()) + return false; + return true; + } + + // Get the timeout value for the /dev/poll DP_POLL operation. The timeout + // value is returned as a number of milliseconds. A return value of -1 + // indicates that the poll should block indefinitely. + int get_timeout() + { + if (all_timer_queues_are_empty()) + return -1; + + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + boost::posix_time::time_duration minimum_wait_duration + = boost::posix_time::minutes(5); + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + boost::posix_time::time_duration wait_duration + = timer_queues_[i]->wait_duration(); + if (wait_duration < minimum_wait_duration) + minimum_wait_duration = wait_duration; + } + + if (minimum_wait_duration > boost::posix_time::time_duration()) + { + int milliseconds = minimum_wait_duration.total_milliseconds(); + return milliseconds > 0 ? milliseconds : 1; + } + else + { + return 0; + } + } + + // Cancel all operations associated with the given descriptor. The do_cancel + // function of the handler objects will be invoked. This function does not + // acquire the dev_poll_reactor's mutex. + void cancel_ops_unlocked(socket_type descriptor) + { + bool interrupt = read_op_queue_.cancel_operations(descriptor); + interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt; + interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt; + if (interrupt) + interrupter_.interrupt(); + } + + // Clean up operations and timers. We must not hold the lock since the + // destructors may make calls back into this reactor. We make a copy of the + // vector of timer queues since the original may be modified while the lock + // is not held. + void complete_operations_and_timers( + boost::asio::detail::mutex::scoped_lock& lock) + { + timer_queues_for_cleanup_ = timer_queues_; + lock.unlock(); + read_op_queue_.complete_operations(); + write_op_queue_.complete_operations(); + except_op_queue_.complete_operations(); + for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) + timer_queues_for_cleanup_[i]->complete_timers(); + } + + // Add a pending event entry for the given descriptor. + ::pollfd& add_pending_event_change(int descriptor) + { + hash_map::iterator iter + = pending_event_change_index_.find(descriptor); + if (iter == pending_event_change_index_.end()) + { + std::size_t index = pending_event_changes_.size(); + pending_event_changes_.reserve(pending_event_changes_.size() + 1); + pending_event_change_index_.insert(std::make_pair(descriptor, index)); + pending_event_changes_.push_back(::pollfd()); + pending_event_changes_[index].fd = descriptor; + pending_event_changes_[index].revents = 0; + return pending_event_changes_[index]; + } + else + { + return pending_event_changes_[iter->second]; + } + } + + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // The /dev/poll file descriptor. + int dev_poll_fd_; + + // Vector of /dev/poll events waiting to be written to the descriptor. + std::vector< ::pollfd> pending_event_changes_; + + // Hash map to associate a descriptor with a pending event change index. + hash_map pending_event_change_index_; + + // Whether the DP_POLL operation is currently in progress + bool wait_in_progress_; + + // The interrupter is used to break a blocking DP_POLL operation. + select_interrupter interrupter_; + + // The queue of read operations. + reactor_op_queue read_op_queue_; + + // The queue of write operations. + reactor_op_queue write_op_queue_; + + // The queue of except operations. + reactor_op_queue except_op_queue_; + + // The timer queues. + std::vector timer_queues_; + + // A copy of the timer queues, used when cleaning up timers. The copy is + // stored as a class data member to avoid unnecessary memory allocation. + std::vector timer_queues_for_cleanup_; + + // The descriptors that are pending cancellation. + std::vector pending_cancellations_; + + // Does the reactor loop thread need to stop. + bool stop_thread_; + + // The thread that is running the reactor loop. + boost::asio::detail::thread* thread_; + + // Whether the service has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_DEV_POLL) + +#include + +#endif // BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_HPP diff --git a/3rdParty/Boost/boost/asio/detail/dev_poll_reactor_fwd.hpp b/3rdParty/Boost/boost/asio/detail/dev_poll_reactor_fwd.hpp new file mode 100644 index 0000000..3308575 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/dev_poll_reactor_fwd.hpp @@ -0,0 +1,42 @@ +// +// dev_poll_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_DEV_POLL_REACTOR_FWD_HPP +#define BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_DISABLE_DEV_POLL) +#if defined(__sun) // This service is only supported on Solaris. + +// Define this to indicate that /dev/poll is supported on the target platform. +#define BOOST_ASIO_HAS_DEV_POLL 1 + +namespace boost { +namespace asio { +namespace detail { + +template +class dev_poll_reactor; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(__sun) +#endif // !defined(BOOST_ASIO_DISABLE_DEV_POLL) + +#include + +#endif // BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP diff --git a/3rdParty/Boost/boost/asio/detail/epoll_reactor.hpp b/3rdParty/Boost/boost/asio/detail/epoll_reactor.hpp new file mode 100644 index 0000000..2770c6a --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/epoll_reactor.hpp @@ -0,0 +1,733 @@ +// +// epoll_reactor.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_EPOLL_REACTOR_HPP +#define BOOST_ASIO_DETAIL_EPOLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if defined(BOOST_ASIO_HAS_EPOLL) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class epoll_reactor + : public boost::asio::detail::service_base > +{ +public: + // Per-descriptor data. + struct per_descriptor_data + { + bool allow_speculative_read; + bool allow_speculative_write; + }; + + // Constructor. + epoll_reactor(boost::asio::io_service& io_service) + : boost::asio::detail::service_base >(io_service), + mutex_(), + epoll_fd_(do_epoll_create()), + wait_in_progress_(false), + interrupter_(), + read_op_queue_(), + write_op_queue_(), + except_op_queue_(), + pending_cancellations_(), + stop_thread_(false), + thread_(0), + shutdown_(false), + need_epoll_wait_(true) + { + // Start the reactor's internal thread only if needed. + if (Own_Thread) + { + boost::asio::detail::signal_blocker sb; + thread_ = new boost::asio::detail::thread( + bind_handler(&epoll_reactor::call_run_thread, this)); + } + + // Add the interrupter's descriptor to epoll. + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR; + ev.data.fd = interrupter_.read_descriptor(); + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); + } + + // Destructor. + ~epoll_reactor() + { + shutdown_service(); + close(epoll_fd_); + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + stop_thread_ = true; + lock.unlock(); + + if (thread_) + { + interrupter_.interrupt(); + thread_->join(); + delete thread_; + thread_ = 0; + } + + read_op_queue_.destroy_operations(); + write_op_queue_.destroy_operations(); + except_op_queue_.destroy_operations(); + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + timer_queues_[i]->destroy_timers(); + timer_queues_.clear(); + } + + // Initialise the task, but only if the reactor is not in its own thread. + void init_task() + { + if (!Own_Thread) + { + typedef task_io_service > task_io_service_type; + use_service(this->get_io_service()).init_task(); + } + } + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data) + { + // No need to lock according to epoll documentation. + + descriptor_data.allow_speculative_read = true; + descriptor_data.allow_speculative_write = true; + + epoll_event ev = { 0, { 0 } }; + ev.events = 0; + ev.data.fd = descriptor; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + return errno; + return 0; + } + + // Start a new read operation. The handler object will be invoked when the + // given descriptor is ready to be read, or an error has occurred. + template + void start_read_op(socket_type descriptor, + per_descriptor_data& descriptor_data, + Handler handler, bool allow_speculative_read = true) + { + if (allow_speculative_read && descriptor_data.allow_speculative_read) + { + boost::system::error_code ec; + std::size_t bytes_transferred = 0; + if (handler.perform(ec, bytes_transferred)) + { + handler.complete(ec, bytes_transferred); + return; + } + + // We only get one shot at a speculative read in this function. + allow_speculative_read = false; + } + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (!allow_speculative_read) + need_epoll_wait_ = true; + else if (!read_op_queue_.has_operation(descriptor)) + { + // Speculative reads are ok as there are no queued read operations. + descriptor_data.allow_speculative_read = true; + + boost::system::error_code ec; + std::size_t bytes_transferred = 0; + if (handler.perform(ec, bytes_transferred)) + { + handler.complete(ec, bytes_transferred); + return; + } + } + + // Speculative reads are not ok as there will be queued read operations. + descriptor_data.allow_speculative_read = false; + + if (read_op_queue_.enqueue_operation(descriptor, handler)) + { + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; + if (write_op_queue_.has_operation(descriptor)) + ev.events |= EPOLLOUT; + if (except_op_queue_.has_operation(descriptor)) + ev.events |= EPOLLPRI; + ev.data.fd = descriptor; + + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + if (result != 0 && errno == ENOENT) + result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + read_op_queue_.perform_all_operations(descriptor, ec); + } + } + } + + // Start a new write operation. The handler object will be invoked when the + // given descriptor is ready to be written, or an error has occurred. + template + void start_write_op(socket_type descriptor, + per_descriptor_data& descriptor_data, + Handler handler, bool allow_speculative_write = true) + { + if (allow_speculative_write && descriptor_data.allow_speculative_write) + { + boost::system::error_code ec; + std::size_t bytes_transferred = 0; + if (handler.perform(ec, bytes_transferred)) + { + handler.complete(ec, bytes_transferred); + return; + } + + // We only get one shot at a speculative write in this function. + allow_speculative_write = false; + } + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (!allow_speculative_write) + need_epoll_wait_ = true; + else if (!write_op_queue_.has_operation(descriptor)) + { + // Speculative writes are ok as there are no queued write operations. + descriptor_data.allow_speculative_write = true; + + boost::system::error_code ec; + std::size_t bytes_transferred = 0; + if (handler.perform(ec, bytes_transferred)) + { + handler.complete(ec, bytes_transferred); + return; + } + } + + // Speculative writes are not ok as there will be queued write operations. + descriptor_data.allow_speculative_write = false; + + if (write_op_queue_.enqueue_operation(descriptor, handler)) + { + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP; + if (read_op_queue_.has_operation(descriptor)) + ev.events |= EPOLLIN; + if (except_op_queue_.has_operation(descriptor)) + ev.events |= EPOLLPRI; + ev.data.fd = descriptor; + + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + if (result != 0 && errno == ENOENT) + result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + write_op_queue_.perform_all_operations(descriptor, ec); + } + } + } + + // Start a new exception operation. The handler object will be invoked when + // the given descriptor has exception information, or an error has occurred. + template + void start_except_op(socket_type descriptor, + per_descriptor_data&, Handler handler) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (except_op_queue_.enqueue_operation(descriptor, handler)) + { + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLPRI | EPOLLERR | EPOLLHUP; + if (read_op_queue_.has_operation(descriptor)) + ev.events |= EPOLLIN; + if (write_op_queue_.has_operation(descriptor)) + ev.events |= EPOLLOUT; + ev.data.fd = descriptor; + + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + if (result != 0 && errno == ENOENT) + result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + except_op_queue_.perform_all_operations(descriptor, ec); + } + } + } + + // Start a new write operation. The handler object will be invoked when the + // given descriptor is ready for writing or an error has occurred. Speculative + // writes are not allowed. + template + void start_connect_op(socket_type descriptor, + per_descriptor_data& descriptor_data, Handler handler) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + // Speculative writes are not ok as there will be queued write operations. + descriptor_data.allow_speculative_write = false; + + if (write_op_queue_.enqueue_operation(descriptor, handler)) + { + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP; + if (read_op_queue_.has_operation(descriptor)) + ev.events |= EPOLLIN; + if (except_op_queue_.has_operation(descriptor)) + ev.events |= EPOLLPRI; + ev.data.fd = descriptor; + + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + if (result != 0 && errno == ENOENT) + result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + write_op_queue_.perform_all_operations(descriptor, ec); + } + } + } + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + void cancel_ops(socket_type descriptor, per_descriptor_data&) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor); + } + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. + void close_descriptor(socket_type descriptor, per_descriptor_data&) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Remove the descriptor from epoll. + epoll_event ev = { 0, { 0 } }; + epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); + + // Cancel any outstanding operations associated with the descriptor. + cancel_ops_unlocked(descriptor); + } + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& timer_queue) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + timer_queues_.push_back(&timer_queue); + } + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& timer_queue) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + if (timer_queues_[i] == &timer_queue) + { + timer_queues_.erase(timer_queues_.begin() + i); + return; + } + } + } + + // Schedule a timer in the given timer queue to expire at the specified + // absolute time. The handler object will be invoked when the timer expires. + template + void schedule_timer(timer_queue& timer_queue, + const typename Time_Traits::time_type& time, Handler handler, void* token) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + if (timer_queue.enqueue_timer(time, handler, token)) + interrupter_.interrupt(); + } + + // Cancel the timer associated with the given token. Returns the number of + // handlers that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& timer_queue, void* token) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + std::size_t n = timer_queue.cancel_timer(token); + if (n > 0) + interrupter_.interrupt(); + return n; + } + +private: + friend class task_io_service >; + + // Run epoll once until interrupted or events are ready to be dispatched. + void run(bool block) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Dispatch any operation cancellations that were made while the select + // loop was not running. + read_op_queue_.perform_cancellations(); + write_op_queue_.perform_cancellations(); + except_op_queue_.perform_cancellations(); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + timer_queues_[i]->dispatch_cancellations(); + + // Check if the thread is supposed to stop. + if (stop_thread_) + { + complete_operations_and_timers(lock); + return; + } + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (!block && read_op_queue_.empty() && write_op_queue_.empty() + && except_op_queue_.empty() && all_timer_queues_are_empty()) + { + complete_operations_and_timers(lock); + return; + } + + int timeout = block ? get_timeout() : 0; + wait_in_progress_ = true; + lock.unlock(); + + // Block on the epoll descriptor. + epoll_event events[128]; + int num_events = (block || need_epoll_wait_) + ? epoll_wait(epoll_fd_, events, 128, timeout) + : 0; + + lock.lock(); + wait_in_progress_ = false; + + // Block signals while performing operations. + boost::asio::detail::signal_blocker sb; + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + int descriptor = events[i].data.fd; + if (descriptor == interrupter_.read_descriptor()) + { + interrupter_.reset(); + } + else + { + bool more_reads = false; + bool more_writes = false; + bool more_except = false; + boost::system::error_code ec; + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + if (events[i].events & (EPOLLPRI | EPOLLERR | EPOLLHUP)) + more_except = except_op_queue_.perform_operation(descriptor, ec); + else + more_except = except_op_queue_.has_operation(descriptor); + + if (events[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP)) + more_reads = read_op_queue_.perform_operation(descriptor, ec); + else + more_reads = read_op_queue_.has_operation(descriptor); + + if (events[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) + more_writes = write_op_queue_.perform_operation(descriptor, ec); + else + more_writes = write_op_queue_.has_operation(descriptor); + + if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0 + && (events[i].events & ~(EPOLLERR | EPOLLHUP)) == 0 + && !more_except && !more_reads && !more_writes) + { + // If we have an event and no operations associated with the + // descriptor then we need to delete the descriptor from epoll. The + // epoll_wait system call can produce EPOLLHUP or EPOLLERR events + // when there is no operation pending, so if we do not remove the + // descriptor we can end up in a tight loop of repeated + // calls to epoll_wait. + epoll_event ev = { 0, { 0 } }; + epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); + } + else + { + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLERR | EPOLLHUP; + if (more_reads) + ev.events |= EPOLLIN; + if (more_writes) + ev.events |= EPOLLOUT; + if (more_except) + ev.events |= EPOLLPRI; + ev.data.fd = descriptor; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + if (result != 0 && errno == ENOENT) + result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + { + ec = boost::system::error_code(errno, + boost::asio::error::get_system_category()); + read_op_queue_.perform_all_operations(descriptor, ec); + write_op_queue_.perform_all_operations(descriptor, ec); + except_op_queue_.perform_all_operations(descriptor, ec); + } + } + } + } + read_op_queue_.perform_cancellations(); + write_op_queue_.perform_cancellations(); + except_op_queue_.perform_cancellations(); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + timer_queues_[i]->dispatch_timers(); + timer_queues_[i]->dispatch_cancellations(); + } + + // Issue any pending cancellations. + for (size_t i = 0; i < pending_cancellations_.size(); ++i) + cancel_ops_unlocked(pending_cancellations_[i]); + pending_cancellations_.clear(); + + // Determine whether epoll_wait should be called when the reactor next runs. + need_epoll_wait_ = !read_op_queue_.empty() + || !write_op_queue_.empty() || !except_op_queue_.empty(); + + complete_operations_and_timers(lock); + } + + // Run the select loop in the thread. + void run_thread() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + lock.unlock(); + run(true); + lock.lock(); + } + } + + // Entry point for the select loop thread. + static void call_run_thread(epoll_reactor* reactor) + { + reactor->run_thread(); + } + + // Interrupt the select loop. + void interrupt() + { + interrupter_.interrupt(); + } + + // The hint to pass to epoll_create to size its data structures. + enum { epoll_size = 20000 }; + + // Create the epoll file descriptor. Throws an exception if the descriptor + // cannot be created. + static int do_epoll_create() + { + int fd = epoll_create(epoll_size); + if (fd == -1) + { + boost::throw_exception( + boost::system::system_error( + boost::system::error_code(errno, + boost::asio::error::get_system_category()), + "epoll")); + } + return fd; + } + + // Check if all timer queues are empty. + bool all_timer_queues_are_empty() const + { + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + if (!timer_queues_[i]->empty()) + return false; + return true; + } + + // Get the timeout value for the epoll_wait call. The timeout value is + // returned as a number of milliseconds. A return value of -1 indicates + // that epoll_wait should block indefinitely. + int get_timeout() + { + if (all_timer_queues_are_empty()) + return -1; + + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + boost::posix_time::time_duration minimum_wait_duration + = boost::posix_time::minutes(5); + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + boost::posix_time::time_duration wait_duration + = timer_queues_[i]->wait_duration(); + if (wait_duration < minimum_wait_duration) + minimum_wait_duration = wait_duration; + } + + if (minimum_wait_duration > boost::posix_time::time_duration()) + { + int milliseconds = minimum_wait_duration.total_milliseconds(); + return milliseconds > 0 ? milliseconds : 1; + } + else + { + return 0; + } + } + + // Cancel all operations associated with the given descriptor. The do_cancel + // function of the handler objects will be invoked. This function does not + // acquire the epoll_reactor's mutex. + void cancel_ops_unlocked(socket_type descriptor) + { + bool interrupt = read_op_queue_.cancel_operations(descriptor); + interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt; + interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt; + if (interrupt) + interrupter_.interrupt(); + } + + // Clean up operations and timers. We must not hold the lock since the + // destructors may make calls back into this reactor. We make a copy of the + // vector of timer queues since the original may be modified while the lock + // is not held. + void complete_operations_and_timers( + boost::asio::detail::mutex::scoped_lock& lock) + { + timer_queues_for_cleanup_ = timer_queues_; + lock.unlock(); + read_op_queue_.complete_operations(); + write_op_queue_.complete_operations(); + except_op_queue_.complete_operations(); + for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) + timer_queues_for_cleanup_[i]->complete_timers(); + } + + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // The epoll file descriptor. + int epoll_fd_; + + // Whether the epoll_wait call is currently in progress + bool wait_in_progress_; + + // The interrupter is used to break a blocking epoll_wait call. + select_interrupter interrupter_; + + // The queue of read operations. + reactor_op_queue read_op_queue_; + + // The queue of write operations. + reactor_op_queue write_op_queue_; + + // The queue of except operations. + reactor_op_queue except_op_queue_; + + // The timer queues. + std::vector timer_queues_; + + // A copy of the timer queues, used when cleaning up timers. The copy is + // stored as a class data member to avoid unnecessary memory allocation. + std::vector timer_queues_for_cleanup_; + + // The descriptors that are pending cancellation. + std::vector pending_cancellations_; + + // Does the reactor loop thread need to stop. + bool stop_thread_; + + // The thread that is running the reactor loop. + boost::asio::detail::thread* thread_; + + // Whether the service has been shut down. + bool shutdown_; + + // Whether we need to call epoll_wait the next time the reactor is run. + bool need_epoll_wait_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_EPOLL) + +#include + +#endif // BOOST_ASIO_DETAIL_EPOLL_REACTOR_HPP diff --git a/3rdParty/Boost/boost/asio/detail/epoll_reactor_fwd.hpp b/3rdParty/Boost/boost/asio/detail/epoll_reactor_fwd.hpp new file mode 100644 index 0000000..567a966 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/epoll_reactor_fwd.hpp @@ -0,0 +1,49 @@ +// +// epoll_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_EPOLL_REACTOR_FWD_HPP +#define BOOST_ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_DISABLE_EPOLL) +#if defined(__linux__) // This service is only supported on Linux. + +#include +#include +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) // Only kernels >= 2.5.45. + +// Define this to indicate that epoll is supported on the target platform. +#define BOOST_ASIO_HAS_EPOLL 1 + +namespace boost { +namespace asio { +namespace detail { + +template +class epoll_reactor; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) +#endif // defined(__linux__) +#endif // !defined(BOOST_ASIO_DISABLE_EPOLL) + +#include + +#endif // BOOST_ASIO_DETAIL_EPOLL_REACTOR_FWD_HPP diff --git a/3rdParty/Boost/boost/asio/detail/event.hpp b/3rdParty/Boost/boost/asio/detail/event.hpp new file mode 100644 index 0000000..67a0118 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/event.hpp @@ -0,0 +1,52 @@ +// +// event.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_EVENT_HPP +#define BOOST_ASIO_DETAIL_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if !defined(BOOST_HAS_THREADS) +# include +#elif defined(BOOST_WINDOWS) +# include +#elif defined(BOOST_HAS_PTHREADS) +# include +#else +# error Only Windows and POSIX are supported! +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if !defined(BOOST_HAS_THREADS) +typedef null_event event; +#elif defined(BOOST_WINDOWS) +typedef win_event event; +#elif defined(BOOST_HAS_PTHREADS) +typedef posix_event event; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_EVENT_HPP diff --git a/3rdParty/Boost/boost/asio/detail/eventfd_select_interrupter.hpp b/3rdParty/Boost/boost/asio/detail/eventfd_select_interrupter.hpp new file mode 100644 index 0000000..cac8405 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/eventfd_select_interrupter.hpp @@ -0,0 +1,157 @@ +// +// eventfd_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail 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_EVENTFD_SELECT_INTERRUPTER_HPP +#define BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +#if defined(linux) +# if !defined(BOOST_ASIO_DISABLE_EVENTFD) +# include +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# define BOOST_ASIO_HAS_EVENTFD +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) +#endif // defined(linux) + +#if defined(BOOST_ASIO_HAS_EVENTFD) + +#include +#include +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class eventfd_select_interrupter +{ +public: + // Constructor. + eventfd_select_interrupter() + { +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0); +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + write_descriptor_ = read_descriptor_ = ::eventfd(0, 0); +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + if (read_descriptor_ != -1) + { + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + } + else + { + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + } + else + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::system::system_error e(ec, "eventfd_select_interrupter"); + boost::throw_exception(e); + } + } + } + + // Destructor. + ~eventfd_select_interrupter() + { + if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_) + ::close(write_descriptor_); + if (read_descriptor_ != -1) + ::close(read_descriptor_); + } + + // Interrupt the select call. + void interrupt() + { + uint64_t counter(1UL); + int result = ::write(write_descriptor_, &counter, sizeof(uint64_t)); + (void)result; + } + + // Reset the select interrupt. Returns true if the call was interrupted. + bool reset() + { + if (write_descriptor_ == read_descriptor_) + { + // Only perform one read. The kernel maintains an atomic counter. + uint64_t counter(0); + int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); + bool was_interrupted = (bytes_read > 0); + return was_interrupted; + } + else + { + // Clear all data from the pipe. + char data[1024]; + int bytes_read = ::read(read_descriptor_, data, sizeof(data)); + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = ::read(read_descriptor_, data, sizeof(data)); + return was_interrupted; + } + } + + // Get the read descriptor to be passed to select. + int read_descriptor() const + { + return read_descriptor_; + } + +private: + // The read end of a connection used to interrupt the select call. This file + // descriptor is passed to select such that when it is time to stop, a single + // 64bit value will be written on the other end of the connection and this + // descriptor will become readable. + int read_descriptor_; + + // The write end of a connection used to interrupt the select call. A single + // 64bit non-zero value may be written to this to wake up the select which is + // waiting for the other end to become readable. This descriptor will only + // differ from the read descriptor when a pipe is used. + int write_descriptor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_EVENTFD) + +#include + +#endif // BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP diff --git a/3rdParty/Boost/boost/asio/detail/fd_set_adapter.hpp b/3rdParty/Boost/boost/asio/detail/fd_set_adapter.hpp new file mode 100644 index 0000000..3fff01e --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/fd_set_adapter.hpp @@ -0,0 +1,43 @@ +// +// fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_FD_SET_ADAPTER_HPP +#define BOOST_ASIO_DETAIL_FD_SET_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +typedef win_fd_set_adapter fd_set_adapter; +#else +typedef posix_fd_set_adapter fd_set_adapter; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_FD_SET_ADAPTER_HPP diff --git a/3rdParty/Boost/boost/asio/detail/handler_alloc_helpers.hpp b/3rdParty/Boost/boost/asio/detail/handler_alloc_helpers.hpp new file mode 100644 index 0000000..bfc918b --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/handler_alloc_helpers.hpp @@ -0,0 +1,258 @@ +// +// handler_alloc_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_HANDLER_ALLOC_HELPERS_HPP +#define BOOST_ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#include +#include + +// Calls to asio_handler_allocate and asio_handler_deallocate must be made from +// a namespace that does not contain any overloads of these functions. The +// boost_asio_handler_alloc_helpers namespace is defined here for that purpose. +namespace boost_asio_handler_alloc_helpers { + +template +inline void* allocate(std::size_t s, Handler* h) +{ +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + return ::operator new(s); +#else + using namespace boost::asio; + return asio_handler_allocate(s, h); +#endif +} + +template +inline void deallocate(void* p, std::size_t s, Handler* h) +{ +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + ::operator delete(p); +#else + using namespace boost::asio; + asio_handler_deallocate(p, s, h); +#endif +} + +} // namespace boost_asio_handler_alloc_helpers + +namespace boost { +namespace asio { +namespace detail { + +// Traits for handler allocation. +template +struct handler_alloc_traits +{ + typedef Handler handler_type; + typedef Object value_type; + typedef Object* pointer_type; + BOOST_STATIC_CONSTANT(std::size_t, value_size = sizeof(Object)); +}; + +template +class handler_ptr; + +// Helper class to provide RAII on uninitialised handler memory. +template +class raw_handler_ptr + : private noncopyable +{ +public: + typedef typename Alloc_Traits::handler_type handler_type; + typedef typename Alloc_Traits::value_type value_type; + typedef typename Alloc_Traits::pointer_type pointer_type; + BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size); + + // Constructor allocates the memory. + raw_handler_ptr(handler_type& handler) + : handler_(handler), + pointer_(static_cast( + boost_asio_handler_alloc_helpers::allocate(value_size, &handler_))) + { + } + + // Destructor automatically deallocates memory, unless it has been stolen by + // a handler_ptr object. + ~raw_handler_ptr() + { + if (pointer_) + boost_asio_handler_alloc_helpers::deallocate( + pointer_, value_size, &handler_); + } + +private: + friend class handler_ptr; + handler_type& handler_; + pointer_type pointer_; +}; + +// Helper class to provide RAII on uninitialised handler memory. +template +class handler_ptr + : private noncopyable +{ +public: + typedef typename Alloc_Traits::handler_type handler_type; + typedef typename Alloc_Traits::value_type value_type; + typedef typename Alloc_Traits::pointer_type pointer_type; + BOOST_STATIC_CONSTANT(std::size_t, value_size = Alloc_Traits::value_size); + typedef raw_handler_ptr raw_ptr_type; + + // Take ownership of existing memory. + handler_ptr(handler_type& handler, pointer_type pointer) + : handler_(handler), + pointer_(pointer) + { + } + + // Construct object in raw memory and take ownership if construction succeeds. + handler_ptr(raw_ptr_type& raw_ptr) + : handler_(raw_ptr.handler_), + pointer_(new (raw_ptr.pointer_) value_type) + { + raw_ptr.pointer_ = 0; + } + + // Construct object in raw memory and take ownership if construction succeeds. + template + handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1) + : handler_(raw_ptr.handler_), + pointer_(new (raw_ptr.pointer_) value_type(a1)) + { + raw_ptr.pointer_ = 0; + } + + // Construct object in raw memory and take ownership if construction succeeds. + template + handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2) + : handler_(raw_ptr.handler_), + pointer_(new (raw_ptr.pointer_) value_type(a1, a2)) + { + raw_ptr.pointer_ = 0; + } + + // Construct object in raw memory and take ownership if construction succeeds. + template + handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3) + : handler_(raw_ptr.handler_), + pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3)) + { + raw_ptr.pointer_ = 0; + } + + // Construct object in raw memory and take ownership if construction succeeds. + template + handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4) + : handler_(raw_ptr.handler_), + pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4)) + { + raw_ptr.pointer_ = 0; + } + + // Construct object in raw memory and take ownership if construction succeeds. + template + handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, + Arg5& a5) + : handler_(raw_ptr.handler_), + pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5)) + { + raw_ptr.pointer_ = 0; + } + + // Construct object in raw memory and take ownership if construction succeeds. + template + handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, + Arg5& a5, Arg6& a6) + : handler_(raw_ptr.handler_), + pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6)) + { + raw_ptr.pointer_ = 0; + } + + // Construct object in raw memory and take ownership if construction succeeds. + template + handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, + Arg5& a5, Arg6& a6, Arg7& a7) + : handler_(raw_ptr.handler_), + pointer_(new (raw_ptr.pointer_) value_type(a1, a2, a3, a4, a5, a6, a7)) + { + raw_ptr.pointer_ = 0; + } + + // Construct object in raw memory and take ownership if construction succeeds. + template + handler_ptr(raw_ptr_type& raw_ptr, Arg1& a1, Arg2& a2, Arg3& a3, Arg4& a4, + Arg5& a5, Arg6& a6, Arg7& a7, Arg8& a8) + : handler_(raw_ptr.handler_), + pointer_(new (raw_ptr.pointer_) value_type( + a1, a2, a3, a4, a5, a6, a7, a8)) + { + raw_ptr.pointer_ = 0; + } + + // Destructor automatically deallocates memory, unless it has been released. + ~handler_ptr() + { + reset(); + } + + // Get the memory. + pointer_type get() const + { + return pointer_; + } + + // Release ownership of the memory. + pointer_type release() + { + pointer_type tmp = pointer_; + pointer_ = 0; + return tmp; + } + + // Explicitly destroy and deallocate the memory. + void reset() + { + if (pointer_) + { + pointer_->value_type::~value_type(); + boost_asio_handler_alloc_helpers::deallocate( + pointer_, value_size, &handler_); + pointer_ = 0; + } + } + +private: + handler_type& handler_; + pointer_type pointer_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP diff --git a/3rdParty/Boost/boost/asio/detail/handler_base_from_member.hpp b/3rdParty/Boost/boost/asio/detail/handler_base_from_member.hpp new file mode 100644 index 0000000..4bd95ed --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/handler_base_from_member.hpp @@ -0,0 +1,78 @@ +// +// handler_base_from_member.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_HANDLER_BASE_FROM_MEMBER_HPP +#define BOOST_ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +// Base class for classes that need a handler data member. Forwards the custom +// allocation and invocation hooks to the contained handler. +template +class handler_base_from_member +{ +public: + handler_base_from_member(Handler handler) + : handler_(handler) + { + } + +//protected: + Handler handler_; + +protected: + // Protected destructor to prevent deletion through this type. + ~handler_base_from_member() + { + } +}; + +template +inline void* asio_handler_allocate(std::size_t size, + handler_base_from_member* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, &this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + handler_base_from_member* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, &this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + handler_base_from_member* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, &this_handler->handler_); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_HANDLER_BASE_FROM_MEMBER_HPP diff --git a/3rdParty/Boost/boost/asio/detail/handler_invoke_helpers.hpp b/3rdParty/Boost/boost/asio/detail/handler_invoke_helpers.hpp new file mode 100644 index 0000000..4da384a --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/handler_invoke_helpers.hpp @@ -0,0 +1,47 @@ +// +// handler_invoke_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_HANDLER_INVOKE_HELPERS_HPP +#define BOOST_ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#include + +// Calls to asio_handler_invoke must be made from a namespace that does not +// contain overloads of this function. The boost_asio_handler_invoke_helpers +// namespace is defined here for that purpose. +namespace boost_asio_handler_invoke_helpers { + +template +inline void invoke(const Function& function, Context* context) +{ +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + Function tmp(function); + tmp(); +#else + using namespace boost::asio; + asio_handler_invoke(function, context); +#endif +} + +} // namespace boost_asio_handler_invoke_helpers + +#include + +#endif // BOOST_ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP diff --git a/3rdParty/Boost/boost/asio/detail/handler_queue.hpp b/3rdParty/Boost/boost/asio/detail/handler_queue.hpp new file mode 100644 index 0000000..ccc1b0c --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/handler_queue.hpp @@ -0,0 +1,231 @@ +// +// handler_queue.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_HANDLER_QUEUE_HPP +#define BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class handler_queue + : private noncopyable +{ +public: + // Base class for handlers in the queue. + class handler + : private noncopyable + { + public: + void invoke() + { + invoke_func_(this); + } + + void destroy() + { + destroy_func_(this); + } + + protected: + typedef void (*invoke_func_type)(handler*); + typedef void (*destroy_func_type)(handler*); + + handler(invoke_func_type invoke_func, + destroy_func_type destroy_func) + : next_(0), + invoke_func_(invoke_func), + destroy_func_(destroy_func) + { + } + + ~handler() + { + } + + private: + friend class handler_queue; + handler* next_; + invoke_func_type invoke_func_; + destroy_func_type destroy_func_; + }; + + // Smart point to manager handler lifetimes. + class scoped_ptr + : private noncopyable + { + public: + explicit scoped_ptr(handler* h) + : handler_(h) + { + } + + ~scoped_ptr() + { + if (handler_) + handler_->destroy(); + } + + handler* get() const + { + return handler_; + } + + handler* release() + { + handler* tmp = handler_; + handler_ = 0; + return tmp; + } + + private: + handler* handler_; + }; + + // Constructor. + handler_queue() + : front_(0), + back_(0) + { + } + + // Wrap a handler to be pushed into the queue. + template + static handler* wrap(Handler h) + { + // Allocate and construct an object to wrap the handler. + typedef handler_wrapper value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(h); + handler_ptr ptr(raw_ptr, h); + return ptr.release(); + } + + // Get the handler at the front of the queue. + handler* front() + { + return front_; + } + + // Pop a handler from the front of the queue. + void pop() + { + if (front_) + { + handler* tmp = front_; + front_ = front_->next_; + if (front_ == 0) + back_ = 0; + tmp->next_= 0; + } + } + + // Push a handler on to the back of the queue. + void push(handler* h) + { + h->next_ = 0; + if (back_) + { + back_->next_ = h; + back_ = h; + } + else + { + front_ = back_ = h; + } + } + + // Whether the queue is empty. + bool empty() const + { + return front_ == 0; + } + +private: + // Template wrapper for handlers. + template + class handler_wrapper + : public handler + { + public: + handler_wrapper(Handler h) + : handler( + &handler_wrapper::do_call, + &handler_wrapper::do_destroy), + handler_(h) + { + } + + static void do_call(handler* base) + { + // Take ownership of the handler object. + typedef handler_wrapper this_type; + this_type* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. + Handler handler(h->handler_); + + // Free the memory associated with the handler. + ptr.reset(); + + // Make the upcall. + boost_asio_handler_invoke_helpers::invoke(handler, &handler); + } + + static void do_destroy(handler* base) + { + // Take ownership of the handler object. + typedef handler_wrapper this_type; + this_type* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + + // A sub-object of the handler may be the true owner of the memory + // associated with the handler. Consequently, a local copy of the handler + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + Handler handler(h->handler_); + (void)handler; + + // Free the memory associated with the handler. + ptr.reset(); + } + + private: + Handler handler_; + }; + + // The front of the queue. + handler* front_; + + // The back of the queue. + handler* back_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_HANDLER_QUEUE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/hash_map.hpp b/3rdParty/Boost/boost/asio/detail/hash_map.hpp new file mode 100644 index 0000000..923ae57 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/hash_map.hpp @@ -0,0 +1,292 @@ +// +// hash_map.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_HASH_MAP_HPP +#define BOOST_ASIO_DETAIL_HASH_MAP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +inline std::size_t calculate_hash_value(const T& t) +{ + return boost::hash_value(t); +} + +#if defined(_WIN64) +inline std::size_t calculate_hash_value(SOCKET s) +{ + return static_cast(s); +} +#endif // defined(_WIN64) + +// Note: assumes K and V are POD types. +template +class hash_map + : private noncopyable +{ +public: + // The type of a value in the map. + typedef std::pair value_type; + + // The type of a non-const iterator over the hash map. + typedef typename std::list::iterator iterator; + + // The type of a const iterator over the hash map. + typedef typename std::list::const_iterator const_iterator; + + // Constructor. + hash_map() + : size_(0) + { + rehash(hash_size(0)); + } + + // Get an iterator for the beginning of the map. + iterator begin() + { + return values_.begin(); + } + + // Get an iterator for the beginning of the map. + const_iterator begin() const + { + return values_.begin(); + } + + // Get an iterator for the end of the map. + iterator end() + { + return values_.end(); + } + + // Get an iterator for the end of the map. + const_iterator end() const + { + return values_.end(); + } + + // Check whether the map is empty. + bool empty() const + { + return values_.empty(); + } + + // Find an entry in the map. + iterator find(const K& k) + { + size_t bucket = calculate_hash_value(k) % buckets_.size(); + iterator it = buckets_[bucket].first; + if (it == values_.end()) + return values_.end(); + iterator end = buckets_[bucket].last; + ++end; + while (it != end) + { + if (it->first == k) + return it; + ++it; + } + return values_.end(); + } + + // Find an entry in the map. + const_iterator find(const K& k) const + { + size_t bucket = calculate_hash_value(k) % buckets_.size(); + const_iterator it = buckets_[bucket].first; + if (it == values_.end()) + return it; + const_iterator end = buckets_[bucket].last; + ++end; + while (it != end) + { + if (it->first == k) + return it; + ++it; + } + return values_.end(); + } + + // Insert a new entry into the map. + std::pair insert(const value_type& v) + { + if (size_ + 1 >= buckets_.size()) + rehash(hash_size(size_ + 1)); + size_t bucket = calculate_hash_value(v.first) % buckets_.size(); + iterator it = buckets_[bucket].first; + if (it == values_.end()) + { + buckets_[bucket].first = buckets_[bucket].last = + values_insert(values_.end(), v); + ++size_; + return std::pair(buckets_[bucket].last, true); + } + iterator end = buckets_[bucket].last; + ++end; + while (it != end) + { + if (it->first == v.first) + return std::pair(it, false); + ++it; + } + buckets_[bucket].last = values_insert(end, v); + ++size_; + return std::pair(buckets_[bucket].last, true); + } + + // Erase an entry from the map. + void erase(iterator it) + { + assert(it != values_.end()); + + size_t bucket = calculate_hash_value(it->first) % buckets_.size(); + bool is_first = (it == buckets_[bucket].first); + bool is_last = (it == buckets_[bucket].last); + if (is_first && is_last) + buckets_[bucket].first = buckets_[bucket].last = values_.end(); + else if (is_first) + ++buckets_[bucket].first; + else if (is_last) + --buckets_[bucket].last; + + values_erase(it); + --size_; + } + + // Remove all entries from the map. + void clear() + { + // Clear the values. + values_.clear(); + size_ = 0; + + // Initialise all buckets to empty. + for (size_t i = 0; i < buckets_.size(); ++i) + buckets_[i].first = buckets_[i].last = values_.end(); + } + +private: + // Calculate the hash size for the specified number of elements. + static std::size_t hash_size(std::size_t num_elems) + { + static std::size_t sizes[] = + { +#if defined(BOOST_ASIO_HASH_MAP_BUCKETS) + BOOST_ASIO_HASH_MAP_BUCKETS +#else // BOOST_ASIO_HASH_MAP_BUCKETS + 3, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, + 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, + 12582917, 25165843 +#endif // BOOST_ASIO_HASH_MAP_BUCKETS + }; + const std::size_t nth_size = sizeof(sizes) / sizeof(std::size_t) - 1; + for (std::size_t i = 0; i < nth_size; ++i) + if (num_elems < sizes[i]) + return sizes[i]; + return sizes[nth_size]; + } + + // Re-initialise the hash from the values already contained in the list. + void rehash(std::size_t num_buckets) + { + iterator end = values_.end(); + + // Update number of buckets and initialise all buckets to empty. + buckets_.resize(num_buckets); + for (std::size_t i = 0; i < buckets_.size(); ++i) + buckets_[i].first = buckets_[i].last = end; + + // Put all values back into the hash. + iterator iter = values_.begin(); + while (iter != end) + { + std::size_t bucket = calculate_hash_value(iter->first) % buckets_.size(); + if (buckets_[bucket].last == end) + { + buckets_[bucket].first = buckets_[bucket].last = iter++; + } + else + { + values_.splice(++buckets_[bucket].last, values_, iter++); + --buckets_[bucket].last; + } + } + } + + // Insert an element into the values list by splicing from the spares list, + // if a spare is available, and otherwise by inserting a new element. + iterator values_insert(iterator it, const value_type& v) + { + if (spares_.empty()) + { + return values_.insert(it, v); + } + else + { + spares_.front() = v; + values_.splice(it, spares_, spares_.begin()); + return --it; + } + } + + // Erase an element from the values list by splicing it to the spares list. + void values_erase(iterator it) + { + *it = value_type(); + spares_.splice(spares_.begin(), values_, it); + } + + // The number of elements in the hash. + std::size_t size_; + + // The list of all values in the hash map. + std::list values_; + + // The list of spare nodes waiting to be recycled. Assumes that POD types only + // are stored in the hash map. + std::list spares_; + + // The type for a bucket in the hash table. + struct bucket_type + { + iterator first; + iterator last; + }; + + // The buckets in the hash. + std::vector buckets_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_HASH_MAP_HPP diff --git a/3rdParty/Boost/boost/asio/detail/indirect_handler_queue.hpp b/3rdParty/Boost/boost/asio/detail/indirect_handler_queue.hpp new file mode 100644 index 0000000..2775078 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/indirect_handler_queue.hpp @@ -0,0 +1,293 @@ +// +// indirect_handler_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_INDIRECT_HANDLER_QUEUE_HPP +#define BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if defined(_MSC_VER) && (_MSC_VER >= 1310) +extern "C" void _ReadWriteBarrier(); +# pragma intrinsic(_ReadWriteBarrier) +#endif // defined(_MSC_VER) && (_MSC_VER >= 1310) + +namespace boost { +namespace asio { +namespace detail { + +class indirect_handler_queue + : private noncopyable +{ +public: + class handler; + + // Element for a node in the queue. + class node + { + public: + node() + : version_(0), + handler_(0), + next_(0) + { + } + + private: + friend class indirect_handler_queue; + unsigned long version_; + handler* handler_; + node* next_; + }; + + // Base class for handlers in the queue. + class handler + : private noncopyable + { + public: + void invoke() + { + invoke_func_(this); + } + + void destroy() + { + destroy_func_(this); + } + + protected: + typedef void (*invoke_func_type)(handler*); + typedef void (*destroy_func_type)(handler*); + + handler(invoke_func_type invoke_func, + destroy_func_type destroy_func) + : node_(new node), + invoke_func_(invoke_func), + destroy_func_(destroy_func) + { + } + + ~handler() + { + if (node_) + delete node_; + } + + private: + friend class indirect_handler_queue; + node* node_; + invoke_func_type invoke_func_; + destroy_func_type destroy_func_; + }; + + // Smart point to manager handler lifetimes. + class scoped_ptr + : private noncopyable + { + public: + explicit scoped_ptr(handler* h) + : handler_(h) + { + } + + ~scoped_ptr() + { + if (handler_) + handler_->destroy(); + } + + handler* get() const + { + return handler_; + } + + handler* release() + { + handler* tmp = handler_; + handler_ = 0; + return tmp; + } + + private: + handler* handler_; + }; + + // Constructor. + indirect_handler_queue() + : front_(new node), + back_(front_), + next_version_(1) + { + } + + // Destructor. + ~indirect_handler_queue() + { + while (front_) + { + node* tmp = front_; + front_ = front_->next_; + delete tmp; + } + } + + // Wrap a handler to be pushed into the queue. + template + static handler* wrap(Handler h) + { + // Allocate and construct an object to wrap the handler. + typedef handler_wrapper value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(h); + handler_ptr ptr(raw_ptr, h); + return ptr.release(); + } + + // Determine whether the queue has something ready to pop. + bool poppable() + { + return front_->next_ != 0; + } + + // The version number at the front of the queue. + unsigned long front_version() + { + return front_->version_; + } + + // The version number at the back of the queue. + unsigned long back_version() + { + return back_->version_; + } + + // Pop a handler from the front of the queue. + handler* pop() + { + node* n = front_; + node* new_front = n->next_; + if (new_front) + { + handler* h = new_front->handler_; + h->node_ = n; + new_front->handler_ = 0; + front_ = new_front; + return h; + } + return 0; + } + + // Push a handler on to the back of the queue. + void push(handler* h) + { + node* n = h->node_; + h->node_ = 0; + n->version_ = next_version_; + next_version_ += 2; + n->handler_ = h; + n->next_ = 0; + memory_barrier(); + back_->next_ = n; + back_ = n; + } + +private: + // Template wrapper for handlers. + template + class handler_wrapper + : public handler + { + public: + handler_wrapper(Handler h) + : handler( + &handler_wrapper::do_call, + &handler_wrapper::do_destroy), + handler_(h) + { + } + + static void do_call(handler* base) + { + // Take ownership of the handler object. + typedef handler_wrapper this_type; + this_type* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. + Handler handler(h->handler_); + + // Free the memory associated with the handler. + ptr.reset(); + + // Make the upcall. + boost_asio_handler_invoke_helpers::invoke(handler, &handler); + } + + static void do_destroy(handler* base) + { + // Take ownership of the handler object. + typedef handler_wrapper this_type; + this_type* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + + // A sub-object of the handler may be the true owner of the memory + // associated with the handler. Consequently, a local copy of the handler + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + Handler handler(h->handler_); + (void)handler; + + // Free the memory associated with the handler. + ptr.reset(); + } + + private: + Handler handler_; + }; + + // Helper function to create a memory barrier. + static void memory_barrier() + { +#if defined(_GLIBCXX_WRITE_MEM_BARRIER) + _GLIBCXX_WRITE_MEM_BARRIER; +#elif defined(_MSC_VER) && (_MSC_VER >= 1310) + _ReadWriteBarrier(); +#else +# error memory barrier required +#endif + } + + // The front of the queue. + node* front_; + + // The back of the queue. + node* back_; + + // The next version counter to be assigned to a node. + unsigned long next_version_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_INDIRECT_HANDLER_QUEUE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/io_control.hpp b/3rdParty/Boost/boost/asio/detail/io_control.hpp new file mode 100644 index 0000000..6730dc3 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/io_control.hpp @@ -0,0 +1,139 @@ +// +// io_control.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_IO_CONTROL_HPP +#define BOOST_ASIO_DETAIL_IO_CONTROL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { +namespace io_control { + +// IO control command for non-blocking I/O. +class non_blocking_io +{ +public: + // Default constructor. + non_blocking_io() + : value_(0) + { + } + + // Construct with a specific command value. + non_blocking_io(bool value) + : value_(value ? 1 : 0) + { + } + + // Get the name of the IO control command. + int name() const + { + return FIONBIO; + } + + // Set the value of the I/O control command. + void set(bool value) + { + value_ = value ? 1 : 0; + } + + // Get the current value of the I/O control command. + bool get() const + { + return value_ != 0; + } + + // Get the address of the command data. + detail::ioctl_arg_type* data() + { + return &value_; + } + + // Get the address of the command data. + const detail::ioctl_arg_type* data() const + { + return &value_; + } + +private: + detail::ioctl_arg_type value_; +}; + +// I/O control command for getting number of bytes available. +class bytes_readable +{ +public: + // Default constructor. + bytes_readable() + : value_(0) + { + } + + // Construct with a specific command value. + bytes_readable(std::size_t value) + : value_(static_cast(value)) + { + } + + // Get the name of the IO control command. + int name() const + { + return FIONREAD; + } + + // Set the value of the I/O control command. + void set(std::size_t value) + { + value_ = static_cast(value); + } + + // Get the current value of the I/O control command. + std::size_t get() const + { + return static_cast(value_); + } + + // Get the address of the command data. + detail::ioctl_arg_type* data() + { + return &value_; + } + + // Get the address of the command data. + const detail::ioctl_arg_type* data() const + { + return &value_; + } + +private: + detail::ioctl_arg_type value_; +}; + +} // namespace io_control +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IO_CONTROL_HPP diff --git a/3rdParty/Boost/boost/asio/detail/kqueue_reactor.hpp b/3rdParty/Boost/boost/asio/detail/kqueue_reactor.hpp new file mode 100644 index 0000000..179b7d4 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/kqueue_reactor.hpp @@ -0,0 +1,714 @@ +// +// kqueue_reactor.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze 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_KQUEUE_REACTOR_HPP +#define BOOST_ASIO_DETAIL_KQUEUE_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if defined(BOOST_ASIO_HAS_KQUEUE) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Older versions of Mac OS X may not define EV_OOBAND. +#if !defined(EV_OOBAND) +# define EV_OOBAND EV_FLAG1 +#endif // !defined(EV_OOBAND) + +namespace boost { +namespace asio { +namespace detail { + +template +class kqueue_reactor + : public boost::asio::detail::service_base > +{ +public: + // Per-descriptor data. + struct per_descriptor_data + { + bool allow_speculative_read; + bool allow_speculative_write; + }; + + // Constructor. + kqueue_reactor(boost::asio::io_service& io_service) + : boost::asio::detail::service_base< + kqueue_reactor >(io_service), + mutex_(), + kqueue_fd_(do_kqueue_create()), + wait_in_progress_(false), + interrupter_(), + read_op_queue_(), + write_op_queue_(), + except_op_queue_(), + pending_cancellations_(), + stop_thread_(false), + thread_(0), + shutdown_(false), + need_kqueue_wait_(true) + { + // Start the reactor's internal thread only if needed. + if (Own_Thread) + { + boost::asio::detail::signal_blocker sb; + thread_ = new boost::asio::detail::thread( + bind_handler(&kqueue_reactor::call_run_thread, this)); + } + + // Add the interrupter's descriptor to the kqueue. + struct kevent event; + EV_SET(&event, interrupter_.read_descriptor(), + EVFILT_READ, EV_ADD, 0, 0, 0); + ::kevent(kqueue_fd_, &event, 1, 0, 0, 0); + } + + // Destructor. + ~kqueue_reactor() + { + shutdown_service(); + close(kqueue_fd_); + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + stop_thread_ = true; + lock.unlock(); + + if (thread_) + { + interrupter_.interrupt(); + thread_->join(); + delete thread_; + thread_ = 0; + } + + read_op_queue_.destroy_operations(); + write_op_queue_.destroy_operations(); + except_op_queue_.destroy_operations(); + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + timer_queues_[i]->destroy_timers(); + timer_queues_.clear(); + } + + // Initialise the task, but only if the reactor is not in its own thread. + void init_task() + { + if (!Own_Thread) + { + typedef task_io_service > task_io_service_type; + use_service(this->get_io_service()).init_task(); + } + } + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + int register_descriptor(socket_type, per_descriptor_data& descriptor_data) + { + descriptor_data.allow_speculative_read = true; + descriptor_data.allow_speculative_write = true; + + return 0; + } + + // Start a new read operation. The handler object will be invoked when the + // given descriptor is ready to be read, or an error has occurred. + template + void start_read_op(socket_type descriptor, + per_descriptor_data& descriptor_data, Handler handler, + bool allow_speculative_read = true) + { + if (allow_speculative_read && descriptor_data.allow_speculative_read) + { + boost::system::error_code ec; + std::size_t bytes_transferred = 0; + if (handler.perform(ec, bytes_transferred)) + { + handler.complete(ec, bytes_transferred); + return; + } + + // We only get one shot at a speculative read in this function. + allow_speculative_read = false; + } + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (!allow_speculative_read) + need_kqueue_wait_ = true; + else if (!read_op_queue_.has_operation(descriptor)) + { + // Speculative reads are ok as there are no queued read operations. + descriptor_data.allow_speculative_read = true; + + boost::system::error_code ec; + std::size_t bytes_transferred = 0; + if (handler.perform(ec, bytes_transferred)) + { + handler.complete(ec, bytes_transferred); + return; + } + } + + // Speculative reads are not ok as there will be queued read operations. + descriptor_data.allow_speculative_read = false; + + if (read_op_queue_.enqueue_operation(descriptor, handler)) + { + struct kevent event; + EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + read_op_queue_.perform_all_operations(descriptor, ec); + } + } + } + + // Start a new write operation. The handler object will be invoked when the + // given descriptor is ready to be written, or an error has occurred. + template + void start_write_op(socket_type descriptor, + per_descriptor_data& descriptor_data, Handler handler, + bool allow_speculative_write = true) + { + if (allow_speculative_write && descriptor_data.allow_speculative_write) + { + boost::system::error_code ec; + std::size_t bytes_transferred = 0; + if (handler.perform(ec, bytes_transferred)) + { + handler.complete(ec, bytes_transferred); + return; + } + + // We only get one shot at a speculative write in this function. + allow_speculative_write = false; + } + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (!allow_speculative_write) + need_kqueue_wait_ = true; + else if (!write_op_queue_.has_operation(descriptor)) + { + // Speculative writes are ok as there are no queued write operations. + descriptor_data.allow_speculative_write = true; + + boost::system::error_code ec; + std::size_t bytes_transferred = 0; + if (handler.perform(ec, bytes_transferred)) + { + handler.complete(ec, bytes_transferred); + return; + } + } + + // Speculative writes are not ok as there will be queued write operations. + descriptor_data.allow_speculative_write = false; + + if (write_op_queue_.enqueue_operation(descriptor, handler)) + { + struct kevent event; + EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + write_op_queue_.perform_all_operations(descriptor, ec); + } + } + } + + // Start a new exception operation. The handler object will be invoked when + // the given descriptor has exception information, or an error has occurred. + template + void start_except_op(socket_type descriptor, + per_descriptor_data&, Handler handler) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (except_op_queue_.enqueue_operation(descriptor, handler)) + { + struct kevent event; + if (read_op_queue_.has_operation(descriptor)) + EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); + else + EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0); + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + except_op_queue_.perform_all_operations(descriptor, ec); + } + } + } + + // Start a new write operation. The handler object will be invoked when the + // given descriptor is ready to be written, or an error has occurred. + template + void start_connect_op(socket_type descriptor, + per_descriptor_data& descriptor_data, Handler handler) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + // Speculative writes are not ok as there will be queued write operations. + descriptor_data.allow_speculative_write = false; + + if (write_op_queue_.enqueue_operation(descriptor, handler)) + { + struct kevent event; + EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + write_op_queue_.perform_all_operations(descriptor, ec); + } + } + } + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + void cancel_ops(socket_type descriptor, per_descriptor_data&) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor); + } + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. + void close_descriptor(socket_type descriptor, per_descriptor_data&) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Remove the descriptor from kqueue. + struct kevent event[2]; + EV_SET(&event[0], descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0); + EV_SET(&event[1], descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0); + ::kevent(kqueue_fd_, event, 2, 0, 0, 0); + + // Cancel any outstanding operations associated with the descriptor. + cancel_ops_unlocked(descriptor); + } + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& timer_queue) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + timer_queues_.push_back(&timer_queue); + } + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& timer_queue) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + if (timer_queues_[i] == &timer_queue) + { + timer_queues_.erase(timer_queues_.begin() + i); + return; + } + } + } + + // Schedule a timer in the given timer queue to expire at the specified + // absolute time. The handler object will be invoked when the timer expires. + template + void schedule_timer(timer_queue& timer_queue, + const typename Time_Traits::time_type& time, Handler handler, void* token) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + if (timer_queue.enqueue_timer(time, handler, token)) + interrupter_.interrupt(); + } + + // Cancel the timer associated with the given token. Returns the number of + // handlers that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& timer_queue, void* token) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + std::size_t n = timer_queue.cancel_timer(token); + if (n > 0) + interrupter_.interrupt(); + return n; + } + +private: + friend class task_io_service >; + + // Run the kqueue loop. + void run(bool block) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Dispatch any operation cancellations that were made while the select + // loop was not running. + read_op_queue_.perform_cancellations(); + write_op_queue_.perform_cancellations(); + except_op_queue_.perform_cancellations(); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + timer_queues_[i]->dispatch_cancellations(); + + // Check if the thread is supposed to stop. + if (stop_thread_) + { + complete_operations_and_timers(lock); + return; + } + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (!block && read_op_queue_.empty() && write_op_queue_.empty() + && except_op_queue_.empty() && all_timer_queues_are_empty()) + { + complete_operations_and_timers(lock); + return; + } + + // Determine how long to block while waiting for events. + timespec timeout_buf = { 0, 0 }; + timespec* timeout = block ? get_timeout(timeout_buf) : &timeout_buf; + + wait_in_progress_ = true; + lock.unlock(); + + // Block on the kqueue descriptor. + struct kevent events[128]; + int num_events = (block || need_kqueue_wait_) + ? kevent(kqueue_fd_, 0, 0, events, 128, timeout) + : 0; + + lock.lock(); + wait_in_progress_ = false; + + // Block signals while performing operations. + boost::asio::detail::signal_blocker sb; + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + int descriptor = events[i].ident; + if (descriptor == interrupter_.read_descriptor()) + { + interrupter_.reset(); + } + else if (events[i].filter == EVFILT_READ) + { + // Dispatch operations associated with the descriptor. + bool more_reads = false; + bool more_except = false; + if (events[i].flags & EV_ERROR) + { + boost::system::error_code error( + events[i].data, boost::asio::error::get_system_category()); + except_op_queue_.perform_all_operations(descriptor, error); + read_op_queue_.perform_all_operations(descriptor, error); + } + else if (events[i].flags & EV_OOBAND) + { + boost::system::error_code error; + more_except = except_op_queue_.perform_operation(descriptor, error); + if (events[i].data > 0) + more_reads = read_op_queue_.perform_operation(descriptor, error); + else + more_reads = read_op_queue_.has_operation(descriptor); + } + else + { + boost::system::error_code error; + more_reads = read_op_queue_.perform_operation(descriptor, error); + more_except = except_op_queue_.has_operation(descriptor); + } + + // Update the descriptor in the kqueue. + struct kevent event; + if (more_reads) + EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); + else if (more_except) + EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0); + else + EV_SET(&event, descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0); + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + { + boost::system::error_code error(errno, + boost::asio::error::get_system_category()); + except_op_queue_.perform_all_operations(descriptor, error); + read_op_queue_.perform_all_operations(descriptor, error); + } + } + else if (events[i].filter == EVFILT_WRITE) + { + // Dispatch operations associated with the descriptor. + bool more_writes = false; + if (events[i].flags & EV_ERROR) + { + boost::system::error_code error( + events[i].data, boost::asio::error::get_system_category()); + write_op_queue_.perform_all_operations(descriptor, error); + } + else + { + boost::system::error_code error; + more_writes = write_op_queue_.perform_operation(descriptor, error); + } + + // Update the descriptor in the kqueue. + struct kevent event; + if (more_writes) + EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); + else + EV_SET(&event, descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0); + if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) + { + boost::system::error_code error(errno, + boost::asio::error::get_system_category()); + write_op_queue_.perform_all_operations(descriptor, error); + } + } + } + + read_op_queue_.perform_cancellations(); + write_op_queue_.perform_cancellations(); + except_op_queue_.perform_cancellations(); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + timer_queues_[i]->dispatch_timers(); + timer_queues_[i]->dispatch_cancellations(); + } + + // Issue any pending cancellations. + for (std::size_t i = 0; i < pending_cancellations_.size(); ++i) + cancel_ops_unlocked(pending_cancellations_[i]); + pending_cancellations_.clear(); + + // Determine whether kqueue needs to be called next time the reactor is run. + need_kqueue_wait_ = !read_op_queue_.empty() + || !write_op_queue_.empty() || !except_op_queue_.empty(); + + complete_operations_and_timers(lock); + } + + // Run the select loop in the thread. + void run_thread() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + lock.unlock(); + run(true); + lock.lock(); + } + } + + // Entry point for the select loop thread. + static void call_run_thread(kqueue_reactor* reactor) + { + reactor->run_thread(); + } + + // Interrupt the select loop. + void interrupt() + { + interrupter_.interrupt(); + } + + // Create the kqueue file descriptor. Throws an exception if the descriptor + // cannot be created. + static int do_kqueue_create() + { + int fd = kqueue(); + if (fd == -1) + { + boost::throw_exception( + boost::system::system_error( + boost::system::error_code(errno, + boost::asio::error::get_system_category()), + "kqueue")); + } + return fd; + } + + // Check if all timer queues are empty. + bool all_timer_queues_are_empty() const + { + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + if (!timer_queues_[i]->empty()) + return false; + return true; + } + + // Get the timeout value for the kevent call. + timespec* get_timeout(timespec& ts) + { + if (all_timer_queues_are_empty()) + return 0; + + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + boost::posix_time::time_duration minimum_wait_duration + = boost::posix_time::minutes(5); + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + boost::posix_time::time_duration wait_duration + = timer_queues_[i]->wait_duration(); + if (wait_duration < minimum_wait_duration) + minimum_wait_duration = wait_duration; + } + + if (minimum_wait_duration > boost::posix_time::time_duration()) + { + ts.tv_sec = minimum_wait_duration.total_seconds(); + ts.tv_nsec = minimum_wait_duration.total_nanoseconds() % 1000000000; + } + else + { + ts.tv_sec = 0; + ts.tv_nsec = 0; + } + + return &ts; + } + + // Cancel all operations associated with the given descriptor. The do_cancel + // function of the handler objects will be invoked. This function does not + // acquire the kqueue_reactor's mutex. + void cancel_ops_unlocked(socket_type descriptor) + { + bool interrupt = read_op_queue_.cancel_operations(descriptor); + interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt; + interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt; + if (interrupt) + interrupter_.interrupt(); + } + + // Clean up operations and timers. We must not hold the lock since the + // destructors may make calls back into this reactor. We make a copy of the + // vector of timer queues since the original may be modified while the lock + // is not held. + void complete_operations_and_timers( + boost::asio::detail::mutex::scoped_lock& lock) + { + timer_queues_for_cleanup_ = timer_queues_; + lock.unlock(); + read_op_queue_.complete_operations(); + write_op_queue_.complete_operations(); + except_op_queue_.complete_operations(); + for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) + timer_queues_for_cleanup_[i]->complete_timers(); + } + + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // The kqueue file descriptor. + int kqueue_fd_; + + // Whether the kqueue wait call is currently in progress + bool wait_in_progress_; + + // The interrupter is used to break a blocking kevent call. + select_interrupter interrupter_; + + // The queue of read operations. + reactor_op_queue read_op_queue_; + + // The queue of write operations. + reactor_op_queue write_op_queue_; + + // The queue of except operations. + reactor_op_queue except_op_queue_; + + // The timer queues. + std::vector timer_queues_; + + // A copy of the timer queues, used when cleaning up timers. The copy is + // stored as a class data member to avoid unnecessary memory allocation. + std::vector timer_queues_for_cleanup_; + + // The descriptors that are pending cancellation. + std::vector pending_cancellations_; + + // Does the reactor loop thread need to stop. + bool stop_thread_; + + // The thread that is running the reactor loop. + boost::asio::detail::thread* thread_; + + // Whether the service has been shut down. + bool shutdown_; + + // Whether we need to call kqueue the next time the reactor is run. + bool need_kqueue_wait_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_KQUEUE) + +#include + +#endif // BOOST_ASIO_DETAIL_KQUEUE_REACTOR_HPP diff --git a/3rdParty/Boost/boost/asio/detail/kqueue_reactor_fwd.hpp b/3rdParty/Boost/boost/asio/detail/kqueue_reactor_fwd.hpp new file mode 100644 index 0000000..e3df284 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/kqueue_reactor_fwd.hpp @@ -0,0 +1,43 @@ +// +// kqueue_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze 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_KQUEUE_REACTOR_FWD_HPP +#define BOOST_ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_DISABLE_KQUEUE) +#if defined(__MACH__) && defined(__APPLE__) + +// Define this to indicate that epoll is supported on the target platform. +#define BOOST_ASIO_HAS_KQUEUE 1 + +namespace boost { +namespace asio { +namespace detail { + +template +class kqueue_reactor; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(__MACH__) && defined(__APPLE__) +#endif // !defined(BOOST_ASIO_DISABLE_KQUEUE) + +#include + +#endif // BOOST_ASIO_DETAIL_KQUEUE_REACTOR_FWD_HPP diff --git a/3rdParty/Boost/boost/asio/detail/mutex.hpp b/3rdParty/Boost/boost/asio/detail/mutex.hpp new file mode 100644 index 0000000..4f64a28 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/mutex.hpp @@ -0,0 +1,52 @@ +// +// mutex.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_MUTEX_HPP +#define BOOST_ASIO_DETAIL_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if !defined(BOOST_HAS_THREADS) +# include +#elif defined(BOOST_WINDOWS) +# include +#elif defined(BOOST_HAS_PTHREADS) +# include +#else +# error Only Windows and POSIX are supported! +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if !defined(BOOST_HAS_THREADS) +typedef null_mutex mutex; +#elif defined(BOOST_WINDOWS) +typedef win_mutex mutex; +#elif defined(BOOST_HAS_PTHREADS) +typedef posix_mutex mutex; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_MUTEX_HPP diff --git a/3rdParty/Boost/boost/asio/detail/noncopyable.hpp b/3rdParty/Boost/boost/asio/detail/noncopyable.hpp new file mode 100644 index 0000000..3a09538 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/noncopyable.hpp @@ -0,0 +1,57 @@ +// +// noncopyable.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_NONCOPYABLE_HPP +#define BOOST_ASIO_DETAIL_NONCOPYABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +// Redefine the noncopyable class for Borland C++ since that compiler does not +// apply the empty base optimisation unless the base class contains a dummy +// char data member. +class noncopyable +{ +protected: + noncopyable() {} + ~noncopyable() {} +private: + noncopyable(const noncopyable&); + const noncopyable& operator=(const noncopyable&); + char dummy_; +}; +#else +using boost::noncopyable; +#endif + +} // namespace detail + +using boost::asio::detail::noncopyable; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_NONCOPYABLE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/null_event.hpp b/3rdParty/Boost/boost/asio/detail/null_event.hpp new file mode 100644 index 0000000..4b667e7 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/null_event.hpp @@ -0,0 +1,73 @@ +// +// null_event.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_NULL_EVENT_HPP +#define BOOST_ASIO_DETAIL_NULL_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if !defined(BOOST_HAS_THREADS) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class null_event + : private noncopyable +{ +public: + // Constructor. + null_event() + { + } + + // Destructor. + ~null_event() + { + } + + // Signal the event. + template + void signal(Lock&) + { + } + + // Reset the event. + template + void clear(Lock&) + { + } + + // Wait for the event to become signalled. + template + void wait(Lock&) + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_HAS_THREADS) + +#include + +#endif // BOOST_ASIO_DETAIL_NULL_EVENT_HPP diff --git a/3rdParty/Boost/boost/asio/detail/null_mutex.hpp b/3rdParty/Boost/boost/asio/detail/null_mutex.hpp new file mode 100644 index 0000000..64bf871 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/null_mutex.hpp @@ -0,0 +1,68 @@ +// +// null_mutex.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_NULL_MUTEX_HPP +#define BOOST_ASIO_DETAIL_NULL_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if !defined(BOOST_HAS_THREADS) + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class null_mutex + : private noncopyable +{ +public: + typedef boost::asio::detail::scoped_lock scoped_lock; + + // Constructor. + null_mutex() + { + } + + // Destructor. + ~null_mutex() + { + } + + // Lock the mutex. + void lock() + { + } + + // Unlock the mutex. + void unlock() + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_HAS_THREADS) + +#include + +#endif // BOOST_ASIO_DETAIL_NULL_MUTEX_HPP diff --git a/3rdParty/Boost/boost/asio/detail/null_signal_blocker.hpp b/3rdParty/Boost/boost/asio/detail/null_signal_blocker.hpp new file mode 100644 index 0000000..1fc65c8 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/null_signal_blocker.hpp @@ -0,0 +1,65 @@ +// +// null_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_NULL_SIGNAL_BLOCKER_HPP +#define BOOST_ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if !defined(BOOST_HAS_THREADS) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class null_signal_blocker + : private noncopyable +{ +public: + // Constructor blocks all signals for the calling thread. + null_signal_blocker() + { + } + + // Destructor restores the previous signal mask. + ~null_signal_blocker() + { + } + + // Block all signals for the calling thread. + void block() + { + } + + // Restore the previous signal mask. + void unblock() + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_HAS_THREADS) + +#include + +#endif // BOOST_ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP diff --git a/3rdParty/Boost/boost/asio/detail/null_thread.hpp b/3rdParty/Boost/boost/asio/detail/null_thread.hpp new file mode 100644 index 0000000..5aed211 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/null_thread.hpp @@ -0,0 +1,70 @@ +// +// null_thread.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_NULL_THREAD_HPP +#define BOOST_ASIO_DETAIL_NULL_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#if !defined(BOOST_HAS_THREADS) + +#include +#include +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class null_thread + : private noncopyable +{ +public: + // Constructor. + template + null_thread(Function f) + { + boost::system::system_error e( + boost::asio::error::operation_not_supported, "thread"); + boost::throw_exception(e); + } + + // Destructor. + ~null_thread() + { + } + + // Wait for the thread to exit. + void join() + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_HAS_THREADS) + +#include + +#endif // BOOST_ASIO_DETAIL_NULL_THREAD_HPP diff --git a/3rdParty/Boost/boost/asio/detail/null_tss_ptr.hpp b/3rdParty/Boost/boost/asio/detail/null_tss_ptr.hpp new file mode 100644 index 0000000..ba4b8f8 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/null_tss_ptr.hpp @@ -0,0 +1,72 @@ +// +// null_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_NULL_TSS_PTR_HPP +#define BOOST_ASIO_DETAIL_NULL_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if !defined(BOOST_HAS_THREADS) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class null_tss_ptr + : private noncopyable +{ +public: + // Constructor. + null_tss_ptr() + : value_(0) + { + } + + // Destructor. + ~null_tss_ptr() + { + } + + // Get the value. + operator T*() const + { + return value_; + } + + // Set the value. + void operator=(T* value) + { + value_ = value; + } + +private: + T* value_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_HAS_THREADS) + +#include + +#endif // BOOST_ASIO_DETAIL_NULL_TSS_PTR_HPP diff --git a/3rdParty/Boost/boost/asio/detail/old_win_sdk_compat.hpp b/3rdParty/Boost/boost/asio/detail/old_win_sdk_compat.hpp new file mode 100644 index 0000000..5f0aba1 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/old_win_sdk_compat.hpp @@ -0,0 +1,342 @@ +// +// old_win_sdk_compat.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_OLD_WIN_SDK_COMPAT_HPP +#define BOOST_ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +// Guess whether we are building against on old Platform SDK. +#if !defined(IN6ADDR_ANY_INIT) +#define BOOST_ASIO_HAS_OLD_WIN_SDK 1 +#endif // !defined(IN6ADDR_ANY_INIT) + +#if defined(BOOST_ASIO_HAS_OLD_WIN_SDK) + +// Emulation of types that are missing from old Platform SDKs. +// +// N.B. this emulation is also used if building for a Windows 2000 target with +// a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support +// in that case. + +namespace boost { +namespace asio { +namespace detail { + +enum +{ + sockaddr_storage_maxsize = 128, // Maximum size. + sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment. + sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)), + sockaddr_storage_pad2size = (sockaddr_storage_maxsize - + (sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize)) +}; + +struct sockaddr_storage_emulation +{ + short ss_family; + char __ss_pad1[sockaddr_storage_pad1size]; + __int64 __ss_align; + char __ss_pad2[sockaddr_storage_pad2size]; +}; + +struct in6_addr_emulation +{ + union + { + u_char Byte[16]; + u_short Word[8]; + } u; +}; + +#if !defined(s6_addr) +# define _S6_un u +# define _S6_u8 Byte +# define s6_addr _S6_un._S6_u8 +#endif // !defined(s6_addr) + +struct sockaddr_in6_emulation +{ + short sin6_family; + u_short sin6_port; + u_long sin6_flowinfo; + in6_addr_emulation sin6_addr; + u_long sin6_scope_id; +}; + +struct ipv6_mreq_emulation +{ + in6_addr_emulation ipv6mr_multiaddr; + unsigned int ipv6mr_interface; +}; + +#if !defined(IN6ADDR_ANY_INIT) +# define IN6ADDR_ANY_INIT { 0 } +#endif + +#if !defined(IN6ADDR_LOOPBACK_INIT) +# define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } +#endif + +struct addrinfo_emulation +{ + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char* ai_canonname; + sockaddr* ai_addr; + addrinfo_emulation* ai_next; +}; + +#if !defined(AI_PASSIVE) +# define AI_PASSIVE 0x1 +#endif + +#if !defined(AI_CANONNAME) +# define AI_CANONNAME 0x2 +#endif + +#if !defined(AI_NUMERICHOST) +# define AI_NUMERICHOST 0x4 +#endif + +#if !defined(EAI_AGAIN) +# define EAI_AGAIN WSATRY_AGAIN +#endif + +#if !defined(EAI_BADFLAGS) +# define EAI_BADFLAGS WSAEINVAL +#endif + +#if !defined(EAI_FAIL) +# define EAI_FAIL WSANO_RECOVERY +#endif + +#if !defined(EAI_FAMILY) +# define EAI_FAMILY WSAEAFNOSUPPORT +#endif + +#if !defined(EAI_MEMORY) +# define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY +#endif + +#if !defined(EAI_NODATA) +# define EAI_NODATA WSANO_DATA +#endif + +#if !defined(EAI_NONAME) +# define EAI_NONAME WSAHOST_NOT_FOUND +#endif + +#if !defined(EAI_SERVICE) +# define EAI_SERVICE WSATYPE_NOT_FOUND +#endif + +#if !defined(EAI_SOCKTYPE) +# define EAI_SOCKTYPE WSAESOCKTNOSUPPORT +#endif + +#if !defined(NI_NOFQDN) +# define NI_NOFQDN 0x01 +#endif + +#if !defined(NI_NUMERICHOST) +# define NI_NUMERICHOST 0x02 +#endif + +#if !defined(NI_NAMEREQD) +# define NI_NAMEREQD 0x04 +#endif + +#if !defined(NI_NUMERICSERV) +# define NI_NUMERICSERV 0x08 +#endif + +#if !defined(NI_DGRAM) +# define NI_DGRAM 0x10 +#endif + +#if !defined(IPPROTO_IPV6) +# define IPPROTO_IPV6 41 +#endif + +#if !defined(IPV6_UNICAST_HOPS) +# define IPV6_UNICAST_HOPS 4 +#endif + +#if !defined(IPV6_MULTICAST_IF) +# define IPV6_MULTICAST_IF 9 +#endif + +#if !defined(IPV6_MULTICAST_HOPS) +# define IPV6_MULTICAST_HOPS 10 +#endif + +#if !defined(IPV6_MULTICAST_LOOP) +# define IPV6_MULTICAST_LOOP 11 +#endif + +#if !defined(IPV6_JOIN_GROUP) +# define IPV6_JOIN_GROUP 12 +#endif + +#if !defined(IPV6_LEAVE_GROUP) +# define IPV6_LEAVE_GROUP 13 +#endif + +inline int IN6_IS_ADDR_UNSPECIFIED(const in6_addr_emulation* a) +{ + return ((a->s6_addr[0] == 0) + && (a->s6_addr[1] == 0) + && (a->s6_addr[2] == 0) + && (a->s6_addr[3] == 0) + && (a->s6_addr[4] == 0) + && (a->s6_addr[5] == 0) + && (a->s6_addr[6] == 0) + && (a->s6_addr[7] == 0) + && (a->s6_addr[8] == 0) + && (a->s6_addr[9] == 0) + && (a->s6_addr[10] == 0) + && (a->s6_addr[11] == 0) + && (a->s6_addr[12] == 0) + && (a->s6_addr[13] == 0) + && (a->s6_addr[14] == 0) + && (a->s6_addr[15] == 0)); +} + +inline int IN6_IS_ADDR_LOOPBACK(const in6_addr_emulation* a) +{ + return ((a->s6_addr[0] == 0) + && (a->s6_addr[1] == 0) + && (a->s6_addr[2] == 0) + && (a->s6_addr[3] == 0) + && (a->s6_addr[4] == 0) + && (a->s6_addr[5] == 0) + && (a->s6_addr[6] == 0) + && (a->s6_addr[7] == 0) + && (a->s6_addr[8] == 0) + && (a->s6_addr[9] == 0) + && (a->s6_addr[10] == 0) + && (a->s6_addr[11] == 0) + && (a->s6_addr[12] == 0) + && (a->s6_addr[13] == 0) + && (a->s6_addr[14] == 0) + && (a->s6_addr[15] == 1)); +} + +inline int IN6_IS_ADDR_MULTICAST(const in6_addr_emulation* a) +{ + return (a->s6_addr[0] == 0xff); +} + +inline int IN6_IS_ADDR_LINKLOCAL(const in6_addr_emulation* a) +{ + return ((a->s6_addr[0] == 0xfe) && ((a->s6_addr[1] & 0xc0) == 0x80)); +} + +inline int IN6_IS_ADDR_SITELOCAL(const in6_addr_emulation* a) +{ + return ((a->s6_addr[0] == 0xfe) && ((a->s6_addr[1] & 0xc0) == 0xc0)); +} + +inline int IN6_IS_ADDR_V4MAPPED(const in6_addr_emulation* a) +{ + return ((a->s6_addr[0] == 0) + && (a->s6_addr[1] == 0) + && (a->s6_addr[2] == 0) + && (a->s6_addr[3] == 0) + && (a->s6_addr[4] == 0) + && (a->s6_addr[5] == 0) + && (a->s6_addr[6] == 0) + && (a->s6_addr[7] == 0) + && (a->s6_addr[8] == 0) + && (a->s6_addr[9] == 0) + && (a->s6_addr[10] == 0xff) + && (a->s6_addr[11] == 0xff)); +} + +inline int IN6_IS_ADDR_V4COMPAT(const in6_addr_emulation* a) +{ + return ((a->s6_addr[0] == 0) + && (a->s6_addr[1] == 0) + && (a->s6_addr[2] == 0) + && (a->s6_addr[3] == 0) + && (a->s6_addr[4] == 0) + && (a->s6_addr[5] == 0) + && (a->s6_addr[6] == 0) + && (a->s6_addr[7] == 0) + && (a->s6_addr[8] == 0) + && (a->s6_addr[9] == 0) + && (a->s6_addr[10] == 0xff) + && (a->s6_addr[11] == 0xff) + && !((a->s6_addr[12] == 0) + && (a->s6_addr[13] == 0) + && (a->s6_addr[14] == 0) + && ((a->s6_addr[15] == 0) || (a->s6_addr[15] == 1)))); +} + +inline int IN6_IS_ADDR_MC_NODELOCAL(const in6_addr_emulation* a) +{ + return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 1); +} + +inline int IN6_IS_ADDR_MC_LINKLOCAL(const in6_addr_emulation* a) +{ + return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 2); +} + +inline int IN6_IS_ADDR_MC_SITELOCAL(const in6_addr_emulation* a) +{ + return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 5); +} + +inline int IN6_IS_ADDR_MC_ORGLOCAL(const in6_addr_emulation* a) +{ + return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 8); +} + +inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a) +{ + return IN6_IS_ADDR_MULTICAST(a) && ((a->s6_addr[1] & 0xf) == 0xe); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_OLD_WIN_SDK) + +// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY. +#if !defined(IPV6_V6ONLY) +# define IPV6_V6ONLY 27 +#endif + +// Some SDKs (e.g. Windows CE) don't define IPPROTO_ICMPV6. +#if !defined(IPPROTO_ICMPV6) +# define IPPROTO_ICMPV6 58 +#endif + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#include + +#endif // BOOST_ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP diff --git a/3rdParty/Boost/boost/asio/detail/pipe_select_interrupter.hpp b/3rdParty/Boost/boost/asio/detail/pipe_select_interrupter.hpp new file mode 100644 index 0000000..51b8c02 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/pipe_select_interrupter.hpp @@ -0,0 +1,117 @@ +// +// pipe_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_PIPE_SELECT_INTERRUPTER_HPP +#define BOOST_ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include +#include +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class pipe_select_interrupter +{ +public: + // Constructor. + pipe_select_interrupter() + { + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + } + else + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::system::system_error e(ec, "pipe_select_interrupter"); + boost::throw_exception(e); + } + } + + // Destructor. + ~pipe_select_interrupter() + { + if (read_descriptor_ != -1) + ::close(read_descriptor_); + if (write_descriptor_ != -1) + ::close(write_descriptor_); + } + + // Interrupt the select call. + void interrupt() + { + char byte = 0; + int result = ::write(write_descriptor_, &byte, 1); + (void)result; + } + + // Reset the select interrupt. Returns true if the call was interrupted. + bool reset() + { + char data[1024]; + int bytes_read = ::read(read_descriptor_, data, sizeof(data)); + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = ::read(read_descriptor_, data, sizeof(data)); + return was_interrupted; + } + + // Get the read descriptor to be passed to select. + int read_descriptor() const + { + return read_descriptor_; + } + +private: + // The read end of a connection used to interrupt the select call. This file + // descriptor is passed to select such that when it is time to stop, a single + // byte will be written on the other end of the connection and this + // descriptor will become readable. + int read_descriptor_; + + // The write end of a connection used to interrupt the select call. A single + // byte may be written to this to wake up the select which is waiting for the + // other end to become readable. + int write_descriptor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include + +#endif // BOOST_ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP diff --git a/3rdParty/Boost/boost/asio/detail/pop_options.hpp b/3rdParty/Boost/boost/asio/detail/pop_options.hpp new file mode 100644 index 0000000..7f56662 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/pop_options.hpp @@ -0,0 +1,88 @@ +// +// pop_options.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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) +// + +// No header guard + +#if defined(__COMO__) + +// Comeau C++ + +#elif defined(__DMC__) + +// Digital Mars C++ + +#elif defined(__INTEL_COMPILER) || defined(__ICL) \ + || defined(__ICC) || defined(__ECC) + +// Intel C++ + +#elif defined(__GNUC__) + +// GNU C++ + +# if defined(__MINGW32__) || defined(__CYGWIN__) +# pragma pack (pop) +# endif + +#elif defined(__KCC) + +// Kai C++ + +#elif defined(__sgi) + +// SGI MIPSpro C++ + +#elif defined(__DECCXX) + +// Compaq Tru64 Unix cxx + +#elif defined(__ghs) + +// Greenhills C++ + +#elif defined(__BORLANDC__) + +// Borland C++ + +# pragma option pop +# pragma nopushoptwarn +# pragma nopackwarning + +#elif defined(__MWERKS__) + +// Metrowerks CodeWarrior + +#elif defined(__SUNPRO_CC) + +// Sun Workshop Compiler C++ + +#elif defined(__HP_aCC) + +// HP aCC + +#elif defined(__MRC__) || defined(__SC__) + +// MPW MrCpp or SCpp + +#elif defined(__IBMCPP__) + +// IBM Visual Age + +#elif defined(_MSC_VER) + +// Microsoft Visual C++ +// +// Must remain the last #elif since some other vendors (Metrowerks, for example) +// also #define _MSC_VER + +# pragma warning (pop) +# pragma pack (pop) + +#endif diff --git a/3rdParty/Boost/boost/asio/detail/posix_event.hpp b/3rdParty/Boost/boost/asio/detail/posix_event.hpp new file mode 100644 index 0000000..f838342 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/posix_event.hpp @@ -0,0 +1,106 @@ +// +// posix_event.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_POSIX_EVENT_HPP +#define BOOST_ASIO_DETAIL_POSIX_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#if defined(BOOST_HAS_PTHREADS) + +#include +#include +#include +#include +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class posix_event + : private noncopyable +{ +public: + // Constructor. + posix_event() + : signalled_(false) + { + int error = ::pthread_cond_init(&cond_, 0); + if (error != 0) + { + boost::system::system_error e( + boost::system::error_code(error, + boost::asio::error::get_system_category()), + "event"); + boost::throw_exception(e); + } + } + + // Destructor. + ~posix_event() + { + ::pthread_cond_destroy(&cond_); + } + + // Signal the event. + template + void signal(Lock& lock) + { + BOOST_ASSERT(lock.locked()); + (void)lock; + signalled_ = true; + ::pthread_cond_signal(&cond_); // Ignore EINVAL. + } + + // Reset the event. + template + void clear(Lock& lock) + { + BOOST_ASSERT(lock.locked()); + (void)lock; + signalled_ = false; + } + + // Wait for the event to become signalled. + template + void wait(Lock& lock) + { + BOOST_ASSERT(lock.locked()); + while (!signalled_) + ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL. + } + +private: + ::pthread_cond_t cond_; + bool signalled_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_HAS_PTHREADS) + +#include + +#endif // BOOST_ASIO_DETAIL_POSIX_EVENT_HPP diff --git a/3rdParty/Boost/boost/asio/detail/posix_fd_set_adapter.hpp b/3rdParty/Boost/boost/asio/detail/posix_fd_set_adapter.hpp new file mode 100644 index 0000000..121b396 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/posix_fd_set_adapter.hpp @@ -0,0 +1,83 @@ +// +// posix_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_POSIX_FD_SET_ADAPTER_HPP +#define BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +namespace boost { +namespace asio { +namespace detail { + +// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements. +class posix_fd_set_adapter +{ +public: + posix_fd_set_adapter() + : max_descriptor_(invalid_socket) + { + using namespace std; // Needed for memset on Solaris. + FD_ZERO(&fd_set_); + } + + bool set(socket_type descriptor) + { + if (descriptor < (socket_type)FD_SETSIZE) + { + if (max_descriptor_ == invalid_socket || descriptor > max_descriptor_) + max_descriptor_ = descriptor; + FD_SET(descriptor, &fd_set_); + return true; + } + return false; + } + + bool is_set(socket_type descriptor) const + { + return FD_ISSET(descriptor, &fd_set_) != 0; + } + + operator fd_set*() + { + return &fd_set_; + } + + socket_type max_descriptor() const + { + return max_descriptor_; + } + +private: + mutable fd_set fd_set_; + socket_type max_descriptor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include + +#endif // BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP diff --git a/3rdParty/Boost/boost/asio/detail/posix_mutex.hpp b/3rdParty/Boost/boost/asio/detail/posix_mutex.hpp new file mode 100644 index 0000000..219d6d0 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/posix_mutex.hpp @@ -0,0 +1,109 @@ +// +// posix_mutex.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_POSIX_MUTEX_HPP +#define BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#if defined(BOOST_HAS_PTHREADS) + +#include +#include +#include +#include + +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class posix_event; + +class posix_mutex + : private noncopyable +{ +public: + typedef boost::asio::detail::scoped_lock scoped_lock; + + // Constructor. + posix_mutex() + { + int error = ::pthread_mutex_init(&mutex_, 0); + if (error != 0) + { + boost::system::system_error e( + boost::system::error_code(error, + boost::asio::error::get_system_category()), + "mutex"); + boost::throw_exception(e); + } + } + + // Destructor. + ~posix_mutex() + { + ::pthread_mutex_destroy(&mutex_); + } + + // Lock the mutex. + void lock() + { + int error = ::pthread_mutex_lock(&mutex_); + if (error != 0) + { + boost::system::system_error e( + boost::system::error_code(error, + boost::asio::error::get_system_category()), + "mutex"); + boost::throw_exception(e); + } + } + + // Unlock the mutex. + void unlock() + { + int error = ::pthread_mutex_unlock(&mutex_); + if (error != 0) + { + boost::system::system_error e( + boost::system::error_code(error, + boost::asio::error::get_system_category()), + "mutex"); + boost::throw_exception(e); + } + } + +private: + friend class posix_event; + ::pthread_mutex_t mutex_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_HAS_PTHREADS) + +#include + +#endif // BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP diff --git a/3rdParty/Boost/boost/asio/detail/posix_signal_blocker.hpp b/3rdParty/Boost/boost/asio/detail/posix_signal_blocker.hpp new file mode 100644 index 0000000..f8234fb --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/posix_signal_blocker.hpp @@ -0,0 +1,92 @@ +// +// posix_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_POSIX_SIGNAL_BLOCKER_HPP +#define BOOST_ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if defined(BOOST_HAS_PTHREADS) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class posix_signal_blocker + : private noncopyable +{ +public: + // Constructor blocks all signals for the calling thread. + posix_signal_blocker() + : blocked_(false) + { + sigset_t new_mask; + sigfillset(&new_mask); + blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0); + } + + // Destructor restores the previous signal mask. + ~posix_signal_blocker() + { + if (blocked_) + pthread_sigmask(SIG_SETMASK, &old_mask_, 0); + } + + // Block all signals for the calling thread. + void block() + { + if (!blocked_) + { + sigset_t new_mask; + sigfillset(&new_mask); + blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0); + } + } + + // Restore the previous signal mask. + void unblock() + { + if (blocked_) + blocked_ = (pthread_sigmask(SIG_SETMASK, &old_mask_, 0) != 0); + } + +private: + // Have signals been blocked. + bool blocked_; + + // The previous signal mask. + sigset_t old_mask_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_HAS_PTHREADS) + +#include + +#endif // BOOST_ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP diff --git a/3rdParty/Boost/boost/asio/detail/posix_thread.hpp b/3rdParty/Boost/boost/asio/detail/posix_thread.hpp new file mode 100644 index 0000000..1e38618 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/posix_thread.hpp @@ -0,0 +1,131 @@ +// +// posix_thread.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_POSIX_THREAD_HPP +#define BOOST_ASIO_DETAIL_POSIX_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#if defined(BOOST_HAS_PTHREADS) + +#include +#include +#include +#include +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +extern "C" void* asio_detail_posix_thread_function(void* arg); + +class posix_thread + : private noncopyable +{ +public: + // Constructor. + template + posix_thread(Function f) + : joined_(false) + { + std::auto_ptr arg(new func(f)); + int error = ::pthread_create(&thread_, 0, + asio_detail_posix_thread_function, arg.get()); + if (error != 0) + { + boost::system::system_error e( + boost::system::error_code(error, + boost::asio::error::get_system_category()), + "thread"); + boost::throw_exception(e); + } + arg.release(); + } + + // Destructor. + ~posix_thread() + { + if (!joined_) + ::pthread_detach(thread_); + } + + // Wait for the thread to exit. + void join() + { + if (!joined_) + { + ::pthread_join(thread_, 0); + joined_ = true; + } + } + +private: + friend void* asio_detail_posix_thread_function(void* arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + template + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ::pthread_t thread_; + bool joined_; +}; + +inline void* asio_detail_posix_thread_function(void* arg) +{ + std::auto_ptr f( + static_cast(arg)); + f->run(); + return 0; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_HAS_PTHREADS) + +#include + +#endif // BOOST_ASIO_DETAIL_POSIX_THREAD_HPP diff --git a/3rdParty/Boost/boost/asio/detail/posix_tss_ptr.hpp b/3rdParty/Boost/boost/asio/detail/posix_tss_ptr.hpp new file mode 100644 index 0000000..f53c2dc --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/posix_tss_ptr.hpp @@ -0,0 +1,90 @@ +// +// posix_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_POSIX_TSS_PTR_HPP +#define BOOST_ASIO_DETAIL_POSIX_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#if defined(BOOST_HAS_PTHREADS) + +#include +#include +#include +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class posix_tss_ptr + : private noncopyable +{ +public: + // Constructor. + posix_tss_ptr() + { + int error = ::pthread_key_create(&tss_key_, 0); + if (error != 0) + { + boost::system::system_error e( + boost::system::error_code(error, + boost::asio::error::get_system_category()), + "tss"); + boost::throw_exception(e); + } + } + + // Destructor. + ~posix_tss_ptr() + { + ::pthread_key_delete(tss_key_); + } + + // Get the value. + operator T*() const + { + return static_cast(::pthread_getspecific(tss_key_)); + } + + // Set the value. + void operator=(T* value) + { + ::pthread_setspecific(tss_key_, value); + } + +private: + // Thread-specific storage to allow unlocked access to determine whether a + // thread is a member of the pool. + pthread_key_t tss_key_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_HAS_PTHREADS) + +#include + +#endif // BOOST_ASIO_DETAIL_POSIX_TSS_PTR_HPP diff --git a/3rdParty/Boost/boost/asio/detail/push_options.hpp b/3rdParty/Boost/boost/asio/detail/push_options.hpp new file mode 100644 index 0000000..47524b2 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/push_options.hpp @@ -0,0 +1,114 @@ +// +// push_options.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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) +// + +// No header guard + +#if defined(__COMO__) + +// Comeau C++ + +#elif defined(__DMC__) + +// Digital Mars C++ + +#elif defined(__INTEL_COMPILER) || defined(__ICL) \ + || defined(__ICC) || defined(__ECC) + +// Intel C++ + +#elif defined(__GNUC__) + +// GNU C++ + +# if defined(__MINGW32__) || defined(__CYGWIN__) +# pragma pack (push, 8) +# endif + +#elif defined(__KCC) + +// Kai C++ + +#elif defined(__sgi) + +// SGI MIPSpro C++ + +#elif defined(__DECCXX) + +// Compaq Tru64 Unix cxx + +#elif defined(__ghs) + +// Greenhills C++ + +#elif defined(__BORLANDC__) + +// Borland C++ + +# pragma option push -a8 -b -Ve- -Vx- -w-inl -vi- +# pragma nopushoptwarn +# pragma nopackwarning +# if !defined(__MT__) +# error Multithreaded RTL must be selected. +# endif // !defined(__MT__) + +#elif defined(__MWERKS__) + +// Metrowerks CodeWarrior + +#elif defined(__SUNPRO_CC) + +// Sun Workshop Compiler C++ + +#elif defined(__HP_aCC) + +// HP aCC + +#elif defined(__MRC__) || defined(__SC__) + +// MPW MrCpp or SCpp + +#elif defined(__IBMCPP__) + +// IBM Visual Age + +#elif defined(_MSC_VER) + +// Microsoft Visual C++ +// +// Must remain the last #elif since some other vendors (Metrowerks, for example) +// also #define _MSC_VER + +# pragma warning (disable:4103) +# pragma warning (push) +# pragma warning (disable:4127) +# pragma warning (disable:4244) +# pragma warning (disable:4355) +# pragma warning (disable:4512) +# pragma warning (disable:4675) +# if defined(_M_IX86) && defined(_Wp64) +// The /Wp64 option is broken. If you want to check 64 bit portability, use a +// 64 bit compiler! +# pragma warning (disable:4311) +# pragma warning (disable:4312) +# endif // defined(_M_IX86) && defined(_Wp64) +# pragma pack (push, 8) +// Note that if the /Og optimisation flag is enabled with MSVC6, the compiler +// has a tendency to incorrectly optimise away some calls to member template +// functions, even though those functions contain code that should not be +// optimised away! Therefore we will always disable this optimisation option +// for the MSVC6 compiler. +# if (_MSC_VER < 1300) +# pragma optimize ("g", off) +# endif +# if !defined(_MT) +# error Multithreaded RTL must be selected. +# endif // !defined(_MT) + +#endif diff --git a/3rdParty/Boost/boost/asio/detail/reactive_descriptor_service.hpp b/3rdParty/Boost/boost/asio/detail/reactive_descriptor_service.hpp new file mode 100644 index 0000000..ad828aa --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/reactive_descriptor_service.hpp @@ -0,0 +1,712 @@ +// +// reactive_descriptor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_REACTIVE_DESCRIPTOR_SERVICE_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_descriptor_service + : public boost::asio::detail::service_base< + reactive_descriptor_service > +{ +public: + // The native type of a descriptor. + typedef int native_type; + + // The implementation type of the descriptor. + class implementation_type + : private boost::asio::detail::noncopyable + { + public: + // Default constructor. + implementation_type() + : descriptor_(-1), + flags_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class reactive_descriptor_service; + + // The native descriptor representation. + int descriptor_; + + enum + { + user_set_non_blocking = 1, // The user wants a non-blocking descriptor. + internal_non_blocking = 2 // The descriptor has been set non-blocking. + }; + + // Flags indicating the current state of the descriptor. + unsigned char flags_; + + // Per-descriptor data used by the reactor. + typename Reactor::per_descriptor_data reactor_data_; + }; + + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; + + // Constructor. + reactive_descriptor_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base< + reactive_descriptor_service >(io_service), + reactor_(boost::asio::use_service(io_service)) + { + reactor_.init_task(); + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + } + + // Construct a new descriptor implementation. + void construct(implementation_type& impl) + { + impl.descriptor_ = -1; + impl.flags_ = 0; + } + + // Destroy a descriptor implementation. + void destroy(implementation_type& impl) + { + if (impl.descriptor_ != -1) + { + reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); + + if (impl.flags_ & implementation_type::internal_non_blocking) + { + ioctl_arg_type non_blocking = 0; + boost::system::error_code ignored_ec; + descriptor_ops::ioctl(impl.descriptor_, + FIONBIO, &non_blocking, ignored_ec); + impl.flags_ &= ~implementation_type::internal_non_blocking; + } + + boost::system::error_code ignored_ec; + descriptor_ops::close(impl.descriptor_, ignored_ec); + + impl.descriptor_ = -1; + } + } + + // Assign a native descriptor to a descriptor implementation. + boost::system::error_code assign(implementation_type& impl, + const native_type& native_descriptor, boost::system::error_code& ec) + { + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_descriptor, impl.reactor_data_)) + { + ec = boost::system::error_code(err, + boost::asio::error::get_system_category()); + return ec; + } + + impl.descriptor_ = native_descriptor; + impl.flags_ = 0; + ec = boost::system::error_code(); + return ec; + } + + // Determine whether the descriptor is open. + bool is_open(const implementation_type& impl) const + { + return impl.descriptor_ != -1; + } + + // Destroy a descriptor implementation. + boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec) + { + if (is_open(impl)) + { + reactor_.close_descriptor(impl.descriptor_, impl.reactor_data_); + + if (impl.flags_ & implementation_type::internal_non_blocking) + { + ioctl_arg_type non_blocking = 0; + boost::system::error_code ignored_ec; + descriptor_ops::ioctl(impl.descriptor_, + FIONBIO, &non_blocking, ignored_ec); + impl.flags_ &= ~implementation_type::internal_non_blocking; + } + + if (descriptor_ops::close(impl.descriptor_, ec) == -1) + return ec; + + impl.descriptor_ = -1; + } + + ec = boost::system::error_code(); + return ec; + } + + // Get the native descriptor representation. + native_type native(const implementation_type& impl) const + { + return impl.descriptor_; + } + + // Cancel all operations associated with the descriptor. + boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_); + ec = boost::system::error_code(); + return ec; + } + + // Perform an IO control command on the descriptor. + template + boost::system::error_code io_control(implementation_type& impl, + IO_Control_Command& command, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + if (command.name() == static_cast(FIONBIO)) + { + if (command.get()) + impl.flags_ |= implementation_type::user_set_non_blocking; + else + impl.flags_ &= ~implementation_type::user_set_non_blocking; + ec = boost::system::error_code(); + } + else + { + descriptor_ops::ioctl(impl.descriptor_, command.name(), + static_cast(command.data()), ec); + } + return ec; + } + + // Write some data to the descriptor. + template + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Copy buffers into array. + descriptor_ops::buf bufs[max_buffers]; + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + size_t total_buffer_size = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::const_buffer buffer(*iter); + descriptor_ops::init_buf(bufs[i], + boost::asio::buffer_cast(buffer), + boost::asio::buffer_size(buffer)); + total_buffer_size += boost::asio::buffer_size(buffer); + } + + // A request to read_some 0 bytes on a stream is a no-op. + if (total_buffer_size == 0) + { + ec = boost::system::error_code(); + return 0; + } + + // Make descriptor non-blocking if user wants non-blocking. + if (impl.flags_ & implementation_type::user_set_non_blocking) + { + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + ioctl_arg_type non_blocking = 1; + if (descriptor_ops::ioctl(impl.descriptor_, + FIONBIO, &non_blocking, ec)) + return 0; + impl.flags_ |= implementation_type::internal_non_blocking; + } + } + + // Send the data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes_sent = descriptor_ops::gather_write( + impl.descriptor_, bufs, i, ec); + + // Check if operation succeeded. + if (bytes_sent >= 0) + return bytes_sent; + + // Operation failed. + if ((impl.flags_ & implementation_type::user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(impl.descriptor_, ec) < 0) + return 0; + } + } + + // Wait until data can be written without blocking. + size_t write_some(implementation_type& impl, + const null_buffers&, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Wait for descriptor to become ready. + descriptor_ops::poll_write(impl.descriptor_, ec); + + return 0; + } + + template + class write_operation : + public handler_base_from_member + { + public: + write_operation(int descriptor, boost::asio::io_service& io_service, + const ConstBufferSequence& buffers, Handler handler) + : handler_base_from_member(handler), + descriptor_(descriptor), + io_service_(io_service), + work_(io_service), + buffers_(buffers) + { + } + + bool perform(boost::system::error_code& ec, + std::size_t& bytes_transferred) + { + // Check whether the operation was successful. + if (ec) + { + bytes_transferred = 0; + return true; + } + + // Copy buffers into array. + descriptor_ops::buf bufs[max_buffers]; + typename ConstBufferSequence::const_iterator iter = buffers_.begin(); + typename ConstBufferSequence::const_iterator end = buffers_.end(); + size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::const_buffer buffer(*iter); + descriptor_ops::init_buf(bufs[i], + boost::asio::buffer_cast(buffer), + boost::asio::buffer_size(buffer)); + } + + // Write the data. + int bytes = descriptor_ops::gather_write(descriptor_, bufs, i, ec); + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + bytes_transferred = (bytes < 0 ? 0 : bytes); + return true; + } + + void complete(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); + } + + private: + int descriptor_; + boost::asio::io_service& io_service_; + boost::asio::io_service::work work_; + ConstBufferSequence buffers_; + }; + + // Start an asynchronous write. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor, 0)); + } + else + { + // Determine total size of buffers. + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + size_t total_buffer_size = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::const_buffer buffer(*iter); + total_buffer_size += boost::asio::buffer_size(buffer); + } + + // A request to read_some 0 bytes on a stream is a no-op. + if (total_buffer_size == 0) + { + this->get_io_service().post(bind_handler(handler, + boost::system::error_code(), 0)); + return; + } + + // Make descriptor non-blocking. + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + ioctl_arg_type non_blocking = 1; + boost::system::error_code ec; + if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec, 0)); + return; + } + impl.flags_ |= implementation_type::internal_non_blocking; + } + + reactor_.start_write_op(impl.descriptor_, impl.reactor_data_, + write_operation( + impl.descriptor_, this->get_io_service(), buffers, handler)); + } + } + + template + class null_buffers_operation : + public handler_base_from_member + { + public: + null_buffers_operation(boost::asio::io_service& io_service, Handler handler) + : handler_base_from_member(handler), + work_(io_service) + { + } + + bool perform(boost::system::error_code&, + std::size_t& bytes_transferred) + { + bytes_transferred = 0; + return true; + } + + void complete(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + work_.get_io_service().post(bind_handler( + this->handler_, ec, bytes_transferred)); + } + + private: + boost::asio::io_service::work work_; + }; + + // Start an asynchronous wait until data can be written without blocking. + template + void async_write_some(implementation_type& impl, + const null_buffers&, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor, 0)); + } + else + { + reactor_.start_write_op(impl.descriptor_, impl.reactor_data_, + null_buffers_operation(this->get_io_service(), handler), + false); + } + } + + // Read some data from the stream. Returns the number of bytes read. + template + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Copy buffers into array. + descriptor_ops::buf bufs[max_buffers]; + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + size_t total_buffer_size = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::mutable_buffer buffer(*iter); + descriptor_ops::init_buf(bufs[i], + boost::asio::buffer_cast(buffer), + boost::asio::buffer_size(buffer)); + total_buffer_size += boost::asio::buffer_size(buffer); + } + + // A request to read_some 0 bytes on a stream is a no-op. + if (total_buffer_size == 0) + { + ec = boost::system::error_code(); + return 0; + } + + // Make descriptor non-blocking if user wants non-blocking. + if (impl.flags_ & implementation_type::user_set_non_blocking) + { + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + ioctl_arg_type non_blocking = 1; + if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) + return 0; + impl.flags_ |= implementation_type::internal_non_blocking; + } + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes_read = descriptor_ops::scatter_read( + impl.descriptor_, bufs, i, ec); + + // Check if operation succeeded. + if (bytes_read > 0) + return bytes_read; + + // Check for EOF. + if (bytes_read == 0) + { + ec = boost::asio::error::eof; + return 0; + } + + // Operation failed. + if ((impl.flags_ & implementation_type::user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(impl.descriptor_, ec) < 0) + return 0; + } + } + + // Wait until data can be read without blocking. + size_t read_some(implementation_type& impl, + const null_buffers&, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Wait for descriptor to become ready. + descriptor_ops::poll_read(impl.descriptor_, ec); + + return 0; + } + + template + class read_operation : + public handler_base_from_member + { + public: + read_operation(int descriptor, boost::asio::io_service& io_service, + const MutableBufferSequence& buffers, Handler handler) + : handler_base_from_member(handler), + descriptor_(descriptor), + io_service_(io_service), + work_(io_service), + buffers_(buffers) + { + } + + bool perform(boost::system::error_code& ec, + std::size_t& bytes_transferred) + { + // Check whether the operation was successful. + if (ec) + { + bytes_transferred = 0; + return true; + } + + // Copy buffers into array. + descriptor_ops::buf bufs[max_buffers]; + typename MutableBufferSequence::const_iterator iter = buffers_.begin(); + typename MutableBufferSequence::const_iterator end = buffers_.end(); + size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::mutable_buffer buffer(*iter); + descriptor_ops::init_buf(bufs[i], + boost::asio::buffer_cast(buffer), + boost::asio::buffer_size(buffer)); + } + + // Read some data. + int bytes = descriptor_ops::scatter_read(descriptor_, bufs, i, ec); + if (bytes == 0) + ec = boost::asio::error::eof; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + bytes_transferred = (bytes < 0 ? 0 : bytes); + return true; + } + + void complete(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); + } + + private: + int descriptor_; + boost::asio::io_service& io_service_; + boost::asio::io_service::work work_; + MutableBufferSequence buffers_; + }; + + // Start an asynchronous read. The buffer for the data being read must be + // valid for the lifetime of the asynchronous operation. + template + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor, 0)); + } + else + { + // Determine total size of buffers. + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + size_t total_buffer_size = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::mutable_buffer buffer(*iter); + total_buffer_size += boost::asio::buffer_size(buffer); + } + + // A request to read_some 0 bytes on a stream is a no-op. + if (total_buffer_size == 0) + { + this->get_io_service().post(bind_handler(handler, + boost::system::error_code(), 0)); + return; + } + + // Make descriptor non-blocking. + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + ioctl_arg_type non_blocking = 1; + boost::system::error_code ec; + if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec, 0)); + return; + } + impl.flags_ |= implementation_type::internal_non_blocking; + } + + reactor_.start_read_op(impl.descriptor_, impl.reactor_data_, + read_operation( + impl.descriptor_, this->get_io_service(), buffers, handler)); + } + } + + // Wait until data can be read without blocking. + template + void async_read_some(implementation_type& impl, + const null_buffers&, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor, 0)); + } + else + { + reactor_.start_read_op(impl.descriptor_, impl.reactor_data_, + null_buffers_operation(this->get_io_service(), handler), + false); + } + } + +private: + // The selector that performs event demultiplexing for the service. + Reactor& reactor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/reactive_serial_port_service.hpp b/3rdParty/Boost/boost/asio/detail/reactive_serial_port_service.hpp new file mode 100644 index 0000000..0beff14 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/reactive_serial_port_service.hpp @@ -0,0 +1,270 @@ +// +// reactive_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ + && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +// Extend reactive_descriptor_service to provide serial port support. +template +class reactive_serial_port_service + : public boost::asio::detail::service_base< + reactive_serial_port_service > +{ +public: + // The native type of a stream handle. + typedef typename reactive_descriptor_service::native_type + native_type; + + // The implementation type of the stream handle. + typedef typename reactive_descriptor_service::implementation_type + implementation_type; + + reactive_serial_port_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base< + reactive_serial_port_service>(io_service), + descriptor_service_(boost::asio::use_service< + reactive_descriptor_service >(io_service)) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + } + + // Construct a new handle implementation. + void construct(implementation_type& impl) + { + descriptor_service_.construct(impl); + } + + // Destroy a handle implementation. + void destroy(implementation_type& impl) + { + descriptor_service_.destroy(impl); + } + + // Open the serial port using the specified device name. + boost::system::error_code open(implementation_type& impl, + const std::string& device, boost::system::error_code& ec) + { + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + int fd = descriptor_ops::open(device.c_str(), + O_RDWR | O_NONBLOCK | O_NOCTTY, ec); + if (fd < 0) + return ec; + + int s = descriptor_ops::fcntl(fd, F_GETFL, ec); + if (s >= 0) + s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec); + if (s < 0) + { + boost::system::error_code ignored_ec; + descriptor_ops::close(fd, ignored_ec); + return ec; + } + + // Set up default serial port options. + termios ios; + descriptor_ops::clear_error(ec); + s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec); + if (s >= 0) + { +#if defined(_BSD_SOURCE) + ::cfmakeraw(&ios); +#else + ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK + | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + ios.c_oflag &= ~OPOST; + ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + ios.c_cflag &= ~(CSIZE | PARENB); + ios.c_cflag |= CS8; +#endif + ios.c_iflag |= IGNPAR; + ios.c_cflag |= CREAD | CLOCAL; + descriptor_ops::clear_error(ec); + s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); + } + if (s < 0) + { + boost::system::error_code ignored_ec; + descriptor_ops::close(fd, ignored_ec); + return ec; + } + + // We're done. Take ownership of the serial port descriptor. + if (descriptor_service_.assign(impl, fd, ec)) + { + boost::system::error_code ignored_ec; + descriptor_ops::close(fd, ignored_ec); + } + + return ec; + } + + // Assign a native handle to a handle implementation. + boost::system::error_code assign(implementation_type& impl, + const native_type& native_descriptor, boost::system::error_code& ec) + { + return descriptor_service_.assign(impl, native_descriptor, ec); + } + + // Determine whether the handle is open. + bool is_open(const implementation_type& impl) const + { + return descriptor_service_.is_open(impl); + } + + // Destroy a handle implementation. + boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec) + { + return descriptor_service_.close(impl, ec); + } + + // Get the native handle representation. + native_type native(implementation_type& impl) + { + return descriptor_service_.native(impl); + } + + // Cancel all operations associated with the handle. + boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec) + { + return descriptor_service_.cancel(impl, ec); + } + + // Set an option on the serial port. + template + boost::system::error_code set_option(implementation_type& impl, + const SettableSerialPortOption& option, boost::system::error_code& ec) + { + termios ios; + descriptor_ops::clear_error(ec); + descriptor_ops::error_wrapper(::tcgetattr( + descriptor_service_.native(impl), &ios), ec); + if (ec) + return ec; + + if (option.store(ios, ec)) + return ec; + + descriptor_ops::clear_error(ec); + descriptor_ops::error_wrapper(::tcsetattr( + descriptor_service_.native(impl), TCSANOW, &ios), ec); + return ec; + } + + // Get an option from the serial port. + template + boost::system::error_code get_option(const implementation_type& impl, + GettableSerialPortOption& option, boost::system::error_code& ec) const + { + termios ios; + descriptor_ops::clear_error(ec); + descriptor_ops::error_wrapper(::tcgetattr( + descriptor_service_.native(impl), &ios), ec); + if (ec) + return ec; + + return option.load(ios, ec); + } + + // Send a break sequence to the serial port. + boost::system::error_code send_break(implementation_type& impl, + boost::system::error_code& ec) + { + descriptor_ops::clear_error(ec); + descriptor_ops::error_wrapper(::tcsendbreak( + descriptor_service_.native(impl), 0), ec); + return ec; + } + + // Write the given data. Returns the number of bytes sent. + template + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, boost::system::error_code& ec) + { + return descriptor_service_.write_some(impl, buffers, ec); + } + + // Start an asynchronous write. The data being written must be valid for the + // lifetime of the asynchronous operation. + template + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, Handler handler) + { + descriptor_service_.async_write_some(impl, buffers, handler); + } + + // Read some data. Returns the number of bytes received. + template + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, boost::system::error_code& ec) + { + return descriptor_service_.read_some(impl, buffers, ec); + } + + // Start an asynchronous read. The buffer for the data being received must be + // valid for the lifetime of the asynchronous operation. + template + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, Handler handler) + { + descriptor_service_.async_read_some(impl, buffers, handler); + } + +private: + // The handle service used for initiating asynchronous operations. + reactive_descriptor_service& descriptor_service_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + // && !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/reactive_socket_service.hpp b/3rdParty/Boost/boost/asio/detail/reactive_socket_service.hpp new file mode 100644 index 0000000..54b8cbd --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/reactive_socket_service.hpp @@ -0,0 +1,1788 @@ +// +// reactive_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_REACTIVE_SOCKET_SERVICE_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_service + : public boost::asio::detail::service_base< + reactive_socket_service > +{ +public: + // The protocol type. + typedef Protocol protocol_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The native type of a socket. + typedef socket_type native_type; + + // The implementation type of the socket. + class implementation_type + : private boost::asio::detail::noncopyable + { + public: + // Default constructor. + implementation_type() + : socket_(invalid_socket), + flags_(0), + protocol_(endpoint_type().protocol()) + { + } + + private: + // Only this service will have access to the internal values. + friend class reactive_socket_service; + + // The native socket representation. + socket_type socket_; + + enum + { + // The user wants a non-blocking socket. + user_set_non_blocking = 1, + + // The implementation wants a non-blocking socket (in order to be able to + // perform asynchronous read and write operations). + internal_non_blocking = 2, + + // Helper "flag" used to determine whether the socket is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking, + + // User wants connection_aborted errors, which are disabled by default. + enable_connection_aborted = 4, + + // The user set the linger option. Needs to be checked when closing. + user_set_linger = 8 + }; + + // Flags indicating the current state of the socket. + unsigned char flags_; + + // The protocol associated with the socket. + protocol_type protocol_; + + // Per-descriptor data used by the reactor. + typename Reactor::per_descriptor_data reactor_data_; + }; + + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; + + // Constructor. + reactive_socket_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base< + reactive_socket_service >(io_service), + reactor_(boost::asio::use_service(io_service)) + { + reactor_.init_task(); + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + } + + // Construct a new socket implementation. + void construct(implementation_type& impl) + { + impl.socket_ = invalid_socket; + impl.flags_ = 0; + } + + // Destroy a socket implementation. + void destroy(implementation_type& impl) + { + if (impl.socket_ != invalid_socket) + { + reactor_.close_descriptor(impl.socket_, impl.reactor_data_); + + if (impl.flags_ & implementation_type::non_blocking) + { + ioctl_arg_type non_blocking = 0; + boost::system::error_code ignored_ec; + socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); + impl.flags_ &= ~implementation_type::non_blocking; + } + + if (impl.flags_ & implementation_type::user_set_linger) + { + ::linger opt; + opt.l_onoff = 0; + opt.l_linger = 0; + boost::system::error_code ignored_ec; + socket_ops::setsockopt(impl.socket_, + SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); + } + + boost::system::error_code ignored_ec; + socket_ops::close(impl.socket_, ignored_ec); + + impl.socket_ = invalid_socket; + } + } + + // Open a new socket implementation. + boost::system::error_code open(implementation_type& impl, + const protocol_type& protocol, boost::system::error_code& ec) + { + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(protocol.family(), + protocol.type(), protocol.protocol(), ec)); + if (sock.get() == invalid_socket) + return ec; + + if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_)) + { + ec = boost::system::error_code(err, + boost::asio::error::get_system_category()); + return ec; + } + + impl.socket_ = sock.release(); + impl.flags_ = 0; + impl.protocol_ = protocol; + ec = boost::system::error_code(); + return ec; + } + + // Assign a native socket to a socket implementation. + boost::system::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_type& native_socket, + boost::system::error_code& ec) + { + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_socket, impl.reactor_data_)) + { + ec = boost::system::error_code(err, + boost::asio::error::get_system_category()); + return ec; + } + + impl.socket_ = native_socket; + impl.flags_ = 0; + impl.protocol_ = protocol; + ec = boost::system::error_code(); + return ec; + } + + // Determine whether the socket is open. + bool is_open(const implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec) + { + if (is_open(impl)) + { + reactor_.close_descriptor(impl.socket_, impl.reactor_data_); + + if (impl.flags_ & implementation_type::non_blocking) + { + ioctl_arg_type non_blocking = 0; + boost::system::error_code ignored_ec; + socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); + impl.flags_ &= ~implementation_type::non_blocking; + } + + if (socket_ops::close(impl.socket_, ec) == socket_error_retval) + return ec; + + impl.socket_ = invalid_socket; + } + + ec = boost::system::error_code(); + return ec; + } + + // Get the native socket representation. + native_type native(implementation_type& impl) + { + return impl.socket_; + } + + // Cancel all operations associated with the socket. + boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + reactor_.cancel_ops(impl.socket_, impl.reactor_data_); + ec = boost::system::error_code(); + return ec; + } + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const implementation_type& impl, + boost::system::error_code& ec) const + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return false; + } + + boost::asio::detail::ioctl_arg_type value = 0; + socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec); +#if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = boost::asio::error::not_socket; +#endif // defined(ENOTTY) + return ec ? false : value != 0; + } + + // Determine the number of bytes available for reading. + std::size_t available(const implementation_type& impl, + boost::system::error_code& ec) const + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + boost::asio::detail::ioctl_arg_type value = 0; + socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec); +#if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = boost::asio::error::not_socket; +#endif // defined(ENOTTY) + return ec ? static_cast(0) : static_cast(value); + } + + // Bind the socket to the specified local endpoint. + boost::system::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); + return ec; + } + + // Place the socket into the state where it will listen for new connections. + boost::system::error_code listen(implementation_type& impl, int backlog, + boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Set a socket option. + template + boost::system::error_code set_option(implementation_type& impl, + const Option& option, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + if (option.level(impl.protocol_) == custom_socket_option_level + && option.name(impl.protocol_) == enable_connection_aborted_option) + { + if (option.size(impl.protocol_) != sizeof(int)) + { + ec = boost::asio::error::invalid_argument; + } + else + { + if (*reinterpret_cast(option.data(impl.protocol_))) + impl.flags_ |= implementation_type::enable_connection_aborted; + else + impl.flags_ &= ~implementation_type::enable_connection_aborted; + ec = boost::system::error_code(); + } + return ec; + } + else + { + if (option.level(impl.protocol_) == SOL_SOCKET + && option.name(impl.protocol_) == SO_LINGER) + { + impl.flags_ |= implementation_type::user_set_linger; + } + + socket_ops::setsockopt(impl.socket_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + +#if defined(__MACH__) && defined(__APPLE__) \ +|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + // To implement portable behaviour for SO_REUSEADDR with UDP sockets we + // need to also set SO_REUSEPORT on BSD-based platforms. + if (!ec && impl.protocol_.type() == SOCK_DGRAM + && option.level(impl.protocol_) == SOL_SOCKET + && option.name(impl.protocol_) == SO_REUSEADDR) + { + boost::system::error_code ignored_ec; + socket_ops::setsockopt(impl.socket_, SOL_SOCKET, SO_REUSEPORT, + option.data(impl.protocol_), option.size(impl.protocol_), + ignored_ec); + } +#endif + + return ec; + } + } + + // Set a socket option. + template + boost::system::error_code get_option(const implementation_type& impl, + Option& option, boost::system::error_code& ec) const + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + if (option.level(impl.protocol_) == custom_socket_option_level + && option.name(impl.protocol_) == enable_connection_aborted_option) + { + if (option.size(impl.protocol_) != sizeof(int)) + { + ec = boost::asio::error::invalid_argument; + } + else + { + int* target = reinterpret_cast(option.data(impl.protocol_)); + if (impl.flags_ & implementation_type::enable_connection_aborted) + *target = 1; + else + *target = 0; + option.resize(impl.protocol_, sizeof(int)); + ec = boost::system::error_code(); + } + return ec; + } + else + { + size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); + return ec; + } + } + + // Perform an IO control command on the socket. + template + boost::system::error_code io_control(implementation_type& impl, + IO_Control_Command& command, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + if (command.name() == static_cast(FIONBIO)) + { + // Flags are manipulated in a temporary variable so that the socket + // implementation is not updated unless the ioctl operation succeeds. + unsigned char new_flags = impl.flags_; + if (*static_cast(command.data())) + new_flags |= implementation_type::user_set_non_blocking; + else + new_flags &= ~implementation_type::user_set_non_blocking; + + // Perform ioctl on socket if the non-blocking state has changed. + if (!(impl.flags_ & implementation_type::non_blocking) + && (new_flags & implementation_type::non_blocking)) + { + ioctl_arg_type non_blocking = 1; + socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec); + } + else if ((impl.flags_ & implementation_type::non_blocking) + && !(new_flags & implementation_type::non_blocking)) + { + ioctl_arg_type non_blocking = 0; + socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec); + } + else + { + ec = boost::system::error_code(); + } + + // Update socket implementation's flags only if successful. + if (!ec) + impl.flags_ = new_flags; + } + else + { + socket_ops::ioctl(impl.socket_, command.name(), + static_cast(command.data()), ec); + } + return ec; + } + + // Get the local endpoint. + endpoint_type local_endpoint(const implementation_type& impl, + boost::system::error_code& ec) const + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return endpoint_type(); + } + + endpoint_type endpoint; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + // Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type& impl, + boost::system::error_code& ec) const + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return endpoint_type(); + } + + endpoint_type endpoint; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + /// Disable sends or receives on the socket. + boost::system::error_code shutdown(implementation_type& impl, + socket_base::shutdown_type what, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + + // Send the given data to the peer. + template + size_t send(implementation_type& impl, const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Copy buffers into array. + socket_ops::buf bufs[max_buffers]; + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + size_t total_buffer_size = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::const_buffer buffer(*iter); + socket_ops::init_buf(bufs[i], + boost::asio::buffer_cast(buffer), + boost::asio::buffer_size(buffer)); + total_buffer_size += boost::asio::buffer_size(buffer); + } + + // A request to receive 0 bytes on a stream socket is a no-op. + if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) + { + ec = boost::system::error_code(); + return 0; + } + + // Send the data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes_sent = socket_ops::send(impl.socket_, bufs, i, flags, ec); + + // Check if operation succeeded. + if (bytes_sent >= 0) + return bytes_sent; + + // Operation failed. + if ((impl.flags_ & implementation_type::user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(impl.socket_, ec) < 0) + return 0; + } + } + + // Wait until data can be sent without blocking. + size_t send(implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, ec); + + return 0; + } + + template + class send_operation : + public handler_base_from_member + { + public: + send_operation(socket_type socket, boost::asio::io_service& io_service, + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler handler) + : handler_base_from_member(handler), + socket_(socket), + io_service_(io_service), + work_(io_service), + buffers_(buffers), + flags_(flags) + { + } + + bool perform(boost::system::error_code& ec, + std::size_t& bytes_transferred) + { + // Check whether the operation was successful. + if (ec) + { + bytes_transferred = 0; + return true; + } + + // Copy buffers into array. + socket_ops::buf bufs[max_buffers]; + typename ConstBufferSequence::const_iterator iter = buffers_.begin(); + typename ConstBufferSequence::const_iterator end = buffers_.end(); + size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::const_buffer buffer(*iter); + socket_ops::init_buf(bufs[i], + boost::asio::buffer_cast(buffer), + boost::asio::buffer_size(buffer)); + } + + // Send the data. + int bytes = socket_ops::send(socket_, bufs, i, flags_, ec); + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + bytes_transferred = (bytes < 0 ? 0 : bytes); + return true; + } + + void complete(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); + } + + private: + socket_type socket_; + boost::asio::io_service& io_service_; + boost::asio::io_service::work work_; + ConstBufferSequence buffers_; + socket_base::message_flags flags_; + }; + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send(implementation_type& impl, const ConstBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor, 0)); + } + else + { + if (impl.protocol_.type() == SOCK_STREAM) + { + // Determine total size of buffers. + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + size_t total_buffer_size = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::const_buffer buffer(*iter); + total_buffer_size += boost::asio::buffer_size(buffer); + } + + // A request to receive 0 bytes on a stream socket is a no-op. + if (total_buffer_size == 0) + { + this->get_io_service().post(bind_handler(handler, + boost::system::error_code(), 0)); + return; + } + } + + // Make socket non-blocking. + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + if (!(impl.flags_ & implementation_type::non_blocking)) + { + ioctl_arg_type non_blocking = 1; + boost::system::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec, 0)); + return; + } + } + impl.flags_ |= implementation_type::internal_non_blocking; + } + + reactor_.start_write_op(impl.socket_, impl.reactor_data_, + send_operation( + impl.socket_, this->get_io_service(), buffers, flags, handler)); + } + } + + template + class null_buffers_operation : + public handler_base_from_member + { + public: + null_buffers_operation(boost::asio::io_service& io_service, Handler handler) + : handler_base_from_member(handler), + work_(io_service) + { + } + + bool perform(boost::system::error_code&, + std::size_t& bytes_transferred) + { + bytes_transferred = 0; + return true; + } + + void complete(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + work_.get_io_service().post(bind_handler( + this->handler_, ec, bytes_transferred)); + } + + private: + boost::asio::io_service::work work_; + }; + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send(implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor, 0)); + } + else + { + reactor_.start_write_op(impl.socket_, impl.reactor_data_, + null_buffers_operation(this->get_io_service(), handler), + false); + } + } + + // Send a datagram to the specified endpoint. Returns the number of bytes + // sent. + template + size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Copy buffers into array. + socket_ops::buf bufs[max_buffers]; + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::const_buffer buffer(*iter); + socket_ops::init_buf(bufs[i], + boost::asio::buffer_cast(buffer), + boost::asio::buffer_size(buffer)); + } + + // Send the data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes_sent = socket_ops::sendto(impl.socket_, bufs, i, flags, + destination.data(), destination.size(), ec); + + // Check if operation succeeded. + if (bytes_sent >= 0) + return bytes_sent; + + // Operation failed. + if ((impl.flags_ & implementation_type::user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(impl.socket_, ec) < 0) + return 0; + } + } + + // Wait until data can be sent without blocking. + size_t send_to(implementation_type& impl, const null_buffers&, + socket_base::message_flags, const endpoint_type&, + boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, ec); + + return 0; + } + + template + class send_to_operation : + public handler_base_from_member + { + public: + send_to_operation(socket_type socket, boost::asio::io_service& io_service, + const ConstBufferSequence& buffers, const endpoint_type& endpoint, + socket_base::message_flags flags, Handler handler) + : handler_base_from_member(handler), + socket_(socket), + io_service_(io_service), + work_(io_service), + buffers_(buffers), + destination_(endpoint), + flags_(flags) + { + } + + bool perform(boost::system::error_code& ec, + std::size_t& bytes_transferred) + { + // Check whether the operation was successful. + if (ec) + { + bytes_transferred = 0; + return true; + } + + // Copy buffers into array. + socket_ops::buf bufs[max_buffers]; + typename ConstBufferSequence::const_iterator iter = buffers_.begin(); + typename ConstBufferSequence::const_iterator end = buffers_.end(); + size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::const_buffer buffer(*iter); + socket_ops::init_buf(bufs[i], + boost::asio::buffer_cast(buffer), + boost::asio::buffer_size(buffer)); + } + + // Send the data. + int bytes = socket_ops::sendto(socket_, bufs, i, flags_, + destination_.data(), destination_.size(), ec); + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + bytes_transferred = (bytes < 0 ? 0 : bytes); + return true; + } + + void complete(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); + } + + private: + socket_type socket_; + boost::asio::io_service& io_service_; + boost::asio::io_service::work work_; + ConstBufferSequence buffers_; + endpoint_type destination_; + socket_base::message_flags flags_; + }; + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send_to(implementation_type& impl, + const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor, 0)); + } + else + { + // Make socket non-blocking. + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + if (!(impl.flags_ & implementation_type::non_blocking)) + { + ioctl_arg_type non_blocking = 1; + boost::system::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec, 0)); + return; + } + } + impl.flags_ |= implementation_type::internal_non_blocking; + } + + reactor_.start_write_op(impl.socket_, impl.reactor_data_, + send_to_operation( + impl.socket_, this->get_io_service(), buffers, + destination, flags, handler)); + } + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send_to(implementation_type& impl, const null_buffers&, + socket_base::message_flags, const endpoint_type&, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor, 0)); + } + else + { + reactor_.start_write_op(impl.socket_, impl.reactor_data_, + null_buffers_operation(this->get_io_service(), handler), + false); + } + } + + // Receive some data from the peer. Returns the number of bytes received. + template + size_t receive(implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Copy buffers into array. + socket_ops::buf bufs[max_buffers]; + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + size_t total_buffer_size = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::mutable_buffer buffer(*iter); + socket_ops::init_buf(bufs[i], + boost::asio::buffer_cast(buffer), + boost::asio::buffer_size(buffer)); + total_buffer_size += boost::asio::buffer_size(buffer); + } + + // A request to receive 0 bytes on a stream socket is a no-op. + if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) + { + ec = boost::system::error_code(); + return 0; + } + + // Receive some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes_recvd = socket_ops::recv(impl.socket_, bufs, i, flags, ec); + + // Check if operation succeeded. + if (bytes_recvd > 0) + return bytes_recvd; + + // Check for EOF. + if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM) + { + ec = boost::asio::error::eof; + return 0; + } + + // Operation failed. + if ((impl.flags_ & implementation_type::user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(impl.socket_, ec) < 0) + return 0; + } + } + + // Wait until data can be received without blocking. + size_t receive(implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, ec); + + return 0; + } + + template + class receive_operation : + public handler_base_from_member + { + public: + receive_operation(socket_type socket, int protocol_type, + boost::asio::io_service& io_service, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + : handler_base_from_member(handler), + socket_(socket), + protocol_type_(protocol_type), + io_service_(io_service), + work_(io_service), + buffers_(buffers), + flags_(flags) + { + } + + bool perform(boost::system::error_code& ec, + std::size_t& bytes_transferred) + { + // Check whether the operation was successful. + if (ec) + { + bytes_transferred = 0; + return true; + } + + // Copy buffers into array. + socket_ops::buf bufs[max_buffers]; + typename MutableBufferSequence::const_iterator iter = buffers_.begin(); + typename MutableBufferSequence::const_iterator end = buffers_.end(); + size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::mutable_buffer buffer(*iter); + socket_ops::init_buf(bufs[i], + boost::asio::buffer_cast(buffer), + boost::asio::buffer_size(buffer)); + } + + // Receive some data. + int bytes = socket_ops::recv(socket_, bufs, i, flags_, ec); + if (bytes == 0 && protocol_type_ == SOCK_STREAM) + ec = boost::asio::error::eof; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + bytes_transferred = (bytes < 0 ? 0 : bytes); + return true; + } + + void complete(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); + } + + private: + socket_type socket_; + int protocol_type_; + boost::asio::io_service& io_service_; + boost::asio::io_service::work work_; + MutableBufferSequence buffers_; + socket_base::message_flags flags_; + }; + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive(implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor, 0)); + } + else + { + if (impl.protocol_.type() == SOCK_STREAM) + { + // Determine total size of buffers. + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + size_t total_buffer_size = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::mutable_buffer buffer(*iter); + total_buffer_size += boost::asio::buffer_size(buffer); + } + + // A request to receive 0 bytes on a stream socket is a no-op. + if (total_buffer_size == 0) + { + this->get_io_service().post(bind_handler(handler, + boost::system::error_code(), 0)); + return; + } + } + + // Make socket non-blocking. + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + if (!(impl.flags_ & implementation_type::non_blocking)) + { + ioctl_arg_type non_blocking = 1; + boost::system::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec, 0)); + return; + } + } + impl.flags_ |= implementation_type::internal_non_blocking; + } + + if (flags & socket_base::message_out_of_band) + { + reactor_.start_except_op(impl.socket_, impl.reactor_data_, + receive_operation( + impl.socket_, impl.protocol_.type(), + this->get_io_service(), buffers, flags, handler)); + } + else + { + reactor_.start_read_op(impl.socket_, impl.reactor_data_, + receive_operation( + impl.socket_, impl.protocol_.type(), + this->get_io_service(), buffers, flags, handler)); + } + } + } + + // Wait until data can be received without blocking. + template + void async_receive(implementation_type& impl, const null_buffers&, + socket_base::message_flags flags, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor, 0)); + } + else if (flags & socket_base::message_out_of_band) + { + reactor_.start_except_op(impl.socket_, impl.reactor_data_, + null_buffers_operation(this->get_io_service(), handler)); + } + else + { + reactor_.start_read_op(impl.socket_, impl.reactor_data_, + null_buffers_operation(this->get_io_service(), handler), + false); + } + } + + // Receive a datagram with the endpoint of the sender. Returns the number of + // bytes received. + template + size_t receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Copy buffers into array. + socket_ops::buf bufs[max_buffers]; + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::mutable_buffer buffer(*iter); + socket_ops::init_buf(bufs[i], + boost::asio::buffer_cast(buffer), + boost::asio::buffer_size(buffer)); + } + + // Receive some data. + for (;;) + { + // Try to complete the operation without blocking. + std::size_t addr_len = sender_endpoint.capacity(); + int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs, i, flags, + sender_endpoint.data(), &addr_len, ec); + + // Check if operation succeeded. + if (bytes_recvd > 0) + { + sender_endpoint.resize(addr_len); + return bytes_recvd; + } + + // Check for EOF. + if (bytes_recvd == 0 && impl.protocol_.type() == SOCK_STREAM) + { + ec = boost::asio::error::eof; + return 0; + } + + // Operation failed. + if ((impl.flags_ & implementation_type::user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(impl.socket_, ec) < 0) + return 0; + } + } + + // Wait until data can be received without blocking. + size_t receive_from(implementation_type& impl, const null_buffers&, + endpoint_type& sender_endpoint, socket_base::message_flags, + boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, ec); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + return 0; + } + + template + class receive_from_operation : + public handler_base_from_member + { + public: + receive_from_operation(socket_type socket, int protocol_type, + boost::asio::io_service& io_service, + const MutableBufferSequence& buffers, endpoint_type& endpoint, + socket_base::message_flags flags, Handler handler) + : handler_base_from_member(handler), + socket_(socket), + protocol_type_(protocol_type), + io_service_(io_service), + work_(io_service), + buffers_(buffers), + sender_endpoint_(endpoint), + flags_(flags) + { + } + + bool perform(boost::system::error_code& ec, + std::size_t& bytes_transferred) + { + // Check whether the operation was successful. + if (ec) + { + bytes_transferred = 0; + return true; + } + + // Copy buffers into array. + socket_ops::buf bufs[max_buffers]; + typename MutableBufferSequence::const_iterator iter = buffers_.begin(); + typename MutableBufferSequence::const_iterator end = buffers_.end(); + size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + boost::asio::mutable_buffer buffer(*iter); + socket_ops::init_buf(bufs[i], + boost::asio::buffer_cast(buffer), + boost::asio::buffer_size(buffer)); + } + + // Receive some data. + std::size_t addr_len = sender_endpoint_.capacity(); + int bytes = socket_ops::recvfrom(socket_, bufs, i, flags_, + sender_endpoint_.data(), &addr_len, ec); + if (bytes == 0 && protocol_type_ == SOCK_STREAM) + ec = boost::asio::error::eof; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + sender_endpoint_.resize(addr_len); + bytes_transferred = (bytes < 0 ? 0 : bytes); + return true; + } + + void complete(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + io_service_.post(bind_handler(this->handler_, ec, bytes_transferred)); + } + + private: + socket_type socket_; + int protocol_type_; + boost::asio::io_service& io_service_; + boost::asio::io_service::work work_; + MutableBufferSequence buffers_; + endpoint_type& sender_endpoint_; + socket_base::message_flags flags_; + }; + + // Start an asynchronous receive. The buffer for the data being received and + // the sender_endpoint object must both be valid for the lifetime of the + // asynchronous operation. + template + void async_receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, + socket_base::message_flags flags, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor, 0)); + } + else + { + // Make socket non-blocking. + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + if (!(impl.flags_ & implementation_type::non_blocking)) + { + ioctl_arg_type non_blocking = 1; + boost::system::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec, 0)); + return; + } + } + impl.flags_ |= implementation_type::internal_non_blocking; + } + + reactor_.start_read_op(impl.socket_, impl.reactor_data_, + receive_from_operation( + impl.socket_, impl.protocol_.type(), this->get_io_service(), + buffers, sender_endpoint, flags, handler)); + } + } + + // Wait until data can be received without blocking. + template + void async_receive_from(implementation_type& impl, + const null_buffers&, endpoint_type& sender_endpoint, + socket_base::message_flags flags, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor, 0)); + } + else + { + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + if (flags & socket_base::message_out_of_band) + { + reactor_.start_except_op(impl.socket_, impl.reactor_data_, + null_buffers_operation(this->get_io_service(), handler)); + } + else + { + reactor_.start_read_op(impl.socket_, impl.reactor_data_, + null_buffers_operation(this->get_io_service(), handler), + false); + } + } + } + + // Accept a new connection. + template + boost::system::error_code accept(implementation_type& impl, + Socket& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + // We cannot accept a socket that is already open. + if (peer.is_open()) + { + ec = boost::asio::error::already_open; + return ec; + } + + // Accept a socket. + for (;;) + { + // Try to complete the operation without blocking. + boost::system::error_code ec; + socket_holder new_socket; + std::size_t addr_len = 0; + if (peer_endpoint) + { + addr_len = peer_endpoint->capacity(); + new_socket.reset(socket_ops::accept(impl.socket_, + peer_endpoint->data(), &addr_len, ec)); + } + else + { + new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec)); + } + + // Check if operation succeeded. + if (new_socket.get() >= 0) + { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) + new_socket.release(); + return ec; + } + + // Operation failed. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + { + if (impl.flags_ & implementation_type::user_set_non_blocking) + return ec; + // Fall through to retry operation. + } + else if (ec == boost::asio::error::connection_aborted) + { + if (impl.flags_ & implementation_type::enable_connection_aborted) + return ec; + // Fall through to retry operation. + } +#if defined(EPROTO) + else if (ec.value() == EPROTO) + { + if (impl.flags_ & implementation_type::enable_connection_aborted) + return ec; + // Fall through to retry operation. + } +#endif // defined(EPROTO) + else + return ec; + + // Wait for socket to become ready. + if (socket_ops::poll_read(impl.socket_, ec) < 0) + return ec; + } + } + + template + class accept_operation : + public handler_base_from_member + { + public: + accept_operation(socket_type socket, boost::asio::io_service& io_service, + Socket& peer, const protocol_type& protocol, + endpoint_type* peer_endpoint, bool enable_connection_aborted, + Handler handler) + : handler_base_from_member(handler), + socket_(socket), + io_service_(io_service), + work_(io_service), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + enable_connection_aborted_(enable_connection_aborted) + { + } + + bool perform(boost::system::error_code& ec, std::size_t&) + { + // Check whether the operation was successful. + if (ec) + return true; + + // Accept the waiting connection. + socket_holder new_socket; + std::size_t addr_len = 0; + if (peer_endpoint_) + { + addr_len = peer_endpoint_->capacity(); + new_socket.reset(socket_ops::accept(socket_, + peer_endpoint_->data(), &addr_len, ec)); + } + else + { + new_socket.reset(socket_ops::accept(socket_, 0, 0, ec)); + } + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + if (ec == boost::asio::error::connection_aborted + && !enable_connection_aborted_) + return false; +#if defined(EPROTO) + if (ec.value() == EPROTO && !enable_connection_aborted_) + return false; +#endif // defined(EPROTO) + + // Transfer ownership of the new socket to the peer object. + if (!ec) + { + if (peer_endpoint_) + peer_endpoint_->resize(addr_len); + peer_.assign(protocol_, new_socket.get(), ec); + if (!ec) + new_socket.release(); + } + + return true; + } + + void complete(const boost::system::error_code& ec, std::size_t) + { + io_service_.post(bind_handler(this->handler_, ec)); + } + + private: + socket_type socket_; + boost::asio::io_service& io_service_; + boost::asio::io_service::work work_; + Socket& peer_; + protocol_type protocol_; + endpoint_type* peer_endpoint_; + bool enable_connection_aborted_; + }; + + // Start an asynchronous accept. The peer and peer_endpoint objects + // must be valid until the accept's handler is invoked. + template + void async_accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor)); + } + else if (peer.is_open()) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::already_open)); + } + else + { + // Make socket non-blocking. + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + if (!(impl.flags_ & implementation_type::non_blocking)) + { + ioctl_arg_type non_blocking = 1; + boost::system::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec)); + return; + } + } + impl.flags_ |= implementation_type::internal_non_blocking; + } + + reactor_.start_read_op(impl.socket_, impl.reactor_data_, + accept_operation( + impl.socket_, this->get_io_service(), + peer, impl.protocol_, peer_endpoint, + (impl.flags_ & implementation_type::enable_connection_aborted) != 0, + handler)); + } + } + + // Connect the socket to the specified endpoint. + boost::system::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + // Perform the connect operation. + socket_ops::connect(impl.socket_, + peer_endpoint.data(), peer_endpoint.size(), ec); + if (ec != boost::asio::error::in_progress + && ec != boost::asio::error::would_block) + { + // The connect operation finished immediately. + return ec; + } + + // Wait for socket to become ready. + if (socket_ops::poll_connect(impl.socket_, ec) < 0) + return ec; + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == socket_error_retval) + return ec; + + // Return the result of the connect operation. + ec = boost::system::error_code(connect_error, + boost::asio::error::get_system_category()); + return ec; + } + + template + class connect_operation : + public handler_base_from_member + { + public: + connect_operation(socket_type socket, + boost::asio::io_service& io_service, Handler handler) + : handler_base_from_member(handler), + socket_(socket), + io_service_(io_service), + work_(io_service) + { + } + + bool perform(boost::system::error_code& ec, std::size_t&) + { + // Check whether the operation was successful. + if (ec) + return true; + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == socket_error_retval) + return true; + + // The connection failed so the handler will be posted with an error code. + if (connect_error) + { + ec = boost::system::error_code(connect_error, + boost::asio::error::get_system_category()); + return true; + } + + return true; + } + + void complete(const boost::system::error_code& ec, std::size_t) + { + io_service_.post(bind_handler(this->handler_, ec)); + } + + private: + socket_type socket_; + boost::asio::io_service& io_service_; + boost::asio::io_service::work work_; + }; + + // Start an asynchronous connect. + template + void async_connect(implementation_type& impl, + const endpoint_type& peer_endpoint, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + boost::asio::error::bad_descriptor)); + return; + } + + // Make socket non-blocking. + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + if (!(impl.flags_ & implementation_type::non_blocking)) + { + ioctl_arg_type non_blocking = 1; + boost::system::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec)); + return; + } + } + impl.flags_ |= implementation_type::internal_non_blocking; + } + + // Start the connect operation. The socket is already marked as non-blocking + // so the connection will take place asynchronously. + boost::system::error_code ec; + if (socket_ops::connect(impl.socket_, peer_endpoint.data(), + peer_endpoint.size(), ec) == 0) + { + // The connect operation has finished successfully so we need to post the + // handler immediately. + this->get_io_service().post(bind_handler(handler, + boost::system::error_code())); + } + else if (ec == boost::asio::error::in_progress + || ec == boost::asio::error::would_block) + { + // The connection is happening in the background, and we need to wait + // until the socket becomes writeable. + reactor_.start_connect_op(impl.socket_, impl.reactor_data_, + connect_operation(impl.socket_, + this->get_io_service(), handler)); + } + else + { + // The connect operation has failed, so post the handler immediately. + this->get_io_service().post(bind_handler(handler, ec)); + } + } + +private: + // The selector that performs event demultiplexing for the service. + Reactor& reactor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/reactor_op_queue.hpp b/3rdParty/Boost/boost/asio/detail/reactor_op_queue.hpp new file mode 100644 index 0000000..0fbbf23 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/reactor_op_queue.hpp @@ -0,0 +1,456 @@ +// +// reactor_op_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_REACTOR_OP_QUEUE_HPP +#define BOOST_ASIO_DETAIL_REACTOR_OP_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactor_op_queue + : private noncopyable +{ +public: + // Constructor. + reactor_op_queue() + : operations_(), + cancelled_operations_(0), + complete_operations_(0) + { + } + + // Add a new operation to the queue. Returns true if this is the only + // operation for the given descriptor, in which case the reactor's event + // demultiplexing function call may need to be interrupted and restarted. + template + bool enqueue_operation(Descriptor descriptor, Operation operation) + { + // Allocate and construct an object to wrap the handler. + typedef handler_alloc_traits > alloc_traits; + raw_handler_ptr raw_ptr(operation); + handler_ptr ptr(raw_ptr, descriptor, operation); + + typedef typename operation_map::iterator iterator; + typedef typename operation_map::value_type value_type; + std::pair entry = + operations_.insert(value_type(descriptor, ptr.get())); + if (entry.second) + { + ptr.release(); + return true; + } + + op_base* current_op = entry.first->second; + while (current_op->next_) + current_op = current_op->next_; + current_op->next_ = ptr.release(); + + return false; + } + + // Cancel all operations associated with the descriptor. Any operations + // pending for the descriptor will be notified that they have been cancelled + // next time perform_cancellations is called. Returns true if any operations + // were cancelled, in which case the reactor's event demultiplexing function + // may need to be interrupted and restarted. + bool cancel_operations(Descriptor descriptor) + { + typename operation_map::iterator i = operations_.find(descriptor); + if (i != operations_.end()) + { + op_base* last_op = i->second; + while (last_op->next_) + last_op = last_op->next_; + last_op->next_ = cancelled_operations_; + cancelled_operations_ = i->second; + operations_.erase(i); + return true; + } + + return false; + } + + // Whether there are no operations in the queue. + bool empty() const + { + return operations_.empty(); + } + + // Determine whether there are any operations associated with the descriptor. + bool has_operation(Descriptor descriptor) const + { + return operations_.find(descriptor) != operations_.end(); + } + + // Perform the first operation corresponding to the descriptor. Returns true + // if there are more operations queued for the descriptor. + bool perform_operation(Descriptor descriptor, + const boost::system::error_code& result) + { + typename operation_map::iterator i = operations_.find(descriptor); + if (i != operations_.end()) + { + op_base* this_op = i->second; + i->second = this_op->next_; + this_op->next_ = complete_operations_; + complete_operations_ = this_op; + bool done = this_op->perform(result); + if (done) + { + // Operation has finished. + if (i->second) + { + return true; + } + else + { + operations_.erase(i); + return false; + } + } + else + { + // Operation wants to be called again. Leave it at the front of the + // queue for this descriptor, and remove from the completed list. + complete_operations_ = this_op->next_; + this_op->next_ = i->second; + i->second = this_op; + return true; + } + } + return false; + } + + // Perform all operations corresponding to the descriptor. + void perform_all_operations(Descriptor descriptor, + const boost::system::error_code& result) + { + typename operation_map::iterator i = operations_.find(descriptor); + if (i != operations_.end()) + { + while (i->second) + { + op_base* this_op = i->second; + i->second = this_op->next_; + this_op->next_ = complete_operations_; + complete_operations_ = this_op; + bool done = this_op->perform(result); + if (!done) + { + // Operation has not finished yet, so leave at front of queue, and + // remove from the completed list. + complete_operations_ = this_op->next_; + this_op->next_ = i->second; + i->second = this_op; + return; + } + } + operations_.erase(i); + } + } + + // Fill a descriptor set with the descriptors corresponding to each active + // operation. + template + void get_descriptors(Descriptor_Set& descriptors) + { + typename operation_map::iterator i = operations_.begin(); + while (i != operations_.end()) + { + Descriptor descriptor = i->first; + ++i; + if (!descriptors.set(descriptor)) + { + boost::system::error_code ec(error::fd_set_failure); + perform_all_operations(descriptor, ec); + } + } + } + + // Perform the operations corresponding to the ready file descriptors + // contained in the given descriptor set. + template + void perform_operations_for_descriptors(const Descriptor_Set& descriptors, + const boost::system::error_code& result) + { + typename operation_map::iterator i = operations_.begin(); + while (i != operations_.end()) + { + typename operation_map::iterator op_iter = i++; + if (descriptors.is_set(op_iter->first)) + { + op_base* this_op = op_iter->second; + op_iter->second = this_op->next_; + this_op->next_ = complete_operations_; + complete_operations_ = this_op; + bool done = this_op->perform(result); + if (done) + { + if (!op_iter->second) + operations_.erase(op_iter); + } + else + { + // Operation has not finished yet, so leave at front of queue, and + // remove from the completed list. + complete_operations_ = this_op->next_; + this_op->next_ = op_iter->second; + op_iter->second = this_op; + } + } + } + } + + // Perform any pending cancels for operations. + void perform_cancellations() + { + while (cancelled_operations_) + { + op_base* this_op = cancelled_operations_; + cancelled_operations_ = this_op->next_; + this_op->next_ = complete_operations_; + complete_operations_ = this_op; + this_op->perform(boost::asio::error::operation_aborted); + } + } + + // Complete all operations that are waiting to be completed. + void complete_operations() + { + while (complete_operations_) + { + op_base* next_op = complete_operations_->next_; + complete_operations_->next_ = 0; + complete_operations_->complete(); + complete_operations_ = next_op; + } + } + + // Destroy all operations owned by the queue. + void destroy_operations() + { + while (cancelled_operations_) + { + op_base* next_op = cancelled_operations_->next_; + cancelled_operations_->next_ = 0; + cancelled_operations_->destroy(); + cancelled_operations_ = next_op; + } + + while (complete_operations_) + { + op_base* next_op = complete_operations_->next_; + complete_operations_->next_ = 0; + complete_operations_->destroy(); + complete_operations_ = next_op; + } + + typename operation_map::iterator i = operations_.begin(); + while (i != operations_.end()) + { + typename operation_map::iterator op_iter = i++; + op_base* curr_op = op_iter->second; + operations_.erase(op_iter); + while (curr_op) + { + op_base* next_op = curr_op->next_; + curr_op->next_ = 0; + curr_op->destroy(); + curr_op = next_op; + } + } + } + +private: + // Base class for reactor operations. A function pointer is used instead of + // virtual functions to avoid the associated overhead. + class op_base + { + public: + // Get the descriptor associated with the operation. + Descriptor descriptor() const + { + return descriptor_; + } + + // Perform the operation. + bool perform(const boost::system::error_code& result) + { + result_ = result; + return perform_func_(this, result_, bytes_transferred_); + } + + // Destroy the operation and post the handler. + void complete() + { + complete_func_(this, result_, bytes_transferred_); + } + + // Destroy the operation. + void destroy() + { + destroy_func_(this); + } + + protected: + typedef bool (*perform_func_type)(op_base*, + boost::system::error_code&, std::size_t&); + typedef void (*complete_func_type)(op_base*, + const boost::system::error_code&, std::size_t); + typedef void (*destroy_func_type)(op_base*); + + // Construct an operation for the given descriptor. + op_base(perform_func_type perform_func, complete_func_type complete_func, + destroy_func_type destroy_func, Descriptor descriptor) + : perform_func_(perform_func), + complete_func_(complete_func), + destroy_func_(destroy_func), + descriptor_(descriptor), + result_(), + bytes_transferred_(0), + next_(0) + { + } + + // Prevent deletion through this type. + ~op_base() + { + } + + private: + friend class reactor_op_queue; + + // The function to be called to perform the operation. + perform_func_type perform_func_; + + // The function to be called to delete the operation and post the handler. + complete_func_type complete_func_; + + // The function to be called to delete the operation. + destroy_func_type destroy_func_; + + // The descriptor associated with the operation. + Descriptor descriptor_; + + // The result of the operation. + boost::system::error_code result_; + + // The number of bytes transferred in the operation. + std::size_t bytes_transferred_; + + // The next operation for the same file descriptor. + op_base* next_; + }; + + // Adaptor class template for operations. + template + class op + : public op_base + { + public: + // Constructor. + op(Descriptor descriptor, Operation operation) + : op_base(&op::do_perform, &op::do_complete, + &op::do_destroy, descriptor), + operation_(operation) + { + } + + // Perform the operation. + static bool do_perform(op_base* base, + boost::system::error_code& result, std::size_t& bytes_transferred) + { + return static_cast*>(base)->operation_.perform( + result, bytes_transferred); + } + + // Destroy the operation and post the handler. + static void do_complete(op_base* base, + const boost::system::error_code& result, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + typedef op this_type; + this_type* this_op(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(this_op->operation_, this_op); + + // Make a copy of the error_code and the operation so that the memory can + // be deallocated before the upcall is made. + boost::system::error_code ec(result); + Operation operation(this_op->operation_); + + // Free the memory associated with the operation. + ptr.reset(); + + // Make the upcall. + operation.complete(ec, bytes_transferred); + } + + // Destroy the operation. + static void do_destroy(op_base* base) + { + // Take ownership of the operation object. + typedef op this_type; + this_type* this_op(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(this_op->operation_, this_op); + + // A sub-object of the operation may be the true owner of the memory + // associated with the operation. Consequently, a local copy of the + // operation is required to ensure that any owning sub-object remains + // valid until after we have deallocated the memory here. + Operation operation(this_op->operation_); + (void)operation; + + // Free the memory associated with the operation. + ptr.reset(); + } + + private: + Operation operation_; + }; + + // The type for a map of operations. + typedef hash_map operation_map; + + // The operations that are currently executing asynchronously. + operation_map operations_; + + // The list of operations that have been cancelled. + op_base* cancelled_operations_; + + // The list of operations waiting to be completed. + op_base* complete_operations_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTOR_OP_QUEUE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/resolver_service.hpp b/3rdParty/Boost/boost/asio/detail/resolver_service.hpp new file mode 100644 index 0000000..9b0aac9 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/resolver_service.hpp @@ -0,0 +1,359 @@ +// +// resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_RESOLVER_SERVICE_HPP +#define BOOST_ASIO_DETAIL_RESOLVER_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class resolver_service + : public boost::asio::detail::service_base > +{ +private: + // Helper class to perform exception-safe cleanup of addrinfo objects. + class auto_addrinfo + : private boost::asio::detail::noncopyable + { + public: + explicit auto_addrinfo(boost::asio::detail::addrinfo_type* ai) + : ai_(ai) + { + } + + ~auto_addrinfo() + { + if (ai_) + socket_ops::freeaddrinfo(ai_); + } + + operator boost::asio::detail::addrinfo_type*() + { + return ai_; + } + + private: + boost::asio::detail::addrinfo_type* ai_; + }; + +public: + // The implementation type of the resolver. The shared pointer is used as a + // cancellation token to indicate to the background thread that the operation + // has been cancelled. + typedef boost::shared_ptr implementation_type; + struct noop_deleter { void operator()(void*) {} }; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The query type. + typedef typename Protocol::resolver_query query_type; + + // The iterator type. + typedef typename Protocol::resolver_iterator iterator_type; + + // Constructor. + resolver_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base< + resolver_service >(io_service), + mutex_(), + work_io_service_(new boost::asio::io_service), + work_(new boost::asio::io_service::work(*work_io_service_)), + work_thread_(0) + { + } + + // Destructor. + ~resolver_service() + { + shutdown_service(); + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + work_.reset(); + if (work_io_service_) + { + work_io_service_->stop(); + if (work_thread_) + { + work_thread_->join(); + work_thread_.reset(); + } + work_io_service_.reset(); + } + } + + // Construct a new resolver implementation. + void construct(implementation_type& impl) + { + impl.reset(static_cast(0), noop_deleter()); + } + + // Destroy a resolver implementation. + void destroy(implementation_type&) + { + } + + // Cancel pending asynchronous operations. + void cancel(implementation_type& impl) + { + impl.reset(static_cast(0), noop_deleter()); + } + + // Resolve a query to a list of entries. + iterator_type resolve(implementation_type&, const query_type& query, + boost::system::error_code& ec) + { + boost::asio::detail::addrinfo_type* address_info = 0; + std::string host_name = query.host_name(); + std::string service_name = query.service_name(); + boost::asio::detail::addrinfo_type hints = query.hints(); + + socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0, + service_name.c_str(), &hints, &address_info, ec); + auto_addrinfo auto_address_info(address_info); + + if (ec) + return iterator_type(); + + return iterator_type::create(address_info, host_name, service_name); + } + + template + class resolve_query_handler + { + public: + resolve_query_handler(implementation_type impl, const query_type& query, + boost::asio::io_service& io_service, Handler handler) + : impl_(impl), + query_(query), + io_service_(io_service), + work_(io_service), + handler_(handler) + { + } + + void operator()() + { + // Check if the operation has been cancelled. + if (impl_.expired()) + { + iterator_type iterator; + io_service_.post(boost::asio::detail::bind_handler(handler_, + boost::asio::error::operation_aborted, iterator)); + return; + } + + // Perform the blocking host resolution operation. + boost::asio::detail::addrinfo_type* address_info = 0; + std::string host_name = query_.host_name(); + std::string service_name = query_.service_name(); + boost::asio::detail::addrinfo_type hints = query_.hints(); + boost::system::error_code ec; + socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0, + service_name.c_str(), &hints, &address_info, ec); + auto_addrinfo auto_address_info(address_info); + + // Invoke the handler and pass the result. + iterator_type iterator; + if (!ec) + iterator = iterator_type::create(address_info, host_name, service_name); + io_service_.post(boost::asio::detail::bind_handler( + handler_, ec, iterator)); + } + + private: + boost::weak_ptr impl_; + query_type query_; + boost::asio::io_service& io_service_; + boost::asio::io_service::work work_; + Handler handler_; + }; + + // Asynchronously resolve a query to a list of entries. + template + void async_resolve(implementation_type& impl, const query_type& query, + Handler handler) + { + if (work_io_service_) + { + start_work_thread(); + work_io_service_->post( + resolve_query_handler( + impl, query, this->get_io_service(), handler)); + } + } + + // Resolve an endpoint to a list of entries. + iterator_type resolve(implementation_type&, + const endpoint_type& endpoint, boost::system::error_code& ec) + { + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + char host_name[NI_MAXHOST]; + char service_name[NI_MAXSERV]; + int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; + socket_ops::getnameinfo(endpoint.data(), endpoint.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); + if (ec) + { + flags |= NI_NUMERICSERV; + socket_ops::getnameinfo(endpoint.data(), endpoint.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); + } + + if (ec) + return iterator_type(); + + return iterator_type::create(endpoint, host_name, service_name); + } + + template + class resolve_endpoint_handler + { + public: + resolve_endpoint_handler(implementation_type impl, + const endpoint_type& endpoint, boost::asio::io_service& io_service, + Handler handler) + : impl_(impl), + endpoint_(endpoint), + io_service_(io_service), + work_(io_service), + handler_(handler) + { + } + + void operator()() + { + // Check if the operation has been cancelled. + if (impl_.expired()) + { + iterator_type iterator; + io_service_.post(boost::asio::detail::bind_handler(handler_, + boost::asio::error::operation_aborted, iterator)); + return; + } + + + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + char host_name[NI_MAXHOST]; + char service_name[NI_MAXSERV]; + int flags = endpoint_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; + boost::system::error_code ec; + socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); + if (ec) + { + flags |= NI_NUMERICSERV; + socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); + } + + // Invoke the handler and pass the result. + iterator_type iterator; + if (!ec) + iterator = iterator_type::create(endpoint_, host_name, service_name); + io_service_.post(boost::asio::detail::bind_handler( + handler_, ec, iterator)); + } + + private: + boost::weak_ptr impl_; + endpoint_type endpoint_; + boost::asio::io_service& io_service_; + boost::asio::io_service::work work_; + Handler handler_; + }; + + // Asynchronously resolve an endpoint to a list of entries. + template + void async_resolve(implementation_type& impl, const endpoint_type& endpoint, + Handler handler) + { + if (work_io_service_) + { + start_work_thread(); + work_io_service_->post( + resolve_endpoint_handler( + impl, endpoint, this->get_io_service(), handler)); + } + } + +private: + // Helper class to run the work io_service in a thread. + class work_io_service_runner + { + public: + work_io_service_runner(boost::asio::io_service& io_service) + : io_service_(io_service) {} + void operator()() { io_service_.run(); } + private: + boost::asio::io_service& io_service_; + }; + + // Start the work thread if it's not already running. + void start_work_thread() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!work_thread_) + { + work_thread_.reset(new boost::asio::detail::thread( + work_io_service_runner(*work_io_service_))); + } + } + + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // Private io_service used for performing asynchronous host resolution. + boost::scoped_ptr work_io_service_; + + // Work for the private io_service to perform. + boost::scoped_ptr work_; + + // Thread used for running the work io_service's run loop. + boost::scoped_ptr work_thread_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_RESOLVER_SERVICE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/scoped_lock.hpp b/3rdParty/Boost/boost/asio/detail/scoped_lock.hpp new file mode 100644 index 0000000..1dd2842 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/scoped_lock.hpp @@ -0,0 +1,93 @@ +// +// scoped_lock.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SCOPED_LOCK_HPP +#define BOOST_ASIO_DETAIL_SCOPED_LOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Helper class to lock and unlock a mutex automatically. +template +class scoped_lock + : private noncopyable +{ +public: + // Constructor acquires the lock. + scoped_lock(Mutex& m) + : mutex_(m) + { + mutex_.lock(); + locked_ = true; + } + + // Destructor releases the lock. + ~scoped_lock() + { + if (locked_) + mutex_.unlock(); + } + + // Explicitly acquire the lock. + void lock() + { + if (!locked_) + { + mutex_.lock(); + locked_ = true; + } + } + + // Explicitly release the lock. + void unlock() + { + if (locked_) + { + mutex_.unlock(); + locked_ = false; + } + } + + // Test whether the lock is held. + bool locked() const + { + return locked_; + } + + // Get the underlying mutex. + Mutex& mutex() + { + return mutex_; + } + +private: + // The underlying mutex. + Mutex& mutex_; + + // Whether the mutex is currently locked or unlocked. + bool locked_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SCOPED_LOCK_HPP diff --git a/3rdParty/Boost/boost/asio/detail/select_interrupter.hpp b/3rdParty/Boost/boost/asio/detail/select_interrupter.hpp new file mode 100644 index 0000000..8bb952c --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/select_interrupter.hpp @@ -0,0 +1,46 @@ +// +// select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SELECT_INTERRUPTER_HPP +#define BOOST_ASIO_DETAIL_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +typedef socket_select_interrupter select_interrupter; +#elif defined(BOOST_ASIO_HAS_EVENTFD) +typedef eventfd_select_interrupter select_interrupter; +#else +typedef pipe_select_interrupter select_interrupter; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SELECT_INTERRUPTER_HPP diff --git a/3rdParty/Boost/boost/asio/detail/select_reactor.hpp b/3rdParty/Boost/boost/asio/detail/select_reactor.hpp new file mode 100644 index 0000000..77caf54 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/select_reactor.hpp @@ -0,0 +1,546 @@ +// +// select_reactor.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SELECT_REACTOR_HPP +#define BOOST_ASIO_DETAIL_SELECT_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include // Must come before posix_time. + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class select_reactor + : public boost::asio::detail::service_base > +{ +public: + // Per-descriptor data. + struct per_descriptor_data + { + }; + + // Constructor. + select_reactor(boost::asio::io_service& io_service) + : boost::asio::detail::service_base< + select_reactor >(io_service), + mutex_(), + select_in_progress_(false), + interrupter_(), + read_op_queue_(), + write_op_queue_(), + except_op_queue_(), + pending_cancellations_(), + stop_thread_(false), + thread_(0), + shutdown_(false) + { + if (Own_Thread) + { + boost::asio::detail::signal_blocker sb; + thread_ = new boost::asio::detail::thread( + bind_handler(&select_reactor::call_run_thread, this)); + } + } + + // Destructor. + ~select_reactor() + { + shutdown_service(); + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + stop_thread_ = true; + lock.unlock(); + + if (thread_) + { + interrupter_.interrupt(); + thread_->join(); + delete thread_; + thread_ = 0; + } + + read_op_queue_.destroy_operations(); + write_op_queue_.destroy_operations(); + except_op_queue_.destroy_operations(); + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + timer_queues_[i]->destroy_timers(); + timer_queues_.clear(); + } + + // Initialise the task, but only if the reactor is not in its own thread. + void init_task() + { + if (!Own_Thread) + { + typedef task_io_service > task_io_service_type; + use_service(this->get_io_service()).init_task(); + } + } + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + int register_descriptor(socket_type, per_descriptor_data&) + { + return 0; + } + + // Start a new read operation. The handler object will be invoked when the + // given descriptor is ready to be read, or an error has occurred. + template + void start_read_op(socket_type descriptor, per_descriptor_data&, + Handler handler, bool /*allow_speculative_read*/ = true) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + if (read_op_queue_.enqueue_operation(descriptor, handler)) + interrupter_.interrupt(); + } + + // Start a new write operation. The handler object will be invoked when the + // given descriptor is ready to be written, or an error has occurred. + template + void start_write_op(socket_type descriptor, per_descriptor_data&, + Handler handler, bool /*allow_speculative_write*/ = true) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + if (write_op_queue_.enqueue_operation(descriptor, handler)) + interrupter_.interrupt(); + } + + // Start a new exception operation. The handler object will be invoked when + // the given descriptor has exception information, or an error has occurred. + template + void start_except_op(socket_type descriptor, + per_descriptor_data&, Handler handler) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + if (except_op_queue_.enqueue_operation(descriptor, handler)) + interrupter_.interrupt(); + } + + // Wrapper for connect handlers to enable the handler object to be placed + // in both the write and the except operation queues, but ensure that only + // one of the handlers is called. + template + class connect_handler_wrapper + { + public: + connect_handler_wrapper(socket_type descriptor, + boost::shared_ptr completed, + select_reactor& reactor, Handler handler) + : descriptor_(descriptor), + completed_(completed), + reactor_(reactor), + handler_(handler) + { + } + + bool perform(boost::system::error_code& ec, + std::size_t& bytes_transferred) + { + // Check whether one of the handlers has already been called. If it has, + // then we don't want to do anything in this handler. + if (*completed_) + { + completed_.reset(); // Indicate that this handler should not complete. + return true; + } + + // Cancel the other reactor operation for the connection. + *completed_ = true; + reactor_.enqueue_cancel_ops_unlocked(descriptor_); + + // Call the contained handler. + return handler_.perform(ec, bytes_transferred); + } + + void complete(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + if (completed_.get()) + handler_.complete(ec, bytes_transferred); + } + + private: + socket_type descriptor_; + boost::shared_ptr completed_; + select_reactor& reactor_; + Handler handler_; + }; + + // Start new write and exception operations. The handler object will be + // invoked when the given descriptor is ready for writing or has exception + // information available, or an error has occurred. The handler will be called + // only once. + template + void start_connect_op(socket_type descriptor, + per_descriptor_data&, Handler handler) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + boost::shared_ptr completed(new bool(false)); + connect_handler_wrapper wrapped_handler( + descriptor, completed, *this, handler); + bool interrupt = write_op_queue_.enqueue_operation( + descriptor, wrapped_handler); + interrupt = except_op_queue_.enqueue_operation( + descriptor, wrapped_handler) || interrupt; + if (interrupt) + interrupter_.interrupt(); + } + } + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + void cancel_ops(socket_type descriptor, per_descriptor_data&) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor); + } + + // Enqueue cancellation of all operations associated with the given + // descriptor. The handlers associated with the descriptor will be invoked + // with the operation_aborted error. This function does not acquire the + // select_reactor's mutex, and so should only be used when the reactor lock is + // already held. + void enqueue_cancel_ops_unlocked(socket_type descriptor) + { + pending_cancellations_.push_back(descriptor); + } + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. + void close_descriptor(socket_type descriptor, per_descriptor_data&) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor); + } + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& timer_queue) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + timer_queues_.push_back(&timer_queue); + } + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& timer_queue) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + if (timer_queues_[i] == &timer_queue) + { + timer_queues_.erase(timer_queues_.begin() + i); + return; + } + } + } + + // Schedule a timer in the given timer queue to expire at the specified + // absolute time. The handler object will be invoked when the timer expires. + template + void schedule_timer(timer_queue& timer_queue, + const typename Time_Traits::time_type& time, Handler handler, void* token) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + if (timer_queue.enqueue_timer(time, handler, token)) + interrupter_.interrupt(); + } + + // Cancel the timer associated with the given token. Returns the number of + // handlers that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& timer_queue, void* token) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + std::size_t n = timer_queue.cancel_timer(token); + if (n > 0) + interrupter_.interrupt(); + return n; + } + +private: + friend class task_io_service >; + + // Run select once until interrupted or events are ready to be dispatched. + void run(bool block) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Dispatch any operation cancellations that were made while the select + // loop was not running. + read_op_queue_.perform_cancellations(); + write_op_queue_.perform_cancellations(); + except_op_queue_.perform_cancellations(); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + timer_queues_[i]->dispatch_cancellations(); + + // Check if the thread is supposed to stop. + if (stop_thread_) + { + complete_operations_and_timers(lock); + return; + } + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (!block && read_op_queue_.empty() && write_op_queue_.empty() + && except_op_queue_.empty() && all_timer_queues_are_empty()) + { + complete_operations_and_timers(lock); + return; + } + + // Set up the descriptor sets. + fd_set_adapter read_fds; + read_fds.set(interrupter_.read_descriptor()); + read_op_queue_.get_descriptors(read_fds); + fd_set_adapter write_fds; + write_op_queue_.get_descriptors(write_fds); + fd_set_adapter except_fds; + except_op_queue_.get_descriptors(except_fds); + socket_type max_fd = read_fds.max_descriptor(); + if (write_fds.max_descriptor() > max_fd) + max_fd = write_fds.max_descriptor(); + if (except_fds.max_descriptor() > max_fd) + max_fd = except_fds.max_descriptor(); + + // Block on the select call without holding the lock so that new + // operations can be started while the call is executing. + timeval tv_buf = { 0, 0 }; + timeval* tv = block ? get_timeout(tv_buf) : &tv_buf; + select_in_progress_ = true; + lock.unlock(); + boost::system::error_code ec; + int retval = socket_ops::select(static_cast(max_fd + 1), + read_fds, write_fds, except_fds, tv, ec); + lock.lock(); + select_in_progress_ = false; + + // Block signals while dispatching operations. + boost::asio::detail::signal_blocker sb; + + // Reset the interrupter. + if (retval > 0 && read_fds.is_set(interrupter_.read_descriptor())) + interrupter_.reset(); + + // Dispatch all ready operations. + if (retval > 0) + { + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + except_op_queue_.perform_operations_for_descriptors( + except_fds, boost::system::error_code()); + read_op_queue_.perform_operations_for_descriptors( + read_fds, boost::system::error_code()); + write_op_queue_.perform_operations_for_descriptors( + write_fds, boost::system::error_code()); + except_op_queue_.perform_cancellations(); + read_op_queue_.perform_cancellations(); + write_op_queue_.perform_cancellations(); + } + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + timer_queues_[i]->dispatch_timers(); + timer_queues_[i]->dispatch_cancellations(); + } + + // Issue any pending cancellations. + for (size_t i = 0; i < pending_cancellations_.size(); ++i) + cancel_ops_unlocked(pending_cancellations_[i]); + pending_cancellations_.clear(); + + complete_operations_and_timers(lock); + } + + // Run the select loop in the thread. + void run_thread() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + lock.unlock(); + run(true); + lock.lock(); + } + } + + // Entry point for the select loop thread. + static void call_run_thread(select_reactor* reactor) + { + reactor->run_thread(); + } + + // Interrupt the select loop. + void interrupt() + { + interrupter_.interrupt(); + } + + // Check if all timer queues are empty. + bool all_timer_queues_are_empty() const + { + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + if (!timer_queues_[i]->empty()) + return false; + return true; + } + + // Get the timeout value for the select call. + timeval* get_timeout(timeval& tv) + { + if (all_timer_queues_are_empty()) + return 0; + + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + boost::posix_time::time_duration minimum_wait_duration + = boost::posix_time::minutes(5); + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + boost::posix_time::time_duration wait_duration + = timer_queues_[i]->wait_duration(); + if (wait_duration < minimum_wait_duration) + minimum_wait_duration = wait_duration; + } + + if (minimum_wait_duration > boost::posix_time::time_duration()) + { + tv.tv_sec = minimum_wait_duration.total_seconds(); + tv.tv_usec = minimum_wait_duration.total_microseconds() % 1000000; + } + else + { + tv.tv_sec = 0; + tv.tv_usec = 0; + } + + return &tv; + } + + // Cancel all operations associated with the given descriptor. The do_cancel + // function of the handler objects will be invoked. This function does not + // acquire the select_reactor's mutex. + void cancel_ops_unlocked(socket_type descriptor) + { + bool interrupt = read_op_queue_.cancel_operations(descriptor); + interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt; + interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt; + if (interrupt) + interrupter_.interrupt(); + } + + // Clean up operations and timers. We must not hold the lock since the + // destructors may make calls back into this reactor. We make a copy of the + // vector of timer queues since the original may be modified while the lock + // is not held. + void complete_operations_and_timers( + boost::asio::detail::mutex::scoped_lock& lock) + { + timer_queues_for_cleanup_ = timer_queues_; + lock.unlock(); + read_op_queue_.complete_operations(); + write_op_queue_.complete_operations(); + except_op_queue_.complete_operations(); + for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) + timer_queues_for_cleanup_[i]->complete_timers(); + } + + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // Whether the select loop is currently running or not. + bool select_in_progress_; + + // The interrupter is used to break a blocking select call. + select_interrupter interrupter_; + + // The queue of read operations. + reactor_op_queue read_op_queue_; + + // The queue of write operations. + reactor_op_queue write_op_queue_; + + // The queue of exception operations. + reactor_op_queue except_op_queue_; + + // The timer queues. + std::vector timer_queues_; + + // A copy of the timer queues, used when cleaning up timers. The copy is + // stored as a class data member to avoid unnecessary memory allocation. + std::vector timer_queues_for_cleanup_; + + // The descriptors that are pending cancellation. + std::vector pending_cancellations_; + + // Does the reactor loop thread need to stop. + bool stop_thread_; + + // The thread that is running the reactor loop. + boost::asio::detail::thread* thread_; + + // Whether the service has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SELECT_REACTOR_HPP diff --git a/3rdParty/Boost/boost/asio/detail/select_reactor_fwd.hpp b/3rdParty/Boost/boost/asio/detail/select_reactor_fwd.hpp new file mode 100644 index 0000000..3bd5d86 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/select_reactor_fwd.hpp @@ -0,0 +1,33 @@ +// +// select_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SELECT_REACTOR_FWD_HPP +#define BOOST_ASIO_DETAIL_SELECT_REACTOR_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class select_reactor; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SELECT_REACTOR_FWD_HPP diff --git a/3rdParty/Boost/boost/asio/detail/service_base.hpp b/3rdParty/Boost/boost/asio/detail/service_base.hpp new file mode 100644 index 0000000..f01cdaf --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/service_base.hpp @@ -0,0 +1,51 @@ +// +// service_base.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SERVICE_BASE_HPP +#define BOOST_ASIO_DETAIL_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +// Special service base class to keep classes header-file only. +template +class service_base + : public boost::asio::io_service::service +{ +public: + static boost::asio::detail::service_id id; + + // Constructor. + service_base(boost::asio::io_service& io_service) + : boost::asio::io_service::service(io_service) + { + } +}; + +template +boost::asio::detail::service_id service_base::id; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SERVICE_BASE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/service_id.hpp b/3rdParty/Boost/boost/asio/detail/service_id.hpp new file mode 100644 index 0000000..f249ddf --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/service_id.hpp @@ -0,0 +1,39 @@ +// +// service_id.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SERVICE_ID_HPP +#define BOOST_ASIO_DETAIL_SERVICE_ID_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Special derived service id type to keep classes header-file only. +template +class service_id + : public boost::asio::io_service::id +{ +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SERVICE_ID_HPP diff --git a/3rdParty/Boost/boost/asio/detail/service_registry.hpp b/3rdParty/Boost/boost/asio/detail/service_registry.hpp new file mode 100644 index 0000000..6b25663 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/service_registry.hpp @@ -0,0 +1,228 @@ +// +// service_registry.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SERVICE_REGISTRY_HPP +#define BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#if defined(BOOST_NO_TYPEID) +# if !defined(BOOST_ASIO_NO_TYPEID) +# define BOOST_ASIO_NO_TYPEID +# endif // !defined(BOOST_ASIO_NO_TYPEID) +#endif // defined(BOOST_NO_TYPEID) + +namespace boost { +namespace asio { +namespace detail { + +#if defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility push (default) +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +#endif // defined(__GNUC__) + +template +class typeid_wrapper {}; + +#if defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility pop +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +#endif // defined(__GNUC__) + +class service_registry + : private noncopyable +{ +public: + // Constructor. + service_registry(boost::asio::io_service& o) + : owner_(o), + first_service_(0) + { + } + + // Destructor. + ~service_registry() + { + // Shutdown all services. This must be done in a separate loop before the + // services are destroyed since the destructors of user-defined handler + // objects may try to access other service objects. + boost::asio::io_service::service* service = first_service_; + while (service) + { + service->shutdown_service(); + service = service->next_; + } + + // Destroy all services. + while (first_service_) + { + boost::asio::io_service::service* next_service = first_service_->next_; + delete first_service_; + first_service_ = next_service; + } + } + + // Get the service object corresponding to the specified service type. Will + // create a new service object automatically if no such object already + // exists. Ownership of the service object is not transferred to the caller. + template + Service& use_service() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // First see if there is an existing service object for the given type. + boost::asio::io_service::service* service = first_service_; + while (service) + { + if (service_id_matches(*service, Service::id)) + return *static_cast(service); + service = service->next_; + } + + // Create a new service object. The service registry's mutex is not locked + // at this time to allow for nested calls into this function from the new + // service's constructor. + lock.unlock(); + std::auto_ptr new_service(new Service(owner_)); + init_service_id(*new_service, Service::id); + Service& new_service_ref = *new_service; + lock.lock(); + + // Check that nobody else created another service object of the same type + // while the lock was released. + service = first_service_; + while (service) + { + if (service_id_matches(*service, Service::id)) + return *static_cast(service); + service = service->next_; + } + + // Service was successfully initialised, pass ownership to registry. + new_service->next_ = first_service_; + first_service_ = new_service.release(); + + return new_service_ref; + } + + // Add a service object. Returns false on error, in which case ownership of + // the object is retained by the caller. + template + bool add_service(Service* new_service) + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Check if there is an existing service object for the given type. + boost::asio::io_service::service* service = first_service_; + while (service) + { + if (service_id_matches(*service, Service::id)) + return false; + service = service->next_; + } + + // Take ownership of the service object. + init_service_id(*new_service, Service::id); + new_service->next_ = first_service_; + first_service_ = new_service; + + return true; + } + + // Check whether a service object of the specified type already exists. + template + bool has_service() const + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + boost::asio::io_service::service* service = first_service_; + while (service) + { + if (service_id_matches(*service, Service::id)) + return true; + service = service->next_; + } + + return false; + } + +private: + // Set a service's id. + void init_service_id(boost::asio::io_service::service& service, + const boost::asio::io_service::id& id) + { + service.type_info_ = 0; + service.id_ = &id; + } + +#if !defined(BOOST_ASIO_NO_TYPEID) + // Set a service's id. + template + void init_service_id(boost::asio::io_service::service& service, + const boost::asio::detail::service_id& /*id*/) + { + service.type_info_ = &typeid(typeid_wrapper); + service.id_ = 0; + } +#endif // !defined(BOOST_ASIO_NO_TYPEID) + + // Check if a service matches the given id. + static bool service_id_matches( + const boost::asio::io_service::service& service, + const boost::asio::io_service::id& id) + { + return service.id_ == &id; + } + +#if !defined(BOOST_ASIO_NO_TYPEID) + // Check if a service matches the given id. + template + static bool service_id_matches( + const boost::asio::io_service::service& service, + const boost::asio::detail::service_id& /*id*/) + { + return service.type_info_ != 0 + && *service.type_info_ == typeid(typeid_wrapper); + } +#endif // !defined(BOOST_ASIO_NO_TYPEID) + + // Mutex to protect access to internal data. + mutable boost::asio::detail::mutex mutex_; + + // The owner of this service registry and the services it contains. + boost::asio::io_service& owner_; + + // The first service in the list of contained services. + boost::asio::io_service::service* first_service_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP diff --git a/3rdParty/Boost/boost/asio/detail/service_registry_fwd.hpp b/3rdParty/Boost/boost/asio/detail/service_registry_fwd.hpp new file mode 100644 index 0000000..e32647b --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/service_registry_fwd.hpp @@ -0,0 +1,32 @@ +// +// service_registry_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SERVICE_REGISTRY_FWD_HPP +#define BOOST_ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class service_registry; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP diff --git a/3rdParty/Boost/boost/asio/detail/signal_blocker.hpp b/3rdParty/Boost/boost/asio/detail/signal_blocker.hpp new file mode 100644 index 0000000..a770549 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/signal_blocker.hpp @@ -0,0 +1,52 @@ +// +// signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SIGNAL_BLOCKER_HPP +#define BOOST_ASIO_DETAIL_SIGNAL_BLOCKER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if !defined(BOOST_HAS_THREADS) +# include +#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# include +#elif defined(BOOST_HAS_PTHREADS) +# include +#else +# error Only Windows and POSIX are supported! +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if !defined(BOOST_HAS_THREADS) +typedef null_signal_blocker signal_blocker; +#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) +typedef win_signal_blocker signal_blocker; +#elif defined(BOOST_HAS_PTHREADS) +typedef posix_signal_blocker signal_blocker; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SIGNAL_BLOCKER_HPP diff --git a/3rdParty/Boost/boost/asio/detail/signal_init.hpp b/3rdParty/Boost/boost/asio/detail/signal_init.hpp new file mode 100644 index 0000000..e5a3d37 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/signal_init.hpp @@ -0,0 +1,53 @@ +// +// signal_init.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SIGNAL_INIT_HPP +#define BOOST_ASIO_DETAIL_SIGNAL_INIT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class signal_init +{ +public: + // Constructor. + signal_init() + { + std::signal(Signal, SIG_IGN); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include + +#endif // BOOST_ASIO_DETAIL_SIGNAL_INIT_HPP diff --git a/3rdParty/Boost/boost/asio/detail/socket_holder.hpp b/3rdParty/Boost/boost/asio/detail/socket_holder.hpp new file mode 100644 index 0000000..be144a6 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/socket_holder.hpp @@ -0,0 +1,97 @@ +// +// socket_holder.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SOCKET_HOLDER_HPP +#define BOOST_ASIO_DETAIL_SOCKET_HOLDER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +// Implement the resource acquisition is initialisation idiom for sockets. +class socket_holder + : private noncopyable +{ +public: + // Construct as an uninitialised socket. + socket_holder() + : socket_(invalid_socket) + { + } + + // Construct to take ownership of the specified socket. + explicit socket_holder(socket_type s) + : socket_(s) + { + } + + // Destructor. + ~socket_holder() + { + if (socket_ != invalid_socket) + { + boost::system::error_code ec; + socket_ops::close(socket_, ec); + } + } + + // Get the underlying socket. + socket_type get() const + { + return socket_; + } + + // Reset to an uninitialised socket. + void reset() + { + if (socket_ != invalid_socket) + { + boost::system::error_code ec; + socket_ops::close(socket_, ec); + socket_ = invalid_socket; + } + } + + // Reset to take ownership of the specified socket. + void reset(socket_type s) + { + reset(); + socket_ = s; + } + + // Release ownership of the socket. + socket_type release() + { + socket_type tmp = socket_; + socket_ = invalid_socket; + return tmp; + } + +private: + // The underlying socket. + socket_type socket_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SOCKET_HOLDER_HPP diff --git a/3rdParty/Boost/boost/asio/detail/socket_ops.hpp b/3rdParty/Boost/boost/asio/detail/socket_ops.hpp new file mode 100644 index 0000000..4969017 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/socket_ops.hpp @@ -0,0 +1,1913 @@ +// +// socket_ops.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SOCKET_OPS_HPP +#define BOOST_ASIO_DETAIL_SOCKET_OPS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace boost { +namespace asio { +namespace detail { +namespace socket_ops { + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +struct msghdr { int msg_namelen; }; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) +// HP-UX doesn't declare these functions extern "C", so they are declared again +// here to avoid linker errors about undefined symbols. +extern "C" char* if_indextoname(unsigned int, char*); +extern "C" unsigned int if_nametoindex(const char*); +#endif // defined(__hpux) + +inline void clear_error(boost::system::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + WSASetLastError(0); +#else + errno = 0; +#endif + ec = boost::system::error_code(); +} + +template +inline ReturnType error_wrapper(ReturnType return_value, + boost::system::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + ec = boost::system::error_code(WSAGetLastError(), + boost::asio::error::get_system_category()); +#else + ec = boost::system::error_code(errno, + boost::asio::error::get_system_category()); +#endif + return return_value; +} + +template +inline socket_type call_accept(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; + socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); + if (addrlen) + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +inline socket_type accept(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec) +{ + clear_error(ec); + + socket_type new_s = error_wrapper(call_accept( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (new_s == invalid_socket) + return new_s; + +#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + int optval = 1; + int result = error_wrapper(::setsockopt(new_s, + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + if (result != 0) + { + ::close(new_s); + return invalid_socket; + } +#endif + + clear_error(ec); + return new_s; +} + +template +inline int call_bind(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::bind(s, addr, (SockLenType)addrlen); +} + +inline int bind(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(call_bind( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + clear_error(ec); + return result; +} + +inline int close(socket_type s, boost::system::error_code& ec) +{ + clear_error(ec); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::closesocket(s), ec); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::close(s), ec); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (result == 0) + clear_error(ec); + return result; +} + +inline int shutdown(socket_type s, int what, boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(::shutdown(s, what), ec); + if (result == 0) + clear_error(ec); + return result; +} + +template +inline int call_connect(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::connect(s, addr, (SockLenType)addrlen); +} + +inline int connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(call_connect( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + clear_error(ec); + return result; +} + +inline int socketpair(int af, int type, int protocol, + socket_type sv[2], boost::system::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)(af); + (void)(type); + (void)(protocol); + (void)(sv); + ec = boost::asio::error::operation_not_supported; + return -1; +#else + clear_error(ec); + int result = error_wrapper(::socketpair(af, type, protocol, sv), ec); + if (result == 0) + clear_error(ec); + return result; +#endif +} + +inline int listen(socket_type s, int backlog, boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(::listen(s, backlog), ec); + if (result == 0) + clear_error(ec); + return result; +} + +inline void init_buf_iov_base(void*& base, void* addr) +{ + base = addr; +} + +template +inline void init_buf_iov_base(T& base, void* addr) +{ + base = static_cast(addr); +} + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +typedef WSABUF buf; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +typedef iovec buf; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +inline void init_buf(buf& b, void* data, size_t size) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast(data); + b.len = static_cast(size); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, data); + b.iov_len = size; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline void init_buf(buf& b, const void* data, size_t size) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast(const_cast(data)); + b.len = static_cast(size); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, const_cast(data)); + b.iov_len = size; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) +{ + name = addr; +} + +inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) +{ + name = const_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) +{ + name = reinterpret_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) +{ + name = reinterpret_cast(const_cast(addr)); +} + +inline int recv(socket_type s, buf* bufs, size_t count, int flags, + boost::system::error_code& ec) +{ + clear_error(ec); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = error_wrapper(::WSARecv(s, bufs, + recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); + if (result != 0) + return -1; + clear_error(ec); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = bufs; + msg.msg_iovlen = count; + int result = error_wrapper(::recvmsg(s, &msg, flags), ec); + if (result >= 0) + clear_error(ec); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec) +{ + clear_error(ec); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int tmp_addrlen = (int)*addrlen; + int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, + &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); + *addrlen = (std::size_t)tmp_addrlen; + if (result != 0) + return -1; + clear_error(ec); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = *addrlen; + msg.msg_iov = bufs; + msg.msg_iovlen = count; + int result = error_wrapper(::recvmsg(s, &msg, flags), ec); + *addrlen = msg.msg_namelen; + if (result >= 0) + clear_error(ec); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline int send(socket_type s, const buf* bufs, size_t count, int flags, + boost::system::error_code& ec) +{ + clear_error(ec); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD send_flags = flags; + int result = error_wrapper(::WSASend(s, const_cast(bufs), + send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); + if (result != 0) + return -1; + clear_error(ec); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = const_cast(bufs); + msg.msg_iovlen = count; +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + int result = error_wrapper(::sendmsg(s, &msg, flags), ec); + if (result >= 0) + clear_error(ec); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline int sendto(socket_type s, const buf* bufs, size_t count, int flags, + const socket_addr_type* addr, std::size_t addrlen, + boost::system::error_code& ec) +{ + clear_error(ec); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + int result = error_wrapper(::WSASendTo(s, const_cast(bufs), + send_buf_count, &bytes_transferred, flags, addr, + static_cast(addrlen), 0, 0), ec); + if (result != 0) + return -1; + clear_error(ec); + return bytes_transferred; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = addrlen; + msg.msg_iov = const_cast(bufs); + msg.msg_iovlen = count; +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + int result = error_wrapper(::sendmsg(s, &msg, flags), ec); + if (result >= 0) + clear_error(ec); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline socket_type socket(int af, int type, int protocol, + boost::system::error_code& ec) +{ + clear_error(ec); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0, + WSA_FLAG_OVERLAPPED), ec); + if (s == invalid_socket) + return s; + + if (af == AF_INET6) + { + // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to + // false. This will only succeed on Windows Vista and later versions of + // Windows, where a dual-stack IPv4/v6 implementation is available. + DWORD optval = 0; + ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + reinterpret_cast(&optval), sizeof(optval)); + } + + clear_error(ec); + + return s; +#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + socket_type s = error_wrapper(::socket(af, type, protocol), ec); + if (s == invalid_socket) + return s; + + int optval = 1; + int result = error_wrapper(::setsockopt(s, + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + if (result != 0) + { + ::close(s); + return invalid_socket; + } + + return s; +#else + int s = error_wrapper(::socket(af, type, protocol), ec); + if (s >= 0) + clear_error(ec); + return s; +#endif +} + +template +inline int call_setsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + const void* optval, std::size_t optlen) +{ + return ::setsockopt(s, level, optname, + (const char*)optval, (SockLenType)optlen); +} + +inline int setsockopt(socket_type s, int level, int optname, + const void* optval, std::size_t optlen, boost::system::error_code& ec) +{ + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = boost::asio::error::invalid_argument; + return -1; + } + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); + if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) + { + clear_error(ec); + return error_wrapper(sso(s, level, optname, + reinterpret_cast(optval), + static_cast(optlen)), ec); + } + } + ec = boost::asio::error::fault; + return -1; +#else // defined(__BORLANDC__) + clear_error(ec); + int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); + if (result == 0) + clear_error(ec); + return result; +#endif // defined(__BORLANDC__) +} + +template +inline int call_getsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + void* optval, std::size_t* optlen) +{ + SockLenType tmp_optlen = (SockLenType)*optlen; + int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); + *optlen = (std::size_t)tmp_optlen; + return result; +} + +inline int getsockopt(socket_type s, int level, int optname, void* optval, + size_t* optlen, boost::system::error_code& ec) +{ + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = boost::asio::error::invalid_argument; + return -1; + } + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); + if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) + { + clear_error(ec); + int tmp_optlen = static_cast(*optlen); + int result = error_wrapper(gso(s, level, optname, + reinterpret_cast(optval), &tmp_optlen), ec); + *optlen = static_cast(tmp_optlen); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are + // only supported on Windows Vista and later. To simplify program logic + // we will fake success of getting this option and specify that the + // value is non-zero (i.e. true). This corresponds to the behavior of + // IPv6 sockets on Windows platforms pre-Vista. + *static_cast(optval) = 1; + clear_error(ec); + } + return result; + } + } + ec = boost::asio::error::fault; + return -1; +#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) + clear_error(ec); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only + // supported on Windows Vista and later. To simplify program logic we will + // fake success of getting this option and specify that the value is + // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets + // on Windows platforms pre-Vista. + *static_cast(optval) = 1; + clear_error(ec); + } + if (result == 0) + clear_error(ec); + return result; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + clear_error(ec); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); +#if defined(__linux__) + if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) + && (optname == SO_SNDBUF || optname == SO_RCVBUF)) + { + // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel + // to set the buffer size to N*2. Linux puts additional stuff into the + // buffers so that only about half is actually available to the application. + // The retrieved value is divided by 2 here to make it appear as though the + // correct value has been set. + *static_cast(optval) /= 2; + } +#endif // defined(__linux__) + if (result == 0) + clear_error(ec); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +template +inline int call_getpeername(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getpeername(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +inline int getpeername(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(call_getpeername( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + clear_error(ec); + return result; +} + +template +inline int call_getsockname(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getsockname(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +inline int getsockname(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(call_getsockname( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + clear_error(ec); + return result; +} + +inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg, + boost::system::error_code& ec) +{ + clear_error(ec); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, cmd, arg), ec); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (result >= 0) + clear_error(ec); + return result; +} + +inline int select(int nfds, fd_set* readfds, fd_set* writefds, + fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec) +{ + clear_error(ec); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + if (!readfds && !writefds && !exceptfds && timeout) + { + DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; + if (milliseconds == 0) + milliseconds = 1; // Force context switch. + ::Sleep(milliseconds); + ec = boost::system::error_code(); + return 0; + } + + // The select() call allows timeout values measured in microseconds, but the + // system clock (as wrapped by boost::posix_time::microsec_clock) typically + // has a resolution of 10 milliseconds. This can lead to a spinning select + // reactor, meaning increased CPU usage, when waiting for the earliest + // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight + // spin we'll use a minimum timeout of 1 millisecond. + if (timeout && timeout->tv_sec == 0 + && timeout->tv_usec > 0 && timeout->tv_usec < 1000) + timeout->tv_usec = 1000; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) && defined(__HP_aCC) + timespec ts; + ts.tv_sec = timeout ? timeout->tv_sec : 0; + ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; + return error_wrapper(::pselect(nfds, readfds, + writefds, exceptfds, timeout ? &ts : 0, 0), ec); +#else + int result = error_wrapper(::select(nfds, readfds, + writefds, exceptfds, timeout), ec); + if (result >= 0) + clear_error(ec); + return result; +#endif +} + +inline int poll_read(socket_type s, boost::system::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + FD_SET fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + clear_error(ec); + int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec); + if (result >= 0) + clear_error(ec); + return result; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + pollfd fds; + fds.fd = s; + fds.events = POLLIN; + fds.revents = 0; + clear_error(ec); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + clear_error(ec); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline int poll_write(socket_type s, boost::system::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + FD_SET fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + clear_error(ec); + int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec); + if (result >= 0) + clear_error(ec); + return result; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + clear_error(ec); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + clear_error(ec); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline int poll_connect(socket_type s, boost::system::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + FD_SET write_fds; + FD_ZERO(&write_fds); + FD_SET(s, &write_fds); + FD_SET except_fds; + FD_ZERO(&except_fds); + FD_SET(s, &except_fds); + clear_error(ec); + int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec); + if (result >= 0) + clear_error(ec); + return result; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + clear_error(ec); + int result = error_wrapper(::poll(&fds, 1, -1), ec); + if (result >= 0) + clear_error(ec); + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline const char* inet_ntop(int af, const void* src, char* dest, size_t length, + unsigned long scope_id, boost::system::error_code& ec) +{ + clear_error(ec); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy. + + if (af != AF_INET && af != AF_INET6) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + DWORD address_length; + if (af == AF_INET) + { + address_length = sizeof(sockaddr_in4_type); + address.v4.sin_family = AF_INET; + address.v4.sin_port = 0; + memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); + } + else // AF_INET6 + { + address_length = sizeof(sockaddr_in6_type); + address.v6.sin6_family = AF_INET6; + address.v6.sin6_port = 0; + address.v6.sin6_flowinfo = 0; + address.v6.sin6_scope_id = scope_id; + memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); + } + + DWORD string_length = static_cast(length); +#if defined(BOOST_NO_ANSI_APIS) + LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); + int result = error_wrapper(::WSAAddressToStringW(&address.base, + address_length, 0, string_buffer, &string_length), ec); + ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); +#else + int result = error_wrapper(::WSAAddressToStringA( + &address.base, address_length, 0, dest, &string_length), ec); +#endif + + // Windows may set error code on success. + if (result != socket_error_retval) + clear_error(ec); + + // Windows may not set an error code on failure. + else if (result == socket_error_retval && !ec) + ec = boost::asio::error::invalid_argument; + + return result == socket_error_retval ? 0 : dest; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec); + if (result == 0 && !ec) + ec = boost::asio::error::invalid_argument; + if (result != 0 && af == AF_INET6 && scope_id != 0) + { + using namespace std; // For strcat and sprintf. + char if_name[IF_NAMESIZE + 1] = "%"; + const in6_addr_type* ipv6_address = static_cast(src); + bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); + if (!is_link_local || if_indextoname(scope_id, if_name + 1) == 0) + sprintf(if_name + 1, "%lu", scope_id); + strcat(dest, if_name); + } + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline int inet_pton(int af, const char* src, void* dest, + unsigned long* scope_id, boost::system::error_code& ec) +{ + clear_error(ec); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy and strcmp. + + if (af != AF_INET && af != AF_INET6) + { + ec = boost::asio::error::address_family_not_supported; + return -1; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + int address_length = sizeof(sockaddr_storage_type); +#if defined(BOOST_NO_ANSI_APIS) + int num_wide_chars = strlen(src) + 1; + LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); + ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); + int result = error_wrapper(::WSAStringToAddressW( + wide_buffer, af, 0, &address.base, &address_length), ec); +#else + int result = error_wrapper(::WSAStringToAddressA( + const_cast(src), af, 0, &address.base, &address_length), ec); +#endif + + if (af == AF_INET) + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); + clear_error(ec); + } + else if (strcmp(src, "255.255.255.255") == 0) + { + static_cast(dest)->s_addr = INADDR_NONE; + clear_error(ec); + } + } + else // AF_INET6 + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); + if (scope_id) + *scope_id = address.v6.sin6_scope_id; + clear_error(ec); + } + } + + // Windows may not set an error code on failure. + if (result == socket_error_retval && !ec) + ec = boost::asio::error::invalid_argument; + + if (result != socket_error_retval) + clear_error(ec); + + return result == socket_error_retval ? -1 : 1; +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::inet_pton(af, src, dest), ec); + if (result <= 0 && !ec) + ec = boost::asio::error::invalid_argument; + if (result > 0 && af == AF_INET6 && scope_id) + { + using namespace std; // For strchr and atoi. + *scope_id = 0; + if (const char* if_name = strchr(src, '%')) + { + in6_addr_type* ipv6_address = static_cast(dest); + bool is_link_local = IN6_IS_ADDR_LINKLOCAL(ipv6_address); + if (is_link_local) + *scope_id = if_nametoindex(if_name + 1); + if (*scope_id == 0) + *scope_id = atoi(if_name + 1); + } + } + return result; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline int gethostname(char* name, int namelen, boost::system::error_code& ec) +{ + clear_error(ec); + int result = error_wrapper(::gethostname(name, namelen), ec); +#if defined(BOOST_WINDOWS) + if (result == 0) + clear_error(ec); +#endif + return result; +} + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \ + || defined(__MACH__) && defined(__APPLE__) + +// The following functions are only needed for emulation of getaddrinfo and +// getnameinfo. + +inline boost::system::error_code translate_netdb_error(int error) +{ + switch (error) + { + case 0: + return boost::system::error_code(); + case HOST_NOT_FOUND: + return boost::asio::error::host_not_found; + case TRY_AGAIN: + return boost::asio::error::host_not_found_try_again; + case NO_RECOVERY: + return boost::asio::error::no_recovery; + case NO_DATA: + return boost::asio::error::no_data; + default: + BOOST_ASSERT(false); + return boost::asio::error::invalid_argument; + } +} + +inline hostent* gethostbyaddr(const char* addr, int length, int af, + hostent* result, char* buffer, int buflength, boost::system::error_code& ec) +{ + clear_error(ec); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); + if (!retval) + return 0; + clear_error(ec); + *result = *retval; + return retval; +#elif defined(__sun) || defined(__QNX__) + int error = 0; + hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, + buffer, buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = error_wrapper(::getipnodebyaddr( + addr, length, af, &error), ec); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + hostent* retval = 0; + int error = 0; + error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, + buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline hostent* gethostbyname(const char* name, int af, struct hostent* result, + char* buffer, int buflength, int ai_flags, boost::system::error_code& ec) +{ + clear_error(ec); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + (void)(ai_flags); + if (af != AF_INET) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + hostent* retval = error_wrapper(::gethostbyname(name), ec); + if (!retval) + return 0; + clear_error(ec); + *result = *retval; + return result; +#elif defined(__sun) || defined(__QNX__) + (void)(ai_flags); + if (af != AF_INET) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + int error = 0; + hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, + buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = error_wrapper(::getipnodebyname( + name, af, ai_flags, &error), ec); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + (void)(ai_flags); + if (af != AF_INET) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + hostent* retval = 0; + int error = 0; + error_wrapper(::gethostbyname_r(name, result, + buffer, buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline void freehostent(hostent* h) +{ +#if defined(__MACH__) && defined(__APPLE__) + if (h) + ::freehostent(h); +#else + (void)(h); +#endif +} + +// Emulation of getaddrinfo based on implementation in: +// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998. + +struct gai_search +{ + const char* host; + int family; +}; + +inline int gai_nsearch(const char* host, + const addrinfo_type* hints, gai_search (&search)[2]) +{ + int search_count = 0; + if (host == 0 || host[0] == '\0') + { + if (hints->ai_flags & AI_PASSIVE) + { + // No host and AI_PASSIVE implies wildcard bind. + switch (hints->ai_family) + { + case AF_INET: + search[search_count].host = "0.0.0.0"; + search[search_count].family = AF_INET; + ++search_count; + break; + case AF_INET6: + search[search_count].host = "0::0"; + search[search_count].family = AF_INET6; + ++search_count; + break; + case AF_UNSPEC: + search[search_count].host = "0::0"; + search[search_count].family = AF_INET6; + ++search_count; + search[search_count].host = "0.0.0.0"; + search[search_count].family = AF_INET; + ++search_count; + break; + default: + break; + } + } + else + { + // No host and not AI_PASSIVE means connect to local host. + switch (hints->ai_family) + { + case AF_INET: + search[search_count].host = "localhost"; + search[search_count].family = AF_INET; + ++search_count; + break; + case AF_INET6: + search[search_count].host = "localhost"; + search[search_count].family = AF_INET6; + ++search_count; + break; + case AF_UNSPEC: + search[search_count].host = "localhost"; + search[search_count].family = AF_INET6; + ++search_count; + search[search_count].host = "localhost"; + search[search_count].family = AF_INET; + ++search_count; + break; + default: + break; + } + } + } + else + { + // Host is specified. + switch (hints->ai_family) + { + case AF_INET: + search[search_count].host = host; + search[search_count].family = AF_INET; + ++search_count; + break; + case AF_INET6: + search[search_count].host = host; + search[search_count].family = AF_INET6; + ++search_count; + break; + case AF_UNSPEC: + search[search_count].host = host; + search[search_count].family = AF_INET6; + ++search_count; + search[search_count].host = host; + search[search_count].family = AF_INET; + ++search_count; + break; + default: + break; + } + } + return search_count; +} + +template +inline T* gai_alloc(std::size_t size = sizeof(T)) +{ + using namespace std; + T* p = static_cast(::operator new(size, std::nothrow)); + if (p) + memset(p, 0, size); + return p; +} + +inline void gai_free(void* p) +{ + ::operator delete(p); +} + +inline void gai_strcpy(char* target, const char* source, std::size_t max_size) +{ + using namespace std; +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) + strcpy_s(target, max_size, source); +#else + *target = 0; + strncat(target, source, max_size); +#endif +} + +enum { gai_clone_flag = 1 << 30 }; + +inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints, + const void* addr, int family) +{ + using namespace std; + + addrinfo_type* ai = gai_alloc(); + if (ai == 0) + return EAI_MEMORY; + + ai->ai_next = 0; + **next = ai; + *next = &ai->ai_next; + + ai->ai_canonname = 0; + ai->ai_socktype = hints->ai_socktype; + if (ai->ai_socktype == 0) + ai->ai_flags |= gai_clone_flag; + ai->ai_protocol = hints->ai_protocol; + ai->ai_family = family; + + switch (ai->ai_family) + { + case AF_INET: + { + sockaddr_in4_type* sinptr = gai_alloc(); + if (sinptr == 0) + return EAI_MEMORY; + sinptr->sin_family = AF_INET; + memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type)); + ai->ai_addr = reinterpret_cast(sinptr); + ai->ai_addrlen = sizeof(sockaddr_in4_type); + break; + } + case AF_INET6: + { + sockaddr_in6_type* sin6ptr = gai_alloc(); + if (sin6ptr == 0) + return EAI_MEMORY; + sin6ptr->sin6_family = AF_INET6; + memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type)); + ai->ai_addr = reinterpret_cast(sin6ptr); + ai->ai_addrlen = sizeof(sockaddr_in6_type); + break; + } + default: + break; + } + + return 0; +} + +inline addrinfo_type* gai_clone(addrinfo_type* ai) +{ + using namespace std; + + addrinfo_type* new_ai = gai_alloc(); + if (new_ai == 0) + return new_ai; + + new_ai->ai_next = ai->ai_next; + ai->ai_next = new_ai; + + new_ai->ai_flags = 0; + new_ai->ai_family = ai->ai_family; + new_ai->ai_socktype = ai->ai_socktype; + new_ai->ai_protocol = ai->ai_protocol; + new_ai->ai_canonname = 0; + new_ai->ai_addrlen = ai->ai_addrlen; + new_ai->ai_addr = gai_alloc(ai->ai_addrlen); + memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen); + + return new_ai; +} + +inline int gai_port(addrinfo_type* aihead, int port, int socktype) +{ + int num_found = 0; + + for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next) + { + if (ai->ai_flags & gai_clone_flag) + { + if (ai->ai_socktype != 0) + { + ai = gai_clone(ai); + if (ai == 0) + return -1; + // ai now points to newly cloned entry. + } + } + else if (ai->ai_socktype != socktype) + { + // Ignore if mismatch on socket type. + continue; + } + + ai->ai_socktype = socktype; + + switch (ai->ai_family) + { + case AF_INET: + { + sockaddr_in4_type* sinptr = + reinterpret_cast(ai->ai_addr); + sinptr->sin_port = port; + ++num_found; + break; + } + case AF_INET6: + { + sockaddr_in6_type* sin6ptr = + reinterpret_cast(ai->ai_addr); + sin6ptr->sin6_port = port; + ++num_found; + break; + } + default: + break; + } + } + + return num_found; +} + +inline int gai_serv(addrinfo_type* aihead, + const addrinfo_type* hints, const char* serv) +{ + using namespace std; + + int num_found = 0; + + if ( +#if defined(AI_NUMERICSERV) + (hints->ai_flags & AI_NUMERICSERV) || +#endif + isdigit(serv[0])) + { + int port = htons(atoi(serv)); + if (hints->ai_socktype) + { + // Caller specifies socket type. + int rc = gai_port(aihead, port, hints->ai_socktype); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + else + { + // Caller does not specify socket type. + int rc = gai_port(aihead, port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + rc = gai_port(aihead, port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + else + { + // Try service name with TCP first, then UDP. + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM) + { + servent* sptr = getservbyname(serv, "tcp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM) + { + servent* sptr = getservbyname(serv, "udp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + } + + if (num_found == 0) + { + if (hints->ai_socktype == 0) + { + // All calls to getservbyname() failed. + return EAI_NONAME; + } + else + { + // Service not supported for socket type. + return EAI_SERVICE; + } + } + + return 0; +} + +inline int gai_echeck(const char* host, const char* service, + int flags, int family, int socktype, int protocol) +{ + (void)(flags); + (void)(protocol); + + // Host or service must be specified. + if (host == 0 || host[0] == '\0') + if (service == 0 || service[0] == '\0') + return EAI_NONAME; + + // Check combination of family and socket type. + switch (family) + { + case AF_UNSPEC: + break; + case AF_INET: + case AF_INET6: + if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM) + return EAI_SOCKTYPE; + break; + default: + return EAI_FAMILY; + } + + return 0; +} + +inline void freeaddrinfo_emulation(addrinfo_type* aihead) +{ + addrinfo_type* ai = aihead; + while (ai) + { + gai_free(ai->ai_addr); + gai_free(ai->ai_canonname); + addrinfo_type* ainext = ai->ai_next; + gai_free(ai); + ai = ainext; + } +} + +inline int getaddrinfo_emulation(const char* host, const char* service, + const addrinfo_type* hintsp, addrinfo_type** result) +{ + // Set up linked list of addrinfo structures. + addrinfo_type* aihead = 0; + addrinfo_type** ainext = &aihead; + char* canon = 0; + + // Supply default hints if not specified by caller. + addrinfo_type hints = addrinfo_type(); + hints.ai_family = AF_UNSPEC; + if (hintsp) + hints = *hintsp; + + // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED + // and AI_ALL flags. +#if defined(AI_V4MAPPED) + if (hints.ai_family != AF_INET6) + hints.ai_flags &= ~AI_V4MAPPED; +#endif +#if defined(AI_ALL) + if (hints.ai_family != AF_INET6) + hints.ai_flags &= ~AI_ALL; +#endif + + // Basic error checking. + int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family, + hints.ai_socktype, hints.ai_protocol); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + + gai_search search[2]; + int search_count = gai_nsearch(host, &hints, search); + for (gai_search* sptr = search; sptr < search + search_count; ++sptr) + { + // Check for IPv4 dotted decimal string. + in4_addr_type inaddr; + boost::system::error_code ec; + if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1) + { + if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == AF_INET) + { + rc = gai_aistruct(&ainext, &hints, &inaddr, AF_INET); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Check for IPv6 hex string. + in6_addr_type in6addr; + if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1) + { + if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == AF_INET6) + { + rc = gai_aistruct(&ainext, &hints, &in6addr, AF_INET6); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Look up hostname. + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyname(sptr->host, + sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec); + if (hptr == 0) + { + if (search_count == 2) + { + // Failure is OK if there are multiple searches. + continue; + } + freeaddrinfo_emulation(aihead); + gai_free(canon); + if (ec == boost::asio::error::host_not_found) + return EAI_NONAME; + if (ec == boost::asio::error::host_not_found_try_again) + return EAI_AGAIN; + if (ec == boost::asio::error::no_recovery) + return EAI_FAIL; + if (ec == boost::asio::error::no_data) + return EAI_NONAME; + return EAI_NONAME; + } + + // Check for address family mismatch if one was specified. + if (hints.ai_family != AF_UNSPEC && hints.ai_family != hptr->h_addrtype) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + + // Save canonical name first time. + if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0] + && (hints.ai_flags & AI_CANONNAME) && canon == 0) + { + std::size_t canon_len = strlen(hptr->h_name) + 1; + canon = gai_alloc(canon_len); + if (canon == 0) + { + freeaddrinfo_emulation(aihead); + socket_ops::freehostent(hptr); + return EAI_MEMORY; + } + gai_strcpy(canon, hptr->h_name, canon_len); + } + + // Create an addrinfo structure for each returned address. + for (char** ap = hptr->h_addr_list; *ap; ++ap) + { + rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + } + + socket_ops::freehostent(hptr); + } + + // Check if we found anything. + if (aihead == 0) + { + gai_free(canon); + return EAI_NONAME; + } + + // Return canonical name in first entry. + if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME)) + { + if (canon) + { + aihead->ai_canonname = canon; + canon = 0; + } + else + { + std::size_t canonname_len = strlen(search[0].host) + 1; + aihead->ai_canonname = gai_alloc(canonname_len); + if (aihead->ai_canonname == 0) + { + freeaddrinfo_emulation(aihead); + return EAI_MEMORY; + } + gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); + } + } + gai_free(canon); + + // Process the service name. + if (service != 0 && service[0] != '\0') + { + rc = gai_serv(aihead, &hints, service); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + } + + // Return result to caller. + *result = aihead; + return 0; +} + +inline boost::system::error_code getnameinfo_emulation( + const socket_addr_type* sa, std::size_t salen, char* host, + std::size_t hostlen, char* serv, std::size_t servlen, int flags, + boost::system::error_code& ec) +{ + using namespace std; + + const char* addr; + size_t addr_len; + unsigned short port; + switch (sa->sa_family) + { + case AF_INET: + if (salen != sizeof(sockaddr_in4_type)) + { + return ec = boost::asio::error::invalid_argument; + } + addr = reinterpret_cast( + &reinterpret_cast(sa)->sin_addr); + addr_len = sizeof(in4_addr_type); + port = reinterpret_cast(sa)->sin_port; + break; + case AF_INET6: + if (salen != sizeof(sockaddr_in6_type)) + { + return ec = boost::asio::error::invalid_argument; + } + addr = reinterpret_cast( + &reinterpret_cast(sa)->sin6_addr); + addr_len = sizeof(in6_addr_type); + port = reinterpret_cast(sa)->sin6_port; + break; + default: + return ec = boost::asio::error::address_family_not_supported; + } + + if (host && hostlen > 0) + { + if (flags & NI_NUMERICHOST) + { + if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + else + { + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyaddr(addr, + static_cast(addr_len), sa->sa_family, + &hent, hbuf, sizeof(hbuf), ec); + if (hptr && hptr->h_name && hptr->h_name[0] != '\0') + { + if (flags & NI_NOFQDN) + { + char* dot = strchr(hptr->h_name, '.'); + if (dot) + { + *dot = 0; + } + } + gai_strcpy(host, hptr->h_name, hostlen); + socket_ops::freehostent(hptr); + } + else + { + socket_ops::freehostent(hptr); + if (flags & NI_NAMEREQD) + { + return ec = boost::asio::error::host_not_found; + } + if (socket_ops::inet_ntop(sa->sa_family, + addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + } + } + + if (serv && servlen > 0) + { + if (flags & NI_NUMERICSERV) + { + if (servlen < 6) + { + return ec = boost::asio::error::no_buffer_space; + } +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else + sprintf(serv, "%u", ntohs(port)); +#endif + } + else + { +#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) + static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + ::pthread_mutex_lock(&mutex); +#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) + servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0); + if (sptr && sptr->s_name && sptr->s_name[0] != '\0') + { + gai_strcpy(serv, sptr->s_name, servlen); + } + else + { + if (servlen < 6) + { + return ec = boost::asio::error::no_buffer_space; + } +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(UNDER_CE) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else + sprintf(serv, "%u", ntohs(port)); +#endif + } +#if defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) + ::pthread_mutex_unlock(&mutex); +#endif // defined(BOOST_HAS_THREADS) && defined(BOOST_HAS_PTHREADS) + } + } + + clear_error(ec); + return ec; +} + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + // || defined(__MACH__) && defined(__APPLE__) + +inline boost::system::error_code translate_addrinfo_error(int error) +{ + switch (error) + { + case 0: + return boost::system::error_code(); + case EAI_AGAIN: + return boost::asio::error::host_not_found_try_again; + case EAI_BADFLAGS: + return boost::asio::error::invalid_argument; + case EAI_FAIL: + return boost::asio::error::no_recovery; + case EAI_FAMILY: + return boost::asio::error::address_family_not_supported; + case EAI_MEMORY: + return boost::asio::error::no_memory; + case EAI_NONAME: +#if defined(EAI_ADDRFAMILY) + case EAI_ADDRFAMILY: +#endif +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) + case EAI_NODATA: +#endif + return boost::asio::error::host_not_found; + case EAI_SERVICE: + return boost::asio::error::service_not_found; + case EAI_SOCKTYPE: + return boost::asio::error::socket_type_not_supported; + default: // Possibly the non-portable EAI_SYSTEM. +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + return boost::system::error_code( + WSAGetLastError(), boost::asio::error::get_system_category()); +#else + return boost::system::error_code( + errno, boost::asio::error::get_system_category()); +#endif + } +} + +inline boost::system::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type* hints, addrinfo_type** result, + boost::system::error_code& ec) +{ + clear_error(ec); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) + // Building for Windows XP, Windows Server 2003, or later. + int error = ::getaddrinfo(host, service, hints, result); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gai_t)(const char*, + const char*, const addrinfo_type*, addrinfo_type**); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo")) + { + int error = gai(host, service, hints, result); + return ec = translate_addrinfo_error(error); + } + } + int error = getaddrinfo_emulation(host, service, hints, result); + return ec = translate_addrinfo_error(error); +# endif +#elif defined(__MACH__) && defined(__APPLE__) + int error = getaddrinfo_emulation(host, service, hints, result); + return ec = translate_addrinfo_error(error); +#else + int error = ::getaddrinfo(host, service, hints, result); + return ec = translate_addrinfo_error(error); +#endif +} + +inline void freeaddrinfo(addrinfo_type* ai) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) + // Building for Windows XP, Windows Server 2003, or later. + ::freeaddrinfo(ai); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *fai_t)(addrinfo_type*); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo")) + { + fai(ai); + return; + } + } + freeaddrinfo_emulation(ai); +# endif +#elif defined(__MACH__) && defined(__APPLE__) + freeaddrinfo_emulation(ai); +#else + ::freeaddrinfo(ai); +#endif +} + +inline boost::system::error_code getnameinfo(const socket_addr_type* addr, + std::size_t addrlen, char* host, std::size_t hostlen, + char* serv, std::size_t servlen, int flags, boost::system::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) + // Building for Windows XP, Windows Server 2003, or later. + clear_error(ec); + int error = ::getnameinfo(addr, static_cast(addrlen), + host, static_cast(hostlen), + serv, static_cast(servlen), flags); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gni_t)(const socket_addr_type*, + int, char*, DWORD, char*, DWORD, int); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) + { + clear_error(ec); + int error = gni(addr, static_cast(addrlen), + host, static_cast(hostlen), + serv, static_cast(servlen), flags); + return ec = translate_addrinfo_error(error); + } + } + clear_error(ec); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +# endif +#elif defined(__MACH__) && defined(__APPLE__) + using namespace std; // For memcpy. + sockaddr_storage_type tmp_addr; + memcpy(&tmp_addr, addr, addrlen); + tmp_addr.ss_len = addrlen; + addr = reinterpret_cast(&tmp_addr); + clear_error(ec); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +#else + clear_error(ec); + int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); + return ec = translate_addrinfo_error(error); +#endif +} + +inline u_long_type network_to_host_long(u_long_type value) +{ + return ntohl(value); +} + +inline u_long_type host_to_network_long(u_long_type value) +{ + return htonl(value); +} + +inline u_short_type network_to_host_short(u_short_type value) +{ + return ntohs(value); +} + +inline u_short_type host_to_network_short(u_short_type value) +{ + return htons(value); +} + +} // namespace socket_ops +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SOCKET_OPS_HPP diff --git a/3rdParty/Boost/boost/asio/detail/socket_option.hpp b/3rdParty/Boost/boost/asio/detail/socket_option.hpp new file mode 100644 index 0000000..c0d7b74 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/socket_option.hpp @@ -0,0 +1,311 @@ +// +// socket_option.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SOCKET_OPTION_HPP +#define BOOST_ASIO_DETAIL_SOCKET_OPTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { +namespace socket_option { + +// Helper template for implementing boolean-based options. +template +class boolean +{ +public: + // Default constructor. + boolean() + : value_(0) + { + } + + // Construct with a specific option value. + explicit boolean(bool v) + : value_(v ? 1 : 0) + { + } + + // Set the current value of the boolean. + boolean& operator=(bool v) + { + value_ = v ? 1 : 0; + return *this; + } + + // Get the current value of the boolean. + bool value() const + { + return !!value_; + } + + // Convert to bool. + operator bool() const + { + return !!value_; + } + + // Test for false. + bool operator!() const + { + return !value_; + } + + // Get the level of the socket option. + template + int level(const Protocol&) const + { + return Level; + } + + // Get the name of the socket option. + template + int name(const Protocol&) const + { + return Name; + } + + // Get the address of the boolean data. + template + int* data(const Protocol&) + { + return &value_; + } + + // Get the address of the boolean data. + template + const int* data(const Protocol&) const + { + return &value_; + } + + // Get the size of the boolean data. + template + std::size_t size(const Protocol&) const + { + return sizeof(value_); + } + + // Set the size of the boolean data. + template + void resize(const Protocol&, std::size_t s) + { + // On some platforms (e.g. Windows Vista), the getsockopt function will + // return the size of a boolean socket option as one byte, even though a + // four byte integer was passed in. + switch (s) + { + case sizeof(char): + value_ = *reinterpret_cast(&value_) ? 1 : 0; + break; + case sizeof(value_): + break; + default: + throw std::length_error("boolean socket option resize"); + } + } + +private: + int value_; +}; + +// Helper template for implementing integer options. +template +class integer +{ +public: + // Default constructor. + integer() + : value_(0) + { + } + + // Construct with a specific option value. + explicit integer(int v) + : value_(v) + { + } + + // Set the value of the int option. + integer& operator=(int v) + { + value_ = v; + return *this; + } + + // Get the current value of the int option. + int value() const + { + return value_; + } + + // Get the level of the socket option. + template + int level(const Protocol&) const + { + return Level; + } + + // Get the name of the socket option. + template + int name(const Protocol&) const + { + return Name; + } + + // Get the address of the int data. + template + int* data(const Protocol&) + { + return &value_; + } + + // Get the address of the int data. + template + const int* data(const Protocol&) const + { + return &value_; + } + + // Get the size of the int data. + template + std::size_t size(const Protocol&) const + { + return sizeof(value_); + } + + // Set the size of the int data. + template + void resize(const Protocol&, std::size_t s) + { + if (s != sizeof(value_)) + throw std::length_error("integer socket option resize"); + } + +private: + int value_; +}; + +// Helper template for implementing linger options. +template +class linger +{ +public: + // Default constructor. + linger() + { + value_.l_onoff = 0; + value_.l_linger = 0; + } + + // Construct with specific option values. + linger(bool e, int t) + { + enabled(e); + timeout BOOST_PREVENT_MACRO_SUBSTITUTION(t); + } + + // Set the value for whether linger is enabled. + void enabled(bool value) + { + value_.l_onoff = value ? 1 : 0; + } + + // Get the value for whether linger is enabled. + bool enabled() const + { + return value_.l_onoff != 0; + } + + // Set the value for the linger timeout. + void timeout BOOST_PREVENT_MACRO_SUBSTITUTION(int value) + { +#if defined(WIN32) + value_.l_linger = static_cast(value); +#else + value_.l_linger = value; +#endif + } + + // Get the value for the linger timeout. + int timeout BOOST_PREVENT_MACRO_SUBSTITUTION() const + { + return static_cast(value_.l_linger); + } + + // Get the level of the socket option. + template + int level(const Protocol&) const + { + return Level; + } + + // Get the name of the socket option. + template + int name(const Protocol&) const + { + return Name; + } + + // Get the address of the linger data. + template + ::linger* data(const Protocol&) + { + return &value_; + } + + // Get the address of the linger data. + template + const ::linger* data(const Protocol&) const + { + return &value_; + } + + // Get the size of the linger data. + template + std::size_t size(const Protocol&) const + { + return sizeof(value_); + } + + // Set the size of the int data. + template + void resize(const Protocol&, std::size_t s) + { + if (s != sizeof(value_)) + throw std::length_error("linger socket option resize"); + } + +private: + ::linger value_; +}; + +} // namespace socket_option +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SOCKET_OPTION_HPP diff --git a/3rdParty/Boost/boost/asio/detail/socket_select_interrupter.hpp b/3rdParty/Boost/boost/asio/detail/socket_select_interrupter.hpp new file mode 100644 index 0000000..a767ba0 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/socket_select_interrupter.hpp @@ -0,0 +1,189 @@ +// +// socket_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SOCKET_SELECT_INTERRUPTER_HPP +#define BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class socket_select_interrupter +{ +public: + // Constructor. + socket_select_interrupter() + { + boost::system::error_code ec; + socket_holder acceptor(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (acceptor.get() == invalid_socket) + { + boost::system::system_error e(ec, "socket_select_interrupter"); + boost::throw_exception(e); + } + + int opt = 1; + socket_ops::setsockopt(acceptor.get(), + SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec); + + using namespace std; // For memset. + sockaddr_in4_type addr; + std::size_t addr_len = sizeof(addr); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + addr.sin_port = 0; + if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + { + boost::system::system_error e(ec, "socket_select_interrupter"); + boost::throw_exception(e); + } + + if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr, + &addr_len, ec) == socket_error_retval) + { + boost::system::system_error e(ec, "socket_select_interrupter"); + boost::throw_exception(e); + } + + if (socket_ops::listen(acceptor.get(), + SOMAXCONN, ec) == socket_error_retval) + { + boost::system::system_error e(ec, "socket_select_interrupter"); + boost::throw_exception(e); + } + + socket_holder client(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (client.get() == invalid_socket) + { + boost::system::system_error e(ec, "socket_select_interrupter"); + boost::throw_exception(e); + } + + if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + { + boost::system::system_error e(ec, "socket_select_interrupter"); + boost::throw_exception(e); + } + + socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec)); + if (server.get() == invalid_socket) + { + boost::system::system_error e(ec, "socket_select_interrupter"); + boost::throw_exception(e); + } + + ioctl_arg_type non_blocking = 1; + if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec)) + { + boost::system::system_error e(ec, "socket_select_interrupter"); + boost::throw_exception(e); + } + + opt = 1; + socket_ops::setsockopt(client.get(), + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + non_blocking = 1; + if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec)) + { + boost::system::system_error e(ec, "socket_select_interrupter"); + boost::throw_exception(e); + } + + opt = 1; + socket_ops::setsockopt(server.get(), + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + read_descriptor_ = server.release(); + write_descriptor_ = client.release(); + } + + // Destructor. + ~socket_select_interrupter() + { + boost::system::error_code ec; + if (read_descriptor_ != invalid_socket) + socket_ops::close(read_descriptor_, ec); + if (write_descriptor_ != invalid_socket) + socket_ops::close(write_descriptor_, ec); + } + + // Interrupt the select call. + void interrupt() + { + char byte = 0; + socket_ops::buf b; + socket_ops::init_buf(b, &byte, 1); + boost::system::error_code ec; + socket_ops::send(write_descriptor_, &b, 1, 0, ec); + } + + // Reset the select interrupt. Returns true if the call was interrupted. + bool reset() + { + char data[1024]; + socket_ops::buf b; + socket_ops::init_buf(b, data, sizeof(data)); + boost::system::error_code ec; + int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + return was_interrupted; + } + + // Get the read descriptor to be passed to select. + socket_type read_descriptor() const + { + return read_descriptor_; + } + +private: + // The read end of a connection used to interrupt the select call. This file + // descriptor is passed to select such that when it is time to stop, a single + // byte will be written on the other end of the connection and this + // descriptor will become readable. + socket_type read_descriptor_; + + // The write end of a connection used to interrupt the select call. A single + // byte may be written to this to wake up the select which is waiting for the + // other end to become readable. + socket_type write_descriptor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP diff --git a/3rdParty/Boost/boost/asio/detail/socket_types.hpp b/3rdParty/Boost/boost/asio/detail/socket_types.hpp new file mode 100644 index 0000000..c7b6a75 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/socket_types.hpp @@ -0,0 +1,212 @@ +// +// socket_types.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_SOCKET_TYPES_HPP +#define BOOST_ASIO_DETAIL_SOCKET_TYPES_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#include +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) +# error WinSock.h has already been included +# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) +# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) || defined(__BORLANDC__) +# pragma message( \ + "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ + "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ + "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ + "Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target).") +# else // defined(_MSC_VER) || defined(__BORLANDC__) +# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. +# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. +# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +# define _WIN32_WINNT 0x0501 +# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) +# if defined(_WIN32) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(_WIN32) && !defined(WIN32) +# endif // defined(_MSC_VER) +# if defined(__BORLANDC__) +# include // Needed for __errno +# if defined(__WIN32__) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(__WIN32__) && !defined(WIN32) +# if !defined(_WSPIAPI_H_) +# define _WSPIAPI_H_ +# define BOOST_ASIO_WSPIAPI_H_DEFINED +# endif // !defined(_WSPIAPI_H_) +# endif // defined(__BORLANDC__) +# if !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif // !defined(WIN32_LEAN_AND_MEAN) +# endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +# if defined(__CYGWIN__) +# if !defined(__USE_W32_SOCKETS) +# error You must add -D__USE_W32_SOCKETS to your compiler options. +# endif // !defined(__USE_W32_SOCKETS) +# if !defined(NOMINMAX) +# define NOMINMAX 1 +# endif // !defined(NOMINMAX) +# endif // defined(__CYGWIN__) +# include +# include +# include +# if defined(BOOST_ASIO_WSPIAPI_H_DEFINED) +# undef _WSPIAPI_H_ +# undef BOOST_ASIO_WSPIAPI_H_DEFINED +# endif // defined(BOOST_ASIO_WSPIAPI_H_DEFINED) +# if !defined(BOOST_ASIO_NO_DEFAULT_LINKED_LIBS) +# if defined(UNDER_CE) +# pragma comment(lib, "ws2.lib") +# elif defined(_MSC_VER) || defined(__BORLANDC__) +# pragma comment(lib, "ws2_32.lib") +# pragma comment(lib, "mswsock.lib") +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +# endif // !defined(BOOST_ASIO_NO_DEFAULT_LINKED_LIBS) +# include +#else +# include +# include +# include +# if defined(__hpux) && !defined(__HP_aCC) +# include +# else +# include +# endif +# include +# include +# include +# include +# include +# include +# include +# include +# include +# if defined(__sun) +# include +# include +# endif +#endif +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +typedef SOCKET socket_type; +const SOCKET invalid_socket = INVALID_SOCKET; +const int socket_error_retval = SOCKET_ERROR; +const int max_addr_v4_str_len = 256; +const int max_addr_v6_str_len = 256; +typedef sockaddr socket_addr_type; +typedef in_addr in4_addr_type; +typedef ip_mreq in4_mreq_type; +typedef sockaddr_in sockaddr_in4_type; +# if defined(BOOST_ASIO_HAS_OLD_WIN_SDK) +typedef in6_addr_emulation in6_addr_type; +typedef ipv6_mreq_emulation in6_mreq_type; +typedef sockaddr_in6_emulation sockaddr_in6_type; +typedef sockaddr_storage_emulation sockaddr_storage_type; +typedef addrinfo_emulation addrinfo_type; +# else +typedef in6_addr in6_addr_type; +typedef ipv6_mreq in6_mreq_type; +typedef sockaddr_in6 sockaddr_in6_type; +typedef sockaddr_storage sockaddr_storage_type; +typedef addrinfo addrinfo_type; +# endif +typedef unsigned long ioctl_arg_type; +typedef u_long u_long_type; +typedef u_short u_short_type; +const int shutdown_receive = SD_RECEIVE; +const int shutdown_send = SD_SEND; +const int shutdown_both = SD_BOTH; +const int message_peek = MSG_PEEK; +const int message_out_of_band = MSG_OOB; +const int message_do_not_route = MSG_DONTROUTE; +# if defined (_WIN32_WINNT) +const int max_iov_len = 64; +# else +const int max_iov_len = 16; +# endif +#else +typedef int socket_type; +const int invalid_socket = -1; +const int socket_error_retval = -1; +const int max_addr_v4_str_len = INET_ADDRSTRLEN; +const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; +typedef sockaddr socket_addr_type; +typedef in_addr in4_addr_type; +# if defined(__hpux) +// HP-UX doesn't provide ip_mreq when _XOPEN_SOURCE_EXTENDED is defined. +struct in4_mreq_type +{ + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; +# else +typedef ip_mreq in4_mreq_type; +# endif +typedef sockaddr_in sockaddr_in4_type; +typedef in6_addr in6_addr_type; +typedef ipv6_mreq in6_mreq_type; +typedef sockaddr_in6 sockaddr_in6_type; +typedef sockaddr_storage sockaddr_storage_type; +typedef sockaddr_un sockaddr_un_type; +typedef addrinfo addrinfo_type; +typedef int ioctl_arg_type; +typedef uint32_t u_long_type; +typedef uint16_t u_short_type; +const int shutdown_receive = SHUT_RD; +const int shutdown_send = SHUT_WR; +const int shutdown_both = SHUT_RDWR; +const int message_peek = MSG_PEEK; +const int message_out_of_band = MSG_OOB; +const int message_do_not_route = MSG_DONTROUTE; +# if defined(IOV_MAX) +const int max_iov_len = IOV_MAX; +# else +// POSIX platforms are not required to define IOV_MAX. +const int max_iov_len = 16; +# endif +#endif +const int custom_socket_option_level = 0xA5100000; +const int enable_connection_aborted_option = 1; +const int always_fail_option = 2; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SOCKET_TYPES_HPP diff --git a/3rdParty/Boost/boost/asio/detail/strand_service.hpp b/3rdParty/Boost/boost/asio/detail/strand_service.hpp new file mode 100644 index 0000000..2c89a61 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/strand_service.hpp @@ -0,0 +1,532 @@ +// +// strand_service.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_STRAND_SERVICE_HPP +#define BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +// Default service implementation for a strand. +class strand_service + : public boost::asio::detail::service_base +{ +public: + class handler_base; + class invoke_current_handler; + class post_next_waiter_on_exit; + + // The underlying implementation of a strand. + class strand_impl + { +#if defined (__BORLANDC__) + public: +#else + private: +#endif + void add_ref() + { + ++ref_count_; + } + + void release() + { + if (--ref_count_ == 0) + delete this; + } + + private: + // Only this service will have access to the internal values. + friend class strand_service; + friend class post_next_waiter_on_exit; + friend class invoke_current_handler; + + strand_impl(strand_service& owner) + : owner_(owner), + current_handler_(0), + first_waiter_(0), + last_waiter_(0), + ref_count_(0) + { + // Insert implementation into linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(owner_.mutex_); + next_ = owner_.impl_list_; + prev_ = 0; + if (owner_.impl_list_) + owner_.impl_list_->prev_ = this; + owner_.impl_list_ = this; + } + + ~strand_impl() + { + // Remove implementation from linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(owner_.mutex_); + if (owner_.impl_list_ == this) + owner_.impl_list_ = next_; + if (prev_) + prev_->next_ = next_; + if (next_) + next_->prev_= prev_; + next_ = 0; + prev_ = 0; + lock.unlock(); + + if (current_handler_) + { + current_handler_->destroy(); + } + + while (first_waiter_) + { + handler_base* next = first_waiter_->next_; + first_waiter_->destroy(); + first_waiter_ = next; + } + } + + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // The service that owns this implementation. + strand_service& owner_; + + // The handler that is ready to execute. If this pointer is non-null then it + // indicates that a handler holds the lock. + handler_base* current_handler_; + + // The start of the list of waiting handlers for the strand. + handler_base* first_waiter_; + + // The end of the list of waiting handlers for the strand. + handler_base* last_waiter_; + + // Storage for posted handlers. + typedef boost::aligned_storage<128> handler_storage_type; +#if defined(__BORLANDC__) + boost::aligned_storage<128> handler_storage_; +#else + handler_storage_type handler_storage_; +#endif + + // Pointers to adjacent socket implementations in linked list. + strand_impl* next_; + strand_impl* prev_; + + // The reference count on the strand implementation. + boost::detail::atomic_count ref_count_; + +#if !defined(__BORLANDC__) + friend void intrusive_ptr_add_ref(strand_impl* p) + { + p->add_ref(); + } + + friend void intrusive_ptr_release(strand_impl* p) + { + p->release(); + } +#endif + }; + + friend class strand_impl; + + typedef boost::intrusive_ptr implementation_type; + + // Base class for all handler types. + class handler_base + { + public: + typedef void (*invoke_func_type)(handler_base*, + strand_service&, implementation_type&); + typedef void (*destroy_func_type)(handler_base*); + + handler_base(invoke_func_type invoke_func, destroy_func_type destroy_func) + : next_(0), + invoke_func_(invoke_func), + destroy_func_(destroy_func) + { + } + + void invoke(strand_service& service_impl, implementation_type& impl) + { + invoke_func_(this, service_impl, impl); + } + + void destroy() + { + destroy_func_(this); + } + + protected: + ~handler_base() + { + } + + private: + friend class strand_service; + friend class strand_impl; + friend class post_next_waiter_on_exit; + handler_base* next_; + invoke_func_type invoke_func_; + destroy_func_type destroy_func_; + }; + + // Helper class to allow handlers to be dispatched. + class invoke_current_handler + { + public: + invoke_current_handler(strand_service& service_impl, + const implementation_type& impl) + : service_impl_(service_impl), + impl_(impl) + { + } + + void operator()() + { + impl_->current_handler_->invoke(service_impl_, impl_); + } + + friend void* asio_handler_allocate(std::size_t size, + invoke_current_handler* this_handler) + { + return this_handler->do_handler_allocate(size); + } + + friend void asio_handler_deallocate(void*, std::size_t, + invoke_current_handler*) + { + } + + void* do_handler_allocate(std::size_t size) + { +#if defined(__BORLANDC__) + BOOST_ASSERT(size <= boost::aligned_storage<128>::size); +#else + BOOST_ASSERT(size <= strand_impl::handler_storage_type::size); +#endif + (void)size; + return impl_->handler_storage_.address(); + } + + // The asio_handler_invoke hook is not defined here since the default one + // provides the correct behaviour, and including it here breaks MSVC 7.1 + // in some situations. + + private: + strand_service& service_impl_; + implementation_type impl_; + }; + + // Helper class to automatically enqueue next waiter on block exit. + class post_next_waiter_on_exit + { + public: + post_next_waiter_on_exit(strand_service& service_impl, + implementation_type& impl) + : service_impl_(service_impl), + impl_(impl), + cancelled_(false) + { + } + + ~post_next_waiter_on_exit() + { + if (!cancelled_) + { + boost::asio::detail::mutex::scoped_lock lock(impl_->mutex_); + impl_->current_handler_ = impl_->first_waiter_; + if (impl_->current_handler_) + { + impl_->first_waiter_ = impl_->first_waiter_->next_; + if (impl_->first_waiter_ == 0) + impl_->last_waiter_ = 0; + lock.unlock(); + service_impl_.get_io_service().post( + invoke_current_handler(service_impl_, impl_)); + } + } + } + + void cancel() + { + cancelled_ = true; + } + + private: + strand_service& service_impl_; + implementation_type& impl_; + bool cancelled_; + }; + + // Class template for a waiter. + template + class handler_wrapper + : public handler_base + { + public: + handler_wrapper(Handler handler) + : handler_base(&handler_wrapper::do_invoke, + &handler_wrapper::do_destroy), + handler_(handler) + { + } + + static void do_invoke(handler_base* base, + strand_service& service_impl, implementation_type& impl) + { + // Take ownership of the handler object. + typedef handler_wrapper this_type; + this_type* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + + post_next_waiter_on_exit p1(service_impl, impl); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. + Handler handler(h->handler_); + + // A handler object must still be valid when the next waiter is posted + // since destroying the last handler might cause the strand object to be + // destroyed. Therefore we create a second post_next_waiter_on_exit object + // that will be destroyed before the handler object. + p1.cancel(); + post_next_waiter_on_exit p2(service_impl, impl); + + // Free the memory associated with the handler. + ptr.reset(); + + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl.get()); + + // Make the upcall. + boost_asio_handler_invoke_helpers::invoke(handler, &handler); + } + + static void do_destroy(handler_base* base) + { + // Take ownership of the handler object. + typedef handler_wrapper this_type; + this_type* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + + // A sub-object of the handler may be the true owner of the memory + // associated with the handler. Consequently, a local copy of the handler + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + Handler handler(h->handler_); + (void)handler; + + // Free the memory associated with the handler. + ptr.reset(); + } + + private: + Handler handler_; + }; + + // Construct a new strand service for the specified io_service. + explicit strand_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + mutex_(), + impl_list_(0) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + // Construct a list of all handlers to be destroyed. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + strand_impl* impl = impl_list_; + handler_base* first_handler = 0; + while (impl) + { + if (impl->current_handler_) + { + impl->current_handler_->next_ = first_handler; + first_handler = impl->current_handler_; + impl->current_handler_ = 0; + } + if (impl->first_waiter_) + { + impl->last_waiter_->next_ = first_handler; + first_handler = impl->first_waiter_; + impl->first_waiter_ = 0; + impl->last_waiter_ = 0; + } + impl = impl->next_; + } + + // Destroy all handlers without holding the lock. + lock.unlock(); + while (first_handler) + { + handler_base* next = first_handler->next_; + first_handler->destroy(); + first_handler = next; + } + } + + // Construct a new strand implementation. + void construct(implementation_type& impl) + { + impl = implementation_type(new strand_impl(*this)); + } + + // Destroy a strand implementation. + void destroy(implementation_type& impl) + { + implementation_type().swap(impl); + } + + // Request the io_service to invoke the given handler. + template + void dispatch(implementation_type& impl, Handler handler) + { + if (call_stack::contains(impl.get())) + { + boost_asio_handler_invoke_helpers::invoke(handler, &handler); + } + else + { + // Allocate and construct an object to wrap the handler. + typedef handler_wrapper value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + boost::asio::detail::mutex::scoped_lock lock(impl->mutex_); + + if (impl->current_handler_ == 0) + { + // This handler now has the lock, so can be dispatched immediately. + impl->current_handler_ = ptr.release(); + lock.unlock(); + this->get_io_service().dispatch(invoke_current_handler(*this, impl)); + } + else + { + // Another handler already holds the lock, so this handler must join + // the list of waiters. The handler will be posted automatically when + // its turn comes. + if (impl->last_waiter_) + { + impl->last_waiter_->next_ = ptr.get(); + impl->last_waiter_ = impl->last_waiter_->next_; + } + else + { + impl->first_waiter_ = ptr.get(); + impl->last_waiter_ = ptr.get(); + } + ptr.release(); + } + } + } + + // Request the io_service to invoke the given handler and return immediately. + template + void post(implementation_type& impl, Handler handler) + { + // Allocate and construct an object to wrap the handler. + typedef handler_wrapper value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(handler); + handler_ptr ptr(raw_ptr, handler); + + boost::asio::detail::mutex::scoped_lock lock(impl->mutex_); + + if (impl->current_handler_ == 0) + { + // This handler now has the lock, so can be dispatched immediately. + impl->current_handler_ = ptr.release(); + lock.unlock(); + this->get_io_service().post(invoke_current_handler(*this, impl)); + } + else + { + // Another handler already holds the lock, so this handler must join the + // list of waiters. The handler will be posted automatically when its turn + // comes. + if (impl->last_waiter_) + { + impl->last_waiter_->next_ = ptr.get(); + impl->last_waiter_ = impl->last_waiter_->next_; + } + else + { + impl->first_waiter_ = ptr.get(); + impl->last_waiter_ = ptr.get(); + } + ptr.release(); + } + } + +private: + // Mutex to protect access to the linked list of implementations. + boost::asio::detail::mutex mutex_; + + // The head of a linked list of all implementations. + strand_impl* impl_list_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#if defined(__BORLANDC__) + +namespace boost { + +inline void intrusive_ptr_add_ref( + boost::asio::detail::strand_service::strand_impl* p) +{ + p->add_ref(); +} + +inline void intrusive_ptr_release( + boost::asio::detail::strand_service::strand_impl* p) +{ + p->release(); +} + +} // namespace boost + +#endif // defined(__BORLANDC__) + +#include + +#endif // BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/task_io_service.hpp b/3rdParty/Boost/boost/asio/detail/task_io_service.hpp new file mode 100644 index 0000000..eeae6b0 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/task_io_service.hpp @@ -0,0 +1,438 @@ +// +// task_io_service.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_TASK_IO_SERVICE_HPP +#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE) +#include +#else // defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE) + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class task_io_service + : public boost::asio::detail::service_base > +{ +public: + // Constructor. + task_io_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base >(io_service), + mutex_(), + task_(0), + task_interrupted_(true), + outstanding_work_(0), + stopped_(false), + shutdown_(false), + first_idle_thread_(0) + { + } + + void init(size_t /*concurrency_hint*/) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + // Destroy handler objects. + while (!handler_queue_.empty()) + { + handler_queue::handler* h = handler_queue_.front(); + handler_queue_.pop(); + if (h != &task_handler_) + h->destroy(); + } + + // Reset to initial state. + task_ = 0; + } + + // Initialise the task, if required. + void init_task() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_ && !task_) + { + task_ = &use_service(this->get_io_service()); + handler_queue_.push(&task_handler_); + interrupt_one_idle_thread(lock); + } + } + + // Run the event loop until interrupted or no more work. + size_t run(boost::system::error_code& ec) + { + typename call_stack::context ctx(this); + + idle_thread_info this_idle_thread; + this_idle_thread.next = 0; + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + size_t n = 0; + while (do_one(lock, &this_idle_thread, ec)) + if (n != (std::numeric_limits::max)()) + ++n; + return n; + } + + // Run until interrupted or one operation is performed. + size_t run_one(boost::system::error_code& ec) + { + typename call_stack::context ctx(this); + + idle_thread_info this_idle_thread; + this_idle_thread.next = 0; + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + return do_one(lock, &this_idle_thread, ec); + } + + // Poll for operations without blocking. + size_t poll(boost::system::error_code& ec) + { + typename call_stack::context ctx(this); + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + size_t n = 0; + while (do_one(lock, 0, ec)) + if (n != (std::numeric_limits::max)()) + ++n; + return n; + } + + // Poll for one operation without blocking. + size_t poll_one(boost::system::error_code& ec) + { + typename call_stack::context ctx(this); + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + return do_one(lock, 0, ec); + } + + // Interrupt the event processing loop. + void stop() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + stop_all_threads(lock); + } + + // Reset in preparation for a subsequent run invocation. + void reset() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + stopped_ = false; + } + + // Notify that some work has started. + void work_started() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + ++outstanding_work_; + } + + // Notify that some work has finished. + void work_finished() + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (--outstanding_work_ == 0) + stop_all_threads(lock); + } + + // Request invocation of the given handler. + template + void dispatch(Handler handler) + { + if (call_stack::contains(this)) + boost_asio_handler_invoke_helpers::invoke(handler, &handler); + else + post(handler); + } + + // Request invocation of the given handler and return immediately. + template + void post(Handler handler) + { + // Allocate and construct an operation to wrap the handler. + handler_queue::scoped_ptr ptr(handler_queue::wrap(handler)); + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // If the service has been shut down we silently discard the handler. + if (shutdown_) + return; + + // Add the handler to the end of the queue. + handler_queue_.push(ptr.get()); + ptr.release(); + + // An undelivered handler is treated as unfinished work. + ++outstanding_work_; + + // Wake up a thread to execute the handler. + if (!interrupt_one_idle_thread(lock)) + { + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } + } + } + +private: + struct idle_thread_info; + + size_t do_one(boost::asio::detail::mutex::scoped_lock& lock, + idle_thread_info* this_idle_thread, boost::system::error_code& ec) + { + if (outstanding_work_ == 0 && !stopped_) + { + stop_all_threads(lock); + ec = boost::system::error_code(); + return 0; + } + + bool polling = !this_idle_thread; + bool task_has_run = false; + while (!stopped_) + { + if (!handler_queue_.empty()) + { + // Prepare to execute first handler from queue. + handler_queue::handler* h = handler_queue_.front(); + handler_queue_.pop(); + + if (h == &task_handler_) + { + bool more_handlers = (!handler_queue_.empty()); + task_interrupted_ = more_handlers || polling; + + // If the task has already run and we're polling then we're done. + if (task_has_run && polling) + { + task_interrupted_ = true; + handler_queue_.push(&task_handler_); + ec = boost::system::error_code(); + return 0; + } + task_has_run = true; + + lock.unlock(); + task_cleanup c(lock, *this); + + // Run the task. May throw an exception. Only block if the handler + // queue is empty and we have an idle_thread_info object, otherwise + // we want to return as soon as possible. + task_->run(!more_handlers && !polling); + } + else + { + lock.unlock(); + handler_cleanup c(lock, *this); + + // Invoke the handler. May throw an exception. + h->invoke(); // invoke() deletes the handler object + + ec = boost::system::error_code(); + return 1; + } + } + else if (this_idle_thread) + { + // Nothing to run right now, so just wait for work to do. + this_idle_thread->next = first_idle_thread_; + first_idle_thread_ = this_idle_thread; + this_idle_thread->wakeup_event.clear(lock); + this_idle_thread->wakeup_event.wait(lock); + } + else + { + ec = boost::system::error_code(); + return 0; + } + } + + ec = boost::system::error_code(); + return 0; + } + + // Stop the task and all idle threads. + void stop_all_threads( + boost::asio::detail::mutex::scoped_lock& lock) + { + stopped_ = true; + interrupt_all_idle_threads(lock); + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } + } + + // Interrupt a single idle thread. Returns true if a thread was interrupted, + // false if no running thread could be found to interrupt. + bool interrupt_one_idle_thread( + boost::asio::detail::mutex::scoped_lock& lock) + { + if (first_idle_thread_) + { + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal(lock); + return true; + } + return false; + } + + // Interrupt all idle threads. + void interrupt_all_idle_threads( + boost::asio::detail::mutex::scoped_lock& lock) + { + while (first_idle_thread_) + { + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal(lock); + } + } + + // Helper class to perform task-related operations on block exit. + class task_cleanup; + friend class task_cleanup; + class task_cleanup + { + public: + task_cleanup(boost::asio::detail::mutex::scoped_lock& lock, + task_io_service& task_io_svc) + : lock_(lock), + task_io_service_(task_io_svc) + { + } + + ~task_cleanup() + { + // Reinsert the task at the end of the handler queue. + lock_.lock(); + task_io_service_.task_interrupted_ = true; + task_io_service_.handler_queue_.push(&task_io_service_.task_handler_); + } + + private: + boost::asio::detail::mutex::scoped_lock& lock_; + task_io_service& task_io_service_; + }; + + // Helper class to perform handler-related operations on block exit. + class handler_cleanup; + friend class handler_cleanup; + class handler_cleanup + { + public: + handler_cleanup(boost::asio::detail::mutex::scoped_lock& lock, + task_io_service& task_io_svc) + : lock_(lock), + task_io_service_(task_io_svc) + { + } + + ~handler_cleanup() + { + lock_.lock(); + if (--task_io_service_.outstanding_work_ == 0) + task_io_service_.stop_all_threads(lock_); + } + + private: + boost::asio::detail::mutex::scoped_lock& lock_; + task_io_service& task_io_service_; + }; + + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // The task to be run by this service. + Task* task_; + + // Handler object to represent the position of the task in the queue. + class task_handler + : public handler_queue::handler + { + public: + task_handler() + : handler_queue::handler(0, 0) + { + } + } task_handler_; + + // Whether the task has been interrupted. + bool task_interrupted_; + + // The count of unfinished work. + int outstanding_work_; + + // The queue of handlers that are ready to be delivered. + handler_queue handler_queue_; + + // Flag to indicate that the dispatcher has been stopped. + bool stopped_; + + // Flag to indicate that the dispatcher has been shut down. + bool shutdown_; + + // Structure containing information about an idle thread. + struct idle_thread_info + { + event wakeup_event; + idle_thread_info* next; + }; + + // The number of threads that are currently idle. + idle_thread_info* first_idle_thread_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include +#include + +#endif // defined(BOOST_ASIO_ENABLE_TWO_LOCK_QUEUE) + +#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/task_io_service_2lock.hpp b/3rdParty/Boost/boost/asio/detail/task_io_service_2lock.hpp new file mode 100644 index 0000000..bd406cb --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/task_io_service_2lock.hpp @@ -0,0 +1,475 @@ +// +// task_io_service_2lock.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_TASK_IO_SERVICE_2LOCK_HPP +#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +// An alternative task_io_service implementation based on a two-lock queue. + +template +class task_io_service + : public boost::asio::detail::service_base > +{ +public: + typedef indirect_handler_queue handler_queue; + + // Constructor. + task_io_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base >(io_service), + front_mutex_(), + back_mutex_(), + task_(&use_service(io_service)), + outstanding_work_(0), + front_stopped_(false), + back_stopped_(false), + back_shutdown_(false), + back_first_idle_thread_(0), + back_task_thread_(0) + { + } + + void init(size_t /*concurrency_hint*/) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); + back_shutdown_ = true; + back_lock.unlock(); + + // Destroy handler objects. + while (handler_queue::handler* h = handler_queue_.pop()) + if (h != &task_handler_) + h->destroy(); + + // Reset to initial state. + task_ = 0; + } + + // Initialise the task, if required. + void init_task() + { + boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); + if (!back_shutdown_ && !task_) + { + task_ = &use_service(this->get_io_service()); + handler_queue_.push(&task_handler_); + interrupt_one_idle_thread(back_lock); + } + } + + // Run the event loop until interrupted or no more work. + size_t run(boost::system::error_code& ec) + { + if (outstanding_work_ == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + typename call_stack::context ctx(this); + + idle_thread_info this_idle_thread; + this_idle_thread.next = 0; + + size_t n = 0; + while (do_one(&this_idle_thread, ec)) + if (n != (std::numeric_limits::max)()) + ++n; + return n; + } + + // Run until interrupted or one operation is performed. + size_t run_one(boost::system::error_code& ec) + { + if (outstanding_work_ == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + typename call_stack::context ctx(this); + + idle_thread_info this_idle_thread; + this_idle_thread.next = 0; + + return do_one(&this_idle_thread, ec); + } + + // Poll for operations without blocking. + size_t poll(boost::system::error_code& ec) + { + if (outstanding_work_ == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + typename call_stack::context ctx(this); + + size_t n = 0; + while (do_one(0, ec)) + if (n != (std::numeric_limits::max)()) + ++n; + return n; + } + + // Poll for one operation without blocking. + size_t poll_one(boost::system::error_code& ec) + { + if (outstanding_work_ == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + typename call_stack::context ctx(this); + + return do_one(0, ec); + } + + // Interrupt the event processing loop. + void stop() + { + boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_); + front_stopped_ = true; + front_lock.unlock(); + + boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); + back_stopped_ = true; + interrupt_all_idle_threads(back_lock); + } + + // Reset in preparation for a subsequent run invocation. + void reset() + { + boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_); + front_stopped_ = false; + front_lock.unlock(); + + boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); + back_stopped_ = false; + } + + // Notify that some work has started. + void work_started() + { + ++outstanding_work_; + } + + // Notify that some work has finished. + void work_finished() + { + if (--outstanding_work_ == 0) + stop(); + } + + // Request invocation of the given handler. + template + void dispatch(Handler handler) + { + if (call_stack::contains(this)) + boost_asio_handler_invoke_helpers::invoke(handler, &handler); + else + post(handler); + } + + // Request invocation of the given handler and return immediately. + template + void post(Handler handler) + { + // Allocate and construct an operation to wrap the handler. + handler_queue::scoped_ptr ptr(handler_queue::wrap(handler)); + + boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); + + // If the service has been shut down we silently discard the handler. + if (back_shutdown_) + return; + + // Add the handler to the end of the queue. + handler_queue_.push(ptr.get()); + ptr.release(); + + // An undelivered handler is treated as unfinished work. + ++outstanding_work_; + + // Wake up a thread to execute the handler. + interrupt_one_idle_thread(back_lock); + } + +private: + struct idle_thread_info; + + size_t do_one(idle_thread_info* this_idle_thread, + boost::system::error_code& ec) + { + bool task_has_run = false; + for (;;) + { + // The front lock must be held before we can pop items from the queue. + boost::asio::detail::mutex::scoped_lock front_lock(front_mutex_); + if (front_stopped_) + { + ec = boost::system::error_code(); + return 0; + } + + if (handler_queue::handler* h = handler_queue_.pop()) + { + if (h == &task_handler_) + { + bool more_handlers = handler_queue_.poppable(); + unsigned long front_version = handler_queue_.front_version(); + front_lock.unlock(); + + // The task is always added to the back of the queue when we exit + // this block. + task_cleanup c(*this); + + // If we're polling and the task has already run then we're done. + bool polling = !this_idle_thread; + if (task_has_run && polling) + { + ec = boost::system::error_code(); + return 0; + } + + // If we're considering going idle we need to check whether the queue + // is still empty. If it is, add the thread to the list of idle + // threads. + if (!more_handlers && !polling) + { + boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); + if (back_stopped_) + { + ec = boost::system::error_code(); + return 0; + } + else if (front_version == handler_queue_.back_version()) + { + back_task_thread_ = this_idle_thread; + } + else + { + more_handlers = true; + } + } + + // Run the task. May throw an exception. Only block if the handler + // queue is empty and we're not polling, otherwise we want to return + // as soon as possible. + task_has_run = true; + task_->run(!more_handlers && !polling); + } + else + { + front_lock.unlock(); + handler_cleanup c(*this); + + // Invoke the handler. May throw an exception. + h->invoke(); // invoke() deletes the handler object + + ec = boost::system::error_code(); + return 1; + } + } + else if (this_idle_thread) + { + unsigned long front_version = handler_queue_.front_version(); + front_lock.unlock(); + + // If we're considering going idle we need to check whether the queue + // is still empty. If it is, add the thread to the list of idle + // threads. + boost::asio::detail::mutex::scoped_lock back_lock(back_mutex_); + if (back_stopped_) + { + ec = boost::system::error_code(); + return 0; + } + else if (front_version == handler_queue_.back_version()) + { + this_idle_thread->next = back_first_idle_thread_; + back_first_idle_thread_ = this_idle_thread; + this_idle_thread->wakeup_event.clear(back_lock); + this_idle_thread->wakeup_event.wait(back_lock); + } + } + else + { + ec = boost::system::error_code(); + return 0; + } + } + } + + // Interrupt a single idle thread. + void interrupt_one_idle_thread( + boost::asio::detail::mutex::scoped_lock& back_lock) + { + if (back_first_idle_thread_) + { + idle_thread_info* idle_thread = back_first_idle_thread_; + back_first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal(back_lock); + } + else if (back_task_thread_ && task_) + { + back_task_thread_ = 0; + task_->interrupt(); + } + } + + // Interrupt all idle threads. + void interrupt_all_idle_threads( + boost::asio::detail::mutex::scoped_lock& back_lock) + { + while (back_first_idle_thread_) + { + idle_thread_info* idle_thread = back_first_idle_thread_; + back_first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal(back_lock); + } + + if (back_task_thread_ && task_) + { + back_task_thread_ = 0; + task_->interrupt(); + } + } + + // Helper class to perform task-related operations on block exit. + class task_cleanup; + friend class task_cleanup; + class task_cleanup + { + public: + task_cleanup(task_io_service& task_io_svc) + : task_io_service_(task_io_svc) + { + } + + ~task_cleanup() + { + // Reinsert the task at the end of the handler queue. + boost::asio::detail::mutex::scoped_lock back_lock( + task_io_service_.back_mutex_); + task_io_service_.back_task_thread_ = 0; + task_io_service_.handler_queue_.push(&task_io_service_.task_handler_); + } + + private: + task_io_service& task_io_service_; + }; + + // Helper class to perform handler-related operations on block exit. + class handler_cleanup + { + public: + handler_cleanup(task_io_service& task_io_svc) + : task_io_service_(task_io_svc) + { + } + + ~handler_cleanup() + { + task_io_service_.work_finished(); + } + + private: + task_io_service& task_io_service_; + }; + + // Mutexes to protect access to internal data. + boost::asio::detail::mutex front_mutex_; + boost::asio::detail::mutex back_mutex_; + + // The task to be run by this service. + Task* task_; + + // Handler object to represent the position of the task in the queue. + class task_handler + : public handler_queue::handler + { + public: + task_handler() + : handler_queue::handler(0, 0) + { + } + } task_handler_; + + // The count of unfinished work. + boost::detail::atomic_count outstanding_work_; + + // The queue of handlers that are ready to be delivered. + handler_queue handler_queue_; + + // Flag to indicate that the dispatcher has been stopped. + bool front_stopped_; + bool back_stopped_; + + // Flag to indicate that the dispatcher has been shut down. + bool back_shutdown_; + + // Structure containing information about an idle thread. + struct idle_thread_info + { + event wakeup_event; + idle_thread_info* next; + }; + + // The number of threads that are currently idle. + idle_thread_info* back_first_idle_thread_; + + // The thread that is currently blocked on the task. + idle_thread_info* back_task_thread_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_2LOCK_HPP diff --git a/3rdParty/Boost/boost/asio/detail/task_io_service_fwd.hpp b/3rdParty/Boost/boost/asio/detail/task_io_service_fwd.hpp new file mode 100644 index 0000000..6dc8955 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/task_io_service_fwd.hpp @@ -0,0 +1,33 @@ +// +// task_io_service_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_TASK_IO_SERVICE_FWD_HPP +#define BOOST_ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class task_io_service; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TASK_IO_SERVICE_FWD_HPP diff --git a/3rdParty/Boost/boost/asio/detail/thread.hpp b/3rdParty/Boost/boost/asio/detail/thread.hpp new file mode 100644 index 0000000..3db5805 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/thread.hpp @@ -0,0 +1,60 @@ +// +// thread.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_THREAD_HPP +#define BOOST_ASIO_DETAIL_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if !defined(BOOST_HAS_THREADS) +# include +#elif defined(BOOST_WINDOWS) +# if defined(UNDER_CE) +# include +# else +# include +# endif +#elif defined(BOOST_HAS_PTHREADS) +# include +#else +# error Only Windows and POSIX are supported! +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if !defined(BOOST_HAS_THREADS) +typedef null_thread thread; +#elif defined(BOOST_WINDOWS) +# if defined(UNDER_CE) +typedef wince_thread thread; +# else +typedef win_thread thread; +# endif +#elif defined(BOOST_HAS_PTHREADS) +typedef posix_thread thread; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_THREAD_HPP diff --git a/3rdParty/Boost/boost/asio/detail/throw_error.hpp b/3rdParty/Boost/boost/asio/detail/throw_error.hpp new file mode 100644 index 0000000..0786c40 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/throw_error.hpp @@ -0,0 +1,46 @@ +// +// throw_error.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_THROW_ERROR_HPP +#define BOOST_ASIO_DETAIL_THROW_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + + +namespace boost { +namespace asio { +namespace detail { + +inline void throw_error(const boost::system::error_code& err) +{ + if (err) + { + boost::system::system_error e(err); + boost::throw_exception(e); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_THROW_ERROR_HPP diff --git a/3rdParty/Boost/boost/asio/detail/timer_queue.hpp b/3rdParty/Boost/boost/asio/detail/timer_queue.hpp new file mode 100644 index 0000000..f5370e5 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/timer_queue.hpp @@ -0,0 +1,438 @@ +// +// timer_queue.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_TIMER_QUEUE_HPP +#define BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class timer_queue + : public timer_queue_base +{ +public: + // The time type. + typedef typename Time_Traits::time_type time_type; + + // The duration type. + typedef typename Time_Traits::duration_type duration_type; + + // Constructor. + timer_queue() + : timers_(), + heap_(), + cancelled_timers_(0), + complete_timers_(0) + { + } + + // Add a new timer to the queue. Returns true if this is the timer that is + // earliest in the queue, in which case the reactor's event demultiplexing + // function call may need to be interrupted and restarted. + template + bool enqueue_timer(const time_type& time, Handler handler, void* token) + { + // Ensure that there is space for the timer in the heap. We reserve here so + // that the push_back below will not throw due to a reallocation failure. + heap_.reserve(heap_.size() + 1); + + // Create a new timer object. + std::auto_ptr > new_timer( + new timer(time, handler, token)); + + // Insert the new timer into the hash. + typedef typename hash_map::iterator iterator; + typedef typename hash_map::value_type value_type; + std::pair result = + timers_.insert(value_type(token, new_timer.get())); + if (!result.second) + { + result.first->second->prev_ = new_timer.get(); + new_timer->next_ = result.first->second; + result.first->second = new_timer.get(); + } + + // Put the timer at the correct position in the heap. + new_timer->heap_index_ = heap_.size(); + heap_.push_back(new_timer.get()); + up_heap(heap_.size() - 1); + bool is_first = (heap_[0] == new_timer.get()); + + // Ownership of the timer is transferred to the timer queue. + new_timer.release(); + + return is_first; + } + + // Whether there are no timers in the queue. + virtual bool empty() const + { + return heap_.empty(); + } + + // Get the time for the timer that is earliest in the queue. + virtual boost::posix_time::time_duration wait_duration() const + { + if (heap_.empty()) + return boost::posix_time::pos_infin; + return Time_Traits::to_posix_duration( + Time_Traits::subtract(heap_[0]->time_, Time_Traits::now())); + } + + // Dispatch the timers that are earlier than the specified time. + virtual void dispatch_timers() + { + const time_type now = Time_Traits::now(); + while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0]->time_)) + { + timer_base* t = heap_[0]; + remove_timer(t); + t->result_ = boost::system::error_code(); + t->prev_ = 0; + t->next_ = complete_timers_; + complete_timers_ = t; + } + } + + // Cancel the timers with the given token. Any timers pending for the token + // will be notified that they have been cancelled next time + // dispatch_cancellations is called. Returns the number of timers that were + // cancelled. + std::size_t cancel_timer(void* timer_token) + { + std::size_t num_cancelled = 0; + typedef typename hash_map::iterator iterator; + iterator it = timers_.find(timer_token); + if (it != timers_.end()) + { + timer_base* t = it->second; + while (t) + { + timer_base* next = t->next_; + remove_timer(t); + t->prev_ = 0; + t->next_ = cancelled_timers_; + cancelled_timers_ = t; + t = next; + ++num_cancelled; + } + } + return num_cancelled; + } + + // Dispatch any pending cancels for timers. + virtual void dispatch_cancellations() + { + while (cancelled_timers_) + { + timer_base* this_timer = cancelled_timers_; + this_timer->result_ = boost::asio::error::operation_aborted; + cancelled_timers_ = this_timer->next_; + this_timer->next_ = complete_timers_; + complete_timers_ = this_timer; + } + } + + // Complete any timers that are waiting to be completed. + virtual void complete_timers() + { + while (complete_timers_) + { + timer_base* this_timer = complete_timers_; + complete_timers_ = this_timer->next_; + this_timer->next_ = 0; + this_timer->complete(); + } + } + + // Destroy all timers. + virtual void destroy_timers() + { + typename hash_map::iterator i = timers_.begin(); + typename hash_map::iterator end = timers_.end(); + while (i != end) + { + timer_base* t = i->second; + typename hash_map::iterator old_i = i++; + timers_.erase(old_i); + destroy_timer_list(t); + } + heap_.clear(); + timers_.clear(); + destroy_timer_list(cancelled_timers_); + destroy_timer_list(complete_timers_); + } + +private: + // Base class for timer operations. Function pointers are used instead of + // virtual functions to avoid the associated overhead. + class timer_base + { + public: + // Delete the timer and post the handler. + void complete() + { + complete_func_(this, result_); + } + + // Delete the timer. + void destroy() + { + destroy_func_(this); + } + + protected: + typedef void (*complete_func_type)(timer_base*, + const boost::system::error_code&); + typedef void (*destroy_func_type)(timer_base*); + + // Constructor. + timer_base(complete_func_type complete_func, destroy_func_type destroy_func, + const time_type& time, void* token) + : complete_func_(complete_func), + destroy_func_(destroy_func), + time_(time), + token_(token), + next_(0), + prev_(0), + heap_index_( + std::numeric_limits::max BOOST_PREVENT_MACRO_SUBSTITUTION()) + { + } + + // Prevent deletion through this type. + ~timer_base() + { + } + + private: + friend class timer_queue; + + // The function to be called to delete the timer and post the handler. + complete_func_type complete_func_; + + // The function to be called to delete the timer. + destroy_func_type destroy_func_; + + // The result of the timer operation. + boost::system::error_code result_; + + // The time when the timer should fire. + time_type time_; + + // The token associated with the timer. + void* token_; + + // The next timer known to the queue. + timer_base* next_; + + // The previous timer known to the queue. + timer_base* prev_; + + // The index of the timer in the heap. + size_t heap_index_; + }; + + // Adaptor class template for using handlers in timers. + template + class timer + : public timer_base + { + public: + // Constructor. + timer(const time_type& time, Handler handler, void* token) + : timer_base(&timer::complete_handler, + &timer::destroy_handler, time, token), + handler_(handler) + { + } + + // Delete the timer and post the handler. + static void complete_handler(timer_base* base, + const boost::system::error_code& result) + { + // Take ownership of the timer object. + typedef timer this_type; + this_type* this_timer(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(this_timer->handler_, this_timer); + + // Make a copy of the error_code and the handler so that the memory can + // be deallocated before the upcall is made. + boost::system::error_code ec(result); + Handler handler(this_timer->handler_); + + // Free the memory associated with the handler. + ptr.reset(); + + // Make the upcall. + handler(ec); + } + + // Delete the timer. + static void destroy_handler(timer_base* base) + { + // Take ownership of the timer object. + typedef timer this_type; + this_type* this_timer(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(this_timer->handler_, this_timer); + + // A sub-object of the handler may be the true owner of the memory + // associated with the handler. Consequently, a local copy of the handler + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + Handler handler(this_timer->handler_); + (void)handler; + + // Free the memory associated with the handler. + ptr.reset(); + } + + private: + Handler handler_; + }; + + // Move the item at the given index up the heap to its correct position. + void up_heap(size_t index) + { + size_t parent = (index - 1) / 2; + while (index > 0 + && Time_Traits::less_than(heap_[index]->time_, heap_[parent]->time_)) + { + swap_heap(index, parent); + index = parent; + parent = (index - 1) / 2; + } + } + + // Move the item at the given index down the heap to its correct position. + void down_heap(size_t index) + { + size_t child = index * 2 + 1; + while (child < heap_.size()) + { + size_t min_child = (child + 1 == heap_.size() + || Time_Traits::less_than( + heap_[child]->time_, heap_[child + 1]->time_)) + ? child : child + 1; + if (Time_Traits::less_than(heap_[index]->time_, heap_[min_child]->time_)) + break; + swap_heap(index, min_child); + index = min_child; + child = index * 2 + 1; + } + } + + // Swap two entries in the heap. + void swap_heap(size_t index1, size_t index2) + { + timer_base* tmp = heap_[index1]; + heap_[index1] = heap_[index2]; + heap_[index2] = tmp; + heap_[index1]->heap_index_ = index1; + heap_[index2]->heap_index_ = index2; + } + + // Remove a timer from the heap and list of timers. + void remove_timer(timer_base* t) + { + // Remove the timer from the heap. + size_t index = t->heap_index_; + if (!heap_.empty() && index < heap_.size()) + { + if (index == heap_.size() - 1) + { + heap_.pop_back(); + } + else + { + swap_heap(index, heap_.size() - 1); + heap_.pop_back(); + size_t parent = (index - 1) / 2; + if (index > 0 && Time_Traits::less_than( + heap_[index]->time_, heap_[parent]->time_)) + up_heap(index); + else + down_heap(index); + } + } + + // Remove the timer from the hash. + typedef typename hash_map::iterator iterator; + iterator it = timers_.find(t->token_); + if (it != timers_.end()) + { + if (it->second == t) + it->second = t->next_; + if (t->prev_) + t->prev_->next_ = t->next_; + if (t->next_) + t->next_->prev_ = t->prev_; + if (it->second == 0) + timers_.erase(it); + } + } + + // Destroy all timers in a linked list. + void destroy_timer_list(timer_base*& t) + { + while (t) + { + timer_base* next = t->next_; + t->next_ = 0; + t->destroy(); + t = next; + } + } + + // A hash of timer token to linked lists of timers. + hash_map timers_; + + // The heap of timers, with the earliest timer at the front. + std::vector heap_; + + // The list of timers to be cancelled. + timer_base* cancelled_timers_; + + // The list of timers waiting to be completed. + timer_base* complete_timers_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/timer_queue_base.hpp b/3rdParty/Boost/boost/asio/detail/timer_queue_base.hpp new file mode 100644 index 0000000..1d986c0 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/timer_queue_base.hpp @@ -0,0 +1,64 @@ +// +// timer_queue_base.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_TIMER_QUEUE_BASE_HPP +#define BOOST_ASIO_DETAIL_TIMER_QUEUE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include // Must come before posix_time. + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class timer_queue_base + : private noncopyable +{ +public: + // Destructor. + virtual ~timer_queue_base() {} + + // Whether there are no timers in the queue. + virtual bool empty() const = 0; + + // Get the time to wait until the next timer. + virtual boost::posix_time::time_duration wait_duration() const = 0; + + // Dispatch all ready timers. + virtual void dispatch_timers() = 0; + + // Dispatch any pending cancels for timers. + virtual void dispatch_cancellations() = 0; + + // Complete all timers that are waiting to be completed. + virtual void complete_timers() = 0; + + // Destroy all timers. + virtual void destroy_timers() = 0; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_BASE_HPP diff --git a/3rdParty/Boost/boost/asio/detail/tss_ptr.hpp b/3rdParty/Boost/boost/asio/detail/tss_ptr.hpp new file mode 100644 index 0000000..2cfd641 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/tss_ptr.hpp @@ -0,0 +1,67 @@ +// +// tss_ptr.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_TSS_PTR_HPP +#define BOOST_ASIO_DETAIL_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#if !defined(BOOST_HAS_THREADS) +# include +#elif defined(BOOST_WINDOWS) +# include +#elif defined(BOOST_HAS_PTHREADS) +# include +#else +# error Only Windows and POSIX are supported! +#endif + +namespace boost { +namespace asio { +namespace detail { + +template +class tss_ptr +#if !defined(BOOST_HAS_THREADS) + : public null_tss_ptr +#elif defined(BOOST_WINDOWS) + : public win_tss_ptr +#elif defined(BOOST_HAS_PTHREADS) + : public posix_tss_ptr +#endif +{ +public: + void operator=(T* value) + { +#if !defined(BOOST_HAS_THREADS) + null_tss_ptr::operator=(value); +#elif defined(BOOST_WINDOWS) + win_tss_ptr::operator=(value); +#elif defined(BOOST_HAS_PTHREADS) + posix_tss_ptr::operator=(value); +#endif + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TSS_PTR_HPP diff --git a/3rdParty/Boost/boost/asio/detail/win_event.hpp b/3rdParty/Boost/boost/asio/detail/win_event.hpp new file mode 100644 index 0000000..d0a135e --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/win_event.hpp @@ -0,0 +1,105 @@ +// +// win_event.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_WIN_EVENT_HPP +#define BOOST_ASIO_DETAIL_WIN_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include + +#if defined(BOOST_WINDOWS) + +#include +#include +#include + +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_event + : private noncopyable +{ +public: + // Constructor. + win_event() + : event_(::CreateEvent(0, true, false, 0)) + { + if (!event_) + { + DWORD last_error = ::GetLastError(); + boost::system::system_error e( + boost::system::error_code(last_error, + boost::asio::error::get_system_category()), + "event"); + boost::throw_exception(e); + } + } + + // Destructor. + ~win_event() + { + ::CloseHandle(event_); + } + + // Signal the event. + template + void signal(Lock& lock) + { + BOOST_ASSERT(lock.locked()); + (void)lock; + ::SetEvent(event_); + } + + // Reset the event. + template + void clear(Lock& lock) + { + BOOST_ASSERT(lock.locked()); + (void)lock; + ::ResetEvent(event_); + } + + // Wait for the event to become signalled. + template + void wait(Lock& lock) + { + BOOST_ASSERT(lock.locked()); + lock.unlock(); + ::WaitForSingleObject(event_, INFINITE); + lock.lock(); + } + +private: + HANDLE event_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_WINDOWS) + +#include + +#endif // BOOST_ASIO_DETAIL_WIN_EVENT_HPP diff --git a/3rdParty/Boost/boost/asio/detail/win_fd_set_adapter.hpp b/3rdParty/Boost/boost/asio/detail/win_fd_set_adapter.hpp new file mode 100644 index 0000000..9127a41 --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/win_fd_set_adapter.hpp @@ -0,0 +1,90 @@ +// +// win_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_WIN_FD_SET_ADAPTER_HPP +#define BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +namespace boost { +namespace asio { +namespace detail { + +// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements. +class win_fd_set_adapter +{ +public: + enum { win_fd_set_size = 1024 }; + + win_fd_set_adapter() + : max_descriptor_(invalid_socket) + { + fd_set_.fd_count = 0; + } + + bool set(socket_type descriptor) + { + for (u_int i = 0; i < fd_set_.fd_count; ++i) + if (fd_set_.fd_array[i] == descriptor) + return true; + if (fd_set_.fd_count < win_fd_set_size) + { + fd_set_.fd_array[fd_set_.fd_count++] = descriptor; + return true; + } + return false; + } + + bool is_set(socket_type descriptor) const + { + return !!__WSAFDIsSet(descriptor, + const_cast(reinterpret_cast(&fd_set_))); + } + + operator fd_set*() + { + return reinterpret_cast(&fd_set_); + } + + socket_type max_descriptor() const + { + return max_descriptor_; + } + +private: + // This structure is defined to be compatible with the Windows API fd_set + // structure, but without being dependent on the value of FD_SETSIZE. + struct win_fd_set + { + u_int fd_count; + SOCKET fd_array[win_fd_set_size]; + }; + + win_fd_set fd_set_; + socket_type max_descriptor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#include + +#endif // BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP diff --git a/3rdParty/Boost/boost/asio/detail/win_iocp_handle_service.hpp b/3rdParty/Boost/boost/asio/detail/win_iocp_handle_service.hpp new file mode 100644 index 0000000..fd204de --- /dev/null +++ b/3rdParty/Boost/boost/asio/detail/win_iocp_handle_service.hpp @@ -0,0 +1,834 @@ +// +// win_iocp_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 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_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_iocp_handle_service + : public boost::asio::detail::service_base +{ +public: + // Base class for all operations. + typedef win_iocp_io_service::operation operation; + + // The native type of a stream handle. + typedef HANDLE native_type; + + // The implementation type of the stream handle. + class implementation_type + { + public: + // Default constructor. + implementation_type() + : handle_(INVALID_HANDLE_VALUE), + safe_cancellation_thread_id_(0), + next_(0), + prev_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class win_iocp_handle_service; + + // The native stream handle representation. + native_type handle_; + + // The ID of the thread from which it is safe to cancel asynchronous + // operations. 0 means no asynchronous operations have been started yet. + // ~0 means asynchronous operations have been started from more than one + // thread, and cancellation is not supported for the handle. + DWORD safe_cancellation_thread_id_; + + // Pointers to adjacent handle implementations in linked list. + implementation_type* next_; + implementation_type* prev_; + }; + + win_iocp_handle_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + iocp_service_(boost::asio::use_service(io_service)), + mutex_(), + impl_list_(0) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + // Close all implementations, causing all operations to complete. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + implementation_type* impl = impl_list_; + while (impl) + { + close_for_destruction(*impl); + impl = impl->next_; + } + } + + // Construct a new handle implementation. + void construct(implementation_type& impl) + { + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + + // Insert implementation into linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; + } + + // Destroy a handle implementation. + void destroy(implementation_type& impl) + { + close_for_destruction(impl); + + // Remove implementation from linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + } + + // Assign a native handle to a handle implementation. + boost::system::error_code assign(implementation_type& impl, + const native_type& native_handle, boost::system::error_code& ec) + { + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + if (iocp_service_.register_handle(native_handle, ec)) + return ec; + + impl.handle_ = native_handle; + ec = boost::system::error_code(); + return ec; + } + + // Determine whether the handle is open. + bool is_open(const implementation_type& impl) const + { + return impl.handle_ != INVALID_HANDLE_VALUE; + } + + // Destroy a handle implementation. + boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec) + { + if (is_open(impl)) + { + if (!::CloseHandle(impl.handle_)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + } + + ec = boost::system::error_code(); + return ec; + } + + // Get the native handle representation. + native_type native(const implementation_type& impl) const + { + return impl.handle_; + } + + // Cancel all operations associated with the handle. + boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec) + { + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + } + else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( + ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) + { + // The version of Windows supports cancellation from any thread. + typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); + cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; + if (!cancel_io_ex(impl.handle_, 0)) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_NOT_FOUND) + { + // ERROR_NOT_FOUND means that there were no operations to be + // cancelled. We swallow this error to match the behaviour on other + // platforms. + ec = boost::system::error_code(); + } + else + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + } + else + { + ec = boost::system::error_code(); + } + } + else if (impl.safe_cancellation_thread_id_ == 0) + { + // No operations have been started, so there's nothing to cancel. + ec = boost::system::error_code(); + } + else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) + { + // Asynchronous operations have been started from the current thread only, + // so it is safe to try to cancel them using CancelIo. + if (!::CancelIo(impl.handle_)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + else + { + ec = boost::system::error_code(); + } + } + else + { + // Asynchronous operations have been started from more than one thread, + // so cancellation is not safe. + ec = boost::asio::error::operation_not_supported; + } + + return ec; + } + + class overlapped_wrapper + : public OVERLAPPED + { + public: + explicit overlapped_wrapper(boost::system::error_code& ec) + { + Internal = 0; + InternalHigh = 0; + Offset = 0; + OffsetHigh = 0; + + // Create