diff --git a/Jamroot b/Jamroot new file mode 100644 index 0000000..ea60541 --- /dev/null +++ b/Jamroot @@ -0,0 +1,329 @@ +# Copyright Vladimir Prus 2002-2006. +# Copyright Dave Abrahams 2005-2006. +# Copyright Rene Rivera 2005-2007. +# Copyright Douglas Gregor 2005. +# +# 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) + +# Usage: +# +# b2 [options] [properties] [install|stage] +# +# Builds and installs Boost. +# +# Targets and Related Options: +# +# install Install headers and compiled library files to the +# ======= configured locations (below). +# +# --prefix= Install architecture independent files here. +# Default: C:\Boost on Windows +# Default: /usr/local on Unix, Linux, etc. +# +# --exec-prefix= Install architecture dependent files here. +# Default: +# +# --libdir= Install library files here. +# Default: /lib +# +# --includedir= Install header files here. +# Default: /include +# +# --cmakedir= Install CMake configuration files here. +# Default: /cmake +# +# --no-cmake-config Do not install CMake configuration files. +# +# stage Build and install only compiled library files to the +# ===== stage directory. +# +# --stagedir= Install library files here +# Default: ./stage +# +# Other Options: +# +# --build-type= Build the specified pre-defined set of variations of +# the libraries. Note, that which variants get built +# depends on what each library supports. +# +# -- minimal -- (default) Builds a minimal set of +# variants. On Windows, these are static +# multithreaded libraries in debug and release +# modes, using shared runtime. On Linux, these are +# static and shared multithreaded libraries in +# release mode. +# +# -- complete -- Build all possible variations. +# +# --build-dir=DIR Build in this location instead of building within +# the distribution tree. Recommended! +# +# --show-libraries Display the list of Boost libraries that require +# build and installation steps, and then exit. +# +# --layout= Determine whether to choose library names and header +# locations such that multiple versions of Boost or +# multiple compilers can be used on the same system. +# +# -- versioned -- Names of boost binaries include +# the Boost version number, name and version of +# the compiler and encoded build properties. Boost +# headers are installed in a subdirectory of +# whose name contains the Boost version +# number. +# +# -- tagged -- Names of boost binaries include the +# encoded build properties such as variant and +# threading, but do not including compiler name +# and version, or Boost version. This option is +# useful if you build several variants of Boost, +# using the same compiler. +# +# -- system -- Binaries names do not include the +# Boost version number or the name and version +# number of the compiler. Boost headers are +# installed directly into . This option is +# intended for system integrators building +# distribution packages. +# +# The default value is 'versioned' on Windows, and +# 'system' on Unix. +# +# --buildid=ID Add the specified ID to the name of built libraries. +# The default is to not add anything. +# +# --python-buildid=ID Add the specified ID to the name of built libraries +# that depend on Python. The default is to not add +# anything. This ID is added in addition to --buildid. +# +# --help This message. +# +# --with- Build and install the specified . If this +# option is used, only libraries specified using this +# option will be built. +# +# --without- Do not build, stage, or install the specified +# . By default, all libraries are built. +# +# Properties: +# +# toolset=toolset Indicate the toolset to build with. +# +# variant=debug|release Select the build variant +# +# link=static|shared Whether to build static or shared libraries +# +# threading=single|multi Whether to build single or multithreaded binaries +# +# runtime-link=static|shared +# Whether to link to static or shared C and C++ +# runtime. +# + +# TODO: +# - handle boost version +# - handle python options such as pydebug + +import boostcpp ; +import package ; + +import sequence ; +import xsltproc ; +import set ; +import path ; +import link ; +import notfile ; +import virtual-target ; +import "class" : new ; +import property-set ; +import threadapi-feature ; +import option ; +# Backslash because of `bcp --namespace` +import tools/boost\_install/boost-install ; + +path-constant BOOST_ROOT : . ; +constant BOOST_VERSION : 1.72.0 ; +constant BOOST_JAMROOT_MODULE : $(__name__) ; + +boostcpp.set-version $(BOOST_VERSION) ; + +use-project /boost/architecture : libs/config/checks/architecture ; + +local all-headers = + [ MATCH .*libs/(.*)/include/boost : [ glob libs/*/include/boost libs/*/*/include/boost ] ] ; + +for dir in $(all-headers) +{ + link-directory $(dir)-headers : libs/$(dir)/include/boost : . ; + explicit $(dir)-headers ; +} + +if $(all-headers) +{ + constant BOOST_MODULARLAYOUT : $(all-headers) ; +} + +project boost + : requirements . + + [ boostcpp.architecture ] + [ boostcpp.address-model ] + + # Disable auto-linking for all targets here, primarily because it caused + # troubles with V2. + BOOST_ALL_NO_LIB=1 + # Used to encode variant in target name. See the 'tag' rule below. + @$(__name__).tag + @handle-static-runtime + # Comeau does not support shared lib + como:static + como-linux:_GNU_SOURCE=1 + # When building docs within Boost, we want the standard Boost style + boost.defaults=Boost + @threadapi-feature.detect + : usage-requirements . + : default-build + hidden + multi + : build-dir bin.v2 + ; + +# This rule is called by Boost.Build to determine the name of target. We use it +# to encode the build variant, compiler name and boost version in the target +# name. +# +rule tag ( name : type ? : property-set ) +{ + return [ boostcpp.tag $(name) : $(type) : $(property-set) ] ; +} + +rule python-tag ( name : type ? : property-set ) +{ + return [ boostcpp.python-tag $(name) : $(type) : $(property-set) ] ; +} + +rule handle-static-runtime ( properties * ) +{ + # Using static runtime with shared libraries is impossible on Linux, and + # dangerous on Windows. Therefore, we disallow it. This might be drastic, + # but it was disabled for a while without anybody complaining. + + # For CW, static runtime is needed so that std::locale works. + if shared in $(properties) && static in $(properties) && + ! ( cw in $(properties) ) + { + if ! $(.shared-static-warning-emitted) + { + ECHO "warning: skipping configuration link=shared, runtime-link=static" ; + ECHO "warning: this combination is either impossible or too dangerous" ; + ECHO "warning: to be of any use" ; + .shared-static-warning-emitted = 1 ; + } + + return no ; + } +} + +all-libraries = [ MATCH .*libs/(.*)/build/.* : [ glob libs/*/build/Jamfile.v2 ] + [ glob libs/*/build/Jamfile ] ] ; + +all-libraries = [ sequence.unique $(all-libraries) ] ; +# The function_types library has a Jamfile, but it's used for maintenance +# purposes, there's no library to build and install. +all-libraries = [ set.difference $(all-libraries) : function_types ] ; + +# Setup convenient aliases for all libraries. + +local rule explicit-alias ( id : targets + ) +{ + alias $(id) : $(targets) ; + explicit $(id) ; +} + +# First, the complicated libraries: where the target name in Jamfile is +# different from its directory name. +explicit-alias prg_exec_monitor : libs/test/build//boost_prg_exec_monitor ; +explicit-alias test_exec_monitor : libs/test/build//boost_test_exec_monitor ; +explicit-alias unit_test_framework : libs/test/build//boost_unit_test_framework ; +explicit-alias bgl-vis : libs/graps/build//bgl-vis ; +explicit-alias serialization : libs/serialization/build//boost_serialization ; +explicit-alias wserialization : libs/serialization/build//boost_wserialization ; +for local l in $(all-libraries) +{ + if ! $(l) in test graph serialization headers + { + explicit-alias $(l) : libs/$(l)/build//boost_$(l) ; + } +} + +# Log has an additional target +explicit-alias log_setup : libs/log/build//boost_log_setup ; + +rule do-nothing { } + +rule generate-alias ( project name : property-set : sources * ) +{ + local action-name = [ $(property-set).get ] ; + local m = [ MATCH ^@(.*) : $(action-name) ] ; + property-set = [ property-set.empty ] ; + local action = [ new action $(sources) : $(m[1]) : $(property-set) ] ; + local t = [ new notfile-target $(name) : $(project) : $(action) ] ; + return [ virtual-target.register $(t) ] ; +} + +generate headers : $(all-headers)-headers : @generate-alias @do-nothing : : . ; + +#alias headers : $(all-headers)-headers : : : . ; +explicit headers ; + +# Make project ids of all libraries known. +for local l in $(all-libraries) +{ + use-project /boost/$(l) : libs/$(l)/build ; +} + +if [ path.exists $(BOOST_ROOT)/tools/inspect/build ] +{ + use-project /boost/tools/inspect : tools/inspect/build ; +} + +if [ path.exists $(BOOST_ROOT)/libs/wave/tool/build ] +{ + use-project /boost/libs/wave/tool : libs/wave/tool/build ; +} + +# Make the boost-install rule visible in subprojects + +# This rule should be called from libraries' Jamfiles and will create two +# targets, "install" and "stage", that will install or stage that library. The +# --prefix option is respected, but --with and --without options, naturally, are +# ignored. +# +# - libraries -- list of library targets to install. + +rule boost-install ( libraries * ) +{ + boost-install.boost-install $(libraries) ; +} + +# Creates a library target, adding autolink support and also creates +# stage and install targets via boost-install, above. +rule boost-lib ( name : sources * : requirements * : default-build * : usage-requirements * ) +{ + autolink = shared:BOOST_$(name:U)_DYN_LINK=1 ; + name = boost_$(name) ; + lib $(name) + : $(sources) + : $(requirements) $(autolink) + : $(default-build) + : $(usage-requirements) $(autolink) + ; + boost-install $(name) ; +} + + +# Declare special top-level targets that build and install the desired variants +# of the libraries. +boostcpp.declare-targets $(all-libraries) ; diff --git a/boost/algorithm/minmax_element.hpp b/boost/algorithm/minmax_element.hpp deleted file mode 100644 index 752f6cb..0000000 --- a/boost/algorithm/minmax_element.hpp +++ /dev/null @@ -1,553 +0,0 @@ -// (C) Copyright Herve Bronnimann 2004. -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -/* - Revision history: - 1 July 2004 - Split the code into two headers to lessen dependence on - Boost.tuple. (Herve) - 26 June 2004 - Added the code for the boost minmax library. (Herve) -*/ - -#ifndef BOOST_ALGORITHM_MINMAX_ELEMENT_HPP -#define BOOST_ALGORITHM_MINMAX_ELEMENT_HPP - -/* PROPOSED STANDARD EXTENSIONS: - * - * minmax_element(first, last) - * Effect: std::make_pair( std::min_element(first, last), - * std::max_element(first, last) ); - * - * minmax_element(first, last, comp) - * Effect: std::make_pair( std::min_element(first, last, comp), - * std::max_element(first, last, comp) ); - */ - -#include // for std::pair and std::make_pair - -namespace boost { - - namespace detail { // for obtaining a uniform version of minmax_element - // that compiles with VC++ 6.0 -- avoid the iterator_traits by - // having comparison object over iterator, not over dereferenced value - - template - struct less_over_iter { - bool operator()(Iterator const& it1, - Iterator const& it2) const { return *it1 < *it2; } - }; - - template - struct binary_pred_over_iter { - explicit binary_pred_over_iter(BinaryPredicate const& p ) : m_p( p ) {} - bool operator()(Iterator const& it1, - Iterator const& it2) const { return m_p(*it1, *it2); } - private: - BinaryPredicate m_p; - }; - - // common base for the two minmax_element overloads - - template - std::pair - basic_minmax_element(ForwardIter first, ForwardIter last, Compare comp) - { - if (first == last) - return std::make_pair(last,last); - - ForwardIter min_result = first; - ForwardIter max_result = first; - - // if only one element - ForwardIter second = first; ++second; - if (second == last) - return std::make_pair(min_result, max_result); - - // treat first pair separately (only one comparison for first two elements) - ForwardIter potential_min_result = last; - if (comp(first, second)) - max_result = second; - else { - min_result = second; - potential_min_result = first; - } - - // then each element by pairs, with at most 3 comparisons per pair - first = ++second; if (first != last) ++second; - while (second != last) { - if (comp(first, second)) { - if (comp(first, min_result)) { - min_result = first; - potential_min_result = last; - } - if (comp(max_result, second)) - max_result = second; - } else { - if (comp(second, min_result)) { - min_result = second; - potential_min_result = first; - } - if (comp(max_result, first)) - max_result = first; - } - first = ++second; - if (first != last) ++second; - } - - // if odd number of elements, treat last element - if (first != last) { // odd number of elements - if (comp(first, min_result)) { - min_result = first; - potential_min_result = last; - } - else if (comp(max_result, first)) - max_result = first; - } - - // resolve min_result being incorrect with one extra comparison - // (in which case potential_min_result is necessarily the correct result) - if (potential_min_result != last - && !comp(min_result, potential_min_result)) - min_result = potential_min_result; - - return std::make_pair(min_result,max_result); - } - - } // namespace detail - - template - std::pair - minmax_element(ForwardIter first, ForwardIter last) - { - return detail::basic_minmax_element(first, last, - detail::less_over_iter() ); - } - - template - std::pair - minmax_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) - { - return detail::basic_minmax_element(first, last, - detail::binary_pred_over_iter(comp) ); - } - -} - -/* PROPOSED BOOST EXTENSIONS - * In the description below, [rfirst,rlast) denotes the reversed range - * of [first,last). Even though the iterator type of first and last may - * be only a Forward Iterator, it is possible to explain the semantics - * by assuming that it is a Bidirectional Iterator. In the sequel, - * reverse(ForwardIterator&) returns the reverse_iterator adaptor. - * This is not how the functions would be implemented! - * - * first_min_element(first, last) - * Effect: std::min_element(first, last); - * - * first_min_element(first, last, comp) - * Effect: std::min_element(first, last, comp); - * - * last_min_element(first, last) - * Effect: reverse( std::min_element(reverse(last), reverse(first)) ); - * - * last_min_element(first, last, comp) - * Effect: reverse( std::min_element(reverse(last), reverse(first), comp) ); - * - * first_max_element(first, last) - * Effect: std::max_element(first, last); - * - * first_max_element(first, last, comp) - * Effect: max_element(first, last); - * - * last_max_element(first, last) - * Effect: reverse( std::max_element(reverse(last), reverse(first)) ); - * - * last_max_element(first, last, comp) - * Effect: reverse( std::max_element(reverse(last), reverse(first), comp) ); - * - * first_min_first_max_element(first, last) - * Effect: std::make_pair( first_min_element(first, last), - * first_max_element(first, last) ); - * - * first_min_first_max_element(first, last, comp) - * Effect: std::make_pair( first_min_element(first, last, comp), - * first_max_element(first, last, comp) ); - * - * first_min_last_max_element(first, last) - * Effect: std::make_pair( first_min_element(first, last), - * last_max_element(first, last) ); - * - * first_min_last_max_element(first, last, comp) - * Effect: std::make_pair( first_min_element(first, last, comp), - * last_max_element(first, last, comp) ); - * - * last_min_first_max_element(first, last) - * Effect: std::make_pair( last_min_element(first, last), - * first_max_element(first, last) ); - * - * last_min_first_max_element(first, last, comp) - * Effect: std::make_pair( last_min_element(first, last, comp), - * first_max_element(first, last, comp) ); - * - * last_min_last_max_element(first, last) - * Effect: std::make_pair( last_min_element(first, last), - * last_max_element(first, last) ); - * - * last_min_last_max_element(first, last, comp) - * Effect: std::make_pair( last_min_element(first, last, comp), - * last_max_element(first, last, comp) ); - */ - -namespace boost { - - // Min_element and max_element variants - - namespace detail { // common base for the overloads - - template - ForwardIter - basic_first_min_element(ForwardIter first, ForwardIter last, - BinaryPredicate comp) - { - if (first == last) return last; - ForwardIter min_result = first; - while (++first != last) - if (comp(first, min_result)) - min_result = first; - return min_result; - } - - template - ForwardIter - basic_last_min_element(ForwardIter first, ForwardIter last, - BinaryPredicate comp) - { - if (first == last) return last; - ForwardIter min_result = first; - while (++first != last) - if (!comp(min_result, first)) - min_result = first; - return min_result; - } - - template - ForwardIter - basic_first_max_element(ForwardIter first, ForwardIter last, - BinaryPredicate comp) - { - if (first == last) return last; - ForwardIter max_result = first; - while (++first != last) - if (comp(max_result, first)) - max_result = first; - return max_result; - } - - template - ForwardIter - basic_last_max_element(ForwardIter first, ForwardIter last, - BinaryPredicate comp) - { - if (first == last) return last; - ForwardIter max_result = first; - while (++first != last) - if (!comp(first, max_result)) - max_result = first; - return max_result; - } - - } // namespace detail - - template - ForwardIter - first_min_element(ForwardIter first, ForwardIter last) - { - return detail::basic_first_min_element(first, last, - detail::less_over_iter() ); - } - - template - ForwardIter - first_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) - { - return detail::basic_first_min_element(first, last, - detail::binary_pred_over_iter(comp) ); - } - - template - ForwardIter - last_min_element(ForwardIter first, ForwardIter last) - { - return detail::basic_last_min_element(first, last, - detail::less_over_iter() ); - } - - template - ForwardIter - last_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) - { - return detail::basic_last_min_element(first, last, - detail::binary_pred_over_iter(comp) ); - } - - template - ForwardIter - first_max_element(ForwardIter first, ForwardIter last) - { - return detail::basic_first_max_element(first, last, - detail::less_over_iter() ); - } - - template - ForwardIter - first_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) - { - return detail::basic_first_max_element(first, last, - detail::binary_pred_over_iter(comp) ); - } - - template - ForwardIter - last_max_element(ForwardIter first, ForwardIter last) - { - return detail::basic_last_max_element(first, last, - detail::less_over_iter() ); - } - - template - ForwardIter - last_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) - { - return detail::basic_last_max_element(first, last, - detail::binary_pred_over_iter(comp) ); - } - - - // Minmax_element variants -- comments removed - - namespace detail { - - template - std::pair - basic_first_min_last_max_element(ForwardIter first, ForwardIter last, - BinaryPredicate comp) - { - if (first == last) - return std::make_pair(last,last); - - ForwardIter min_result = first; - ForwardIter max_result = first; - - ForwardIter second = ++first; - if (second == last) - return std::make_pair(min_result, max_result); - - if (comp(second, min_result)) - min_result = second; - else - max_result = second; - - first = ++second; if (first != last) ++second; - while (second != last) { - if (!comp(second, first)) { - if (comp(first, min_result)) - min_result = first; - if (!comp(second, max_result)) - max_result = second; - } else { - if (comp(second, min_result)) - min_result = second; - if (!comp(first, max_result)) - max_result = first; - } - first = ++second; if (first != last) ++second; - } - - if (first != last) { - if (comp(first, min_result)) - min_result = first; - else if (!comp(first, max_result)) - max_result = first; - } - - return std::make_pair(min_result, max_result); - } - - template - std::pair - basic_last_min_first_max_element(ForwardIter first, ForwardIter last, - BinaryPredicate comp) - { - if (first == last) return std::make_pair(last,last); - - ForwardIter min_result = first; - ForwardIter max_result = first; - - ForwardIter second = ++first; - if (second == last) - return std::make_pair(min_result, max_result); - - if (comp(max_result, second)) - max_result = second; - else - min_result = second; - - first = ++second; if (first != last) ++second; - while (second != last) { - if (comp(first, second)) { - if (!comp(min_result, first)) - min_result = first; - if (comp(max_result, second)) - max_result = second; - } else { - if (!comp(min_result, second)) - min_result = second; - if (comp(max_result, first)) - max_result = first; - } - first = ++second; if (first != last) ++second; - } - - if (first != last) { - if (!comp(min_result, first)) - min_result = first; - else if (comp(max_result, first)) - max_result = first; - } - - return std::make_pair(min_result, max_result); - } - - template - std::pair - basic_last_min_last_max_element(ForwardIter first, ForwardIter last, - BinaryPredicate comp) - { - if (first == last) return std::make_pair(last,last); - - ForwardIter min_result = first; - ForwardIter max_result = first; - - ForwardIter second = first; ++second; - if (second == last) - return std::make_pair(min_result,max_result); - - ForwardIter potential_max_result = last; - if (comp(first, second)) - max_result = second; - else { - min_result = second; - potential_max_result = second; - } - - first = ++second; if (first != last) ++second; - while (second != last) { - if (comp(first, second)) { - if (!comp(min_result, first)) - min_result = first; - if (!comp(second, max_result)) { - max_result = second; - potential_max_result = last; - } - } else { - if (!comp(min_result, second)) - min_result = second; - if (!comp(first, max_result)) { - max_result = first; - potential_max_result = second; - } - } - first = ++second; - if (first != last) ++second; - } - - if (first != last) { - if (!comp(min_result, first)) - min_result = first; - if (!comp(first, max_result)) { - max_result = first; - potential_max_result = last; - } - } - - if (potential_max_result != last - && !comp(potential_max_result, max_result)) - max_result = potential_max_result; - - return std::make_pair(min_result,max_result); - } - - } // namespace detail - - template - inline std::pair - first_min_first_max_element(ForwardIter first, ForwardIter last) - { - return minmax_element(first, last); - } - - template - inline std::pair - first_min_first_max_element(ForwardIter first, ForwardIter last, - BinaryPredicate comp) - { - return minmax_element(first, last, comp); - } - - template - std::pair - first_min_last_max_element(ForwardIter first, ForwardIter last) - { - return detail::basic_first_min_last_max_element(first, last, - detail::less_over_iter() ); - } - - template - inline std::pair - first_min_last_max_element(ForwardIter first, ForwardIter last, - BinaryPredicate comp) - { - return detail::basic_first_min_last_max_element(first, last, - detail::binary_pred_over_iter(comp) ); - } - - template - std::pair - last_min_first_max_element(ForwardIter first, ForwardIter last) - { - return detail::basic_last_min_first_max_element(first, last, - detail::less_over_iter() ); - } - - template - inline std::pair - last_min_first_max_element(ForwardIter first, ForwardIter last, - BinaryPredicate comp) - { - return detail::basic_last_min_first_max_element(first, last, - detail::binary_pred_over_iter(comp) ); - } - - template - std::pair - last_min_last_max_element(ForwardIter first, ForwardIter last) - { - return detail::basic_last_min_last_max_element(first, last, - detail::less_over_iter() ); - } - - template - inline std::pair - last_min_last_max_element(ForwardIter first, ForwardIter last, - BinaryPredicate comp) - { - return detail::basic_last_min_last_max_element(first, last, - detail::binary_pred_over_iter(comp) ); - } - -} // namespace boost - -#endif // BOOST_ALGORITHM_MINMAX_ELEMENT_HPP diff --git a/boost/algorithm/string/classification.hpp b/boost/algorithm/string/classification.hpp new file mode 100644 index 0000000..ca43602 --- /dev/null +++ b/boost/algorithm/string/classification.hpp @@ -0,0 +1,312 @@ +// Boost string_algo library classification.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_CLASSIFICATION_HPP +#define BOOST_STRING_CLASSIFICATION_HPP + +#include +#include +#include +#include +#include +#include + + +/*! \file + Classification predicates are included in the library to give + some more convenience when using algorithms like \c trim() and \c all(). + They wrap functionality of STL classification functions ( e.g. \c std::isspace() ) + into generic functors. +*/ + +namespace boost { + namespace algorithm { + +// classification functor generator -------------------------------------// + + //! is_classified predicate + /*! + Construct the \c is_classified predicate. This predicate holds if the input is + of specified \c std::ctype category. + + \param Type A \c std::ctype category + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_classified(std::ctype_base::mask Type, const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(Type, Loc); + } + + //! is_space predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::space category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_space(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::space, Loc); + } + + //! is_alnum predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::alnum category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_alnum(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::alnum, Loc); + } + + //! is_alpha predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::alpha category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_alpha(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::alpha, Loc); + } + + //! is_cntrl predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::cntrl category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_cntrl(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::cntrl, Loc); + } + + //! is_digit predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::digit category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_digit(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::digit, Loc); + } + + //! is_graph predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::graph category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_graph(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::graph, Loc); + } + + //! is_lower predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::lower category. + + \param Loc A locale used for classification + \return An instance of \c is_classified predicate + */ + inline detail::is_classifiedF + is_lower(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::lower, Loc); + } + + //! is_print predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::print category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_print(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::print, Loc); + } + + //! is_punct predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::punct category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_punct(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::punct, Loc); + } + + //! is_upper predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::upper category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_upper(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::upper, Loc); + } + + //! is_xdigit predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::xdigit category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_xdigit(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::xdigit, Loc); + } + + //! is_any_of predicate + /*! + Construct the \c is_any_of predicate. The predicate holds if the input + is included in the specified set of characters. + + \param Set A set of characters to be recognized + \return An instance of the \c is_any_of predicate + */ + template + inline detail::is_any_ofF< + BOOST_STRING_TYPENAME range_value::type> + is_any_of( const RangeT& Set ) + { + iterator_range::type> lit_set(boost::as_literal(Set)); + return detail::is_any_ofF::type>(lit_set); + } + + //! is_from_range predicate + /*! + Construct the \c is_from_range predicate. The predicate holds if the input + is included in the specified range. (i.e. From <= Ch <= To ) + + \param From The start of the range + \param To The end of the range + \return An instance of the \c is_from_range predicate + */ + template + inline detail::is_from_rangeF is_from_range(CharT From, CharT To) + { + return detail::is_from_rangeF(From,To); + } + + // predicate combinators ---------------------------------------------------// + + //! predicate 'and' composition predicate + /*! + Construct the \c class_and predicate. This predicate can be used + to logically combine two classification predicates. \c class_and holds, + if both predicates return true. + + \param Pred1 The first predicate + \param Pred2 The second predicate + \return An instance of the \c class_and predicate + */ + template + inline detail::pred_andF + operator&&( + const predicate_facade& Pred1, + const predicate_facade& Pred2 ) + { + // Doing the static_cast with the pointer instead of the reference + // is a workaround for some compilers which have problems with + // static_cast's of template references, i.e. CW8. /grafik/ + return detail::pred_andF( + *static_cast(&Pred1), + *static_cast(&Pred2) ); + } + + //! predicate 'or' composition predicate + /*! + Construct the \c class_or predicate. This predicate can be used + to logically combine two classification predicates. \c class_or holds, + if one of the predicates return true. + + \param Pred1 The first predicate + \param Pred2 The second predicate + \return An instance of the \c class_or predicate + */ + template + inline detail::pred_orF + operator||( + const predicate_facade& Pred1, + const predicate_facade& Pred2 ) + { + // Doing the static_cast with the pointer instead of the reference + // is a workaround for some compilers which have problems with + // static_cast's of template references, i.e. CW8. /grafik/ + return detail::pred_orF( + *static_cast(&Pred1), + *static_cast(&Pred2)); + } + + //! predicate negation operator + /*! + Construct the \c class_not predicate. This predicate represents a negation. + \c class_or holds if of the predicates return false. + + \param Pred The predicate to be negated + \return An instance of the \c class_not predicate + */ + template + inline detail::pred_notF + operator!( const predicate_facade& Pred ) + { + // Doing the static_cast with the pointer instead of the reference + // is a workaround for some compilers which have problems with + // static_cast's of template references, i.e. CW8. /grafik/ + return detail::pred_notF(*static_cast(&Pred)); + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::is_classified; + using algorithm::is_space; + using algorithm::is_alnum; + using algorithm::is_alpha; + using algorithm::is_cntrl; + using algorithm::is_digit; + using algorithm::is_graph; + using algorithm::is_lower; + using algorithm::is_upper; + using algorithm::is_print; + using algorithm::is_punct; + using algorithm::is_xdigit; + using algorithm::is_any_of; + using algorithm::is_from_range; + +} // namespace boost + +#endif // BOOST_STRING_PREDICATE_HPP diff --git a/boost/algorithm/string/detail/classification.hpp b/boost/algorithm/string/detail/classification.hpp new file mode 100644 index 0000000..704d9d2 --- /dev/null +++ b/boost/algorithm/string/detail/classification.hpp @@ -0,0 +1,353 @@ +// Boost string_algo library classification.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_CLASSIFICATION_DETAIL_HPP +#define BOOST_STRING_CLASSIFICATION_DETAIL_HPP + +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// classification functors -----------------------------------------------// + + // is_classified functor + struct is_classifiedF : + public predicate_facade + { + // Boost.ResultOf support + typedef bool result_type; + + // Constructor from a locale + is_classifiedF(std::ctype_base::mask Type, std::locale const & Loc = std::locale()) : + m_Type(Type), m_Locale(Loc) {} + // Operation + template + bool operator()( CharT Ch ) const + { + return std::use_facet< std::ctype >(m_Locale).is( m_Type, Ch ); + } + + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x582) && !defined(_USE_OLD_RW_STL) + template<> + bool operator()( char const Ch ) const + { + return std::use_facet< std::ctype >(m_Locale).is( m_Type, Ch ); + } + #endif + + private: + std::ctype_base::mask m_Type; + std::locale m_Locale; + }; + + + // is_any_of functor + /* + returns true if the value is from the specified set + */ + template + struct is_any_ofF : + public predicate_facade > + { + private: + // set cannot operate on const value-type + typedef typename ::boost::remove_const::type set_value_type; + + public: + // Boost.ResultOf support + typedef bool result_type; + + // Constructor + template + is_any_ofF( const RangeT& Range ) : m_Size(0) + { + // Prepare storage + m_Storage.m_dynSet=0; + + std::size_t Size=::boost::distance(Range); + m_Size=Size; + set_value_type* Storage=0; + + if(use_fixed_storage(m_Size)) + { + // Use fixed storage + Storage=&m_Storage.m_fixSet[0]; + } + else + { + // Use dynamic storage + m_Storage.m_dynSet=new set_value_type[m_Size]; + Storage=m_Storage.m_dynSet; + } + + // Use fixed storage + ::std::copy(::boost::begin(Range), ::boost::end(Range), Storage); + ::std::sort(Storage, Storage+m_Size); + } + + // Copy constructor + is_any_ofF(const is_any_ofF& Other) : m_Size(Other.m_Size) + { + // Prepare storage + m_Storage.m_dynSet=0; + const set_value_type* SrcStorage=0; + set_value_type* DestStorage=0; + + if(use_fixed_storage(m_Size)) + { + // Use fixed storage + DestStorage=&m_Storage.m_fixSet[0]; + SrcStorage=&Other.m_Storage.m_fixSet[0]; + } + else + { + // Use dynamic storage + m_Storage.m_dynSet=new set_value_type[m_Size]; + DestStorage=m_Storage.m_dynSet; + SrcStorage=Other.m_Storage.m_dynSet; + } + + // Use fixed storage + ::std::memcpy(DestStorage, SrcStorage, sizeof(set_value_type)*m_Size); + } + + // Destructor + ~is_any_ofF() + { + if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0) + { + delete [] m_Storage.m_dynSet; + } + } + + // Assignment + is_any_ofF& operator=(const is_any_ofF& Other) + { + // Handle self assignment + if(this==&Other) return *this; + + // Prepare storage + const set_value_type* SrcStorage; + set_value_type* DestStorage; + + if(use_fixed_storage(Other.m_Size)) + { + // Use fixed storage + DestStorage=&m_Storage.m_fixSet[0]; + SrcStorage=&Other.m_Storage.m_fixSet[0]; + + // Delete old storage if was present + if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0) + { + delete [] m_Storage.m_dynSet; + } + + // Set new size + m_Size=Other.m_Size; + } + else + { + // Other uses dynamic storage + SrcStorage=Other.m_Storage.m_dynSet; + + // Check what kind of storage are we using right now + if(use_fixed_storage(m_Size)) + { + // Using fixed storage, allocate new + set_value_type* pTemp=new set_value_type[Other.m_Size]; + DestStorage=pTemp; + m_Storage.m_dynSet=pTemp; + m_Size=Other.m_Size; + } + else + { + // Using dynamic storage, check if can reuse + if(m_Storage.m_dynSet!=0 && m_Size>=Other.m_Size && m_Size + bool operator()( Char2T Ch ) const + { + const set_value_type* Storage= + (use_fixed_storage(m_Size)) + ? &m_Storage.m_fixSet[0] + : m_Storage.m_dynSet; + + return ::std::binary_search(Storage, Storage+m_Size, Ch); + } + private: + // check if the size is eligible for fixed storage + static bool use_fixed_storage(std::size_t size) + { + return size<=sizeof(set_value_type*)*2; + } + + + private: + // storage + // The actual used storage is selected on the type + union + { + set_value_type* m_dynSet; + set_value_type m_fixSet[sizeof(set_value_type*)*2]; + } + m_Storage; + + // storage size + ::std::size_t m_Size; + }; + + // is_from_range functor + /* + returns true if the value is from the specified range. + (i.e. x>=From && x>=To) + */ + template + struct is_from_rangeF : + public predicate_facade< is_from_rangeF > + { + // Boost.ResultOf support + typedef bool result_type; + + // Constructor + is_from_rangeF( CharT From, CharT To ) : m_From(From), m_To(To) {} + + // Operation + template + bool operator()( Char2T Ch ) const + { + return ( m_From <= Ch ) && ( Ch <= m_To ); + } + + private: + CharT m_From; + CharT m_To; + }; + + // class_and composition predicate + template + struct pred_andF : + public predicate_facade< pred_andF > + { + public: + + // Boost.ResultOf support + typedef bool result_type; + + // Constructor + pred_andF( Pred1T Pred1, Pred2T Pred2 ) : + m_Pred1(Pred1), m_Pred2(Pred2) {} + + // Operation + template + bool operator()( CharT Ch ) const + { + return m_Pred1(Ch) && m_Pred2(Ch); + } + + private: + Pred1T m_Pred1; + Pred2T m_Pred2; + }; + + // class_or composition predicate + template + struct pred_orF : + public predicate_facade< pred_orF > + { + public: + // Boost.ResultOf support + typedef bool result_type; + + // Constructor + pred_orF( Pred1T Pred1, Pred2T Pred2 ) : + m_Pred1(Pred1), m_Pred2(Pred2) {} + + // Operation + template + bool operator()( CharT Ch ) const + { + return m_Pred1(Ch) || m_Pred2(Ch); + } + + private: + Pred1T m_Pred1; + Pred2T m_Pred2; + }; + + // class_not composition predicate + template< typename PredT > + struct pred_notF : + public predicate_facade< pred_notF > + { + public: + // Boost.ResultOf support + typedef bool result_type; + + // Constructor + pred_notF( PredT Pred ) : m_Pred(Pred) {} + + // Operation + template + bool operator()( CharT Ch ) const + { + return !m_Pred(Ch); + } + + private: + PredT m_Pred; + }; + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_CLASSIFICATION_DETAIL_HPP diff --git a/boost/algorithm/string/detail/find_iterator.hpp b/boost/algorithm/string/detail/find_iterator.hpp new file mode 100644 index 0000000..4f90a98 --- /dev/null +++ b/boost/algorithm/string/detail/find_iterator.hpp @@ -0,0 +1,87 @@ +// Boost string_algo library find_iterator.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_ITERATOR_DETAIL_HPP +#define BOOST_STRING_FIND_ITERATOR_DETAIL_HPP + +#include +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// find_iterator base -----------------------------------------------// + + // Find iterator base + template + class find_iterator_base + { + protected: + // typedefs + typedef IteratorT input_iterator_type; + typedef iterator_range match_type; + typedef function2< + match_type, + input_iterator_type, + input_iterator_type> finder_type; + + protected: + // Protected construction/destruction + + // Default constructor + find_iterator_base() {} + // Copy construction + find_iterator_base( const find_iterator_base& Other ) : + m_Finder(Other.m_Finder) {} + + // Constructor + template + find_iterator_base( FinderT Finder, int ) : + m_Finder(Finder) {} + + // Destructor + ~find_iterator_base() {} + + // Find operation + match_type do_find( + input_iterator_type Begin, + input_iterator_type End ) const + { + if (!m_Finder.empty()) + { + return m_Finder(Begin,End); + } + else + { + return match_type(End,End); + } + } + + // Check + bool is_null() const + { + return m_Finder.empty(); + } + + private: + // Finder + finder_type m_Finder; + }; + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_FIND_ITERATOR_DETAIL_HPP diff --git a/boost/algorithm/string/detail/trim.hpp b/boost/algorithm/string/detail/trim.hpp new file mode 100644 index 0000000..1233e49 --- /dev/null +++ b/boost/algorithm/string/detail/trim.hpp @@ -0,0 +1,95 @@ +// Boost string_algo library trim.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_TRIM_DETAIL_HPP +#define BOOST_STRING_TRIM_DETAIL_HPP + +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// trim iterator helper -----------------------------------------------// + + template< typename ForwardIteratorT, typename PredicateT > + inline ForwardIteratorT trim_end_iter_select( + ForwardIteratorT InBegin, + ForwardIteratorT InEnd, + PredicateT IsSpace, + std::forward_iterator_tag ) + { + ForwardIteratorT TrimIt=InBegin; + + for( ForwardIteratorT It=InBegin; It!=InEnd; ++It ) + { + if ( !IsSpace(*It) ) + { + TrimIt=It; + ++TrimIt; + } + } + + return TrimIt; + } + + template< typename ForwardIteratorT, typename PredicateT > + inline ForwardIteratorT trim_end_iter_select( + ForwardIteratorT InBegin, + ForwardIteratorT InEnd, + PredicateT IsSpace, + std::bidirectional_iterator_tag ) + { + for( ForwardIteratorT It=InEnd; It!=InBegin; ) + { + if ( !IsSpace(*(--It)) ) + return ++It; + } + + return InBegin; + } + // Search for first non matching character from the beginning of the sequence + template< typename ForwardIteratorT, typename PredicateT > + inline ForwardIteratorT trim_begin( + ForwardIteratorT InBegin, + ForwardIteratorT InEnd, + PredicateT IsSpace ) + { + ForwardIteratorT It=InBegin; + for(; It!=InEnd; ++It ) + { + if (!IsSpace(*It)) + return It; + } + + return It; + } + + // Search for first non matching character from the end of the sequence + template< typename ForwardIteratorT, typename PredicateT > + inline ForwardIteratorT trim_end( + ForwardIteratorT InBegin, + ForwardIteratorT InEnd, + PredicateT IsSpace ) + { + typedef BOOST_STRING_TYPENAME boost::detail:: + iterator_traits::iterator_category category; + + return ::boost::algorithm::detail::trim_end_iter_select( InBegin, InEnd, IsSpace, category() ); + } + + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_TRIM_DETAIL_HPP diff --git a/boost/algorithm/string/find_iterator.hpp b/boost/algorithm/string/find_iterator.hpp new file mode 100644 index 0000000..5a52d92 --- /dev/null +++ b/boost/algorithm/string/find_iterator.hpp @@ -0,0 +1,388 @@ +// Boost string_algo library find_iterator.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FIND_ITERATOR_HPP +#define BOOST_STRING_FIND_ITERATOR_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +/*! \file + Defines find iterator classes. Find iterator repeatedly applies a Finder + to the specified input string to search for matches. Dereferencing + the iterator yields the current match or a range between the last and the current + match depending on the iterator used. +*/ + +namespace boost { + namespace algorithm { + +// find_iterator -----------------------------------------------// + + //! find_iterator + /*! + Find iterator encapsulates a Finder and allows + for incremental searching in a string. + Each increment moves the iterator to the next match. + + Find iterator is a readable forward traversal iterator. + + Dereferencing the iterator yields an iterator_range delimiting + the current match. + */ + template + class find_iterator : + public iterator_facade< + find_iterator, + const iterator_range, + forward_traversal_tag >, + private detail::find_iterator_base + { + private: + // facade support + friend class ::boost::iterator_core_access; + + private: + // typedefs + + typedef detail::find_iterator_base base_type; + typedef BOOST_STRING_TYPENAME + base_type::input_iterator_type input_iterator_type; + typedef BOOST_STRING_TYPENAME + base_type::match_type match_type; + + public: + //! Default constructor + /*! + Construct null iterator. All null iterators are equal. + + \post eof()==true + */ + find_iterator() {} + + //! Copy constructor + /*! + Construct a copy of the find_iterator + */ + find_iterator( const find_iterator& Other ) : + base_type(Other), + m_Match(Other.m_Match), + m_End(Other.m_End) {} + + //! Constructor + /*! + Construct new find_iterator for a given finder + and a range. + */ + template + find_iterator( + IteratorT Begin, + IteratorT End, + FinderT Finder ) : + detail::find_iterator_base(Finder,0), + m_Match(Begin,Begin), + m_End(End) + { + increment(); + } + + //! Constructor + /*! + Construct new find_iterator for a given finder + and a range. + */ + template + find_iterator( + RangeT& Col, + FinderT Finder ) : + detail::find_iterator_base(Finder,0) + { + iterator_range::type> lit_col(::boost::as_literal(Col)); + m_Match=::boost::make_iterator_range(::boost::begin(lit_col), ::boost::begin(lit_col)); + m_End=::boost::end(lit_col); + + increment(); + } + + private: + // iterator operations + + // dereference + const match_type& dereference() const + { + return m_Match; + } + + // increment + void increment() + { + m_Match=this->do_find(m_Match.end(),m_End); + } + + // comparison + bool equal( const find_iterator& Other ) const + { + bool bEof=eof(); + bool bOtherEof=Other.eof(); + + return bEof || bOtherEof ? bEof==bOtherEof : + ( + m_Match==Other.m_Match && + m_End==Other.m_End + ); + } + + public: + // operations + + //! Eof check + /*! + Check the eof condition. Eof condition means that + there is nothing more to be searched i.e. find_iterator + is after the last match. + */ + bool eof() const + { + return + this->is_null() || + ( + m_Match.begin() == m_End && + m_Match.end() == m_End + ); + } + + private: + // Attributes + match_type m_Match; + input_iterator_type m_End; + }; + + //! find iterator construction helper + /*! + * Construct a find iterator to iterate through the specified string + */ + template + inline find_iterator< + BOOST_STRING_TYPENAME range_iterator::type> + make_find_iterator( + RangeT& Collection, + FinderT Finder) + { + return find_iterator::type>( + Collection, Finder); + } + +// split iterator -----------------------------------------------// + + //! split_iterator + /*! + Split iterator encapsulates a Finder and allows + for incremental searching in a string. + Unlike the find iterator, split iterator iterates + through gaps between matches. + + Find iterator is a readable forward traversal iterator. + + Dereferencing the iterator yields an iterator_range delimiting + the current match. + */ + template + class split_iterator : + public iterator_facade< + split_iterator, + const iterator_range, + forward_traversal_tag >, + private detail::find_iterator_base + { + private: + // facade support + friend class ::boost::iterator_core_access; + + private: + // typedefs + + typedef detail::find_iterator_base base_type; + typedef BOOST_STRING_TYPENAME + base_type::input_iterator_type input_iterator_type; + typedef BOOST_STRING_TYPENAME + base_type::match_type match_type; + + public: + //! Default constructor + /*! + Construct null iterator. All null iterators are equal. + + \post eof()==true + */ + split_iterator() : + m_Next(), + m_End(), + m_bEof(true) + {} + + //! Copy constructor + /*! + Construct a copy of the split_iterator + */ + split_iterator( const split_iterator& Other ) : + base_type(Other), + m_Match(Other.m_Match), + m_Next(Other.m_Next), + m_End(Other.m_End), + m_bEof(Other.m_bEof) + {} + + //! Constructor + /*! + Construct new split_iterator for a given finder + and a range. + */ + template + split_iterator( + IteratorT Begin, + IteratorT End, + FinderT Finder ) : + detail::find_iterator_base(Finder,0), + m_Match(Begin,Begin), + m_Next(Begin), + m_End(End), + m_bEof(false) + { + // force the correct behavior for empty sequences and yield at least one token + if(Begin!=End) + { + increment(); + } + } + //! Constructor + /*! + Construct new split_iterator for a given finder + and a collection. + */ + template + split_iterator( + RangeT& Col, + FinderT Finder ) : + detail::find_iterator_base(Finder,0), + m_bEof(false) + { + iterator_range::type> lit_col(::boost::as_literal(Col)); + m_Match=make_iterator_range(::boost::begin(lit_col), ::boost::begin(lit_col)); + m_Next=::boost::begin(lit_col); + m_End=::boost::end(lit_col); + + // force the correct behavior for empty sequences and yield at least one token + if(m_Next!=m_End) + { + increment(); + } + } + + + private: + // iterator operations + + // dereference + const match_type& dereference() const + { + return m_Match; + } + + // increment + void increment() + { + match_type FindMatch=this->do_find( m_Next, m_End ); + + if(FindMatch.begin()==m_End && FindMatch.end()==m_End) + { + if(m_Match.end()==m_End) + { + // Mark iterator as eof + m_bEof=true; + } + } + + m_Match=match_type( m_Next, FindMatch.begin() ); + m_Next=FindMatch.end(); + } + + // comparison + bool equal( const split_iterator& Other ) const + { + bool bEof=eof(); + bool bOtherEof=Other.eof(); + + return bEof || bOtherEof ? bEof==bOtherEof : + ( + m_Match==Other.m_Match && + m_Next==Other.m_Next && + m_End==Other.m_End + ); + } + + public: + // operations + + //! Eof check + /*! + Check the eof condition. Eof condition means that + there is nothing more to be searched i.e. find_iterator + is after the last match. + */ + bool eof() const + { + return this->is_null() || m_bEof; + } + + private: + // Attributes + match_type m_Match; + input_iterator_type m_Next; + input_iterator_type m_End; + bool m_bEof; + }; + + //! split iterator construction helper + /*! + * Construct a split iterator to iterate through the specified collection + */ + template + inline split_iterator< + BOOST_STRING_TYPENAME range_iterator::type> + make_split_iterator( + RangeT& Collection, + FinderT Finder) + { + return split_iterator::type>( + Collection, Finder); + } + + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::find_iterator; + using algorithm::make_find_iterator; + using algorithm::split_iterator; + using algorithm::make_split_iterator; + +} // namespace boost + + +#endif // BOOST_STRING_FIND_ITERATOR_HPP diff --git a/boost/algorithm/string/iter_find.hpp b/boost/algorithm/string/iter_find.hpp new file mode 100644 index 0000000..d76a819 --- /dev/null +++ b/boost/algorithm/string/iter_find.hpp @@ -0,0 +1,201 @@ +// Boost string_algo library iter_find.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_ITER_FIND_HPP +#define BOOST_STRING_ITER_FIND_HPP + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file + Defines generic split algorithms. Split algorithms can be + used to divide a sequence into several part according + to a given criteria. Result is given as a 'container + of containers' where elements are copies or references + to extracted parts. + + There are two algorithms provided. One iterates over matching + substrings, the other one over the gaps between these matches. +*/ + +namespace boost { + namespace algorithm { + +// iterate find ---------------------------------------------------// + + //! Iter find algorithm + /*! + This algorithm executes a given finder in iteration on the input, + until the end of input is reached, or no match is found. + Iteration is done using built-in find_iterator, so the real + searching is performed only when needed. + In each iteration new match is found and added to the result. + + \param Result A 'container container' to contain the result of search. + Both outer and inner container must have constructor taking a pair + of iterators as an argument. + Typical type of the result is + \c std::vector> + (each element of such a vector will container a range delimiting + a match). + \param Input A container which will be searched. + \param Finder A Finder object used for searching + \return A reference to the result + + \note Prior content of the result will be overwritten. + */ + template< + typename SequenceSequenceT, + typename RangeT, + typename FinderT > + inline SequenceSequenceT& + iter_find( + SequenceSequenceT& Result, +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + RangeT&& Input, +#else + RangeT& Input, +#endif + FinderT Finder ) + { + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_iterator::type> + )); + + iterator_range::type> lit_input(::boost::as_literal(Input)); + + typedef BOOST_STRING_TYPENAME + range_iterator::type input_iterator_type; + typedef find_iterator find_iterator_type; + typedef detail::copy_iterator_rangeF< + BOOST_STRING_TYPENAME + range_value::type, + input_iterator_type> copy_range_type; + + input_iterator_type InputEnd=::boost::end(lit_input); + + typedef transform_iterator + transform_iter_type; + + transform_iter_type itBegin= + ::boost::make_transform_iterator( + find_iterator_type( ::boost::begin(lit_input), InputEnd, Finder ), + copy_range_type()); + + transform_iter_type itEnd= + ::boost::make_transform_iterator( + find_iterator_type(), + copy_range_type()); + + SequenceSequenceT Tmp(itBegin, itEnd); + + Result.swap(Tmp); + return Result; + } + +// iterate split ---------------------------------------------------// + + //! Split find algorithm + /*! + This algorithm executes a given finder in iteration on the input, + until the end of input is reached, or no match is found. + Iteration is done using built-in find_iterator, so the real + searching is performed only when needed. + Each match is used as a separator of segments. These segments are then + returned in the result. + + \param Result A 'container container' to contain the result of search. + Both outer and inner container must have constructor taking a pair + of iterators as an argument. + Typical type of the result is + \c std::vector> + (each element of such a vector will container a range delimiting + a match). + \param Input A container which will be searched. + \param Finder A finder object used for searching + \return A reference to the result + + \note Prior content of the result will be overwritten. + */ + template< + typename SequenceSequenceT, + typename RangeT, + typename FinderT > + inline SequenceSequenceT& + iter_split( + SequenceSequenceT& Result, +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + RangeT&& Input, +#else + RangeT& Input, +#endif + FinderT Finder ) + { + BOOST_CONCEPT_ASSERT(( + FinderConcept::type> + )); + + iterator_range::type> lit_input(::boost::as_literal(Input)); + + typedef BOOST_STRING_TYPENAME + range_iterator::type input_iterator_type; + typedef split_iterator find_iterator_type; + typedef detail::copy_iterator_rangeF< + BOOST_STRING_TYPENAME + range_value::type, + input_iterator_type> copy_range_type; + + input_iterator_type InputEnd=::boost::end(lit_input); + + typedef transform_iterator + transform_iter_type; + + transform_iter_type itBegin= + ::boost::make_transform_iterator( + find_iterator_type( ::boost::begin(lit_input), InputEnd, Finder ), + copy_range_type() ); + + transform_iter_type itEnd= + ::boost::make_transform_iterator( + find_iterator_type(), + copy_range_type() ); + + SequenceSequenceT Tmp(itBegin, itEnd); + + Result.swap(Tmp); + return Result; + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::iter_find; + using algorithm::iter_split; + +} // namespace boost + + +#endif // BOOST_STRING_ITER_FIND_HPP diff --git a/boost/algorithm/string/predicate_facade.hpp b/boost/algorithm/string/predicate_facade.hpp new file mode 100644 index 0000000..a9753fc --- /dev/null +++ b/boost/algorithm/string/predicate_facade.hpp @@ -0,0 +1,42 @@ +// Boost string_algo library predicate_facade.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_PREDICATE_FACADE_HPP +#define BOOST_STRING_PREDICATE_FACADE_HPP + +#include + +/* + \file boost/algorith/string/predicate_facade.hpp + This file contains predicate_facade definition. This template class is used + to identify classification predicates, so they can be combined using + composition operators. +*/ + +namespace boost { + namespace algorithm { + +// predicate facade ------------------------------------------------------// + + //! Predicate facade + /*! + This class allows to recognize classification + predicates, so that they can be combined using + composition operators. + Every classification predicate must be derived from this class. + */ + template + struct predicate_facade {}; + + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_CLASSIFICATION_DETAIL_HPP diff --git a/boost/algorithm/string/split.hpp b/boost/algorithm/string/split.hpp new file mode 100644 index 0000000..e0b30fb --- /dev/null +++ b/boost/algorithm/string/split.hpp @@ -0,0 +1,175 @@ +// Boost string_algo library split.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_SPLIT_HPP +#define BOOST_STRING_SPLIT_HPP + +#include + +#include +#include +#include + +/*! \file + Defines basic split algorithms. + Split algorithms can be used to divide a string + into several parts according to given criteria. + + Each part is copied and added as a new element to the + output container. + Thus the result container must be able to hold copies + of the matches (in a compatible structure like std::string) or + a reference to it (e.g. using the iterator range class). + Examples of such a container are \c std::vector + or \c std::list> +*/ + +namespace boost { + namespace algorithm { + +// find_all ------------------------------------------------------------// + + //! Find all algorithm + /*! + This algorithm finds all occurrences of the search string + in the input. + + Each part is copied and added as a new element to the + output container. + Thus the result container must be able to hold copies + of the matches (in a compatible structure like std::string) or + a reference to it (e.g. using the iterator range class). + Examples of such a container are \c std::vector + or \c std::list> + + \param Result A container that can hold copies of references to the substrings + \param Input A container which will be searched. + \param Search A substring to be searched for. + \return A reference the result + + \note Prior content of the result will be overwritten. + + \note This function provides the strong exception-safety guarantee + */ + template< typename SequenceSequenceT, typename Range1T, typename Range2T > + inline SequenceSequenceT& find_all( + SequenceSequenceT& Result, +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + Range1T&& Input, +#else + Range1T& Input, +#endif + const Range2T& Search) + { + return ::boost::algorithm::iter_find( + Result, + Input, + ::boost::algorithm::first_finder(Search) ); + } + + //! Find all algorithm ( case insensitive ) + /*! + This algorithm finds all occurrences of the search string + in the input. + Each part is copied and added as a new element to the + output container. Thus the result container must be able to hold copies + of the matches (in a compatible structure like std::string) or + a reference to it (e.g. using the iterator range class). + Examples of such a container are \c std::vector + or \c std::list> + + Searching is case insensitive. + + \param Result A container that can hold copies of references to the substrings + \param Input A container which will be searched. + \param Search A substring to be searched for. + \param Loc A locale used for case insensitive comparison + \return A reference the result + + \note Prior content of the result will be overwritten. + + \note This function provides the strong exception-safety guarantee + */ + template< typename SequenceSequenceT, typename Range1T, typename Range2T > + inline SequenceSequenceT& ifind_all( + SequenceSequenceT& Result, +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + Range1T&& Input, +#else + Range1T& Input, +#endif + const Range2T& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::iter_find( + Result, + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc) ) ); + } + + +// tokenize -------------------------------------------------------------// + + //! Split algorithm + /*! + Tokenize expression. This function is equivalent to C strtok. Input + sequence is split into tokens, separated by separators. Separators + are given by means of the predicate. + + Each part is copied and added as a new element to the + output container. + Thus the result container must be able to hold copies + of the matches (in a compatible structure like std::string) or + a reference to it (e.g. using the iterator range class). + Examples of such a container are \c std::vector + or \c std::list> + + \param Result A container that can hold copies of references to the substrings + \param Input A container which will be searched. + \param Pred A predicate to identify separators. This predicate is + supposed to return true if a given element is a separator. + \param eCompress If eCompress argument is set to token_compress_on, adjacent + separators are merged together. Otherwise, every two separators + delimit a token. + \return A reference the result + + \note Prior content of the result will be overwritten. + + \note This function provides the strong exception-safety guarantee + */ + template< typename SequenceSequenceT, typename RangeT, typename PredicateT > + inline SequenceSequenceT& split( + SequenceSequenceT& Result, +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + RangeT&& Input, +#else + RangeT& Input, +#endif + PredicateT Pred, + token_compress_mode_type eCompress=token_compress_off ) + { + return ::boost::algorithm::iter_split( + Result, + Input, + ::boost::algorithm::token_finder( Pred, eCompress ) ); + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::find_all; + using algorithm::ifind_all; + using algorithm::split; + +} // namespace boost + + +#endif // BOOST_STRING_SPLIT_HPP + diff --git a/boost/algorithm/string/trim.hpp b/boost/algorithm/string/trim.hpp new file mode 100644 index 0000000..e740d57 --- /dev/null +++ b/boost/algorithm/string/trim.hpp @@ -0,0 +1,398 @@ +// Boost string_algo library trim.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_TRIM_HPP +#define BOOST_STRING_TRIM_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file + Defines trim algorithms. + Trim algorithms are used to remove trailing and leading spaces from a + sequence (string). Space is recognized using given locales. + + Parametric (\c _if) variants use a predicate (functor) to select which characters + are to be trimmed.. + Functions take a selection predicate as a parameter, which is used to determine + whether a character is a space. Common predicates are provided in classification.hpp header. + +*/ + +namespace boost { + namespace algorithm { + + // left trim -----------------------------------------------// + + + //! Left trim - parametric + /*! + Remove all leading spaces from the input. + The supplied predicate is used to determine which characters are considered spaces. + The result is a trimmed 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 range + \param IsSpace A unary predicate identifying spaces + \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 trim_left_copy_if( + OutputIteratorT Output, + const RangeT& Input, + PredicateT IsSpace) + { + iterator_range::type> lit_range(::boost::as_literal(Input)); + + std::copy( + ::boost::algorithm::detail::trim_begin( + ::boost::begin(lit_range), + ::boost::end(lit_range), + IsSpace ), + ::boost::end(lit_range), + Output); + + return Output; + } + + //! Left trim - parametric + /*! + \overload + */ + template + inline SequenceT trim_left_copy_if(const SequenceT& Input, PredicateT IsSpace) + { + return SequenceT( + ::boost::algorithm::detail::trim_begin( + ::boost::begin(Input), + ::boost::end(Input), + IsSpace ), + ::boost::end(Input)); + } + + //! Left trim - parametric + /*! + Remove all leading spaces from the input. + The result is a trimmed copy of the input. + + \param Input An input sequence + \param Loc a locale used for 'space' classification + \return A trimmed copy of the input + + \note This function provides the strong exception-safety guarantee + */ + template + inline SequenceT trim_left_copy(const SequenceT& Input, const std::locale& Loc=std::locale()) + { + return + ::boost::algorithm::trim_left_copy_if( + Input, + is_space(Loc)); + } + + //! Left trim + /*! + Remove all leading spaces from the input. The supplied predicate is + used to determine which characters are considered spaces. + The input sequence is modified in-place. + + \param Input An input sequence + \param IsSpace A unary predicate identifying spaces + */ + template + inline void trim_left_if(SequenceT& Input, PredicateT IsSpace) + { + Input.erase( + ::boost::begin(Input), + ::boost::algorithm::detail::trim_begin( + ::boost::begin(Input), + ::boost::end(Input), + IsSpace)); + } + + //! Left trim + /*! + Remove all leading spaces from the input. + The Input sequence is modified in-place. + + \param Input An input sequence + \param Loc A locale used for 'space' classification + */ + template + inline void trim_left(SequenceT& Input, const std::locale& Loc=std::locale()) + { + ::boost::algorithm::trim_left_if( + Input, + is_space(Loc)); + } + + // right trim -----------------------------------------------// + + //! Right trim - parametric + /*! + Remove all trailing spaces from the input. + The supplied predicate is used to determine which characters are considered spaces. + The result is a trimmed 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 range + \param IsSpace A unary predicate identifying spaces + \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 trim_right_copy_if( + OutputIteratorT Output, + const RangeT& Input, + PredicateT IsSpace ) + { + iterator_range::type> lit_range(::boost::as_literal(Input)); + + std::copy( + ::boost::begin(lit_range), + ::boost::algorithm::detail::trim_end( + ::boost::begin(lit_range), + ::boost::end(lit_range), + IsSpace ), + Output ); + + return Output; + } + + //! Right trim - parametric + /*! + \overload + */ + template + inline SequenceT trim_right_copy_if(const SequenceT& Input, PredicateT IsSpace) + { + return SequenceT( + ::boost::begin(Input), + ::boost::algorithm::detail::trim_end( + ::boost::begin(Input), + ::boost::end(Input), + IsSpace) + ); + } + + //! Right trim + /*! + Remove all trailing spaces from the input. + The result is a trimmed copy of the input + + \param Input An input sequence + \param Loc A locale used for 'space' classification + \return A trimmed copy of the input + + \note This function provides the strong exception-safety guarantee + */ + template + inline SequenceT trim_right_copy(const SequenceT& Input, const std::locale& Loc=std::locale()) + { + return + ::boost::algorithm::trim_right_copy_if( + Input, + is_space(Loc)); + } + + + //! Right trim - parametric + /*! + Remove all trailing spaces from the input. + The supplied predicate is used to determine which characters are considered spaces. + The input sequence is modified in-place. + + \param Input An input sequence + \param IsSpace A unary predicate identifying spaces + */ + template + inline void trim_right_if(SequenceT& Input, PredicateT IsSpace) + { + Input.erase( + ::boost::algorithm::detail::trim_end( + ::boost::begin(Input), + ::boost::end(Input), + IsSpace ), + ::boost::end(Input) + ); + } + + + //! Right trim + /*! + Remove all trailing spaces from the input. + The input sequence is modified in-place. + + \param Input An input sequence + \param Loc A locale used for 'space' classification + */ + template + inline void trim_right(SequenceT& Input, const std::locale& Loc=std::locale()) + { + ::boost::algorithm::trim_right_if( + Input, + is_space(Loc) ); + } + + // both side trim -----------------------------------------------// + + //! Trim - parametric + /*! + Remove all trailing and leading spaces from the input. + The supplied predicate is used to determine which characters are considered spaces. + The result is a trimmed 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 range + \param IsSpace A unary predicate identifying spaces + \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 trim_copy_if( + OutputIteratorT Output, + const RangeT& Input, + PredicateT IsSpace) + { + iterator_range::type> lit_range(::boost::as_literal(Input)); + + BOOST_STRING_TYPENAME + range_const_iterator::type TrimEnd= + ::boost::algorithm::detail::trim_end( + ::boost::begin(lit_range), + ::boost::end(lit_range), + IsSpace); + + std::copy( + detail::trim_begin( + ::boost::begin(lit_range), TrimEnd, IsSpace), + TrimEnd, + Output + ); + + return Output; + } + + //! Trim - parametric + /*! + \overload + */ + template + inline SequenceT trim_copy_if(const SequenceT& Input, PredicateT IsSpace) + { + BOOST_STRING_TYPENAME + range_const_iterator::type TrimEnd= + ::boost::algorithm::detail::trim_end( + ::boost::begin(Input), + ::boost::end(Input), + IsSpace); + + return SequenceT( + detail::trim_begin( + ::boost::begin(Input), + TrimEnd, + IsSpace), + TrimEnd + ); + } + + //! Trim + /*! + Remove all leading and trailing spaces from the input. + The result is a trimmed copy of the input + + \param Input An input sequence + \param Loc A locale used for 'space' classification + \return A trimmed copy of the input + + \note This function provides the strong exception-safety guarantee + */ + template + inline SequenceT trim_copy( const SequenceT& Input, const std::locale& Loc=std::locale() ) + { + return + ::boost::algorithm::trim_copy_if( + Input, + is_space(Loc) ); + } + + //! Trim + /*! + Remove all leading and trailing spaces from the input. + The supplied predicate is used to determine which characters are considered spaces. + The input sequence is modified in-place. + + \param Input An input sequence + \param IsSpace A unary predicate identifying spaces + */ + template + inline void trim_if(SequenceT& Input, PredicateT IsSpace) + { + ::boost::algorithm::trim_right_if( Input, IsSpace ); + ::boost::algorithm::trim_left_if( Input, IsSpace ); + } + + //! Trim + /*! + Remove all leading and trailing spaces from the input. + The input sequence is modified in-place. + + \param Input An input sequence + \param Loc A locale used for 'space' classification + */ + template + inline void trim(SequenceT& Input, const std::locale& Loc=std::locale()) + { + ::boost::algorithm::trim_if( + Input, + is_space( Loc ) ); + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::trim_left; + using algorithm::trim_left_if; + using algorithm::trim_left_copy; + using algorithm::trim_left_copy_if; + using algorithm::trim_right; + using algorithm::trim_right_if; + using algorithm::trim_right_copy; + using algorithm::trim_right_copy_if; + using algorithm::trim; + using algorithm::trim_if; + using algorithm::trim_copy; + using algorithm::trim_copy_if; + +} // namespace boost + +#endif // BOOST_STRING_TRIM_HPP diff --git a/boost/asio/async_result.hpp b/boost/asio/async_result.hpp index 4f3bb1e..d085798 100644 --- a/boost/asio/async_result.hpp +++ b/boost/asio/async_result.hpp @@ -24,6 +24,66 @@ namespace boost { namespace asio { +#if defined(BOOST_ASIO_HAS_CONCEPTS) \ + && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ + && defined(BOOST_ASIO_HAS_DECLTYPE) + +namespace detail { + +template +struct is_completion_signature : false_type +{ +}; + +template +struct is_completion_signature : true_type +{ +}; + +template +BOOST_ASIO_CONCEPT callable_with = requires(T t, Args&&... args) +{ + t(static_cast(args)...); +}; + +template +struct is_completion_handler_for : false_type +{ +}; + +template +struct is_completion_handler_for + : integral_constant)> +{ +}; + +} // namespace detail + +template +BOOST_ASIO_CONCEPT completion_signature = + detail::is_completion_signature::value; + +#define BOOST_ASIO_COMPLETION_SIGNATURE \ + ::boost::asio::completion_signature + +template +BOOST_ASIO_CONCEPT completion_handler_for = + detail::is_completion_handler_for::value; + +#define BOOST_ASIO_COMPLETION_HANDLER_FOR(s) \ + ::boost::asio::completion_handler_for + +#else // defined(BOOST_ASIO_HAS_CONCEPTS) + // && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // && defined(BOOST_ASIO_HAS_DECLTYPE) + +#define BOOST_ASIO_COMPLETION_SIGNATURE typename +#define BOOST_ASIO_COMPLETION_HANDLER_FOR(s) typename + +#endif // defined(BOOST_ASIO_HAS_CONCEPTS) + // && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // && defined(BOOST_ASIO_HAS_DECLTYPE) + /// An interface for customising the behaviour of an initiating function. /** * The async_result traits class is used for determining: @@ -42,7 +102,7 @@ namespace asio { * The primary template assumes that the CompletionToken is the completion * handler. */ -template +template class async_result { public: @@ -68,12 +128,21 @@ public: { } -#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ - || defined(GENERATING_DOCUMENTATION) +#if defined(GENERATING_DOCUMENTATION) /// Initiate the asynchronous operation that will produce the result, and /// obtain the value to be returned from the initiating function. template + static return_type initiate( + BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_MOVE_ARG(RawCompletionToken) token, + BOOST_ASIO_MOVE_ARG(Args)... args); + +#elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template static return_type initiate( BOOST_ASIO_MOVE_ARG(Initiation) initiation, BOOST_ASIO_MOVE_ARG(RawCompletionToken) token, @@ -85,9 +154,9 @@ public: } #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) - // || defined(GENERATING_DOCUMENTATION) - template + template static return_type initiate( BOOST_ASIO_MOVE_ARG(Initiation) initiation, BOOST_ASIO_MOVE_ARG(RawCompletionToken) token) @@ -97,7 +166,8 @@ public: } #define BOOST_ASIO_PRIVATE_INITIATE_DEF(n) \ - template \ static return_type initiate( \ BOOST_ASIO_MOVE_ARG(Initiation) initiation, \ @@ -113,17 +183,26 @@ public: #undef BOOST_ASIO_PRIVATE_INITIATE_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) - // || defined(GENERATING_DOCUMENTATION) private: async_result(const async_result&) BOOST_ASIO_DELETED; async_result& operator=(const async_result&) BOOST_ASIO_DELETED; }; +#if !defined(GENERATING_DOCUMENTATION) + +template +class async_result +{ + // Empty. +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + /// Helper template to deduce the handler type from a CompletionToken, capture /// a local copy of the handler, and then create an async_result for the /// handler. -template +template struct async_completion { /// The real handler type to be used for the asynchronous operation. @@ -233,22 +312,50 @@ struct async_result_has_initiate_memfn typename ::boost::asio::decay::type, sig>::completion_handler_type #endif +#if defined(GENERATION_DOCUMENTATION) +# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \ + auto +#elif defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) +# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \ + auto +#else +# define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \ + BOOST_ASIO_INITFN_RESULT_TYPE(ct, sig) +#endif + +#if defined(GENERATION_DOCUMENTATION) +# define BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \ + void_or_deduced +#elif defined(BOOST_ASIO_HAS_DECLTYPE) +# define BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \ + decltype expr +#else +# define BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \ + BOOST_ASIO_INITFN_RESULT_TYPE(ct, sig) +#endif + #if defined(GENERATING_DOCUMENTATION) -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) -async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, +void_or_deduced async_initiate( + BOOST_ASIO_MOVE_ARG(Initiation) initiation, BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken), BOOST_ASIO_MOVE_ARG(Args)... args); #elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) -template inline typename enable_if< detail::async_result_has_initiate_memfn::value, - BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type + BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature, + (async_result::type, + Signature>::initiate(declval(), + declval(), + declval()...)))>::type async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, BOOST_ASIO_MOVE_ARG(Args)... args) @@ -259,7 +366,8 @@ async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, BOOST_ASIO_MOVE_CAST(Args)(args)...); } -template inline typename enable_if< !detail::async_result_has_initiate_memfn::value, @@ -280,10 +388,15 @@ async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) -template +template inline typename enable_if< detail::async_result_has_initiate_memfn::value, - BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type + BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature, + (async_result::type, + Signature>::initiate(declval(), + declval())))>::type async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token) { @@ -292,7 +405,9 @@ async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); } -template +template inline typename enable_if< !detail::async_result_has_initiate_memfn::value, BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type @@ -309,12 +424,17 @@ async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, } #define BOOST_ASIO_PRIVATE_INITIATE_DEF(n) \ - template \ inline typename enable_if< \ detail::async_result_has_initiate_memfn< \ CompletionToken, Signature>::value, \ - BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type \ + BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature, \ + (async_result::type, \ + Signature>::initiate(declval(), \ + declval(), \ + BOOST_ASIO_VARIADIC_MOVE_DECLVAL(n))))>::type \ async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, \ BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \ BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ @@ -325,7 +445,8 @@ async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ } \ \ - template \ inline typename enable_if< \ !detail::async_result_has_initiate_memfn< \ @@ -350,6 +471,114 @@ async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#if defined(BOOST_ASIO_HAS_CONCEPTS) \ + && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ + && defined(BOOST_ASIO_HAS_DECLTYPE) + +namespace detail { + +template +struct initiation_archetype +{ + template CompletionHandler> + void operator()(CompletionHandler&&) const + { + } +}; + +} // namespace detail + +template +BOOST_ASIO_CONCEPT completion_token_for = requires(T&& t) +{ + async_initiate(detail::initiation_archetype{}, t); +}; + +#define BOOST_ASIO_COMPLETION_TOKEN_FOR(s) \ + ::boost::asio::completion_token_for + +#else // defined(BOOST_ASIO_HAS_CONCEPTS) + // && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // && defined(BOOST_ASIO_HAS_DECLTYPE) + +#define BOOST_ASIO_COMPLETION_TOKEN_FOR(s) typename + +#endif // defined(BOOST_ASIO_HAS_CONCEPTS) + // && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // && defined(BOOST_ASIO_HAS_DECLTYPE) + +namespace detail { + +template +struct default_completion_token_check +{ + typedef void type; +}; + +template +struct default_completion_token_impl +{ + typedef void type; +}; + +template +struct default_completion_token_impl::type> +{ + typedef typename T::default_completion_token_type type; +}; + +} // namespace detail + +#if defined(GENERATING_DOCUMENTATION) + +/// Traits type used to determine the default completion token type associated +/// with a type (such as an executor). +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. + * + * Specialisations of this trait may provide a nested typedef @c type, which is + * a default-constructible completion token type. + */ +template +struct default_completion_token +{ + /// If @c T has a nested type @c default_completion_token_type, + /// T::default_completion_token_type. Otherwise the typedef @c type + /// is not defined. + typedef see_below type; +}; +#else +template +struct default_completion_token + : detail::default_completion_token_impl +{ +}; +#endif + +#if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + +template +using default_completion_token_t = typename default_completion_token::type; + +#endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + +#if defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) + +#define BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(e) \ + = typename ::boost::asio::default_completion_token::type +#define BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(e) \ + = typename ::boost::asio::default_completion_token::type() + +#else // defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) + +#define BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(e) +#define BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(e) + +#endif // defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) + } // namespace asio } // namespace boost diff --git a/boost/asio/basic_datagram_socket.hpp b/boost/asio/basic_datagram_socket.hpp index b058f78..55087de 100644 --- a/boost/asio/basic_datagram_socket.hpp +++ b/boost/asio/basic_datagram_socket.hpp @@ -249,7 +249,7 @@ public: * constructed using the @c basic_datagram_socket(const executor_type&) * constructor. */ - basic_datagram_socket(basic_datagram_socket&& other) + basic_datagram_socket(basic_datagram_socket&& other) BOOST_ASIO_NOEXCEPT : basic_socket(std::move(other)) { } @@ -448,15 +448,19 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send(const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_send(), handler, this, + initiate_async_send(this), handler, buffers, socket_base::message_flags(0)); } @@ -488,16 +492,20 @@ public: * Use the async_send_to function to send data on an unconnected datagram * socket. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send(const ConstBufferSequence& buffers, socket_base::message_flags flags, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_send(), handler, this, buffers, flags); + initiate_async_send(this), handler, buffers, flags); } /// Send a datagram to the specified endpoint. @@ -625,16 +633,20 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_send_to(), handler, this, buffers, + initiate_async_send_to(this), handler, buffers, destination, socket_base::message_flags(0)); } @@ -665,16 +677,20 @@ public: * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_send_to(), handler, this, buffers, destination, flags); + initiate_async_send_to(this), handler, buffers, destination, flags); } /// Receive some data on a connected socket. @@ -802,15 +818,19 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive(const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_receive(), handler, this, + initiate_async_receive(this), handler, buffers, socket_base::message_flags(0)); } @@ -842,16 +862,20 @@ public: * Use the async_receive_from function to receive data on an unconnected * datagram socket. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_receive(), handler, this, buffers, flags); + initiate_async_receive(this), handler, buffers, flags); } /// Receive a datagram with the endpoint of the sender. @@ -979,16 +1003,20 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_receive_from(), handler, this, buffers, + initiate_async_receive_from(this), handler, buffers, &sender_endpoint, socket_base::message_flags(0)); } @@ -1021,25 +1049,42 @@ public: * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_receive_from(), handler, - this, buffers, &sender_endpoint, flags); + initiate_async_receive_from(this), handler, + buffers, &sender_endpoint, flags); } private: - struct initiate_async_send - { + class initiate_async_send + { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_datagram_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - basic_datagram_socket* self, const ConstBufferSequence& buffers, + const ConstBufferSequence& buffers, socket_base::message_flags flags) const { // If you get an error on the following line it means that your handler @@ -1047,18 +1092,33 @@ private: BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_send( - self->impl_.get_implementation(), buffers, flags, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_send( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_datagram_socket* self_; }; - struct initiate_async_send_to + class initiate_async_send_to { + public: + typedef Executor executor_type; + + explicit initiate_async_send_to(basic_datagram_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - basic_datagram_socket* self, const ConstBufferSequence& buffers, - const endpoint_type& destination, + const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags) const { // If you get an error on the following line it means that your handler @@ -1066,17 +1126,33 @@ private: BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_send_to( - self->impl_.get_implementation(), buffers, destination, flags, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_send_to( + self_->impl_.get_implementation(), buffers, destination, flags, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_datagram_socket* self_; }; - struct initiate_async_receive + class initiate_async_receive { + public: + typedef Executor executor_type; + + explicit initiate_async_receive(basic_datagram_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - basic_datagram_socket* self, const MutableBufferSequence& buffers, + const MutableBufferSequence& buffers, socket_base::message_flags flags) const { // If you get an error on the following line it means that your handler @@ -1084,28 +1160,47 @@ private: BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_receive( - self->impl_.get_implementation(), buffers, flags, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_receive( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_datagram_socket* self_; }; - struct initiate_async_receive_from + class initiate_async_receive_from { + public: + typedef Executor executor_type; + + explicit initiate_async_receive_from(basic_datagram_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - basic_datagram_socket* self, const MutableBufferSequence& buffers, - endpoint_type* sender_endpoint, socket_base::message_flags flags) const + const MutableBufferSequence& buffers, endpoint_type* sender_endpoint, + socket_base::message_flags flags) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_receive_from( - self->impl_.get_implementation(), buffers, *sender_endpoint, flags, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_receive_from( + self_->impl_.get_implementation(), buffers, *sender_endpoint, flags, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_datagram_socket* self_; }; }; diff --git a/boost/asio/basic_deadline_timer.hpp b/boost/asio/basic_deadline_timer.hpp index 75f0fcd..9093464 100644 --- a/boost/asio/basic_deadline_timer.hpp +++ b/boost/asio/basic_deadline_timer.hpp @@ -133,6 +133,14 @@ public: /// The type of the executor associated with the object. typedef Executor executor_type; + /// Rebinds the timer type to another executor. + template + struct rebind_executor + { + /// The timer type when rebound to the specified executor. + typedef basic_deadline_timer other; + }; + /// The time traits type. typedef TimeTraits traits_type; @@ -621,13 +629,17 @@ public: * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) + WaitHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (boost::system::error_code)) - async_wait(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + async_wait( + BOOST_ASIO_MOVE_ARG(WaitHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_wait(), handler, this); + initiate_async_wait(this), handler); } private: @@ -636,21 +648,36 @@ private: basic_deadline_timer& operator=( const basic_deadline_timer&) BOOST_ASIO_DELETED; - struct initiate_async_wait + class initiate_async_wait { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_deadline_timer* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template - void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, - basic_deadline_timer* self) const + void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a WaitHandler. BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_wait( - self->impl_.get_implementation(), handler2.value, - self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), handler2.value, + self_->impl_.get_implementation_executor()); } + + private: + basic_deadline_timer* self_; }; detail::io_object_impl< diff --git a/boost/asio/basic_raw_socket.hpp b/boost/asio/basic_raw_socket.hpp index cc45d37..88f064d 100644 --- a/boost/asio/basic_raw_socket.hpp +++ b/boost/asio/basic_raw_socket.hpp @@ -247,7 +247,7 @@ public: * constructed using the @c basic_raw_socket(const executor_type&) * constructor. */ - basic_raw_socket(basic_raw_socket&& other) + basic_raw_socket(basic_raw_socket&& other) BOOST_ASIO_NOEXCEPT : basic_socket(std::move(other)) { } @@ -440,15 +440,19 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send(const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_send(), handler, this, + initiate_async_send(this), handler, buffers, socket_base::message_flags(0)); } @@ -480,16 +484,20 @@ public: * Use the async_send_to function to send data on an unconnected raw * socket. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send(const ConstBufferSequence& buffers, socket_base::message_flags flags, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_send(), handler, this, buffers, flags); + initiate_async_send(this), handler, buffers, flags); } /// Send raw data to the specified endpoint. @@ -617,16 +625,20 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_send_to(), handler, this, buffers, + initiate_async_send_to(this), handler, buffers, destination, socket_base::message_flags(0)); } @@ -657,16 +669,20 @@ public: * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_send_to(), handler, this, buffers, destination, flags); + initiate_async_send_to(this), handler, buffers, destination, flags); } /// Receive some data on a connected socket. @@ -794,15 +810,19 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive(const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_receive(), handler, this, + initiate_async_receive(this), handler, buffers, socket_base::message_flags(0)); } @@ -834,16 +854,20 @@ public: * Use the async_receive_from function to receive data on an unconnected * raw socket. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_receive(), handler, this, buffers, flags); + initiate_async_receive(this), handler, buffers, flags); } /// Receive raw data with the endpoint of the sender. @@ -971,16 +995,20 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_receive_from(), handler, this, buffers, + initiate_async_receive_from(this), handler, buffers, &sender_endpoint, socket_base::message_flags(0)); } @@ -1013,25 +1041,42 @@ public: * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_receive_from(), handler, - this, buffers, &sender_endpoint, flags); + initiate_async_receive_from(this), handler, + buffers, &sender_endpoint, flags); } private: - struct initiate_async_send + class initiate_async_send { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_raw_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - basic_raw_socket* self, const ConstBufferSequence& buffers, + const ConstBufferSequence& buffers, socket_base::message_flags flags) const { // If you get an error on the following line it means that your handler @@ -1039,18 +1084,33 @@ private: BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_send( - self->impl_.get_implementation(), buffers, flags, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_send( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_raw_socket* self_; }; - struct initiate_async_send_to + class initiate_async_send_to { + public: + typedef Executor executor_type; + + explicit initiate_async_send_to(basic_raw_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - basic_raw_socket* self, const ConstBufferSequence& buffers, - const endpoint_type& destination, + const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags) const { // If you get an error on the following line it means that your handler @@ -1058,17 +1118,33 @@ private: BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_send_to( - self->impl_.get_implementation(), buffers, destination, flags, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_send_to( + self_->impl_.get_implementation(), buffers, destination, flags, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_raw_socket* self_; }; - struct initiate_async_receive + class initiate_async_receive { + public: + typedef Executor executor_type; + + explicit initiate_async_receive(basic_raw_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - basic_raw_socket* self, const MutableBufferSequence& buffers, + const MutableBufferSequence& buffers, socket_base::message_flags flags) const { // If you get an error on the following line it means that your handler @@ -1076,28 +1152,47 @@ private: BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_receive( - self->impl_.get_implementation(), buffers, flags, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_receive( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_raw_socket* self_; }; - struct initiate_async_receive_from + class initiate_async_receive_from { + public: + typedef Executor executor_type; + + explicit initiate_async_receive_from(basic_raw_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - basic_raw_socket* self, const MutableBufferSequence& buffers, - endpoint_type* sender_endpoint, socket_base::message_flags flags) const + const MutableBufferSequence& buffers, endpoint_type* sender_endpoint, + socket_base::message_flags flags) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_receive_from( - self->impl_.get_implementation(), buffers, *sender_endpoint, flags, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_receive_from( + self_->impl_.get_implementation(), buffers, *sender_endpoint, flags, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_raw_socket* self_; }; }; diff --git a/boost/asio/basic_seq_packet_socket.hpp b/boost/asio/basic_seq_packet_socket.hpp index 7c3903e..4a2e0ef 100644 --- a/boost/asio/basic_seq_packet_socket.hpp +++ b/boost/asio/basic_seq_packet_socket.hpp @@ -256,7 +256,7 @@ public: * constructed using the @c basic_seq_packet_socket(const executor_type&) * constructor. */ - basic_seq_packet_socket(basic_seq_packet_socket&& other) + basic_seq_packet_socket(basic_seq_packet_socket&& other) BOOST_ASIO_NOEXCEPT : basic_socket(std::move(other)) { } @@ -429,16 +429,20 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send(const ConstBufferSequence& buffers, socket_base::message_flags flags, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_send(), handler, this, buffers, flags); + initiate_async_send(this), handler, buffers, flags); } /// Receive some data on the socket. @@ -598,16 +602,20 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive(const MutableBufferSequence& buffers, socket_base::message_flags& out_flags, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_receive_with_flags(), handler, this, + initiate_async_receive_with_flags(this), handler, buffers, socket_base::message_flags(0), &out_flags); } @@ -653,26 +661,43 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive(const MutableBufferSequence& buffers, socket_base::message_flags in_flags, socket_base::message_flags& out_flags, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_receive_with_flags(), handler, - this, buffers, in_flags, &out_flags); + initiate_async_receive_with_flags(this), + handler, buffers, in_flags, &out_flags); } private: - struct initiate_async_send + class initiate_async_send { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_seq_packet_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - basic_seq_packet_socket* self, const ConstBufferSequence& buffers, + const ConstBufferSequence& buffers, socket_base::message_flags flags) const { // If you get an error on the following line it means that your handler @@ -680,17 +705,33 @@ private: BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_send( - self->impl_.get_implementation(), buffers, flags, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_send( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_seq_packet_socket* self_; }; - struct initiate_async_receive_with_flags + class initiate_async_receive_with_flags { + public: + typedef Executor executor_type; + + explicit initiate_async_receive_with_flags(basic_seq_packet_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - basic_seq_packet_socket* self, const MutableBufferSequence& buffers, + const MutableBufferSequence& buffers, socket_base::message_flags in_flags, socket_base::message_flags* out_flags) const { @@ -699,10 +740,13 @@ private: BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_receive_with_flags( - self->impl_.get_implementation(), buffers, in_flags, *out_flags, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_receive_with_flags( + self_->impl_.get_implementation(), buffers, in_flags, *out_flags, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_seq_packet_socket* self_; }; }; diff --git a/boost/asio/basic_serial_port.hpp b/boost/asio/basic_serial_port.hpp index 55144ee..72e37b3 100644 --- a/boost/asio/basic_serial_port.hpp +++ b/boost/asio/basic_serial_port.hpp @@ -64,6 +64,14 @@ public: /// The type of the executor associated with the object. typedef Executor executor_type; + /// Rebinds the serial port type to another executor. + template + struct rebind_executor + { + /// The serial port type when rebound to the specified executor. + typedef basic_serial_port other; + }; + /// The native representation of a serial port. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -682,15 +690,19 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_write_some(), handler, this, buffers); + initiate_async_write_some(this), handler, buffers); } /// Read some data from the serial port. @@ -793,15 +805,19 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_read_some(), handler, this, buffers); + initiate_async_read_some(this), handler, buffers); } private: @@ -809,38 +825,70 @@ private: basic_serial_port(const basic_serial_port&) BOOST_ASIO_DELETED; basic_serial_port& operator=(const basic_serial_port&) BOOST_ASIO_DELETED; - struct initiate_async_write_some + class initiate_async_write_some { + public: + typedef Executor executor_type; + + explicit initiate_async_write_some(basic_serial_port* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - basic_serial_port* self, const ConstBufferSequence& buffers) const + const ConstBufferSequence& buffers) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_write_some( - self->impl_.get_implementation(), buffers, handler2.value, - self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_write_some( + self_->impl_.get_implementation(), buffers, handler2.value, + self_->impl_.get_implementation_executor()); } + + private: + basic_serial_port* self_; }; - struct initiate_async_read_some + class initiate_async_read_some { + public: + typedef Executor executor_type; + + explicit initiate_async_read_some(basic_serial_port* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - basic_serial_port* self, const MutableBufferSequence& buffers) const + const MutableBufferSequence& buffers) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a ReadHandler. BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_read_some( - self->impl_.get_implementation(), buffers, handler2.value, - self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_read_some( + self_->impl_.get_implementation(), buffers, handler2.value, + self_->impl_.get_implementation_executor()); } + + private: + basic_serial_port* self_; }; #if defined(BOOST_ASIO_HAS_IOCP) diff --git a/boost/asio/basic_signal_set.hpp b/boost/asio/basic_signal_set.hpp index 175b4f4..d5a3b60 100644 --- a/boost/asio/basic_signal_set.hpp +++ b/boost/asio/basic_signal_set.hpp @@ -98,6 +98,14 @@ public: /// The type of the executor associated with the object. typedef Executor executor_type; + /// Rebinds the signal set type to another executor. + template + struct rebind_executor + { + /// The signal set type when rebound to the specified executor. + typedef basic_signal_set other; + }; + /// Construct a signal set without adding any signals. /** * This constructor creates a signal set without registering for any signals. @@ -503,13 +511,17 @@ public: * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(SignalHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, int)) + SignalHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(SignalHandler, void (boost::system::error_code, int)) - async_wait(BOOST_ASIO_MOVE_ARG(SignalHandler) handler) + async_wait( + BOOST_ASIO_MOVE_ARG(SignalHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_wait(), handler, this); + initiate_async_wait(this), handler); } private: @@ -517,21 +529,36 @@ private: basic_signal_set(const basic_signal_set&) BOOST_ASIO_DELETED; basic_signal_set& operator=(const basic_signal_set&) BOOST_ASIO_DELETED; - struct initiate_async_wait + class initiate_async_wait { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_signal_set* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template - void operator()(BOOST_ASIO_MOVE_ARG(SignalHandler) handler, - basic_signal_set* self) const + void operator()(BOOST_ASIO_MOVE_ARG(SignalHandler) handler) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a SignalHandler. BOOST_ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_wait( - self->impl_.get_implementation(), handler2.value, - self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), handler2.value, + self_->impl_.get_implementation_executor()); } + + private: + basic_signal_set* self_; }; detail::io_object_impl impl_; diff --git a/boost/asio/basic_socket.hpp b/boost/asio/basic_socket.hpp index 4f15f58..1561214 100644 --- a/boost/asio/basic_socket.hpp +++ b/boost/asio/basic_socket.hpp @@ -295,7 +295,7 @@ public: * @note Following the move, the moved-from object is in the same state as if * constructed using the @c basic_socket(const executor_type&) constructor. */ - basic_socket(basic_socket&& other) + basic_socket(basic_socket&& other) BOOST_ASIO_NOEXCEPT : impl_(std::move(other.impl_)) { } @@ -940,11 +940,14 @@ public: * socket.async_connect(endpoint, connect_handler); * @endcode */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) + ConnectHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ConnectHandler, void (boost::system::error_code)) async_connect(const endpoint_type& peer_endpoint, - BOOST_ASIO_MOVE_ARG(ConnectHandler) handler) + BOOST_ASIO_MOVE_ARG(ConnectHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { boost::system::error_code open_ec; if (!is_open()) @@ -954,7 +957,7 @@ public: } return async_initiate( - initiate_async_connect(), handler, this, peer_endpoint, open_ec); + initiate_async_connect(this), handler, peer_endpoint, open_ec); } /// Set an option on the socket. @@ -1770,13 +1773,17 @@ public: * socket.async_wait(boost::asio::ip::tcp::socket::wait_read, wait_handler); * @endcode */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) + WaitHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (boost::system::error_code)) - async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + async_wait(wait_type w, + BOOST_ASIO_MOVE_ARG(WaitHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_wait(), handler, this, w); + initiate_async_wait(this), handler, w); } protected: @@ -1805,11 +1812,24 @@ private: basic_socket(const basic_socket&) BOOST_ASIO_DELETED; basic_socket& operator=(const basic_socket&) BOOST_ASIO_DELETED; - struct initiate_async_connect + class initiate_async_connect { + public: + typedef Executor executor_type; + + explicit initiate_async_connect(basic_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(ConnectHandler) handler, - basic_socket* self, const endpoint_type& peer_endpoint, + const endpoint_type& peer_endpoint, const boost::system::error_code& open_ec) const { // If you get an error on the following line it means that your handler @@ -1818,35 +1838,53 @@ private: if (open_ec) { - boost::asio::post(self->impl_.get_executor(), + boost::asio::post(self_->impl_.get_executor(), boost::asio::detail::bind_handler( BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler), open_ec)); } else { detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_connect( - self->impl_.get_implementation(), peer_endpoint, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_connect( + self_->impl_.get_implementation(), peer_endpoint, + handler2.value, self_->impl_.get_implementation_executor()); } } + + private: + basic_socket* self_; }; - struct initiate_async_wait + class initiate_async_wait { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template - void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, - basic_socket* self, wait_type w) const + void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, wait_type w) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a WaitHandler. BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_wait( - self->impl_.get_implementation(), w, handler2.value, - self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), w, handler2.value, + self_->impl_.get_implementation_executor()); } + + private: + basic_socket* self_; }; }; diff --git a/boost/asio/basic_socket_acceptor.hpp b/boost/asio/basic_socket_acceptor.hpp index 12613b8..de5a392 100644 --- a/boost/asio/basic_socket_acceptor.hpp +++ b/boost/asio/basic_socket_acceptor.hpp @@ -81,6 +81,14 @@ public: /// The type of the executor associated with the object. typedef Executor executor_type; + /// Rebinds the acceptor type to another executor. + template + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_socket_acceptor other; + }; + /// The native representation of an acceptor. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -1211,13 +1219,17 @@ public: * wait_handler); * @endcode */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) + WaitHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (boost::system::error_code)) - async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + async_wait(wait_type w, + BOOST_ASIO_MOVE_ARG(WaitHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_wait(), handler, this, w); + initiate_async_wait(this), handler, w); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) @@ -1324,17 +1336,20 @@ public: * acceptor.async_accept(socket, accept_handler); * @endcode */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(AcceptHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(AcceptHandler, void (boost::system::error_code)) async_accept(basic_socket& peer, - BOOST_ASIO_MOVE_ARG(AcceptHandler) handler, + BOOST_ASIO_MOVE_ARG(AcceptHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), typename enable_if< is_convertible::value >::type* = 0) { return async_initiate( - initiate_async_accept(), handler, this, + initiate_async_accept(this), handler, &peer, static_cast(0)); } @@ -1434,14 +1449,18 @@ public: * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(AcceptHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(AcceptHandler, void (boost::system::error_code)) async_accept(basic_socket& peer, - endpoint_type& peer_endpoint, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler) + endpoint_type& peer_endpoint, + BOOST_ASIO_MOVE_ARG(AcceptHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_accept(), handler, this, &peer, &peer_endpoint); + initiate_async_accept(this), handler, &peer, &peer_endpoint); } #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) @@ -1466,10 +1485,12 @@ public: * boost::asio::ip::tcp::socket socket(acceptor.accept()); * @endcode */ - typename Protocol::socket accept() + typename Protocol::socket::template rebind_executor::other + accept() { boost::system::error_code ec; - typename Protocol::socket peer(impl_.get_executor()); + typename Protocol::socket::template rebind_executor< + executor_type>::other peer(impl_.get_executor()); impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); boost::asio::detail::throw_error(ec, "accept"); return peer; @@ -1500,9 +1521,11 @@ public: * } * @endcode */ - typename Protocol::socket accept(boost::system::error_code& ec) + typename Protocol::socket::template rebind_executor::other + accept(boost::system::error_code& ec) { - typename Protocol::socket peer(impl_.get_executor()); + typename Protocol::socket::template rebind_executor< + executor_type>::other peer(impl_.get_executor()); impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); return peer; } @@ -1519,8 +1542,11 @@ public: * 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. - * typename Protocol::socket peer // On success, the newly accepted socket. + * // Result of operation. + * const boost::system::error_code& error, + * // On success, the newly accepted socket. + * typename Protocol::socket::template + * rebind_executor::other peer * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. On @@ -1545,16 +1571,26 @@ public: * acceptor.async_accept(accept_handler); * @endcode */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, - void (boost::system::error_code, typename Protocol::socket)) - async_accept(BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler) + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + typename Protocol::socket::template rebind_executor< + executor_type>::other)) MoveAcceptHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, + void (boost::system::error_code, + typename Protocol::socket::template + rebind_executor::other)) + async_accept( + BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_move_accept(), handler, this, - impl_.get_executor(), static_cast(0), - static_cast(0)); + void (boost::system::error_code, typename Protocol::socket::template + rebind_executor::other)>( + initiate_async_move_accept(this), handler, + impl_.get_executor(), static_cast(0), + static_cast::other*>(0)); } /// Accept a new connection. @@ -1759,13 +1795,18 @@ public: * acceptor.async_accept(my_context2, accept_handler); * @endcode */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + template ::other)) MoveAcceptHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, void (boost::system::error_code, typename Protocol::socket::template rebind_executor< Executor1>::other)) async_accept(const Executor1& ex, - BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler, + BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), typename enable_if< is_executor::value >::type* = 0) @@ -1775,7 +1816,7 @@ public: return async_initiate( - initiate_async_move_accept(), handler, this, + initiate_async_move_accept(this), handler, ex, static_cast(0), static_cast(0)); } @@ -1823,13 +1864,18 @@ public: * acceptor.async_accept(my_context2, accept_handler); * @endcode */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + template ::other)) MoveAcceptHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, void (boost::system::error_code, typename Protocol::socket::template rebind_executor< typename ExecutionContext::executor_type>::other)) async_accept(ExecutionContext& context, - BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler, + BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), typename enable_if< is_convertible::value >::type* = 0) @@ -1839,7 +1885,7 @@ public: return async_initiate( - initiate_async_move_accept(), handler, this, + initiate_async_move_accept(this), handler, context.get_executor(), static_cast(0), static_cast(0)); } @@ -1868,10 +1914,12 @@ public: * boost::asio::ip::tcp::socket socket(acceptor.accept(endpoint)); * @endcode */ - typename Protocol::socket accept(endpoint_type& peer_endpoint) + typename Protocol::socket::template rebind_executor::other + accept(endpoint_type& peer_endpoint) { boost::system::error_code ec; - typename Protocol::socket peer(impl_.get_executor()); + typename Protocol::socket::template rebind_executor< + executor_type>::other peer(impl_.get_executor()); impl_.get_service().accept(impl_.get_implementation(), peer, &peer_endpoint, ec); boost::asio::detail::throw_error(ec, "accept"); @@ -1907,10 +1955,11 @@ public: * } * @endcode */ - typename Protocol::socket accept( - endpoint_type& peer_endpoint, boost::system::error_code& ec) + typename Protocol::socket::template rebind_executor::other + accept(endpoint_type& peer_endpoint, boost::system::error_code& ec) { - typename Protocol::socket peer(impl_.get_executor()); + typename Protocol::socket::template rebind_executor< + executor_type>::other peer(impl_.get_executor()); impl_.get_service().accept(impl_.get_implementation(), peer, &peer_endpoint, ec); return peer; @@ -1933,8 +1982,11 @@ public: * 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. - * typename Protocol::socket peer // On success, the newly accepted socket. + * // Result of operation. + * const boost::system::error_code& error, + * // On success, the newly accepted socket. + * typename Protocol::socket::template + * rebind_executor::other peer * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. On @@ -1960,17 +2012,26 @@ public: * acceptor.async_accept(endpoint, accept_handler); * @endcode */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, - void (boost::system::error_code, typename Protocol::socket)) + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + typename Protocol::socket::template rebind_executor< + executor_type>::other)) MoveAcceptHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, + void (boost::system::error_code, + typename Protocol::socket::template + rebind_executor::other)) async_accept(endpoint_type& peer_endpoint, - BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler) + BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_move_accept(), handler, this, - impl_.get_executor(), &peer_endpoint, - static_cast(0)); + void (boost::system::error_code, typename Protocol::socket::template + rebind_executor::other)>( + initiate_async_move_accept(this), handler, + impl_.get_executor(), &peer_endpoint, + static_cast::other*>(0)); } /// Accept a new connection. @@ -2207,13 +2268,18 @@ public: * acceptor.async_accept(my_context2, endpoint, accept_handler); * @endcode */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + template ::other)) MoveAcceptHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, void (boost::system::error_code, typename Protocol::socket::template rebind_executor< Executor1>::other)) async_accept(const Executor1& ex, endpoint_type& peer_endpoint, - BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler, + BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), typename enable_if< is_executor::value >::type* = 0) @@ -2223,7 +2289,7 @@ public: return async_initiate( - initiate_async_move_accept(), handler, this, + initiate_async_move_accept(this), handler, ex, &peer_endpoint, static_cast(0)); } @@ -2277,14 +2343,19 @@ public: * acceptor.async_accept(my_context2, endpoint, accept_handler); * @endcode */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + template ::other)) MoveAcceptHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, void (boost::system::error_code, typename Protocol::socket::template rebind_executor< typename ExecutionContext::executor_type>::other)) async_accept(ExecutionContext& context, endpoint_type& peer_endpoint, - BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler, + BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), typename enable_if< is_convertible::value >::type* = 0) @@ -2294,7 +2365,7 @@ public: return async_initiate( - initiate_async_move_accept(), handler, this, + initiate_async_move_accept(this), handler, context.get_executor(), &peer_endpoint, static_cast(0)); } @@ -2306,28 +2377,56 @@ private: basic_socket_acceptor& operator=( const basic_socket_acceptor&) BOOST_ASIO_DELETED; - struct initiate_async_wait + class initiate_async_wait { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_socket_acceptor* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template - void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, - basic_socket_acceptor* self, wait_type w) const + void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, wait_type w) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a WaitHandler. BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_wait( - self->impl_.get_implementation(), w, handler2.value, - self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), w, handler2.value, + self_->impl_.get_implementation_executor()); } + + private: + basic_socket_acceptor* self_; }; - struct initiate_async_accept + class initiate_async_accept { + public: + typedef Executor executor_type; + + explicit initiate_async_accept(basic_socket_acceptor* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(AcceptHandler) handler, - basic_socket_acceptor* self, basic_socket* peer, + basic_socket* peer, endpoint_type* peer_endpoint) const { // If you get an error on the following line it means that your handler @@ -2335,18 +2434,33 @@ private: BOOST_ASIO_ACCEPT_HANDLER_CHECK(AcceptHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_accept( - self->impl_.get_implementation(), *peer, peer_endpoint, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_accept( + self_->impl_.get_implementation(), *peer, peer_endpoint, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_socket_acceptor* self_; }; - struct initiate_async_move_accept + class initiate_async_move_accept { + public: + typedef Executor executor_type; + + explicit initiate_async_move_accept(basic_socket_acceptor* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler, - basic_socket_acceptor* self, const Executor1& peer_ex, - endpoint_type* peer_endpoint, Socket*) const + const Executor1& peer_ex, endpoint_type* peer_endpoint, Socket*) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a MoveAcceptHandler. @@ -2354,10 +2468,13 @@ private: MoveAcceptHandler, handler, Socket) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_move_accept( - self->impl_.get_implementation(), peer_ex, peer_endpoint, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_move_accept( + self_->impl_.get_implementation(), peer_ex, peer_endpoint, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_socket_acceptor* self_; }; #if defined(BOOST_ASIO_WINDOWS_RUNTIME) diff --git a/boost/asio/basic_stream_socket.hpp b/boost/asio/basic_stream_socket.hpp index 18d9dac..6170e0c 100644 --- a/boost/asio/basic_stream_socket.hpp +++ b/boost/asio/basic_stream_socket.hpp @@ -254,7 +254,7 @@ public: * constructed using the @c basic_stream_socket(const executor_type&) * constructor. */ - basic_stream_socket(basic_stream_socket&& other) + basic_stream_socket(basic_stream_socket&& other) BOOST_ASIO_NOEXCEPT : basic_socket(std::move(other)) { } @@ -464,15 +464,19 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send(const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_send(), handler, this, + initiate_async_send(this), handler, buffers, socket_base::message_flags(0)); } @@ -513,16 +517,20 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send(const ConstBufferSequence& buffers, socket_base::message_flags flags, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_send(), handler, this, buffers, flags); + initiate_async_send(this), handler, buffers, flags); } /// Receive some data on the socket. @@ -667,15 +675,19 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive(const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_receive(), handler, this, + initiate_async_receive(this), handler, buffers, socket_base::message_flags(0)); } @@ -718,16 +730,20 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive(const MutableBufferSequence& buffers, socket_base::message_flags flags, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_receive(), handler, this, buffers, flags); + initiate_async_receive(this), handler, buffers, flags); } /// Write some data to the socket. @@ -826,15 +842,19 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_send(), handler, this, + initiate_async_send(this), handler, buffers, socket_base::message_flags(0)); } @@ -937,24 +957,41 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_receive(), handler, this, + initiate_async_receive(this), handler, buffers, socket_base::message_flags(0)); } private: - struct initiate_async_send + class initiate_async_send { + public: + typedef Executor executor_type; + + explicit initiate_async_send(basic_stream_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - basic_stream_socket* self, const ConstBufferSequence& buffers, + const ConstBufferSequence& buffers, socket_base::message_flags flags) const { // If you get an error on the following line it means that your handler @@ -962,17 +999,33 @@ private: BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_send( - self->impl_.get_implementation(), buffers, flags, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_send( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_stream_socket* self_; }; - struct initiate_async_receive + class initiate_async_receive { + public: + typedef Executor executor_type; + + explicit initiate_async_receive(basic_stream_socket* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - basic_stream_socket* self, const MutableBufferSequence& buffers, + const MutableBufferSequence& buffers, socket_base::message_flags flags) const { // If you get an error on the following line it means that your handler @@ -980,10 +1033,13 @@ private: BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_receive( - self->impl_.get_implementation(), buffers, flags, - handler2.value, self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_receive( + self_->impl_.get_implementation(), buffers, flags, + handler2.value, self_->impl_.get_implementation_executor()); } + + private: + basic_stream_socket* self_; }; }; diff --git a/boost/asio/basic_waitable_timer.hpp b/boost/asio/basic_waitable_timer.hpp index 45373f7..806db86 100644 --- a/boost/asio/basic_waitable_timer.hpp +++ b/boost/asio/basic_waitable_timer.hpp @@ -146,6 +146,14 @@ public: /// The type of the executor associated with the object. typedef Executor executor_type; + /// Rebinds the timer type to another executor. + template + struct rebind_executor + { + /// The timer type when rebound to the specified executor. + typedef basic_waitable_timer other; + }; + /// The clock type. typedef Clock clock_type; @@ -692,13 +700,17 @@ public: * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) + WaitHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (boost::system::error_code)) - async_wait(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + async_wait( + BOOST_ASIO_MOVE_ARG(WaitHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_wait(), handler, this); + initiate_async_wait(this), handler); } private: @@ -707,21 +719,36 @@ private: basic_waitable_timer& operator=( const basic_waitable_timer&) BOOST_ASIO_DELETED; - struct initiate_async_wait + class initiate_async_wait { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_waitable_timer* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template - void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, - basic_waitable_timer* self) const + void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a WaitHandler. BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_wait( - self->impl_.get_implementation(), handler2.value, - self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), handler2.value, + self_->impl_.get_implementation_executor()); } + + private: + basic_waitable_timer* self_; }; detail::io_object_impl< diff --git a/boost/asio/buffered_read_stream.hpp b/boost/asio/buffered_read_stream.hpp index cd1e062..926e20d 100644 --- a/boost/asio/buffered_read_stream.hpp +++ b/boost/asio/buffered_read_stream.hpp @@ -137,11 +137,15 @@ public: /// Start an asynchronous write. The data being written must be valid for the /// lifetime of the asynchronous operation. - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return next_layer_.async_write_some(buffers, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); @@ -156,10 +160,15 @@ public: std::size_t fill(boost::system::error_code& ec); /// Start an asynchronous fill. - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) ReadHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) - async_fill(BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + async_fill( + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)); /// Read some data from the stream. Returns the number of bytes read. Throws /// an exception on failure. @@ -174,11 +183,15 @@ public: /// Start an asynchronous read. The buffer into which the data will be read /// must be valid for the lifetime of the asynchronous operation. - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)); /// Peek at the incoming data on the stream. Returns the number of bytes read. /// Throws an exception on failure. diff --git a/boost/asio/buffered_stream.hpp b/boost/asio/buffered_stream.hpp index d28abf1..b713c1a 100644 --- a/boost/asio/buffered_stream.hpp +++ b/boost/asio/buffered_stream.hpp @@ -126,10 +126,15 @@ public: } /// Start an asynchronous flush. - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) WriteHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) - async_flush(BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + async_flush( + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return stream_impl_.next_layer().async_flush( BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); @@ -154,11 +159,15 @@ public: /// Start an asynchronous write. The data being written must be valid for the /// lifetime of the asynchronous operation. - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return stream_impl_.async_write_some(buffers, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); @@ -179,10 +188,15 @@ public: } /// Start an asynchronous fill. - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) ReadHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) - async_fill(BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + async_fill( + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return stream_impl_.async_fill(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } @@ -206,11 +220,15 @@ public: /// Start an asynchronous read. The buffer into which the data will be read /// must be valid for the lifetime of the asynchronous operation. - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return stream_impl_.async_read_some(buffers, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); diff --git a/boost/asio/buffered_write_stream.hpp b/boost/asio/buffered_write_stream.hpp index aab02b5..266b8d4 100644 --- a/boost/asio/buffered_write_stream.hpp +++ b/boost/asio/buffered_write_stream.hpp @@ -129,10 +129,15 @@ public: std::size_t flush(boost::system::error_code& ec); /// Start an asynchronous flush. - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) WriteHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) - async_flush(BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + async_flush( + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)); /// Write the given data to the stream. Returns the number of bytes written. /// Throws an exception on failure. @@ -147,11 +152,15 @@ public: /// Start an asynchronous write. The data being written must be valid for the /// lifetime of the asynchronous operation. - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)); /// Read some data from the stream. Returns the number of bytes read. Throws /// an exception on failure. @@ -172,11 +181,15 @@ public: /// Start an asynchronous read. The buffer into which the data will be read /// must be valid for the lifetime of the asynchronous operation. - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return next_layer_.async_read_some(buffers, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); diff --git a/boost/asio/co_spawn.hpp b/boost/asio/co_spawn.hpp index 67d17e2..bb55c55 100644 --- a/boost/asio/co_spawn.hpp +++ b/boost/asio/co_spawn.hpp @@ -54,10 +54,15 @@ struct awaitable_signature> * * where @c E is convertible from @c Executor. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, +template ::type>::type) CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, typename detail::awaitable_signature::type>::type) -co_spawn(const Executor& ex, F&& f, CompletionToken&& token, +co_spawn(const Executor& ex, F&& f, + CompletionToken&& token + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if< is_executor::value >::type* = 0); @@ -70,10 +75,17 @@ co_spawn(const Executor& ex, F&& f, CompletionToken&& token, * * where @c E is convertible from @c ExecutionContext::executor_type. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, +template ::type>::type) CompletionToken + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( + typename ExecutionContext::executor_type)> +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, typename detail::awaitable_signature::type>::type) -co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token, +co_spawn(ExecutionContext& ctx, F&& f, + CompletionToken&& token + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), typename enable_if< is_convertible::value >::type* = 0); diff --git a/boost/asio/compose.hpp b/boost/asio/compose.hpp index b38e4fa..15cf4ac 100644 --- a/boost/asio/compose.hpp +++ b/boost/asio/compose.hpp @@ -101,7 +101,7 @@ namespace asio { */ template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, BOOST_ASIO_MOVE_ARG(IoObjectsOrExecutors)... io_objects_or_executors); @@ -110,14 +110,14 @@ async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, // || defined(GENERATING_DOCUMENTATION) template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token); #define BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \ template \ - BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) \ + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) \ async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, \ BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \ BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)); diff --git a/boost/asio/connect.hpp b/boost/asio/connect.hpp index a500392..4bd09ff 100644 --- a/boost/asio/connect.hpp +++ b/boost/asio/connect.hpp @@ -666,13 +666,16 @@ Iterator connect(basic_socket& s, * // ... * } @endcode */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler, void (boost::system::error_code, typename Protocol::endpoint)) async_connect(basic_socket& s, const EndpointSequence& endpoints, - BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, + BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if::value>::type* = 0); @@ -712,12 +715,15 @@ async_connect(basic_socket& s, * Iterator represents the end of the sequence. This is a valid assumption for * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket& s, Iterator begin, - BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if::value>::type* = 0); #endif // !defined(BOOST_ASIO_NO_DEPRECATED) @@ -770,12 +776,15 @@ async_connect(basic_socket& s, Iterator begin, * // ... * } @endcode */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket& s, Iterator begin, Iterator end, - BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler); + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor)); /// Asynchronously establishes a socket connection by trying each endpoint in a /// sequence. @@ -872,13 +881,17 @@ async_connect(basic_socket& s, Iterator begin, Iterator end, * } * } @endcode */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler, void (boost::system::error_code, typename Protocol::endpoint)) async_connect(basic_socket& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, - BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, + BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if::value>::type* = 0); @@ -929,13 +942,17 @@ async_connect(basic_socket& s, * Iterator represents the end of the sequence. This is a valid assumption for * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket& s, Iterator begin, ConnectCondition connect_condition, - BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if::value>::type* = 0); #endif // !defined(BOOST_ASIO_NO_DEPRECATED) @@ -1037,13 +1054,17 @@ async_connect(basic_socket& s, Iterator begin, * } * } @endcode */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket& s, Iterator begin, Iterator end, ConnectCondition connect_condition, - BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler); + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor)); /*@}*/ diff --git a/boost/asio/defer.hpp b/boost/asio/defer.hpp index 319063a..f010b8d 100644 --- a/boost/asio/defer.hpp +++ b/boost/asio/defer.hpp @@ -55,8 +55,8 @@ namespace asio { * * @li Returns result.get(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( BOOST_ASIO_MOVE_ARG(CompletionToken) token); /// Submits a completion token or function object for execution. @@ -94,18 +94,28 @@ BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( * * @li Returns result.get(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( - const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( + const Executor& ex, + BOOST_ASIO_MOVE_ARG(CompletionToken) token + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if::value>::type* = 0); /// Submits a completion token or function object for execution. /** * @returns defer(ctx.get_executor(), forward(token)). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( - ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( + ExecutionContext& ctx, + BOOST_ASIO_MOVE_ARG(CompletionToken) token + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), typename enable_if::value>::type* = 0); diff --git a/boost/asio/detail/config.hpp b/boost/asio/detail/config.hpp index 683a2b1..215c8da 100644 --- a/boost/asio/detail/config.hpp +++ b/boost/asio/detail/config.hpp @@ -314,6 +314,42 @@ # endif // !defined(BOOST_ASIO_DISABLE_ALIAS_TEMPLATES) #endif // !defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) +// Support return type deduction on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) +# if !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) +# if defined(__clang__) +# if __has_feature(__cxx_return_type_deduction__) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // __has_feature(__cxx_alias_templates__) +# elif (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# elif defined(__cpp_return_type_deduction) +# if (__cpp_return_type_deduction >= 201304) +# define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 +# endif // (__cpp_return_type_deduction >= 201304) +# endif // defined(__cpp_return_type_deduction) +# endif // !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) +#endif // !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) + +// Support default function template arguments on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) +# if !defined(BOOST_ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) +# if (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1 +# endif // (__cplusplus >= 201103) +# endif // !defined(BOOST_ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) +#endif // !defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) + +// Support concepts on compilers known to allow them. +#if !defined(BOOST_ASIO_HAS_CONCEPTS) +# if !defined(BOOST_ASIO_DISABLE_CONCEPTS) +# if __cpp_concepts +# define BOOST_ASIO_HAS_CONCEPTS 1 +# define BOOST_ASIO_CONCEPT concept bool +# endif // __cpp_concepts +# endif // !defined(BOOST_ASIO_DISABLE_CONCEPTS) +#endif // !defined(BOOST_ASIO_HAS_CONCEPTS) + // Standard library support for system errors. # if !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR) # if defined(__clang__) diff --git a/boost/asio/detail/impl/reactive_socket_service_base.ipp b/boost/asio/detail/impl/reactive_socket_service_base.ipp index 5ae4b64..178a49d 100644 --- a/boost/asio/detail/impl/reactive_socket_service_base.ipp +++ b/boost/asio/detail/impl/reactive_socket_service_base.ipp @@ -49,6 +49,7 @@ void reactive_socket_service_base::construct( void reactive_socket_service_base::base_move_construct( reactive_socket_service_base::base_implementation_type& impl, reactive_socket_service_base::base_implementation_type& other_impl) + BOOST_ASIO_NOEXCEPT { impl.socket_ = other_impl.socket_; other_impl.socket_ = invalid_socket; diff --git a/boost/asio/detail/impl/win_iocp_serial_port_service.ipp b/boost/asio/detail/impl/win_iocp_serial_port_service.ipp index a8133fa..916d569 100644 --- a/boost/asio/detail/impl/win_iocp_serial_port_service.ipp +++ b/boost/asio/detail/impl/win_iocp_serial_port_service.ipp @@ -84,7 +84,7 @@ boost::system::error_code win_iocp_serial_port_service::open( dcb.fBinary = TRUE; // Win32 only supports binary mode. dcb.fNull = FALSE; // Do not ignore NULL characters. dcb.fAbortOnError = FALSE; // Ignore serial framing errors. - dcb.BaudRate = 0; // 0 baud by default + dcb.BaudRate = CBR_9600; // 9600 baud by default dcb.ByteSize = 8; // 8 bit bytes dcb.fOutxCtsFlow = FALSE; // No flow control dcb.fOutxDsrFlow = FALSE; @@ -92,7 +92,7 @@ boost::system::error_code win_iocp_serial_port_service::open( dcb.fDsrSensitivity = FALSE; dcb.fOutX = FALSE; dcb.fInX = FALSE; - dcb.fRtsControl = DTR_CONTROL_DISABLE; + dcb.fRtsControl = RTS_CONTROL_DISABLE; dcb.fParity = FALSE; // No parity dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; // One stop bit diff --git a/boost/asio/detail/impl/win_iocp_socket_service_base.ipp b/boost/asio/detail/impl/win_iocp_socket_service_base.ipp index 5691cdb..777e76d 100644 --- a/boost/asio/detail/impl/win_iocp_socket_service_base.ipp +++ b/boost/asio/detail/impl/win_iocp_socket_service_base.ipp @@ -73,6 +73,7 @@ void win_iocp_socket_service_base::construct( void win_iocp_socket_service_base::base_move_construct( win_iocp_socket_service_base::base_implementation_type& impl, win_iocp_socket_service_base::base_implementation_type& other_impl) + BOOST_ASIO_NOEXCEPT { impl.socket_ = other_impl.socket_; other_impl.socket_ = invalid_socket; diff --git a/boost/asio/detail/reactive_socket_service.hpp b/boost/asio/detail/reactive_socket_service.hpp index fb3a0e4..aa87a2c 100644 --- a/boost/asio/detail/reactive_socket_service.hpp +++ b/boost/asio/detail/reactive_socket_service.hpp @@ -89,7 +89,7 @@ public: // Move-construct a new socket implementation. void move_construct(implementation_type& impl, - implementation_type& other_impl) + implementation_type& other_impl) BOOST_ASIO_NOEXCEPT { this->base_move_construct(impl, other_impl); diff --git a/boost/asio/detail/reactive_socket_service_base.hpp b/boost/asio/detail/reactive_socket_service_base.hpp index 26fb828..d77a575 100644 --- a/boost/asio/detail/reactive_socket_service_base.hpp +++ b/boost/asio/detail/reactive_socket_service_base.hpp @@ -73,7 +73,7 @@ public: // Move-construct a new socket implementation. BOOST_ASIO_DECL void base_move_construct(base_implementation_type& impl, - base_implementation_type& other_impl); + base_implementation_type& other_impl) BOOST_ASIO_NOEXCEPT; // Move-assign from another socket implementation. BOOST_ASIO_DECL void base_move_assign(base_implementation_type& impl, diff --git a/boost/asio/detail/type_traits.hpp b/boost/asio/detail/type_traits.hpp index c53a7e7..59106a2 100644 --- a/boost/asio/detail/type_traits.hpp +++ b/boost/asio/detail/type_traits.hpp @@ -32,6 +32,7 @@ # include # include # include +# include # include # include #endif // defined(BOOST_ASIO_HAS_TYPE_TRAITS) @@ -43,6 +44,7 @@ namespace asio { using std::add_const; using std::conditional; using std::decay; +using std::declval; using std::enable_if; using std::false_type; using std::integral_constant; @@ -68,6 +70,7 @@ template struct enable_if : boost::enable_if_c {}; using boost::conditional; using boost::decay; +using boost::declval; using boost::false_type; using boost::integral_constant; using boost::is_base_of; diff --git a/boost/asio/detail/variadic_templates.hpp b/boost/asio/detail/variadic_templates.hpp index f552b4b..7a6df1c 100644 --- a/boost/asio/detail/variadic_templates.hpp +++ b/boost/asio/detail/variadic_templates.hpp @@ -108,6 +108,24 @@ BOOST_ASIO_MOVE_CAST(T3)(x3), BOOST_ASIO_MOVE_CAST(T4)(x4), \ BOOST_ASIO_MOVE_CAST(T5)(x5) +# define BOOST_ASIO_VARIADIC_MOVE_DECLVAL(n) \ + BOOST_ASIO_VARIADIC_MOVE_DECLVAL_##n + +# define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_1 \ + declval() +# define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_2 \ + declval(), declval() +# define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_3 \ + declval(), declval(), \ + declval() +# define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_4 \ + declval(), declval(), \ + declval(), declval() +# define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_5 \ + declval(), declval(), \ + declval(), declval(), \ + declval() + # define BOOST_ASIO_VARIADIC_DECAY(n) \ BOOST_ASIO_VARIADIC_DECAY_##n diff --git a/boost/asio/detail/win_iocp_socket_accept_op.hpp b/boost/asio/detail/win_iocp_socket_accept_op.hpp index 75dadc2..bee7dda 100644 --- a/boost/asio/detail/win_iocp_socket_accept_op.hpp +++ b/boost/asio/detail/win_iocp_socket_accept_op.hpp @@ -100,6 +100,7 @@ public: if (ec == boost::asio::error::connection_aborted && !o->enable_connection_aborted_) { + handler_work::start(o->handler_, o->io_executor_); o->reset(); o->socket_service_.restart_accept_op(o->socket_, o->new_socket_, o->protocol_.family(), @@ -229,6 +230,7 @@ public: if (ec == boost::asio::error::connection_aborted && !o->enable_connection_aborted_) { + handler_work::start(o->handler_, o->io_executor_); o->reset(); o->socket_service_.restart_accept_op(o->socket_, o->new_socket_, o->protocol_.family(), diff --git a/boost/asio/detail/win_iocp_socket_service.hpp b/boost/asio/detail/win_iocp_socket_service.hpp index df2292a..5022414 100644 --- a/boost/asio/detail/win_iocp_socket_service.hpp +++ b/boost/asio/detail/win_iocp_socket_service.hpp @@ -145,7 +145,7 @@ public: // Move-construct a new socket implementation. void move_construct(implementation_type& impl, - implementation_type& other_impl) + implementation_type& other_impl) BOOST_ASIO_NOEXCEPT { this->base_move_construct(impl, other_impl); diff --git a/boost/asio/detail/win_iocp_socket_service_base.hpp b/boost/asio/detail/win_iocp_socket_service_base.hpp index 7a7c900..e17d296 100644 --- a/boost/asio/detail/win_iocp_socket_service_base.hpp +++ b/boost/asio/detail/win_iocp_socket_service_base.hpp @@ -96,7 +96,7 @@ public: // Move-construct a new socket implementation. BOOST_ASIO_DECL void base_move_construct(base_implementation_type& impl, - base_implementation_type& other_impl); + base_implementation_type& other_impl) BOOST_ASIO_NOEXCEPT; // Move-assign from another socket implementation. BOOST_ASIO_DECL void base_move_assign(base_implementation_type& impl, diff --git a/boost/asio/dispatch.hpp b/boost/asio/dispatch.hpp index 578608c..7db10bb 100644 --- a/boost/asio/dispatch.hpp +++ b/boost/asio/dispatch.hpp @@ -50,8 +50,8 @@ namespace asio { * * @li Returns result.get(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( BOOST_ASIO_MOVE_ARG(CompletionToken) token); /// Submits a completion token or function object for execution. @@ -84,9 +84,13 @@ BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( * * @li Returns result.get(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( - const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( + const Executor& ex, + BOOST_ASIO_MOVE_ARG(CompletionToken) token + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if::value>::type* = 0); /// Submits a completion token or function object for execution. @@ -94,9 +98,15 @@ BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( * @returns dispatch(ctx.get_executor(), * forward(token)). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( - ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( + ExecutionContext& ctx, + BOOST_ASIO_MOVE_ARG(CompletionToken) token + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), typename enable_if::value>::type* = 0); diff --git a/boost/asio/generic/basic_endpoint.hpp b/boost/asio/generic/basic_endpoint.hpp index 048a960..f9e5bdb 100644 --- a/boost/asio/generic/basic_endpoint.hpp +++ b/boost/asio/generic/basic_endpoint.hpp @@ -55,7 +55,7 @@ public: #endif /// Default constructor. - basic_endpoint() + basic_endpoint() BOOST_ASIO_NOEXCEPT { } diff --git a/boost/asio/generic/datagram_protocol.hpp b/boost/asio/generic/datagram_protocol.hpp index 51e95b5..16ef6ee 100644 --- a/boost/asio/generic/datagram_protocol.hpp +++ b/boost/asio/generic/datagram_protocol.hpp @@ -74,19 +74,19 @@ public: } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_DGRAM); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const BOOST_ASIO_NOEXCEPT { return protocol_; } /// Obtain an identifier for the protocol family. - int family() const + int family() const BOOST_ASIO_NOEXCEPT { return family_; } diff --git a/boost/asio/generic/raw_protocol.hpp b/boost/asio/generic/raw_protocol.hpp index ae28faf..9de731d 100644 --- a/boost/asio/generic/raw_protocol.hpp +++ b/boost/asio/generic/raw_protocol.hpp @@ -74,19 +74,19 @@ public: } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_RAW); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const BOOST_ASIO_NOEXCEPT { return protocol_; } /// Obtain an identifier for the protocol family. - int family() const + int family() const BOOST_ASIO_NOEXCEPT { return family_; } diff --git a/boost/asio/generic/seq_packet_protocol.hpp b/boost/asio/generic/seq_packet_protocol.hpp index d9b719f..84ac7a7 100644 --- a/boost/asio/generic/seq_packet_protocol.hpp +++ b/boost/asio/generic/seq_packet_protocol.hpp @@ -73,19 +73,19 @@ public: } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_SEQPACKET); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const BOOST_ASIO_NOEXCEPT { return protocol_; } /// Obtain an identifier for the protocol family. - int family() const + int family() const BOOST_ASIO_NOEXCEPT { return family_; } diff --git a/boost/asio/generic/stream_protocol.hpp b/boost/asio/generic/stream_protocol.hpp index ca5fbb2..76cfe26 100644 --- a/boost/asio/generic/stream_protocol.hpp +++ b/boost/asio/generic/stream_protocol.hpp @@ -75,19 +75,19 @@ public: } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_STREAM); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const BOOST_ASIO_NOEXCEPT { return protocol_; } /// Obtain an identifier for the protocol family. - int family() const + int family() const BOOST_ASIO_NOEXCEPT { return family_; } diff --git a/boost/asio/impl/buffered_read_stream.hpp b/boost/asio/impl/buffered_read_stream.hpp index 6a51d8e..c3b8b7a 100644 --- a/boost/asio/impl/buffered_read_stream.hpp +++ b/boost/asio/impl/buffered_read_stream.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -140,11 +141,26 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_buffered_fill + template + class initiate_async_buffered_fill { - template + public: + typedef typename remove_reference< + Stream>::type::lowest_layer_type::executor_type executor_type; + + explicit initiate_async_buffered_fill(Stream& next_layer) + : next_layer_(next_layer) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return next_layer_.lowest_layer().get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - buffered_stream_storage* storage, Stream* next_layer) const + buffered_stream_storage* storage) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a ReadHandler. @@ -153,13 +169,16 @@ namespace detail non_const_lvalue handler2(handler); std::size_t previous_size = storage->size(); storage->resize(storage->capacity()); - next_layer->async_read_some( + next_layer_.async_read_some( buffer( storage->data() + previous_size, storage->size() - previous_size), buffered_fill_handler::type>( *storage, previous_size, handler2.value)); } + + private: + Stream& next_layer_; }; } // namespace detail @@ -194,15 +213,18 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) template -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) ReadHandler> +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) buffered_read_stream::async_fill( BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { return async_initiate( - detail::initiate_async_buffered_fill(), handler, &storage_, &next_layer_); + detail::initiate_async_buffered_fill(next_layer_), + handler, &storage_); } template @@ -336,12 +358,26 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_buffered_read_some + template + class initiate_async_buffered_read_some { - template + public: + typedef typename remove_reference< + Stream>::type::lowest_layer_type::executor_type executor_type; + + explicit initiate_async_buffered_read_some(Stream& next_layer) + : next_layer_(next_layer) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return next_layer_.lowest_layer().get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - buffered_stream_storage* storage, Stream* next_layer, + buffered_stream_storage* storage, const MutableBufferSequence& buffers) const { // If you get an error on the following line it means that your handler @@ -352,20 +388,23 @@ namespace detail non_const_lvalue handler2(handler); if (buffer_size(buffers) == 0 || !storage->empty()) { - next_layer->async_read_some(BOOST_ASIO_MUTABLE_BUFFER(0, 0), + next_layer_.async_read_some(BOOST_ASIO_MUTABLE_BUFFER(0, 0), buffered_read_some_handler::type>( *storage, buffers, handler2.value)); } else { - initiate_async_buffered_fill()( + initiate_async_buffered_fill(this->next_layer_)( buffered_read_some_handler::type>( *storage, buffers, handler2.value), - storage, next_layer); + storage); } } + + private: + Stream& next_layer_; }; } // namespace detail @@ -408,8 +447,10 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) template -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) buffered_read_stream::async_read_some( const MutableBufferSequence& buffers, @@ -417,8 +458,8 @@ buffered_read_stream::async_read_some( { return async_initiate( - detail::initiate_async_buffered_read_some(), - handler, &storage_, &next_layer_, buffers); + detail::initiate_async_buffered_read_some(next_layer_), + handler, &storage_, buffers); } template diff --git a/boost/asio/impl/buffered_write_stream.hpp b/boost/asio/impl/buffered_write_stream.hpp index 05d4406..fdfeca2 100644 --- a/boost/asio/impl/buffered_write_stream.hpp +++ b/boost/asio/impl/buffered_write_stream.hpp @@ -126,21 +126,39 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_buffered_flush + template + class initiate_async_buffered_flush { - template + public: + typedef typename remove_reference< + Stream>::type::lowest_layer_type::executor_type executor_type; + + explicit initiate_async_buffered_flush(Stream& next_layer) + : next_layer_(next_layer) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return next_layer_.lowest_layer().get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - buffered_stream_storage* storage, Stream* next_layer) const + buffered_stream_storage* storage) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a WriteHandler. BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; non_const_lvalue handler2(handler); - async_write(*next_layer, buffer(storage->data(), storage->size()), + async_write(next_layer_, buffer(storage->data(), storage->size()), buffered_flush_handler::type>( *storage, handler2.value)); } + + private: + Stream& next_layer_; }; } // namespace detail @@ -175,16 +193,18 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) template -template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) WriteHandler> +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) buffered_write_stream::async_flush( BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { return async_initiate( - detail::initiate_async_buffered_flush(), - handler, &storage_, &next_layer_); + detail::initiate_async_buffered_flush(next_layer_), + handler, &storage_); } template @@ -324,12 +344,26 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_buffered_write_some + template + class initiate_async_buffered_write_some { - template + public: + typedef typename remove_reference< + Stream>::type::lowest_layer_type::executor_type executor_type; + + explicit initiate_async_buffered_write_some(Stream& next_layer) + : next_layer_(next_layer) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return next_layer_.lowest_layer().get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - buffered_stream_storage* storage, Stream* next_layer, + buffered_stream_storage* storage, const ConstBufferSequence& buffers) const { // If you get an error on the following line it means that your handler @@ -340,20 +374,23 @@ namespace detail non_const_lvalue handler2(handler); if (buffer_size(buffers) == 0 || storage->size() < storage->capacity()) { - next_layer->async_write_some(BOOST_ASIO_CONST_BUFFER(0, 0), + next_layer_.async_write_some(BOOST_ASIO_CONST_BUFFER(0, 0), buffered_write_some_handler::type>( *storage, buffers, handler2.value)); } else { - initiate_async_buffered_flush()( + initiate_async_buffered_flush(this->next_layer_)( buffered_write_some_handler::type>( *storage, buffers, handler2.value), - storage, next_layer); + storage); } } + + private: + Stream& next_layer_; }; } // namespace detail @@ -396,8 +433,10 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) template -template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) buffered_write_stream::async_write_some( const ConstBufferSequence& buffers, @@ -405,8 +444,8 @@ buffered_write_stream::async_write_some( { return async_initiate( - detail::initiate_async_buffered_write_some(), - handler, &storage_, &next_layer_, buffers); + detail::initiate_async_buffered_write_some(next_layer_), + handler, &storage_, buffers); } template diff --git a/boost/asio/impl/co_spawn.hpp b/boost/asio/impl/co_spawn.hpp index 19770cd..9df7fcc 100644 --- a/boost/asio/impl/co_spawn.hpp +++ b/boost/asio/impl/co_spawn.hpp @@ -90,25 +90,43 @@ awaitable co_spawn_entry_point( }); } -struct initiate_co_spawn +template +class initiate_co_spawn { - template - void operator()(Handler&& handler, const Executor& ex, F&& f) const +public: + typedef Executor executor_type; + + template + explicit initiate_co_spawn(const OtherExecutor& ex) + : ex_(ex) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return ex_; + } + + template + void operator()(Handler&& handler, F&& f) const { typedef typename result_of::type awaitable_type; - typedef typename awaitable_type::executor_type executor_type; - executor_type ex2(ex); auto a = (co_spawn_entry_point)(static_cast(nullptr), - ex2, std::forward(f), std::forward(handler)); - awaitable_handler(std::move(a), ex2).launch(); + ex_, std::forward(f), std::forward(handler)); + awaitable_handler(std::move(a), ex_).launch(); } + +private: + Executor ex_; }; } // namespace detail -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, +template ::type>::type) CompletionToken> +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, typename detail::awaitable_signature::type>::type) co_spawn(const Executor& ex, F&& f, CompletionToken&& token, typename enable_if< @@ -117,11 +135,15 @@ co_spawn(const Executor& ex, F&& f, CompletionToken&& token, { return async_initiate::type>>( - detail::initiate_co_spawn(), token, ex, std::forward(f)); + detail::initiate_co_spawn< + typename result_of::type::executor_type>(ex), + token, std::forward(f)); } -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, +template ::type>::type) CompletionToken> +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, typename detail::awaitable_signature::type>::type) co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token, typename enable_if< diff --git a/boost/asio/impl/compose.hpp b/boost/asio/impl/compose.hpp index 76fe54d..2dfc4bb 100644 --- a/boost/asio/impl/compose.hpp +++ b/boost/asio/impl/compose.hpp @@ -32,13 +32,123 @@ namespace asio { namespace detail { + template + struct composed_io_executors; + + template <> + struct composed_io_executors + { + composed_io_executors() BOOST_ASIO_NOEXCEPT + : head_(system_executor()) + { + } + + typedef system_executor head_type; + system_executor head_; + }; + + inline composed_io_executors make_composed_io_executors() + { + return composed_io_executors(); + } + + template + struct composed_io_executors + { + explicit composed_io_executors(const Head& ex) BOOST_ASIO_NOEXCEPT + : head_(ex) + { + } + + typedef Head head_type; + Head head_; + }; + + template + inline composed_io_executors + make_composed_io_executors(const Head& head) + { + return composed_io_executors(head); + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + struct composed_io_executors + { + explicit composed_io_executors(const Head& head, + const Tail&... tail) BOOST_ASIO_NOEXCEPT + : head_(head), + tail_(tail...) + { + } + + void reset() + { + head_.reset(); + tail_.reset(); + } + + typedef Head head_type; + Head head_; + composed_io_executors tail_; + }; + + template + inline composed_io_executors + make_composed_io_executors(const Head& head, const Tail&... tail) + { + return composed_io_executors(head, tail...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF(n) \ + template \ + struct composed_io_executors \ + { \ + explicit composed_io_executors(const Head& head, \ + BOOST_ASIO_VARIADIC_CONSTREF_PARAMS(n)) BOOST_ASIO_NOEXCEPT \ + : head_(head), \ + tail_(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)) \ + { \ + } \ + \ + void reset() \ + { \ + head_.reset(); \ + tail_.reset(); \ + } \ + \ + typedef Head head_type; \ + Head head_; \ + composed_io_executors tail_; \ + }; \ + \ + template \ + inline composed_io_executors \ + make_composed_io_executors(const Head& head, \ + BOOST_ASIO_VARIADIC_CONSTREF_PARAMS(n)) \ + { \ + return composed_io_executors< \ + void(Head, BOOST_ASIO_VARIADIC_TARGS(n))>( \ + head, BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF) +#undef BOOST_ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + template struct composed_work; template <> struct composed_work { - composed_work() BOOST_ASIO_NOEXCEPT + typedef composed_io_executors executors_type; + + composed_work(const executors_type&) BOOST_ASIO_NOEXCEPT : head_(system_executor()) { } @@ -52,16 +162,13 @@ namespace detail executor_work_guard head_; }; - inline composed_work make_composed_work() - { - return composed_work(); - } - template struct composed_work { - explicit composed_work(const Head& ex) BOOST_ASIO_NOEXCEPT - : head_(ex) + typedef composed_io_executors executors_type; + + explicit composed_work(const executors_type& ex) BOOST_ASIO_NOEXCEPT + : head_(ex.head_) { } @@ -74,21 +181,16 @@ namespace detail executor_work_guard head_; }; - template - inline composed_work make_composed_work(const Head& head) - { - return composed_work(head); - } - #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template struct composed_work { - explicit composed_work(const Head& head, - const Tail&... tail) BOOST_ASIO_NOEXCEPT - : head_(head), - tail_(tail...) + typedef composed_io_executors executors_type; + + explicit composed_work(const executors_type& ex) BOOST_ASIO_NOEXCEPT + : head_(ex.head_), + tail_(ex.tail_) { } @@ -103,23 +205,18 @@ namespace detail composed_work tail_; }; - template - inline composed_work - make_composed_work(const Head& head, const Tail&... tail) - { - return composed_work(head, tail...); - } - #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #define BOOST_ASIO_PRIVATE_COMPOSED_WORK_DEF(n) \ template \ struct composed_work \ { \ - explicit composed_work(const Head& head, \ - BOOST_ASIO_VARIADIC_CONSTREF_PARAMS(n)) BOOST_ASIO_NOEXCEPT \ - : head_(head), \ - tail_(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)) \ + typedef composed_io_executors executors_type; \ + \ + explicit composed_work(const executors_type& ex) BOOST_ASIO_NOEXCEPT \ + : head_(ex.head_), \ + tail_(ex.tail_) \ { \ } \ \ @@ -133,15 +230,6 @@ namespace detail executor_work_guard head_; \ composed_work tail_; \ }; \ - \ - template \ - inline composed_work \ - make_composed_work(const Head& head, BOOST_ASIO_VARIADIC_CONSTREF_PARAMS(n)) \ - { \ - return composed_work< \ - void(Head, BOOST_ASIO_VARIADIC_TARGS(n))>( \ - head, BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)); \ - } \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_COMPOSED_WORK_DEF) #undef BOOST_ASIO_PRIVATE_COMPOSED_WORK_DEF @@ -299,21 +387,46 @@ namespace detail function, this_handler->handler_); } - template - struct initiate_composed_op + template + class initiate_composed_op { - template - void operator()(BOOST_ASIO_MOVE_ARG(Handler) handler, - BOOST_ASIO_MOVE_ARG(Impl) impl, - BOOST_ASIO_MOVE_ARG(Work) work) const + public: + typedef typename composed_io_executors::head_type executor_type; + + template + explicit initiate_composed_op(BOOST_ASIO_MOVE_ARG(T) executors) + : executors_(BOOST_ASIO_MOVE_CAST(T)(executors)) { - composed_op::type, typename decay::type, + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return executors_.head_; + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(Handler) handler, + BOOST_ASIO_MOVE_ARG(Impl) impl) const + { + composed_op::type, composed_work, typename decay::type, Signature>( - BOOST_ASIO_MOVE_CAST(Impl)(impl), BOOST_ASIO_MOVE_CAST(Work)(work), + BOOST_ASIO_MOVE_CAST(Impl)(impl), + composed_work(executors_), BOOST_ASIO_MOVE_CAST(Handler)(handler))(); } + + private: + composed_io_executors executors_; }; + template + inline initiate_composed_op make_initiate_composed_op( + BOOST_ASIO_MOVE_ARG(composed_io_executors) executors) + { + return initiate_composed_op( + BOOST_ASIO_MOVE_CAST(composed_io_executors)(executors)); + } + template inline typename IoObject::executor_type get_composed_io_executor(IoObject& io_object) @@ -334,31 +447,31 @@ namespace detail template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, BOOST_ASIO_MOVE_ARG(IoObjectsOrExecutors)... io_objects_or_executors) { return async_initiate( - detail::initiate_composed_op(), token, - BOOST_ASIO_MOVE_CAST(Implementation)(implementation), - detail::make_composed_work( - detail::get_composed_io_executor( - BOOST_ASIO_MOVE_CAST(IoObjectsOrExecutors)( - io_objects_or_executors))...)); + detail::make_initiate_composed_op( + detail::make_composed_io_executors( + detail::get_composed_io_executor( + BOOST_ASIO_MOVE_CAST(IoObjectsOrExecutors)( + io_objects_or_executors))...)), + token, BOOST_ASIO_MOVE_CAST(Implementation)(implementation)); } #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token) { return async_initiate( - detail::initiate_composed_op(), token, - BOOST_ASIO_MOVE_CAST(Implementation)(implementation), - detail::make_composed_work()); + detail::make_initiate_composed_op( + detail::make_composed_io_executors()), + token, BOOST_ASIO_MOVE_CAST(Implementation)(implementation)); } # define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR(n) \ @@ -388,16 +501,16 @@ async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, #define BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \ template \ - BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) \ + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) \ async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, \ BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \ BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ { \ return async_initiate( \ - detail::initiate_composed_op(), token, \ - BOOST_ASIO_MOVE_CAST(Implementation)(implementation), \ - detail::make_composed_work( \ - BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR(n))); \ + detail::make_initiate_composed_op( \ + detail::make_composed_io_executors( \ + BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR(n))), \ + token, BOOST_ASIO_MOVE_CAST(Implementation)(implementation)); \ } \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF) diff --git a/boost/asio/impl/connect.hpp b/boost/asio/impl/connect.hpp index 7089316..90039b6 100644 --- a/boost/asio/impl/connect.hpp +++ b/boost/asio/impl/connect.hpp @@ -455,12 +455,26 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_range_connect + template + class initiate_async_range_connect { - template + public: + typedef Executor executor_type; + + explicit initiate_async_range_connect(basic_socket& s) + : socket_(s) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return socket_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, - basic_socket* s, const EndpointSequence& endpoints, + const EndpointSequence& endpoints, const ConnectCondition& connect_condition) const { // If you get an error on the following line it means that your @@ -471,9 +485,12 @@ namespace detail non_const_lvalue handler2(handler); range_connect_op::type>(*s, endpoints, + typename decay::type>(socket_, endpoints, connect_condition, handler2.value)(boost::system::error_code(), 1); } + + private: + basic_socket& socket_; }; template handler_); } - struct initiate_async_iterator_connect + template + class initiate_async_iterator_connect { - template + public: + typedef Executor executor_type; + + explicit initiate_async_iterator_connect( + basic_socket& s) + : socket_(s) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return socket_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, - basic_socket* s, Iterator begin, - Iterator end, const ConnectCondition& connect_condition) const + Iterator begin, Iterator end, + const ConnectCondition& connect_condition) const { // If you get an error on the following line it means that your // handler does not meet the documented type requirements for an @@ -640,9 +672,12 @@ namespace detail non_const_lvalue handler2(handler); iterator_connect_op::type>(*s, begin, end, + typename decay::type>(socket_, begin, end, connect_condition, handler2.value)(boost::system::error_code(), 1); } + + private: + basic_socket& socket_; }; } // namespace detail @@ -730,9 +765,10 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler, void (boost::system::error_code, typename Protocol::endpoint)) async_connect(basic_socket& s, const EndpointSequence& endpoints, @@ -742,14 +778,15 @@ async_connect(basic_socket& s, { return async_initiate( - detail::initiate_async_range_connect(), handler, - &s, endpoints, detail::default_connect_condition()); + detail::initiate_async_range_connect(s), + handler, endpoints, detail::default_connect_condition()); } #if !defined(BOOST_ASIO_NO_DEPRECATED) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket& s, Iterator begin, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, @@ -757,27 +794,30 @@ async_connect(basic_socket& s, Iterator begin, { return async_initiate( - detail::initiate_async_iterator_connect(), handler, - &s, begin, Iterator(), detail::default_connect_condition()); + detail::initiate_async_iterator_connect(s), + handler, begin, Iterator(), detail::default_connect_condition()); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket& s, Iterator begin, Iterator end, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler) { return async_initiate( - detail::initiate_async_iterator_connect(), handler, - &s, begin, end, detail::default_connect_condition()); + detail::initiate_async_iterator_connect(s), + handler, begin, end, detail::default_connect_condition()); } -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler, void (boost::system::error_code, typename Protocol::endpoint)) async_connect(basic_socket& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, @@ -787,14 +827,16 @@ async_connect(basic_socket& s, { return async_initiate( - detail::initiate_async_range_connect(), - handler, &s, endpoints, connect_condition); + detail::initiate_async_range_connect(s), + handler, endpoints, connect_condition); } #if !defined(BOOST_ASIO_NO_DEPRECATED) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket& s, Iterator begin, ConnectCondition connect_condition, @@ -803,14 +845,16 @@ async_connect(basic_socket& s, Iterator begin, { return async_initiate( - detail::initiate_async_iterator_connect(), - handler, &s, begin, Iterator(), connect_condition); + detail::initiate_async_iterator_connect(s), + handler, begin, Iterator(), connect_condition); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket& s, Iterator begin, Iterator end, ConnectCondition connect_condition, @@ -818,8 +862,8 @@ async_connect(basic_socket& s, Iterator begin, { return async_initiate( - detail::initiate_async_iterator_connect(), - handler, &s, begin, end, connect_condition); + detail::initiate_async_iterator_connect(s), + handler, begin, end, connect_condition); } } // namespace asio diff --git a/boost/asio/impl/defer.hpp b/boost/asio/impl/defer.hpp index 856a33c..d507eb1 100644 --- a/boost/asio/impl/defer.hpp +++ b/boost/asio/impl/defer.hpp @@ -26,8 +26,9 @@ namespace boost { namespace asio { namespace detail { -struct initiate_defer +class initiate_defer { +public: template void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const { @@ -41,42 +42,63 @@ struct initiate_defer ex.defer(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); } +}; - template - void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, - BOOST_ASIO_MOVE_ARG(Executor) ex) const +template +class initiate_defer_with_executor +{ +public: + typedef Executor executor_type; + + explicit initiate_defer_with_executor(const Executor& ex) + : ex_(ex) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return ex_; + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const { typedef typename decay::type DecayedHandler; typename associated_allocator::type alloc( (get_associated_allocator)(handler)); - ex.defer(detail::work_dispatcher( + ex_.defer(detail::work_dispatcher( BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), alloc); } + +private: + Executor ex_; }; } // namespace detail -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( BOOST_ASIO_MOVE_ARG(CompletionToken) token) { return async_initiate( detail::initiate_defer(), token); } -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if::value>::type*) { return async_initiate( - detail::initiate_defer(), token, ex); + detail::initiate_defer_with_executor(ex), token); } -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if::value>::type*) diff --git a/boost/asio/impl/dispatch.hpp b/boost/asio/impl/dispatch.hpp index bcba2ee..8cddff5 100644 --- a/boost/asio/impl/dispatch.hpp +++ b/boost/asio/impl/dispatch.hpp @@ -26,8 +26,9 @@ namespace boost { namespace asio { namespace detail { -struct initiate_dispatch +class initiate_dispatch { +public: template void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const { @@ -41,42 +42,63 @@ struct initiate_dispatch ex.dispatch(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); } +}; - template - void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, - BOOST_ASIO_MOVE_ARG(Executor) ex) const +template +class initiate_dispatch_with_executor +{ +public: + typedef Executor executor_type; + + explicit initiate_dispatch_with_executor(const Executor& ex) + : ex_(ex) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return ex_; + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const { typedef typename decay::type DecayedHandler; typename associated_allocator::type alloc( (get_associated_allocator)(handler)); - ex.dispatch(detail::work_dispatcher( + ex_.dispatch(detail::work_dispatcher( BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), alloc); } + +private: + Executor ex_; }; } // namespace detail -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( BOOST_ASIO_MOVE_ARG(CompletionToken) token) { return async_initiate( detail::initiate_dispatch(), token); } -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if::value>::type*) { return async_initiate( - detail::initiate_dispatch(), token, ex); + detail::initiate_dispatch_with_executor(ex), token); } -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if::value>::type*) diff --git a/boost/asio/impl/io_context.hpp b/boost/asio/impl/io_context.hpp index 2cf8c4b..c96c757 100644 --- a/boost/asio/impl/io_context.hpp +++ b/boost/asio/impl/io_context.hpp @@ -172,7 +172,7 @@ struct io_context::initiate_dispatch }; template -BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) io_context::dispatch(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) { return async_initiate( @@ -211,7 +211,7 @@ struct io_context::initiate_post }; template -BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) io_context::post(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) { return async_initiate( diff --git a/boost/asio/impl/post.hpp b/boost/asio/impl/post.hpp index ac0831e..5dc0885 100644 --- a/boost/asio/impl/post.hpp +++ b/boost/asio/impl/post.hpp @@ -26,8 +26,9 @@ namespace boost { namespace asio { namespace detail { -struct initiate_post +class initiate_post { +public: template void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const { @@ -41,42 +42,63 @@ struct initiate_post ex.post(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); } +}; - template - void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, - BOOST_ASIO_MOVE_ARG(Executor) ex) const +template +class initiate_post_with_executor +{ +public: + typedef Executor executor_type; + + explicit initiate_post_with_executor(const Executor& ex) + : ex_(ex) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return ex_; + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const { typedef typename decay::type DecayedHandler; typename associated_allocator::type alloc( (get_associated_allocator)(handler)); - ex.post(detail::work_dispatcher( + ex_.post(detail::work_dispatcher( BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), alloc); } + +private: + Executor ex_; }; } // namespace detail -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( BOOST_ASIO_MOVE_ARG(CompletionToken) token) { return async_initiate( detail::initiate_post(), token); } -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if::value>::type*) { return async_initiate( - detail::initiate_post(), token, ex); + detail::initiate_post_with_executor(ex), token); } -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if::value>::type*) diff --git a/boost/asio/impl/read.hpp b/boost/asio/impl/read.hpp index 6eabf0f..2bcbe15 100644 --- a/boost/asio/impl/read.hpp +++ b/boost/asio/impl/read.hpp @@ -453,12 +453,26 @@ namespace detail boost::system::error_code(), 0, 1); } - struct initiate_async_read_buffer_sequence + template + class initiate_async_read_buffer_sequence { - template + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_buffer_sequence(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return stream_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - AsyncReadStream* s, const MutableBufferSequence& buffers, + const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const { // If you get an error on the following line it means that your handler @@ -467,10 +481,13 @@ namespace detail non_const_lvalue handler2(handler); non_const_lvalue completion_cond2(completion_cond); - start_read_buffer_sequence_op(*s, buffers, + start_read_buffer_sequence_op(stream_, buffers, boost::asio::buffer_sequence_begin(buffers), completion_cond2.value, handler2.value); } + + private: + AsyncReadStream& stream_; }; } // namespace detail @@ -516,9 +533,11 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, @@ -529,13 +548,14 @@ async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, { return async_initiate( - detail::initiate_async_read_buffer_sequence(), handler, &s, buffers, - BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); + detail::initiate_async_read_buffer_sequence(s), handler, + buffers, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) ReadHandler> +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, @@ -545,8 +565,8 @@ async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, { return async_initiate( - detail::initiate_async_read_buffer_sequence(), - handler, &s, buffers, transfer_all()); + detail::initiate_async_read_buffer_sequence(s), + handler, buffers, transfer_all()); } #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) @@ -692,12 +712,26 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_read_dynbuf_v1 + template + class initiate_async_read_dynbuf_v1 { - template + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_dynbuf_v1(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return stream_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const { // If you get an error on the following line it means that your handler @@ -708,10 +742,13 @@ namespace detail non_const_lvalue completion_cond2(completion_cond); read_dynbuf_v1_op::type, CompletionCondition, typename decay::type>( - *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), completion_cond2.value, handler2.value)( boost::system::error_code(), 0, 1); } + + private: + AsyncReadStream& stream_; }; } // namespace detail @@ -755,9 +792,10 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, @@ -772,9 +810,11 @@ async_read(AsyncReadStream& s, transfer_all(), BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, @@ -791,16 +831,18 @@ async_read(AsyncReadStream& s, return async_initiate( - detail::initiate_async_read_dynbuf_v1(), handler, &s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + detail::initiate_async_read_dynbuf_v1(s), + handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, basic_streambuf& b, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) @@ -809,9 +851,11 @@ async_read(AsyncReadStream& s, basic_streambuf& b, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, basic_streambuf& b, CompletionCondition completion_condition, @@ -973,12 +1017,26 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_read_dynbuf_v2 + template + class initiate_async_read_dynbuf_v2 { - template + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_dynbuf_v2(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return stream_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const { // If you get an error on the following line it means that your handler @@ -989,10 +1047,13 @@ namespace detail non_const_lvalue completion_cond2(completion_cond); read_dynbuf_v2_op::type, CompletionCondition, typename decay::type>( - *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), completion_cond2.value, handler2.value)( boost::system::error_code(), 0, 1); } + + private: + AsyncReadStream& stream_; }; } // namespace detail @@ -1036,9 +1097,10 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, @@ -1051,9 +1113,11 @@ async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, transfer_all(), BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, CompletionCondition completion_condition, @@ -1068,8 +1132,8 @@ async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, return async_initiate( - detail::initiate_async_read_dynbuf_v2(), handler, &s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + detail::initiate_async_read_dynbuf_v2(s), + handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } diff --git a/boost/asio/impl/read_at.hpp b/boost/asio/impl/read_at.hpp index 8152ef9..52fc360 100644 --- a/boost/asio/impl/read_at.hpp +++ b/boost/asio/impl/read_at.hpp @@ -321,13 +321,27 @@ namespace detail boost::system::error_code(), 0, 1); } - struct initiate_async_read_at_buffer_sequence + template + class initiate_async_read_at_buffer_sequence { - template + public: + typedef typename AsyncRandomAccessReadDevice::executor_type executor_type; + + explicit initiate_async_read_at_buffer_sequence( + AsyncRandomAccessReadDevice& device) + : device_(device) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return device_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - AsyncRandomAccessReadDevice* d, uint64_t offset, - const MutableBufferSequence& buffers, + uint64_t offset, const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const { // If you get an error on the following line it means that your handler @@ -336,10 +350,13 @@ namespace detail non_const_lvalue handler2(handler); non_const_lvalue completion_cond2(completion_cond); - start_read_at_buffer_sequence_op(*d, offset, buffers, + start_read_at_buffer_sequence_op(device_, offset, buffers, boost::asio::buffer_sequence_begin(buffers), completion_cond2.value, handler2.value); } + + private: + AsyncRandomAccessReadDevice& device_; }; } // namespace detail @@ -387,9 +404,11 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, const MutableBufferSequence& buffers, @@ -398,13 +417,16 @@ async_read_at(AsyncRandomAccessReadDevice& d, { return async_initiate( - detail::initiate_async_read_at_buffer_sequence(), handler, &d, offset, - buffers, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); + detail::initiate_async_read_at_buffer_sequence< + AsyncRandomAccessReadDevice>(d), + handler, offset, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) ReadHandler> +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, const MutableBufferSequence& buffers, @@ -412,8 +434,9 @@ async_read_at(AsyncRandomAccessReadDevice& d, { return async_initiate( - detail::initiate_async_read_at_buffer_sequence(), - handler, &d, offset, buffers, transfer_all()); + detail::initiate_async_read_at_buffer_sequence< + AsyncRandomAccessReadDevice>(d), + handler, offset, buffers, transfer_all()); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) @@ -554,13 +577,27 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_read_at_streambuf + template + class initiate_async_read_at_streambuf { - template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - AsyncRandomAccessReadDevice* d, uint64_t offset, - basic_streambuf* b, + uint64_t offset, basic_streambuf* b, BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const { // If you get an error on the following line it means that your handler @@ -571,9 +608,12 @@ namespace detail non_const_lvalue completion_cond2(completion_cond); read_at_streambuf_op::type>( - *d, offset, *b, completion_cond2.value, handler2.value)( + device_, offset, *b, completion_cond2.value, handler2.value)( boost::system::error_code(), 0, 1); } + + private: + AsyncRandomAccessReadDevice& device_; }; } // namespace detail @@ -617,9 +657,11 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, boost::asio::basic_streambuf& b, @@ -628,13 +670,15 @@ async_read_at(AsyncRandomAccessReadDevice& d, { return async_initiate( - detail::initiate_async_read_at_streambuf(), handler, &d, offset, - &b, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); + detail::initiate_async_read_at_streambuf(d), + handler, offset, &b, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) ReadHandler> +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, boost::asio::basic_streambuf& b, @@ -642,8 +686,8 @@ async_read_at(AsyncRandomAccessReadDevice& d, { return async_initiate( - detail::initiate_async_read_at_streambuf(), - handler, &d, offset, &b, transfer_all()); + detail::initiate_async_read_at_streambuf(d), + handler, offset, &b, transfer_all()); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) diff --git a/boost/asio/impl/read_until.hpp b/boost/asio/impl/read_until.hpp index 63b86f8..17e1506 100644 --- a/boost/asio/impl/read_until.hpp +++ b/boost/asio/impl/read_until.hpp @@ -952,12 +952,25 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_read_until_delim_v1 + template + class initiate_async_read_until_delim_v1 { - template + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_until_delim_v1(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return stream_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim) const { // If you get an error on the following line it means that your handler @@ -968,9 +981,12 @@ namespace detail read_until_delim_op_v1::type, typename decay::type>( - *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, handler2.value)(boost::system::error_code(), 0, 1); } + + private: + AsyncReadStream& stream_; }; } // namespace detail @@ -1014,9 +1030,10 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, @@ -1028,8 +1045,8 @@ async_read_until(AsyncReadStream& s, { return async_initiate( - detail::initiate_async_read_until_delim_v1(), handler, - &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim); + detail::initiate_async_read_until_delim_v1(s), + handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim); } namespace detail @@ -1219,12 +1236,25 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_read_until_delim_string_v1 + template + class initiate_async_read_until_delim_string_v1 { - template + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_until_delim_string_v1(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return stream_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, const std::string& delim) const { // If you get an error on the following line it means that your handler @@ -1235,9 +1265,12 @@ namespace detail read_until_delim_string_op_v1::type, typename decay::type>( - *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, handler2.value)(boost::system::error_code(), 0, 1); } + + private: + AsyncReadStream& stream_; }; } // namespace detail @@ -1281,9 +1314,10 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, @@ -1296,8 +1330,8 @@ async_read_until(AsyncReadStream& s, { return async_initiate( - detail::initiate_async_read_until_delim_string_v1(), - handler, &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + detail::initiate_async_read_until_delim_string_v1(s), + handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), static_cast(delim)); } @@ -1494,13 +1528,25 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_read_until_expr_v1 + template + class initiate_async_read_until_expr_v1 { - template + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_until_expr_v1(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return stream_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, - const RegEx& expr) const + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, const RegEx& expr) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a ReadHandler. @@ -1510,9 +1556,12 @@ namespace detail read_until_expr_op_v1::type, RegEx, typename decay::type>( - *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr, handler2.value)(boost::system::error_code(), 0, 1); } + + private: + AsyncReadStream& stream_; }; } // namespace detail @@ -1556,9 +1605,10 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, @@ -1571,8 +1621,8 @@ async_read_until(AsyncReadStream& s, { return async_initiate( - detail::initiate_async_read_until_expr_v1(), handler, - &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr); + detail::initiate_async_read_until_expr_v1(s), + handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr); } #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) @@ -1765,12 +1815,26 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_read_until_match_v1 + template + class initiate_async_read_until_match_v1 { - template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, MatchCondition match_condition) const { // If you get an error on the following line it means that your handler @@ -1781,9 +1845,12 @@ namespace detail read_until_match_op_v1::type, MatchCondition, typename decay::type>( - *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), match_condition, handler2.value)(boost::system::error_code(), 0, 1); } + + private: + AsyncReadStream& stream_; }; } // namespace detail @@ -1827,9 +1894,11 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, @@ -1842,14 +1911,16 @@ async_read_until(AsyncReadStream& s, { return async_initiate( - detail::initiate_async_read_until_match_v1(), handler, - &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), match_condition); + detail::initiate_async_read_until_match_v1(s), handler, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), match_condition); } #if !defined(BOOST_ASIO_NO_IOSTREAM) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf& b, @@ -1859,8 +1930,10 @@ async_read_until(AsyncReadStream& s, delim, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf& b, @@ -1873,8 +1946,10 @@ async_read_until(AsyncReadStream& s, #if defined(BOOST_ASIO_HAS_BOOST_REGEX) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf& b, const boost::regex& expr, @@ -1886,9 +1961,10 @@ async_read_until(AsyncReadStream& s, #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf& b, @@ -2087,13 +2163,25 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_read_until_delim_v2 + template + class initiate_async_read_until_delim_v2 { - template + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_until_delim_v2(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return stream_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, - char delim) const + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, char delim) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a ReadHandler. @@ -2103,9 +2191,12 @@ namespace detail read_until_delim_op_v2::type, typename decay::type>( - *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, handler2.value)(boost::system::error_code(), 0, 1); } + + private: + AsyncReadStream& stream_; }; } // namespace detail @@ -2149,9 +2240,10 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, @@ -2161,8 +2253,8 @@ async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, { return async_initiate( - detail::initiate_async_read_until_delim_v2(), handler, - &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim); + detail::initiate_async_read_until_delim_v2(s), + handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim); } namespace detail @@ -2360,12 +2452,25 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_read_until_delim_string_v2 + template + class initiate_async_read_until_delim_string_v2 { - template + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_until_delim_string_v2(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return stream_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, const std::string& delim) const { // If you get an error on the following line it means that your handler @@ -2376,9 +2481,12 @@ namespace detail read_until_delim_string_op_v2::type, typename decay::type>( - *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, handler2.value)(boost::system::error_code(), 0, 1); } + + private: + AsyncReadStream& stream_; }; } // namespace detail @@ -2423,8 +2531,10 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + typename DynamicBuffer_v2, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) ReadHandler> +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, BOOST_ASIO_STRING_VIEW_PARAM delim, @@ -2435,8 +2545,8 @@ async_read_until(AsyncReadStream& s, { return async_initiate( - detail::initiate_async_read_until_delim_string_v2(), - handler, &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + detail::initiate_async_read_until_delim_string_v2(s), + handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), static_cast(delim)); } @@ -2641,12 +2751,25 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_read_until_expr_v2 + template + class initiate_async_read_until_expr_v2 { - template + public: + typedef typename AsyncReadStream::executor_type executor_type; + + explicit initiate_async_read_until_expr_v2(AsyncReadStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return stream_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, const RegEx& expr) const { // If you get an error on the following line it means that your handler @@ -2657,9 +2780,12 @@ namespace detail read_until_expr_op_v2::type, RegEx, typename decay::type>( - *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr, handler2.value)(boost::system::error_code(), 0, 1); } + + private: + AsyncReadStream& stream_; }; } // namespace detail @@ -2703,9 +2829,10 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, const boost::regex& expr, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, @@ -2715,8 +2842,8 @@ async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, { return async_initiate( - detail::initiate_async_read_until_expr_v2(), handler, - &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr); + detail::initiate_async_read_until_expr_v2(s), + handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr); } #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) @@ -2917,12 +3044,26 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_read_until_match_v2 + template + class initiate_async_read_until_match_v2 { - template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, MatchCondition match_condition) const { // If you get an error on the following line it means that your handler @@ -2933,9 +3074,12 @@ namespace detail read_until_match_op_v2::type, MatchCondition, typename decay::type>( - *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), match_condition, handler2.value)(boost::system::error_code(), 0, 1); } + + private: + AsyncReadStream& stream_; }; } // namespace detail @@ -2979,9 +3123,11 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, @@ -2992,8 +3138,8 @@ async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, { return async_initiate( - detail::initiate_async_read_until_match_v2(), handler, - &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), match_condition); + detail::initiate_async_read_until_match_v2(s), handler, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), match_condition); } #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) diff --git a/boost/asio/impl/write.hpp b/boost/asio/impl/write.hpp index 9624359..1f8c74d 100644 --- a/boost/asio/impl/write.hpp +++ b/boost/asio/impl/write.hpp @@ -418,12 +418,26 @@ namespace detail boost::system::error_code(), 0, 1); } - struct initiate_async_write_buffer_sequence + template + class initiate_async_write_buffer_sequence { - template + public: + typedef typename AsyncWriteStream::executor_type executor_type; + + explicit initiate_async_write_buffer_sequence(AsyncWriteStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return stream_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - AsyncWriteStream* s, const ConstBufferSequence& buffers, + const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const { // If you get an error on the following line it means that your handler @@ -432,10 +446,13 @@ namespace detail non_const_lvalue handler2(handler); non_const_lvalue completion_cond2(completion_cond); - start_write_buffer_sequence_op(*s, buffers, + start_write_buffer_sequence_op(stream_, buffers, boost::asio::buffer_sequence_begin(buffers), completion_cond2.value, handler2.value); } + + private: + AsyncWriteStream& stream_; }; } // namespace detail @@ -481,9 +498,11 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, @@ -494,13 +513,15 @@ async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, { return async_initiate( - detail::initiate_async_write_buffer_sequence(), handler, &s, buffers, + detail::initiate_async_write_buffer_sequence(s), + handler, buffers, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template -inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) WriteHandler> +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler, @@ -510,8 +531,8 @@ async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, { return async_initiate( - detail::initiate_async_write_buffer_sequence(), - handler, &s, buffers, transfer_all()); + detail::initiate_async_write_buffer_sequence(s), + handler, buffers, transfer_all()); } #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) @@ -629,12 +650,26 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_write_dynbuf_v1 + template + class initiate_async_write_dynbuf_v1 { - template + public: + typedef typename AsyncWriteStream::executor_type executor_type; + + explicit initiate_async_write_dynbuf_v1(AsyncWriteStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return stream_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - AsyncWriteStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const { // If you get an error on the following line it means that your handler @@ -646,10 +681,13 @@ namespace detail write_dynbuf_v1_op::type, CompletionCondition, typename decay::type>( - *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), completion_cond2.value, handler2.value)( boost::system::error_code(), 0, 1); } + + private: + AsyncWriteStream& stream_; }; } // namespace detail @@ -693,9 +731,10 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, @@ -710,9 +749,11 @@ async_write(AsyncWriteStream& s, transfer_all(), BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); } -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, @@ -725,16 +766,18 @@ async_write(AsyncWriteStream& s, { return async_initiate( - detail::initiate_async_write_dynbuf_v1(), handler, &s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + detail::initiate_async_write_dynbuf_v1(s), + handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, boost::asio::basic_streambuf& b, @@ -744,9 +787,11 @@ async_write(AsyncWriteStream& s, BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); } -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, boost::asio::basic_streambuf& b, @@ -875,12 +920,26 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_write_dynbuf_v2 + template + class initiate_async_write_dynbuf_v2 { - template + public: + typedef typename AsyncWriteStream::executor_type executor_type; + + explicit initiate_async_write_dynbuf_v2(AsyncWriteStream& stream) + : stream_(stream) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return stream_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - AsyncWriteStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const { // If you get an error on the following line it means that your handler @@ -892,10 +951,13 @@ namespace detail write_dynbuf_v2_op::type, CompletionCondition, typename decay::type>( - *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), completion_cond2.value, handler2.value)( boost::system::error_code(), 0, 1); } + + private: + AsyncWriteStream& stream_; }; } // namespace detail @@ -939,9 +1001,10 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler, @@ -954,9 +1017,11 @@ async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, transfer_all(), BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); } -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, CompletionCondition completion_condition, @@ -967,8 +1032,8 @@ async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, { return async_initiate( - detail::initiate_async_write_dynbuf_v2(), handler, &s, - BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + detail::initiate_async_write_dynbuf_v2(s), + handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } diff --git a/boost/asio/impl/write_at.hpp b/boost/asio/impl/write_at.hpp index 3cad9c5..6fe119a 100644 --- a/boost/asio/impl/write_at.hpp +++ b/boost/asio/impl/write_at.hpp @@ -306,13 +306,27 @@ namespace detail boost::system::error_code(), 0, 1); } - struct initiate_async_write_at_buffer_sequence + template + class initiate_async_write_at_buffer_sequence { - template + public: + typedef typename AsyncRandomAccessWriteDevice::executor_type executor_type; + + explicit initiate_async_write_at_buffer_sequence( + AsyncRandomAccessWriteDevice& device) + : device_(device) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return device_.get_executor(); + } + + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - AsyncRandomAccessWriteDevice* d, uint64_t offset, - const ConstBufferSequence& buffers, + uint64_t offset, const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const { // If you get an error on the following line it means that your handler @@ -321,10 +335,13 @@ namespace detail non_const_lvalue handler2(handler); non_const_lvalue completion_cond2(completion_cond); - start_write_at_buffer_sequence_op(*d, offset, buffers, + start_write_at_buffer_sequence_op(device_, offset, buffers, boost::asio::buffer_sequence_begin(buffers), completion_cond2.value, handler2.value); } + + private: + AsyncRandomAccessWriteDevice& device_; }; } // namespace detail @@ -372,9 +389,11 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, const ConstBufferSequence& buffers, @@ -383,13 +402,16 @@ async_write_at(AsyncRandomAccessWriteDevice& d, { return async_initiate( - detail::initiate_async_write_at_buffer_sequence(), handler, &d, offset, - buffers, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); + detail::initiate_async_write_at_buffer_sequence< + AsyncRandomAccessWriteDevice>(d), + handler, offset, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template -inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) WriteHandler> +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, const ConstBufferSequence& buffers, @@ -397,8 +419,9 @@ async_write_at(AsyncRandomAccessWriteDevice& d, { return async_initiate( - detail::initiate_async_write_at_buffer_sequence(), - handler, &d, offset, buffers, transfer_all()); + detail::initiate_async_write_at_buffer_sequence< + AsyncRandomAccessWriteDevice>(d), + handler, offset, buffers, transfer_all()); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) @@ -484,13 +507,27 @@ namespace detail function, this_handler->handler_); } - struct initiate_async_write_at_streambuf + template + class initiate_async_write_at_streambuf { - template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - AsyncRandomAccessWriteDevice* d, uint64_t offset, - basic_streambuf* b, + uint64_t offset, basic_streambuf* b, BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_condition) const { // If you get an error on the following line it means that your handler @@ -498,11 +535,14 @@ namespace detail BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; non_const_lvalue handler2(handler); - async_write_at(*d, offset, b->data(), + async_write_at(device_, offset, b->data(), BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), write_at_streambuf_op::type>( *b, handler2.value)); } + + private: + AsyncRandomAccessWriteDevice& device_; }; } // namespace detail @@ -540,9 +580,11 @@ struct associated_executor< #endif // !defined(GENERATING_DOCUMENTATION) -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, boost::asio::basic_streambuf& b, @@ -551,13 +593,16 @@ async_write_at(AsyncRandomAccessWriteDevice& d, { return async_initiate( - detail::initiate_async_write_at_streambuf(), handler, &d, offset, - &b, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); + detail::initiate_async_write_at_streambuf< + AsyncRandomAccessWriteDevice>(d), + handler, offset, &b, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template -inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) WriteHandler> +inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, boost::asio::basic_streambuf& b, @@ -565,8 +610,9 @@ async_write_at(AsyncRandomAccessWriteDevice& d, { return async_initiate( - detail::initiate_async_write_at_streambuf(), - handler, &d, offset, &b, transfer_all()); + detail::initiate_async_write_at_streambuf< + AsyncRandomAccessWriteDevice>(d), + handler, offset, &b, transfer_all()); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) diff --git a/boost/asio/io_context.hpp b/boost/asio/io_context.hpp index 1fb3864..10c5883 100644 --- a/boost/asio/io_context.hpp +++ b/boost/asio/io_context.hpp @@ -533,7 +533,7 @@ public: * throws an exception. */ template - BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) dispatch(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler); /// (Deprecated: Use boost::asio::post().) Request the io_context to invoke @@ -560,7 +560,7 @@ public: * throws an exception. */ template - BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) post(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler); /// (Deprecated: Use boost::asio::bind_executor().) Create a new handler that diff --git a/boost/asio/io_context_strand.hpp b/boost/asio/io_context_strand.hpp index a9a9b52..68e0be4 100644 --- a/boost/asio/io_context_strand.hpp +++ b/boost/asio/io_context_strand.hpp @@ -183,7 +183,7 @@ public: * @code void handler(); @endcode */ template - BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) dispatch(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) { return async_initiate( @@ -230,7 +230,7 @@ public: * @code void handler(); @endcode */ template - BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) post(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) { return async_initiate( diff --git a/boost/asio/ip/basic_resolver.hpp b/boost/asio/ip/basic_resolver.hpp index b937ce5..21e025c 100644 --- a/boost/asio/ip/basic_resolver.hpp +++ b/boost/asio/ip/basic_resolver.hpp @@ -72,6 +72,14 @@ public: /// The type of the executor associated with the object. typedef Executor executor_type; + /// Rebinds the resolver type to another executor. + template + struct rebind_executor + { + /// The resolver type when rebound to the specified executor. + typedef basic_resolver other; + }; + /// The protocol type. typedef InternetProtocol protocol_type; @@ -613,15 +621,19 @@ public: * A successful resolve operation is guaranteed to pass a non-empty range to * the handler. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + results_type)) ResolveHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler, void (boost::system::error_code, results_type)) async_resolve(const query& q, - BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return boost::asio::async_initiate( - initiate_async_resolve(), handler, this, q); + initiate_async_resolve(this), handler, q); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) @@ -667,12 +679,16 @@ public: * c:\\windows\\system32\\drivers\\etc\\services. Operating systems * may use additional locations when resolving service names. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + results_type)) ResolveHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler, void (boost::system::error_code, results_type)) async_resolve(BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, - BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_resolve(host, service, resolver_base::flags(), BOOST_ASIO_MOVE_CAST(ResolveHandler)(handler)); @@ -725,20 +741,24 @@ public: * c:\\windows\\system32\\drivers\\etc\\services. Operating systems * may use additional locations when resolving service names. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + results_type)) ResolveHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler, void (boost::system::error_code, results_type)) async_resolve(BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, resolver_base::flags resolve_flags, - BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { basic_resolver_query q(static_cast(host), static_cast(service), resolve_flags); return boost::asio::async_initiate( - initiate_async_resolve(), handler, this, q); + initiate_async_resolve(this), handler, q); } /// Asynchronously perform forward resolution of a query to a list of entries. @@ -786,12 +806,16 @@ public: * c:\\windows\\system32\\drivers\\etc\\services. Operating systems * may use additional locations when resolving service names. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + results_type)) ResolveHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler, void (boost::system::error_code, results_type)) async_resolve(const protocol_type& protocol, BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, - BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_resolve(protocol, host, service, resolver_base::flags(), BOOST_ASIO_MOVE_CAST(ResolveHandler)(handler)); @@ -847,13 +871,17 @@ public: * c:\\windows\\system32\\drivers\\etc\\services. Operating systems * may use additional locations when resolving service names. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + results_type)) ResolveHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler, void (boost::system::error_code, results_type)) async_resolve(const protocol_type& protocol, BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, resolver_base::flags resolve_flags, - BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { basic_resolver_query q( protocol, static_cast(host), @@ -861,7 +889,7 @@ public: return boost::asio::async_initiate( - initiate_async_resolve(), handler, this, q); + initiate_async_resolve(this), handler, q); } /// Perform reverse resolution of an endpoint to a list of entries. @@ -930,15 +958,19 @@ public: * A successful resolve operation is guaranteed to pass a non-empty range to * the handler. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + results_type)) ResolveHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler, void (boost::system::error_code, results_type)) async_resolve(const endpoint_type& e, - BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return boost::asio::async_initiate( - initiate_async_resolve(), handler, this, e); + initiate_async_resolve(this), handler, e); } private: @@ -946,11 +978,24 @@ private: basic_resolver(const basic_resolver&) BOOST_ASIO_DELETED; basic_resolver& operator=(const basic_resolver&) BOOST_ASIO_DELETED; - struct initiate_async_resolve + class initiate_async_resolve { + public: + typedef Executor executor_type; + + explicit initiate_async_resolve(basic_resolver* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(ResolveHandler) handler, - basic_resolver* self, const Query& q) const + const Query& q) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a ResolveHandler. @@ -958,10 +1003,13 @@ private: ResolveHandler, handler, results_type) type_check; boost::asio::detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_resolve( - self->impl_.get_implementation(), q, handler2.value, - self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_resolve( + self_->impl_.get_implementation(), q, handler2.value, + self_->impl_.get_implementation_executor()); } + + private: + basic_resolver* self_; }; # if defined(BOOST_ASIO_WINDOWS_RUNTIME) diff --git a/boost/asio/ip/icmp.hpp b/boost/asio/ip/icmp.hpp index 229529f..497307f 100644 --- a/boost/asio/ip/icmp.hpp +++ b/boost/asio/ip/icmp.hpp @@ -47,33 +47,33 @@ public: typedef basic_endpoint endpoint; /// Construct to represent the IPv4 ICMP protocol. - static icmp v4() + static icmp v4() BOOST_ASIO_NOEXCEPT { return icmp(BOOST_ASIO_OS_DEF(IPPROTO_ICMP), BOOST_ASIO_OS_DEF(AF_INET)); } /// Construct to represent the IPv6 ICMP protocol. - static icmp v6() + static icmp v6() BOOST_ASIO_NOEXCEPT { return icmp(BOOST_ASIO_OS_DEF(IPPROTO_ICMPV6), BOOST_ASIO_OS_DEF(AF_INET6)); } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_RAW); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const BOOST_ASIO_NOEXCEPT { return protocol_; } /// Obtain an identifier for the protocol family. - int family() const + int family() const BOOST_ASIO_NOEXCEPT { return family_; } @@ -98,7 +98,7 @@ public: private: // Construct with a specific family. - explicit icmp(int protocol_id, int protocol_family) + explicit icmp(int protocol_id, int protocol_family) BOOST_ASIO_NOEXCEPT : protocol_(protocol_id), family_(protocol_family) { diff --git a/boost/asio/ip/tcp.hpp b/boost/asio/ip/tcp.hpp index d37b012..b73341b 100644 --- a/boost/asio/ip/tcp.hpp +++ b/boost/asio/ip/tcp.hpp @@ -50,31 +50,31 @@ public: typedef basic_endpoint endpoint; /// Construct to represent the IPv4 TCP protocol. - static tcp v4() + static tcp v4() BOOST_ASIO_NOEXCEPT { return tcp(BOOST_ASIO_OS_DEF(AF_INET)); } /// Construct to represent the IPv6 TCP protocol. - static tcp v6() + static tcp v6() BOOST_ASIO_NOEXCEPT { return tcp(BOOST_ASIO_OS_DEF(AF_INET6)); } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_STREAM); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(IPPROTO_TCP); } /// Obtain an identifier for the protocol family. - int family() const + int family() const BOOST_ASIO_NOEXCEPT { return family_; } @@ -140,7 +140,7 @@ public: private: // Construct with a specific family. - explicit tcp(int protocol_family) + explicit tcp(int protocol_family) BOOST_ASIO_NOEXCEPT : family_(protocol_family) { } diff --git a/boost/asio/ip/udp.hpp b/boost/asio/ip/udp.hpp index 8ba20b4..7f12b99 100644 --- a/boost/asio/ip/udp.hpp +++ b/boost/asio/ip/udp.hpp @@ -47,31 +47,31 @@ public: typedef basic_endpoint endpoint; /// Construct to represent the IPv4 UDP protocol. - static udp v4() + static udp v4() BOOST_ASIO_NOEXCEPT { return udp(BOOST_ASIO_OS_DEF(AF_INET)); } /// Construct to represent the IPv6 UDP protocol. - static udp v6() + static udp v6() BOOST_ASIO_NOEXCEPT { return udp(BOOST_ASIO_OS_DEF(AF_INET6)); } /// Obtain an identifier for the type of the protocol. - int type() const + int type() const BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_DGRAM); } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(IPPROTO_UDP); } /// Obtain an identifier for the protocol family. - int family() const + int family() const BOOST_ASIO_NOEXCEPT { return family_; } @@ -96,7 +96,7 @@ public: private: // Construct with a specific family. - explicit udp(int protocol_family) + explicit udp(int protocol_family) BOOST_ASIO_NOEXCEPT : family_(protocol_family) { } diff --git a/boost/asio/local/basic_endpoint.hpp b/boost/asio/local/basic_endpoint.hpp index 835eb20..70ddd89 100644 --- a/boost/asio/local/basic_endpoint.hpp +++ b/boost/asio/local/basic_endpoint.hpp @@ -61,7 +61,7 @@ public: #endif /// Default constructor. - basic_endpoint() + basic_endpoint() BOOST_ASIO_NOEXCEPT { } diff --git a/boost/asio/local/datagram_protocol.hpp b/boost/asio/local/datagram_protocol.hpp index b29add6..8385a53 100644 --- a/boost/asio/local/datagram_protocol.hpp +++ b/boost/asio/local/datagram_protocol.hpp @@ -46,19 +46,19 @@ class datagram_protocol { public: /// Obtain an identifier for the type of the protocol. - int type() const + int type() const BOOST_ASIO_NOEXCEPT { return SOCK_DGRAM; } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const BOOST_ASIO_NOEXCEPT { return 0; } /// Obtain an identifier for the protocol family. - int family() const + int family() const BOOST_ASIO_NOEXCEPT { return AF_UNIX; } diff --git a/boost/asio/local/stream_protocol.hpp b/boost/asio/local/stream_protocol.hpp index 4fe0de5..8afd82c 100644 --- a/boost/asio/local/stream_protocol.hpp +++ b/boost/asio/local/stream_protocol.hpp @@ -48,19 +48,19 @@ class stream_protocol { public: /// Obtain an identifier for the type of the protocol. - int type() const + int type() const BOOST_ASIO_NOEXCEPT { return SOCK_STREAM; } /// Obtain an identifier for the protocol. - int protocol() const + int protocol() const BOOST_ASIO_NOEXCEPT { return 0; } /// Obtain an identifier for the protocol family. - int family() const + int family() const BOOST_ASIO_NOEXCEPT { return AF_UNIX; } diff --git a/boost/asio/posix/basic_descriptor.hpp b/boost/asio/posix/basic_descriptor.hpp index 301c618..f17153b 100644 --- a/boost/asio/posix/basic_descriptor.hpp +++ b/boost/asio/posix/basic_descriptor.hpp @@ -58,6 +58,14 @@ public: /// The type of the executor associated with the object. typedef Executor executor_type; + /// Rebinds the descriptor type to another executor. + template + struct rebind_executor + { + /// The descriptor type when rebound to the specified executor. + typedef basic_descriptor other; + }; + /// The native representation of a descriptor. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -615,13 +623,17 @@ public: * wait_handler); * @endcode */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) + WaitHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (boost::system::error_code)) - async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + async_wait(wait_type w, + BOOST_ASIO_MOVE_ARG(WaitHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_wait(), handler, this, w); + initiate_async_wait(this), handler, w); } protected: @@ -642,21 +654,36 @@ private: basic_descriptor(const basic_descriptor&) BOOST_ASIO_DELETED; basic_descriptor& operator=(const basic_descriptor&) BOOST_ASIO_DELETED; - struct initiate_async_wait + class initiate_async_wait { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_descriptor* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template - void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, - basic_descriptor* self, wait_type w) const + void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, wait_type w) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a WaitHandler. BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_wait( - self->impl_.get_implementation(), w, handler2.value, - self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), w, handler2.value, + self_->impl_.get_implementation_executor()); } + + private: + basic_descriptor* self_; }; }; diff --git a/boost/asio/posix/basic_stream_descriptor.hpp b/boost/asio/posix/basic_stream_descriptor.hpp index 0098802..24f67e6 100644 --- a/boost/asio/posix/basic_stream_descriptor.hpp +++ b/boost/asio/posix/basic_stream_descriptor.hpp @@ -45,6 +45,14 @@ public: /// The type of the executor associated with the object. typedef Executor executor_type; + /// Rebinds the descriptor type to another executor. + template + struct rebind_executor + { + /// The descriptor type when rebound to the specified executor. + typedef basic_stream_descriptor other; + }; + /// The native representation of a descriptor. typedef typename basic_descriptor::native_handle_type native_handle_type; @@ -257,15 +265,19 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_write_some(), handler, this, buffers); + initiate_async_write_some(this), handler, buffers); } /// Read some data from the descriptor. @@ -367,23 +379,39 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate( - initiate_async_read_some(), handler, this, buffers); + initiate_async_read_some(this), handler, buffers); } private: - struct initiate_async_write_some + class initiate_async_write_some { + public: + typedef Executor executor_type; + + explicit initiate_async_write_some(basic_stream_descriptor* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, - basic_stream_descriptor* self, const ConstBufferSequence& buffers) const { // If you get an error on the following line it means that your handler @@ -391,17 +419,32 @@ private: BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_write_some( - self->impl_.get_implementation(), buffers, handler2.value, - self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_write_some( + self_->impl_.get_implementation(), buffers, handler2.value, + self_->impl_.get_implementation_executor()); } + + private: + basic_stream_descriptor* self_; }; - struct initiate_async_read_some + class initiate_async_read_some { + public: + typedef Executor executor_type; + + explicit initiate_async_read_some(basic_stream_descriptor* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + template void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, - basic_stream_descriptor* self, const MutableBufferSequence& buffers) const { // If you get an error on the following line it means that your handler @@ -409,10 +452,13 @@ private: BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; detail::non_const_lvalue handler2(handler); - self->impl_.get_service().async_read_some( - self->impl_.get_implementation(), buffers, handler2.value, - self->impl_.get_implementation_executor()); + self_->impl_.get_service().async_read_some( + self_->impl_.get_implementation(), buffers, handler2.value, + self_->impl_.get_implementation_executor()); } + + private: + basic_stream_descriptor* self_; }; }; diff --git a/boost/asio/post.hpp b/boost/asio/post.hpp index 0fbdbf0..4d5a668 100644 --- a/boost/asio/post.hpp +++ b/boost/asio/post.hpp @@ -53,8 +53,8 @@ namespace asio { * * @li Returns result.get(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( BOOST_ASIO_MOVE_ARG(CompletionToken) token); /// Submits a completion token or function object for execution. @@ -90,18 +90,28 @@ BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( * * @li Returns result.get(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( - const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( + const Executor& ex, + BOOST_ASIO_MOVE_ARG(CompletionToken) token + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if::value>::type* = 0); /// Submits a completion token or function object for execution. /** * @returns post(ctx.get_executor(), forward(token)). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( - ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( + ExecutionContext& ctx, + BOOST_ASIO_MOVE_ARG(CompletionToken) token + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename ExecutionContext::executor_type), typename enable_if::value>::type* = 0); diff --git a/boost/asio/read.hpp b/boost/asio/read.hpp index 3c48686..cb01639 100644 --- a/boost/asio/read.hpp +++ b/boost/asio/read.hpp @@ -761,11 +761,16 @@ std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, * handler); @endcode */ template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) ReadHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( + typename AsyncReadStream::executor_type)> +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_mutable_buffer_sequence::value >::type* = 0); @@ -833,13 +838,19 @@ async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_mutable_buffer_sequence::value >::type* = 0); @@ -896,13 +907,18 @@ async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, * boost::asio::transfer_all(), * handler); @endcode */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v1::type>::value && !is_dynamic_buffer_v2::type>::value @@ -966,14 +982,20 @@ async_read(AsyncReadStream& s, * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v1::type>::value && !is_dynamic_buffer_v2::type>::value @@ -1030,11 +1052,17 @@ async_read(AsyncReadStream& s, * boost::asio::transfer_all(), * handler); @endcode */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, basic_streambuf& b, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type)); /// Start an asynchronous operation to read a certain amount of data from a /// stream. @@ -1092,13 +1120,19 @@ async_read(AsyncReadStream& s, basic_streambuf& b, * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, basic_streambuf& b, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type)); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) @@ -1154,12 +1188,17 @@ async_read(AsyncReadStream& s, basic_streambuf& b, * boost::asio::transfer_all(), * handler); @endcode */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v2::value >::type* = 0); @@ -1222,13 +1261,19 @@ async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v2::value >::type* = 0); diff --git a/boost/asio/read_at.hpp b/boost/asio/read_at.hpp index 8319feb..ed0296c 100644 --- a/boost/asio/read_at.hpp +++ b/boost/asio/read_at.hpp @@ -460,12 +460,17 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * handler); @endcode */ template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) ReadHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( + typename AsyncRandomAccessReadDevice::executor_type)> +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncRandomAccessReadDevice::executor_type)); /// Start an asynchronous operation to read a certain amount of data at the /// specified offset. @@ -532,14 +537,20 @@ async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncRandomAccessReadDevice::executor_type)); #if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) @@ -590,11 +601,17 @@ async_read_at(AsyncRandomAccessReadDevice& d, * handler); @endcode */ template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) ReadHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( + typename AsyncRandomAccessReadDevice::executor_type)> +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) -async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, - basic_streambuf& b, BOOST_ASIO_MOVE_ARG(ReadHandler) handler); +async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, basic_streambuf& b, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncRandomAccessReadDevice::executor_type)); /// Start an asynchronous operation to read a certain amount of data at the /// specified offset. @@ -649,14 +666,20 @@ async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, basic_streambuf& b, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncRandomAccessReadDevice::executor_type)); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) diff --git a/boost/asio/read_until.hpp b/boost/asio/read_until.hpp index 96ed6a7..413477d 100644 --- a/boost/asio/read_until.hpp +++ b/boost/asio/read_until.hpp @@ -1599,13 +1599,18 @@ std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, - char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v1::type>::value && !is_dynamic_buffer_v2::type>::value @@ -1693,14 +1698,19 @@ async_read_until(AsyncReadStream& s, * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, BOOST_ASIO_STRING_VIEW_PARAM delim, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v1::type>::value && !is_dynamic_buffer_v2::type>::value @@ -1795,14 +1805,19 @@ async_read_until(AsyncReadStream& s, * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, const boost::regex& expr, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v1::type>::value && !is_dynamic_buffer_v2::type>::value @@ -1939,13 +1954,20 @@ async_read_until(AsyncReadStream& s, * boost::asio::async_read_until(s, data, match_char('a'), handler); * @endcode */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, - MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + MatchCondition match_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_match_condition::value && is_dynamic_buffer_v1::type>::value @@ -2032,12 +2054,18 @@ async_read_until(AsyncReadStream& s, * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, - boost::asio::basic_streambuf& b, - char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + boost::asio::basic_streambuf& b, char delim, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type)); /// Start an asynchronous operation to read data into a streambuf until it /// contains a specified delimiter. @@ -2117,13 +2145,19 @@ async_read_until(AsyncReadStream& s, * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf& b, BOOST_ASIO_STRING_VIEW_PARAM delim, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type)); #if defined(BOOST_ASIO_HAS_BOOST_REGEX) \ || defined(GENERATING_DOCUMENTATION) @@ -2210,12 +2244,18 @@ async_read_until(AsyncReadStream& s, * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf& b, const boost::regex& expr, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type)); #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) // || defined(GENERATING_DOCUMENTATION) @@ -2343,13 +2383,19 @@ async_read_until(AsyncReadStream& s, * boost::asio::async_read_until(s, b, match_char('a'), handler); * @endcode */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf& b, - MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + MatchCondition match_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if::value>::type* = 0); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) @@ -2438,12 +2484,17 @@ async_read_until(AsyncReadStream& s, * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) -async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, - char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, +async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, char delim, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v2::value >::type* = 0); @@ -2530,13 +2581,18 @@ async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, BOOST_ASIO_STRING_VIEW_PARAM delim, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v2::value >::type* = 0); @@ -2630,13 +2686,18 @@ async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, * This data may be the start of a new line, to be extracted by a subsequent * @c async_read_until operation. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, const boost::regex& expr, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v2::value >::type* = 0); @@ -2772,12 +2833,19 @@ async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, * boost::asio::async_read_until(s, data, match_char('a'), handler); * @endcode */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, - MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + MatchCondition match_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncReadStream::executor_type), typename enable_if< is_match_condition::value && is_dynamic_buffer_v2::value diff --git a/boost/asio/use_awaitable.hpp b/boost/asio/use_awaitable.hpp index 8764b3d..fa5eddd 100644 --- a/boost/asio/use_awaitable.hpp +++ b/boost/asio/use_awaitable.hpp @@ -46,9 +46,47 @@ namespace asio { template struct use_awaitable_t { + /// Default constructor. BOOST_ASIO_CONSTEXPR use_awaitable_t() { } + + /// Adapts an executor to add the @c use_awaitable_t completion token as the + /// default. + template + struct executor_with_default : InnerExecutor + { + /// Specify @c use_awaitable_t as the default completion token type. + typedef use_awaitable_t default_completion_token_type; + + /// Construct the adapted executor from the inner executor type. + executor_with_default(const InnerExecutor& ex) BOOST_ASIO_NOEXCEPT + : InnerExecutor(ex) + { + } + }; + + /// Type alias to adapt an I/O object to use @c use_awaitable_t as its + /// default completion token type. +#if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) \ + || defined(GENERATING_DOCUMENTATION) + template + using as_default_on_t = typename T::template rebind_executor< + executor_with_default >::other; +#endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + + /// Function helper to adapt an I/O object to use @c use_awaitable_t as its + /// default completion token type. + template + static typename T::template rebind_executor< + executor_with_default + >::other + as_default_on(BOOST_ASIO_MOVE_ARG(T) object) + { + return typename as_default_on_t::type>::type( + BOOST_ASIO_MOVE_CAST(T)(object)); + } }; /// A completion token object that represents the currently executing coroutine. diff --git a/boost/asio/version.hpp b/boost/asio/version.hpp index b93824d..0057cad 100644 --- a/boost/asio/version.hpp +++ b/boost/asio/version.hpp @@ -18,6 +18,6 @@ // BOOST_ASIO_VERSION % 100 is the sub-minor version // BOOST_ASIO_VERSION / 100 % 1000 is the minor version // BOOST_ASIO_VERSION / 100000 is the major version -#define BOOST_ASIO_VERSION 101401 // 1.14.1 +#define BOOST_ASIO_VERSION 101600 // 1.16.0 #endif // BOOST_ASIO_VERSION_HPP diff --git a/boost/asio/windows/basic_object_handle.hpp b/boost/asio/windows/basic_object_handle.hpp index 9519bc7..0f18030 100644 --- a/boost/asio/windows/basic_object_handle.hpp +++ b/boost/asio/windows/basic_object_handle.hpp @@ -55,6 +55,14 @@ public: /// The type of the executor associated with the object. typedef Executor executor_type; + /// Rebinds the handle type to another executor. + template + struct rebind_executor + { + /// The handle type when rebound to the specified executor. + typedef basic_object_handle other; + }; + /// The native representation of a handle. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -363,18 +371,17 @@ public: * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + template < + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) + WaitHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (boost::system::error_code)) - async_wait(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + async_wait( + BOOST_ASIO_MOVE_ARG(WaitHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { - boost::asio::async_completion init(handler); - - impl_.get_service().async_wait(impl_.get_implementation(), - init.completion_handler, impl_.get_implementation_executor()); - - return init.result.get(); + return async_initiate( + initiate_async_wait(this), handler); } private: @@ -382,6 +389,38 @@ private: basic_object_handle(const basic_object_handle&) BOOST_ASIO_DELETED; basic_object_handle& operator=(const basic_object_handle&) BOOST_ASIO_DELETED; + class initiate_async_wait + { + public: + typedef Executor executor_type; + + explicit initiate_async_wait(basic_object_handle* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_wait( + self_->impl_.get_implementation(), handler2.value, + self_->impl_.get_implementation_executor()); + } + + private: + basic_object_handle* self_; + }; + boost::asio::detail::io_object_impl< boost::asio::detail::win_object_handle_service, Executor> impl_; }; diff --git a/boost/asio/windows/basic_overlapped_handle.hpp b/boost/asio/windows/basic_overlapped_handle.hpp index ccce21f..07dc12b 100644 --- a/boost/asio/windows/basic_overlapped_handle.hpp +++ b/boost/asio/windows/basic_overlapped_handle.hpp @@ -58,6 +58,14 @@ public: /// The type of the executor associated with the object. typedef Executor executor_type; + /// Rebinds the handle type to another executor. + template + struct rebind_executor + { + /// The handle type when rebound to the specified executor. + typedef basic_overlapped_handle other; + }; + /// The native representation of a handle. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; diff --git a/boost/asio/windows/basic_random_access_handle.hpp b/boost/asio/windows/basic_random_access_handle.hpp index 5f0d6d4..4a9d20d 100644 --- a/boost/asio/windows/basic_random_access_handle.hpp +++ b/boost/asio/windows/basic_random_access_handle.hpp @@ -44,6 +44,14 @@ public: /// The type of the executor associated with the object. typedef Executor executor_type; + /// Rebinds the handle type to another executor. + template + struct rebind_executor + { + /// The handle type when rebound to the specified executor. + typedef basic_random_access_handle other; + }; + /// The native representation of a handle. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -266,26 +274,20 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some_at(uint64_t offset, const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - boost::asio::async_completion init(handler); - - this->impl_.get_service().async_write_some_at( - this->impl_.get_implementation(), offset, - buffers, init.completion_handler, - this->impl_.get_implementation_executor()); - - return init.result.get(); + return async_initiate( + initiate_async_write_some_at(this), handler, offset, buffers); } /// Read some data from the handle at the specified offset. @@ -394,27 +396,88 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some_at(uint64_t offset, const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - boost::asio::async_completion init(handler); - - this->impl_.get_service().async_read_some_at( - this->impl_.get_implementation(), offset, - buffers, init.completion_handler, - this->impl_.get_implementation_executor()); - - return init.result.get(); + return async_initiate( + initiate_async_read_some_at(this), handler, offset, buffers); } + +private: + class initiate_async_write_some_at + { + public: + typedef Executor executor_type; + + explicit initiate_async_write_some_at(basic_random_access_handle* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + uint64_t offset, const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_write_some_at( + self_->impl_.get_implementation(), offset, buffers, handler2.value, + self_->impl_.get_implementation_executor()); + } + + private: + basic_random_access_handle* self_; + }; + + class initiate_async_read_some_at + { + public: + typedef Executor executor_type; + + explicit initiate_async_read_some_at(basic_random_access_handle* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + uint64_t offset, const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_read_some_at( + self_->impl_.get_implementation(), offset, buffers, handler2.value, + self_->impl_.get_implementation_executor()); + } + + private: + basic_random_access_handle* self_; + }; }; } // namespace windows diff --git a/boost/asio/windows/basic_stream_handle.hpp b/boost/asio/windows/basic_stream_handle.hpp index f8d50d5..70fdaea 100644 --- a/boost/asio/windows/basic_stream_handle.hpp +++ b/boost/asio/windows/basic_stream_handle.hpp @@ -47,6 +47,14 @@ public: /// The type of the executor associated with the object. typedef Executor executor_type; + /// Rebinds the handle type to another executor. + template + struct rebind_executor + { + /// The handle type when rebound to the specified executor. + typedef basic_stream_handle other; + }; + /// The native representation of a handle. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; @@ -259,25 +267,19 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a WriteHandler. - BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; - - boost::asio::async_completion init(handler); - - this->impl_.get_service().async_write_some( - this->impl_.get_implementation(), - buffers, init.completion_handler, - this->impl_.get_implementation_executor()); - - return init.result.get(); + return async_initiate( + initiate_async_write_some(this), handler, buffers); } /// Read some data from the handle. @@ -379,26 +381,87 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + template + BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + BOOST_ASIO_MOVE_ARG(ReadHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { - // If you get an error on the following line it means that your handler does - // not meet the documented type requirements for a ReadHandler. - BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; - - boost::asio::async_completion init(handler); - - this->impl_.get_service().async_read_some( - this->impl_.get_implementation(), - buffers, init.completion_handler, - this->impl_.get_implementation_executor()); - - return init.result.get(); + return async_initiate( + initiate_async_read_some(this), handler, buffers); } + +private: + class initiate_async_write_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_write_some(basic_stream_handle* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_write_some( + self_->impl_.get_implementation(), buffers, handler2.value, + self_->impl_.get_implementation_executor()); + } + + private: + basic_stream_handle* self_; + }; + + class initiate_async_read_some + { + public: + typedef Executor executor_type; + + explicit initiate_async_read_some(basic_stream_handle* self) + : self_(self) + { + } + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return self_->get_executor(); + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self_->impl_.get_service().async_read_some( + self_->impl_.get_implementation(), buffers, handler2.value, + self_->impl_.get_implementation_executor()); + } + + private: + basic_stream_handle* self_; + }; }; } // namespace windows diff --git a/boost/asio/write.hpp b/boost/asio/write.hpp index 041f163..896b93c 100644 --- a/boost/asio/write.hpp +++ b/boost/asio/write.hpp @@ -755,11 +755,16 @@ std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, * std::vector. */ template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) WriteHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( + typename AsyncWriteStream::executor_type)> +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncWriteStream::executor_type), typename enable_if< is_const_buffer_sequence::value >::type* = 0); @@ -831,9 +836,11 @@ async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, @@ -887,13 +894,18 @@ async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncWriteStream::executor_type), typename enable_if< is_dynamic_buffer_v1::type>::value && !is_dynamic_buffer_v2::type>::value @@ -956,9 +968,11 @@ async_write(AsyncWriteStream& s, * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, @@ -1013,11 +1027,17 @@ async_write(AsyncWriteStream& s, * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, basic_streambuf& b, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncWriteStream::executor_type)); /// Start an asynchronous operation to write a certain amount of data to a /// stream. @@ -1074,9 +1094,11 @@ async_write(AsyncWriteStream& s, basic_streambuf& b, * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, basic_streambuf& b, CompletionCondition completion_condition, @@ -1129,12 +1151,17 @@ async_write(AsyncWriteStream& s, basic_streambuf& b, * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncWriteStream::executor_type), typename enable_if< is_dynamic_buffer_v2::value >::type* = 0); @@ -1196,9 +1223,11 @@ async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, CompletionCondition completion_condition, diff --git a/boost/asio/write_at.hpp b/boost/asio/write_at.hpp index d874327..c014952 100644 --- a/boost/asio/write_at.hpp +++ b/boost/asio/write_at.hpp @@ -457,12 +457,17 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, * std::vector. */ template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) WriteHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( + typename AsyncRandomAccessWriteDevice::executor_type)> +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, const ConstBufferSequence& buffers, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncRandomAccessWriteDevice::executor_type)); /// Start an asynchronous operation to write a certain amount of data at the /// specified offset. @@ -535,14 +540,20 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncRandomAccessWriteDevice::executor_type)); #if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) @@ -593,11 +604,17 @@ async_write_at(AsyncRandomAccessWriteDevice& d, * manner equivalent to using boost::asio::post(). */ template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, + std::size_t)) WriteHandler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( + typename AsyncRandomAccessWriteDevice::executor_type)> +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) -async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, - basic_streambuf& b, BOOST_ASIO_MOVE_ARG(WriteHandler) handler); +async_write_at(AsyncRandomAccessWriteDevice& d, + uint64_t offset, basic_streambuf& b, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncRandomAccessWriteDevice::executor_type)); /// Start an asynchronous operation to write a certain amount of data at the /// specified offset. @@ -658,13 +675,19 @@ async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, * immediate completion, invocation of the handler will be performed in a * manner equivalent to using boost::asio::post(). */ -template -BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, +template +BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, basic_streambuf& b, CompletionCondition completion_condition, - BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + BOOST_ASIO_MOVE_ARG(WriteHandler) handler + BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( + typename AsyncRandomAccessWriteDevice::executor_type)); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) diff --git a/boost/atomic.hpp b/boost/atomic.hpp new file mode 100644 index 0000000..cc28b1a --- /dev/null +++ b/boost/atomic.hpp @@ -0,0 +1,18 @@ +#ifndef BOOST_ATOMIC_HPP +#define BOOST_ATOMIC_HPP + +// Copyright (c) 2011 Helge Bahmann +// +// 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) + +// This header includes all Boost.Atomic public headers + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif diff --git a/boost/atomic/atomic.hpp b/boost/atomic/atomic.hpp new file mode 100644 index 0000000..5a80588 --- /dev/null +++ b/boost/atomic/atomic.hpp @@ -0,0 +1,104 @@ +/* + * 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) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/atomic.hpp + * + * This header contains definition of \c atomic template and \c atomic_flag. + */ + +#ifndef BOOST_ATOMIC_ATOMIC_HPP_INCLUDED_ +#define BOOST_ATOMIC_ATOMIC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +#include +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +using atomics::atomic; + +using atomics::atomic_char; +using atomics::atomic_uchar; +using atomics::atomic_schar; +using atomics::atomic_uint8_t; +using atomics::atomic_int8_t; +using atomics::atomic_ushort; +using atomics::atomic_short; +using atomics::atomic_uint16_t; +using atomics::atomic_int16_t; +using atomics::atomic_uint; +using atomics::atomic_int; +using atomics::atomic_uint32_t; +using atomics::atomic_int32_t; +using atomics::atomic_ulong; +using atomics::atomic_long; +using atomics::atomic_uint64_t; +using atomics::atomic_int64_t; +#ifdef BOOST_HAS_LONG_LONG +using atomics::atomic_ullong; +using atomics::atomic_llong; +#endif +using atomics::atomic_address; +using atomics::atomic_bool; +using atomics::atomic_wchar_t; +#if !defined(BOOST_NO_CXX11_CHAR16_T) +using atomics::atomic_char16_t; +#endif +#if !defined(BOOST_NO_CXX11_CHAR32_T) +using atomics::atomic_char32_t; +#endif + +using atomics::atomic_int_least8_t; +using atomics::atomic_uint_least8_t; +using atomics::atomic_int_least16_t; +using atomics::atomic_uint_least16_t; +using atomics::atomic_int_least32_t; +using atomics::atomic_uint_least32_t; +using atomics::atomic_int_least64_t; +using atomics::atomic_uint_least64_t; +using atomics::atomic_int_fast8_t; +using atomics::atomic_uint_fast8_t; +using atomics::atomic_int_fast16_t; +using atomics::atomic_uint_fast16_t; +using atomics::atomic_int_fast32_t; +using atomics::atomic_uint_fast32_t; +using atomics::atomic_int_fast64_t; +using atomics::atomic_uint_fast64_t; +using atomics::atomic_intmax_t; +using atomics::atomic_uintmax_t; + +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +using atomics::atomic_float_t; +using atomics::atomic_double_t; +using atomics::atomic_long_double_t; +#endif + +using atomics::atomic_size_t; +using atomics::atomic_ptrdiff_t; + +#if defined(BOOST_HAS_INTPTR_T) +using atomics::atomic_intptr_t; +using atomics::atomic_uintptr_t; +#endif + +} // namespace boost + +#endif // BOOST_ATOMIC_ATOMIC_HPP_INCLUDED_ diff --git a/boost/atomic/atomic_flag.hpp b/boost/atomic/atomic_flag.hpp new file mode 100644 index 0000000..ac296bc --- /dev/null +++ b/boost/atomic/atomic_flag.hpp @@ -0,0 +1,33 @@ +/* + * 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) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/atomic_flag.hpp + * + * This header contains definition of \c atomic_flag. + */ + +#ifndef BOOST_ATOMIC_ATOMIC_FLAG_HPP_INCLUDED_ +#define BOOST_ATOMIC_ATOMIC_FLAG_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +using atomics::atomic_flag; + +} // namespace boost + +#endif // BOOST_ATOMIC_ATOMIC_FLAG_HPP_INCLUDED_ diff --git a/boost/atomic/capabilities.hpp b/boost/atomic/capabilities.hpp new file mode 100644 index 0000000..5c7434d --- /dev/null +++ b/boost/atomic/capabilities.hpp @@ -0,0 +1,210 @@ +/* + * 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) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/capabilities.hpp + * + * This header defines feature capabilities macros. + */ + +#ifndef BOOST_ATOMIC_CAPABILITIES_HPP_INCLUDED_ +#define BOOST_ATOMIC_CAPABILITIES_HPP_INCLUDED_ + +#include +#include +#include +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +#include +#endif + +#if !defined(BOOST_ATOMIC_EMULATED) +#include BOOST_ATOMIC_DETAIL_BACKEND_HEADER(boost/atomic/detail/caps_) +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#ifndef BOOST_ATOMIC_INT8_LOCK_FREE +#define BOOST_ATOMIC_INT8_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_INT16_LOCK_FREE +#define BOOST_ATOMIC_INT16_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_INT32_LOCK_FREE +#define BOOST_ATOMIC_INT32_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_INT64_LOCK_FREE +#define BOOST_ATOMIC_INT64_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_INT128_LOCK_FREE +#define BOOST_ATOMIC_INT128_LOCK_FREE 0 +#endif + + +#ifndef BOOST_ATOMIC_CHAR_LOCK_FREE +#define BOOST_ATOMIC_CHAR_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#endif + +#ifndef BOOST_ATOMIC_CHAR16_T_LOCK_FREE +#define BOOST_ATOMIC_CHAR16_T_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#endif + +#ifndef BOOST_ATOMIC_CHAR32_T_LOCK_FREE +#define BOOST_ATOMIC_CHAR32_T_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#endif + +#ifndef BOOST_ATOMIC_WCHAR_T_LOCK_FREE +#if BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 1 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 2 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 4 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 8 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#else +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_SHORT_LOCK_FREE +#if BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 1 +#define BOOST_ATOMIC_SHORT_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 2 +#define BOOST_ATOMIC_SHORT_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 4 +#define BOOST_ATOMIC_SHORT_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 8 +#define BOOST_ATOMIC_SHORT_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#else +#define BOOST_ATOMIC_SHORT_LOCK_FREE 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_INT_LOCK_FREE +#if BOOST_ATOMIC_DETAIL_SIZEOF_INT == 1 +#define BOOST_ATOMIC_INT_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 2 +#define BOOST_ATOMIC_INT_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 4 +#define BOOST_ATOMIC_INT_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 8 +#define BOOST_ATOMIC_INT_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#else +#define BOOST_ATOMIC_INT_LOCK_FREE 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_LONG_LOCK_FREE +#if BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 1 +#define BOOST_ATOMIC_LONG_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 2 +#define BOOST_ATOMIC_LONG_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 4 +#define BOOST_ATOMIC_LONG_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 8 +#define BOOST_ATOMIC_LONG_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#else +#define BOOST_ATOMIC_LONG_LOCK_FREE 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_LLONG_LOCK_FREE +#if BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 1 +#define BOOST_ATOMIC_LLONG_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 2 +#define BOOST_ATOMIC_LLONG_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 4 +#define BOOST_ATOMIC_LLONG_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 8 +#define BOOST_ATOMIC_LLONG_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#else +#define BOOST_ATOMIC_LLONG_LOCK_FREE 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_POINTER_LOCK_FREE +#if (BOOST_ATOMIC_DETAIL_SIZEOF_POINTER + 0) == 8 +#define BOOST_ATOMIC_POINTER_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#elif (BOOST_ATOMIC_DETAIL_SIZEOF_POINTER + 0) == 4 +#define BOOST_ATOMIC_POINTER_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#else +#define BOOST_ATOMIC_POINTER_LOCK_FREE 0 +#endif +#endif + +#define BOOST_ATOMIC_ADDRESS_LOCK_FREE BOOST_ATOMIC_POINTER_LOCK_FREE + +#ifndef BOOST_ATOMIC_BOOL_LOCK_FREE +// We store bools in 1-byte storage in all backends +#define BOOST_ATOMIC_BOOL_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#endif + +#ifndef BOOST_ATOMIC_FLAG_LOCK_FREE +#define BOOST_ATOMIC_FLAG_LOCK_FREE BOOST_ATOMIC_BOOL_LOCK_FREE +#endif + +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) + +#if !defined(BOOST_ATOMIC_FLOAT_LOCK_FREE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) +#if BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 2 +#define BOOST_ATOMIC_FLOAT_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 4 +#define BOOST_ATOMIC_FLOAT_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 8 +#define BOOST_ATOMIC_FLOAT_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 16 +#define BOOST_ATOMIC_FLOAT_LOCK_FREE BOOST_ATOMIC_INT128_LOCK_FREE +#else +#define BOOST_ATOMIC_FLOAT_LOCK_FREE 0 +#endif +#endif + +#if !defined(BOOST_ATOMIC_DOUBLE_LOCK_FREE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) +#if BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 2 +#define BOOST_ATOMIC_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 4 +#define BOOST_ATOMIC_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 8 +#define BOOST_ATOMIC_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 16 +#define BOOST_ATOMIC_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT128_LOCK_FREE +#else +#define BOOST_ATOMIC_DOUBLE_LOCK_FREE 0 +#endif +#endif + +#if !defined(BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE) +#if BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 2 +#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 4 +#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 8 +#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 16 +#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT128_LOCK_FREE +#else +#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE 0 +#endif +#endif + +#endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT) + +#ifndef BOOST_ATOMIC_THREAD_FENCE +#define BOOST_ATOMIC_THREAD_FENCE 0 +#endif + +#ifndef BOOST_ATOMIC_SIGNAL_FENCE +#define BOOST_ATOMIC_SIGNAL_FENCE 0 +#endif + +#endif // BOOST_ATOMIC_CAPABILITIES_HPP_INCLUDED_ diff --git a/boost/atomic/detail/addressof.hpp b/boost/atomic/detail/addressof.hpp new file mode 100644 index 0000000..38e876e --- /dev/null +++ b/boost/atomic/detail/addressof.hpp @@ -0,0 +1,58 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/addressof.hpp + * + * This header defines \c addressof helper function. It is similar to \c boost::addressof but it is more + * lightweight and also contains a workaround for some compiler warnings. + */ + +#ifndef BOOST_ATOMIC_DETAIL_ADDRESSOF_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_ADDRESSOF_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// Detection logic is based on boost/core/addressof.hpp +#if defined(BOOST_MSVC_FULL_VER) && BOOST_MSVC_FULL_VER >= 190024215 +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_ADDRESSOF +#elif defined(BOOST_GCC) && BOOST_GCC >= 70000 +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_ADDRESSOF +#elif defined(__has_builtin) +#if __has_builtin(__builtin_addressof) +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_ADDRESSOF +#endif +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename T > +BOOST_FORCEINLINE T* addressof(T& value) BOOST_NOEXCEPT +{ +#if defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_ADDRESSOF) + return __builtin_addressof(value); +#else + // Note: The point of using a local struct as the intermediate type instead of char is to avoid gcc warnings + // if T is a const volatile char*: + // warning: casting 'const volatile char* const' to 'const volatile char&' does not dereference pointer + // The local struct makes sure T is not related to the cast target type. + struct opaque_type; + return reinterpret_cast< T* >(&const_cast< opaque_type& >(reinterpret_cast< const volatile opaque_type& >(value))); +#endif +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_ADDRESSOF_HPP_INCLUDED_ diff --git a/boost/atomic/detail/atomic_flag.hpp b/boost/atomic/detail/atomic_flag.hpp new file mode 100644 index 0000000..6f5fc8a --- /dev/null +++ b/boost/atomic/detail/atomic_flag.hpp @@ -0,0 +1,71 @@ +/* + * 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) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/atomic_flag.hpp + * + * This header contains interface definition of \c atomic_flag. + */ + +#ifndef BOOST_ATOMIC_DETAIL_ATOMIC_FLAG_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_ATOMIC_FLAG_HPP_INCLUDED_ + +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +/* + * IMPLEMENTATION NOTE: All interface functions MUST be declared with BOOST_FORCEINLINE, + * see comment for convert_memory_order_to_gcc in ops_gcc_atomic.hpp. + */ + +namespace boost { +namespace atomics { + +#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) +#define BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT +#else +#define BOOST_ATOMIC_FLAG_INIT {} +#endif + +struct atomic_flag +{ + typedef atomics::detail::operations< 1u, false > operations; + typedef operations::storage_type storage_type; + + operations::aligned_storage_type m_storage; + + BOOST_FORCEINLINE BOOST_CONSTEXPR atomic_flag() BOOST_NOEXCEPT : m_storage(0) + { + } + + BOOST_FORCEINLINE bool test_and_set(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return operations::test_and_set(m_storage.value, order); + } + + BOOST_FORCEINLINE void clear(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_consume); + BOOST_ASSERT(order != memory_order_acquire); + BOOST_ASSERT(order != memory_order_acq_rel); + operations::clear(m_storage.value, order); + } + + BOOST_DELETED_FUNCTION(atomic_flag(atomic_flag const&)) + BOOST_DELETED_FUNCTION(atomic_flag& operator= (atomic_flag const&)) +}; + +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_ATOMIC_FLAG_HPP_INCLUDED_ diff --git a/boost/atomic/detail/atomic_template.hpp b/boost/atomic/detail/atomic_template.hpp new file mode 100644 index 0000000..fb0a8f5 --- /dev/null +++ b/boost/atomic/detail/atomic_template.hpp @@ -0,0 +1,1248 @@ +/* + * 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) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/atomic_template.hpp + * + * This header contains interface definition of \c atomic template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_ATOMIC_TEMPLATE_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_ATOMIC_TEMPLATE_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +#include +#include +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// 'boost::atomics::atomic' : multiple assignment operators specified +#pragma warning(disable: 4522) +#endif + +/* + * IMPLEMENTATION NOTE: All interface functions MUST be declared with BOOST_FORCEINLINE, + * see comment for convert_memory_order_to_gcc in ops_gcc_atomic.hpp. + */ + +namespace boost { +namespace atomics { +namespace detail { + +BOOST_FORCEINLINE BOOST_CONSTEXPR memory_order deduce_failure_order(memory_order order) BOOST_NOEXCEPT +{ + return order == memory_order_acq_rel ? memory_order_acquire : (order == memory_order_release ? memory_order_relaxed : order); +} + +BOOST_FORCEINLINE BOOST_CONSTEXPR bool cas_failure_order_must_not_be_stronger_than_success_order(memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT +{ + // 15 == (memory_order_seq_cst | memory_order_consume), see memory_order.hpp + // Given the enum values we can test the strength of memory order requirements with this single condition. + return (static_cast< unsigned int >(failure_order) & 15u) <= (static_cast< unsigned int >(success_order) & 15u); +} + +template< typename T, bool IsFunction = atomics::detail::is_function< T >::value > +struct classify_pointer +{ + typedef void* type; +}; + +template< typename T > +struct classify_pointer< T, true > +{ + typedef void type; +}; + +template< typename T, bool IsInt = atomics::detail::is_integral< T >::value, bool IsFloat = atomics::detail::is_floating_point< T >::value > +struct classify +{ + typedef void type; +}; + +template< typename T > +struct classify< T, true, false > { typedef int type; }; + +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +template< typename T > +struct classify< T, false, true > { typedef float type; }; +#endif + +template< typename T > +struct classify< T*, false, false > { typedef typename classify_pointer< T >::type type; }; + +template< > +struct classify< void*, false, false > { typedef void type; }; + +template< > +struct classify< const void*, false, false > { typedef void type; }; + +template< > +struct classify< volatile void*, false, false > { typedef void type; }; + +template< > +struct classify< const volatile void*, false, false > { typedef void type; }; + +template< typename T, typename U > +struct classify< T U::*, false, false > { typedef void type; }; + + +#if defined(BOOST_INTEL) || (defined(BOOST_GCC) && (BOOST_GCC+0) < 40700) ||\ + (defined(BOOST_CLANG) && !defined(__apple_build_version__) && ((__clang_major__+0) * 100 + (__clang_minor__+0)) < 302) ||\ + (defined(__clang__) && defined(__apple_build_version__) && ((__clang_major__+0) * 100 + (__clang_minor__+0)) < 402) +// Intel compiler (at least 18.0 update 1) breaks if noexcept specification is used in defaulted function declarations: +// error: the default constructor of "boost::atomics::atomic" cannot be referenced -- it is a deleted function +// GCC 4.6 doesn't seem to support that either. Clang 3.1 deduces wrong noexcept for the defaulted function and fails as well. +#define BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL +#define BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL BOOST_NOEXCEPT +#else +#define BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL BOOST_NOEXCEPT +#define BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL +#endif + +template< typename T, bool IsTriviallyDefaultConstructible = atomics::detail::is_trivially_default_constructible< T >::value > +class base_atomic_generic; + +template< typename T > +class base_atomic_generic< T, true > +{ +public: + typedef T value_type; + +protected: + typedef atomics::detail::operations< storage_size_of< value_type >::value, false > operations; + typedef typename atomics::detail::conditional< sizeof(value_type) <= sizeof(void*), value_type, value_type const& >::type value_arg_type; + +public: + typedef typename operations::storage_type storage_type; + +protected: + typename operations::aligned_storage_type m_storage; + +public: + BOOST_DEFAULTED_FUNCTION(base_atomic_generic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE explicit base_atomic_generic(value_arg_type v) BOOST_NOEXCEPT : m_storage(atomics::detail::bitwise_cast< storage_type >(v)) + { + } +}; + +template< typename T > +class base_atomic_generic< T, false > +{ +public: + typedef T value_type; + +protected: + typedef atomics::detail::operations< storage_size_of< value_type >::value, false > operations; + typedef typename atomics::detail::conditional< sizeof(value_type) <= sizeof(void*), value_type, value_type const& >::type value_arg_type; + +public: + typedef typename operations::storage_type storage_type; + +protected: + typename operations::aligned_storage_type m_storage; + +public: + BOOST_FORCEINLINE explicit base_atomic_generic(value_arg_type v = value_type()) BOOST_NOEXCEPT : m_storage(atomics::detail::bitwise_cast< storage_type >(v)) + { + } +}; + + +template< typename T, typename Kind > +class base_atomic; + +//! General template. Implementation for user-defined types, such as structs and enums, and pointers to non-object types +template< typename T > +class base_atomic< T, void > : + public base_atomic_generic< T > +{ +private: + typedef base_atomic_generic< T > base_type; + +public: + typedef typename base_type::value_type value_type; + typedef typename base_type::storage_type storage_type; + +protected: + typedef typename base_type::operations operations; + typedef typename base_type::value_arg_type value_arg_type; + +private: + typedef atomics::detail::integral_constant< bool, sizeof(value_type) == sizeof(storage_type) > value_matches_storage; + +public: + BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE explicit base_atomic(value_arg_type v) BOOST_NOEXCEPT : base_type(v) + { + } + + BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_consume); + BOOST_ASSERT(order != memory_order_acquire); + BOOST_ASSERT(order != memory_order_acq_rel); + + operations::store(this->m_storage.value, atomics::detail::bitwise_cast< storage_type >(v), order); + } + + BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_release); + BOOST_ASSERT(order != memory_order_acq_rel); + + return atomics::detail::bitwise_cast< value_type >(operations::load(this->m_storage.value, order)); + } + + BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_cast< value_type >(operations::exchange(this->m_storage.value, atomics::detail::bitwise_cast< storage_type >(v), order)); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&)) + BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&)) + +private: + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_strong(this->m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::bitwise_cast< storage_type >(expected); + const bool res = operations::compare_exchange_strong(this->m_storage.value, old_value, atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order); + expected = atomics::detail::bitwise_cast< value_type >(old_value); + return res; + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_weak(this->m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::bitwise_cast< storage_type >(expected); + const bool res = operations::compare_exchange_weak(this->m_storage.value, old_value, atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order); + expected = atomics::detail::bitwise_cast< value_type >(old_value); + return res; + } +}; + + +//! Implementation for integers +template< typename T > +class base_atomic< T, int > +{ +public: + typedef T value_type; + typedef T difference_type; + +protected: + typedef atomics::detail::operations< storage_size_of< value_type >::value, atomics::detail::is_signed< T >::value > operations; + typedef atomics::detail::extra_operations< operations, operations::storage_size, operations::is_signed > extra_operations; + typedef value_type value_arg_type; + +public: + typedef typename operations::storage_type storage_type; + +private: + typedef atomics::detail::integral_constant< bool, sizeof(value_type) == sizeof(storage_type) > value_matches_storage; + +protected: + typename operations::aligned_storage_type m_storage; + +public: + BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit base_atomic(value_arg_type v) BOOST_NOEXCEPT : m_storage(v) {} + + // Standard methods + BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_consume); + BOOST_ASSERT(order != memory_order_acquire); + BOOST_ASSERT(order != memory_order_acq_rel); + + operations::store(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_release); + BOOST_ASSERT(order != memory_order_acq_rel); + + return atomics::detail::integral_truncate< value_type >(operations::load(m_storage.value, order)); + } + + BOOST_FORCEINLINE value_type fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(operations::fetch_add(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(operations::fetch_sub(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(operations::exchange(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_FORCEINLINE value_type fetch_and(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(operations::fetch_and(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type fetch_or(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(operations::fetch_or(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type fetch_xor(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(operations::fetch_xor(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + // Boost.Atomic extensions + BOOST_FORCEINLINE value_type fetch_negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::fetch_negate(m_storage.value, order)); + } + + BOOST_FORCEINLINE value_type fetch_complement(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::fetch_complement(m_storage.value, order)); + } + + BOOST_FORCEINLINE value_type add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::add(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::sub(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::negate(m_storage.value, order)); + } + + BOOST_FORCEINLINE value_type bitwise_and(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::bitwise_and(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type bitwise_or(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::bitwise_or(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type bitwise_xor(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::bitwise_xor(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type bitwise_complement(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::bitwise_complement(m_storage.value, order)); + } + + BOOST_FORCEINLINE void opaque_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_add(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE void opaque_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_sub(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE void opaque_negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_negate(m_storage.value, order); + } + + BOOST_FORCEINLINE void opaque_and(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_and(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE void opaque_or(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_or(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE void opaque_xor(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_xor(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE void opaque_complement(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_complement(m_storage.value, order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool add_and_test(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::add_and_test(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool sub_and_test(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::sub_and_test(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE bool negate_and_test(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::negate_and_test(m_storage.value, order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool and_and_test(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::and_and_test(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool or_and_test(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::or_and_test(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool xor_and_test(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::xor_and_test(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE bool complement_and_test(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::complement_and_test(m_storage.value, order); + } + + BOOST_FORCEINLINE bool bit_test_and_set(unsigned int bit_number, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(bit_number < sizeof(value_type) * 8u); + return extra_operations::bit_test_and_set(m_storage.value, bit_number, order); + } + + BOOST_FORCEINLINE bool bit_test_and_reset(unsigned int bit_number, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(bit_number < sizeof(value_type) * 8u); + return extra_operations::bit_test_and_reset(m_storage.value, bit_number, order); + } + + BOOST_FORCEINLINE bool bit_test_and_complement(unsigned int bit_number, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(bit_number < sizeof(value_type) * 8u); + return extra_operations::bit_test_and_complement(m_storage.value, bit_number, order); + } + + // Operators + BOOST_FORCEINLINE value_type operator++(int) volatile BOOST_NOEXCEPT + { + return fetch_add(1); + } + + BOOST_FORCEINLINE value_type operator++() volatile BOOST_NOEXCEPT + { + return add(1); + } + + BOOST_FORCEINLINE value_type operator--(int) volatile BOOST_NOEXCEPT + { + return fetch_sub(1); + } + + BOOST_FORCEINLINE value_type operator--() volatile BOOST_NOEXCEPT + { + return sub(1); + } + + BOOST_FORCEINLINE value_type operator+=(difference_type v) volatile BOOST_NOEXCEPT + { + return add(v); + } + + BOOST_FORCEINLINE value_type operator-=(difference_type v) volatile BOOST_NOEXCEPT + { + return sub(v); + } + + BOOST_FORCEINLINE value_type operator&=(value_type v) volatile BOOST_NOEXCEPT + { + return bitwise_and(v); + } + + BOOST_FORCEINLINE value_type operator|=(value_type v) volatile BOOST_NOEXCEPT + { + return bitwise_or(v); + } + + BOOST_FORCEINLINE value_type operator^=(value_type v) volatile BOOST_NOEXCEPT + { + return bitwise_xor(v); + } + + BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&)) + BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&)) + +private: + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_strong(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::integral_extend< operations::is_signed, storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::integral_extend< operations::is_signed, storage_type >(expected); + const bool res = operations::compare_exchange_strong(m_storage.value, old_value, atomics::detail::integral_extend< operations::is_signed, storage_type >(desired), success_order, failure_order); + expected = atomics::detail::integral_truncate< value_type >(old_value); + return res; + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_weak(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::integral_extend< operations::is_signed, storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::integral_extend< operations::is_signed, storage_type >(expected); + const bool res = operations::compare_exchange_weak(m_storage.value, old_value, atomics::detail::integral_extend< operations::is_signed, storage_type >(desired), success_order, failure_order); + expected = atomics::detail::integral_truncate< value_type >(old_value); + return res; + } +}; + +//! Implementation for bool +template< > +class base_atomic< bool, int > +{ +public: + typedef bool value_type; + +protected: + typedef atomics::detail::operations< 1u, false > operations; + typedef value_type value_arg_type; + +public: + typedef operations::storage_type storage_type; + +private: + typedef atomics::detail::integral_constant< bool, sizeof(value_type) == sizeof(storage_type) > value_matches_storage; + +protected: + operations::aligned_storage_type m_storage; + +public: + BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit base_atomic(value_arg_type v) BOOST_NOEXCEPT : m_storage(v) {} + + // Standard methods + BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_consume); + BOOST_ASSERT(order != memory_order_acquire); + BOOST_ASSERT(order != memory_order_acq_rel); + + operations::store(m_storage.value, static_cast< storage_type >(v), order); + } + + BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_release); + BOOST_ASSERT(order != memory_order_acq_rel); + + return !!operations::load(m_storage.value, order); + } + + BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return !!operations::exchange(m_storage.value, static_cast< storage_type >(v), order); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&)) + BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&)) + +private: + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_strong(m_storage.value, reinterpret_cast< storage_type& >(expected), static_cast< storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = static_cast< storage_type >(expected); + const bool res = operations::compare_exchange_strong(m_storage.value, old_value, static_cast< storage_type >(desired), success_order, failure_order); + expected = !!old_value; + return res; + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_weak(m_storage.value, reinterpret_cast< storage_type& >(expected), static_cast< storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = static_cast< storage_type >(expected); + const bool res = operations::compare_exchange_weak(m_storage.value, old_value, static_cast< storage_type >(desired), success_order, failure_order); + expected = !!old_value; + return res; + } +}; + + +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) + +//! Implementation for floating point types +template< typename T > +class base_atomic< T, float > +{ +public: + typedef T value_type; + typedef T difference_type; + +protected: + typedef atomics::detail::operations< storage_size_of< value_type >::value, false > operations; + typedef atomics::detail::extra_operations< operations, operations::storage_size, operations::is_signed > extra_operations; + typedef atomics::detail::fp_operations< extra_operations, value_type, operations::storage_size > fp_operations; + typedef atomics::detail::extra_fp_operations< fp_operations, value_type, operations::storage_size > extra_fp_operations; + typedef value_type value_arg_type; + +public: + typedef typename operations::storage_type storage_type; + +private: + typedef atomics::detail::integral_constant< bool, atomics::detail::value_sizeof< value_type >::value == sizeof(storage_type) > value_matches_storage; + +protected: + typename operations::aligned_storage_type m_storage; + +public: + BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE explicit base_atomic(value_arg_type v) BOOST_NOEXCEPT : m_storage(atomics::detail::bitwise_fp_cast< storage_type >(v)) {} + + BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_consume); + BOOST_ASSERT(order != memory_order_acquire); + BOOST_ASSERT(order != memory_order_acq_rel); + + operations::store(m_storage.value, atomics::detail::bitwise_fp_cast< storage_type >(v), order); + } + + BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_release); + BOOST_ASSERT(order != memory_order_acq_rel); + + return atomics::detail::bitwise_fp_cast< value_type >(operations::load(m_storage.value, order)); + } + + BOOST_FORCEINLINE value_type fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return fp_operations::fetch_add(m_storage.value, v, order); + } + + BOOST_FORCEINLINE value_type fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return fp_operations::fetch_sub(m_storage.value, v, order); + } + + BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_fp_cast< value_type >(operations::exchange(m_storage.value, atomics::detail::bitwise_fp_cast< storage_type >(v), order)); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + // Boost.Atomic extensions + BOOST_FORCEINLINE value_type fetch_negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_fp_operations::fetch_negate(m_storage.value, order); + } + + BOOST_FORCEINLINE value_type add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_fp_operations::add(m_storage.value, v, order); + } + + BOOST_FORCEINLINE value_type sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_fp_operations::sub(m_storage.value, v, order); + } + + BOOST_FORCEINLINE value_type negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_fp_operations::negate(m_storage.value, order); + } + + BOOST_FORCEINLINE void opaque_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_fp_operations::opaque_add(m_storage.value, v, order); + } + + BOOST_FORCEINLINE void opaque_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_fp_operations::opaque_sub(m_storage.value, v, order); + } + + BOOST_FORCEINLINE void opaque_negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_fp_operations::opaque_negate(m_storage.value, order); + } + + // Operators + BOOST_FORCEINLINE value_type operator+=(difference_type v) volatile BOOST_NOEXCEPT + { + return add(v); + } + + BOOST_FORCEINLINE value_type operator-=(difference_type v) volatile BOOST_NOEXCEPT + { + return sub(v); + } + + BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&)) + BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&)) + +private: + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_strong(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::bitwise_fp_cast< storage_type >(expected); + const bool res = operations::compare_exchange_strong(m_storage.value, old_value, atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order); + expected = atomics::detail::bitwise_fp_cast< value_type >(old_value); + return res; + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_weak(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::bitwise_fp_cast< storage_type >(expected); + const bool res = operations::compare_exchange_weak(m_storage.value, old_value, atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order); + expected = atomics::detail::bitwise_fp_cast< value_type >(old_value); + return res; + } +}; + +#endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT) + + +//! Implementation for pointers to object types +template< typename T > +class base_atomic< T*, void* > +{ +public: + typedef T* value_type; + typedef std::ptrdiff_t difference_type; + +protected: + typedef atomics::detail::operations< storage_size_of< value_type >::value, false > operations; + typedef atomics::detail::extra_operations< operations, operations::storage_size, operations::is_signed > extra_operations; + typedef value_type value_arg_type; + +public: + typedef typename operations::storage_type storage_type; + +private: + typedef atomics::detail::integral_constant< bool, sizeof(value_type) == sizeof(storage_type) > value_matches_storage; + + // uintptr_storage_type is the minimal storage type that is enough to store pointers. The actual storage_type theoretically may be larger, + // if the target architecture only supports atomic ops on larger data. Typically, though, they are the same type. +#if defined(BOOST_HAS_INTPTR_T) + typedef uintptr_t uintptr_storage_type; +#else + typedef typename atomics::detail::make_storage_type< sizeof(value_type) >::type uintptr_storage_type; +#endif + +protected: + typename operations::aligned_storage_type m_storage; + +public: + BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE explicit base_atomic(value_arg_type v) BOOST_NOEXCEPT : m_storage(atomics::detail::bitwise_cast< uintptr_storage_type >(v)) + { + } + + // Standard methods + BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_consume); + BOOST_ASSERT(order != memory_order_acquire); + BOOST_ASSERT(order != memory_order_acq_rel); + + operations::store(m_storage.value, atomics::detail::bitwise_cast< uintptr_storage_type >(v), order); + } + + BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_release); + BOOST_ASSERT(order != memory_order_acq_rel); + + return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(operations::load(m_storage.value, order))); + } + + BOOST_FORCEINLINE value_type fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(operations::fetch_add(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order))); + } + + BOOST_FORCEINLINE value_type fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(operations::fetch_sub(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order))); + } + + BOOST_FORCEINLINE value_type exchange(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(operations::exchange(m_storage.value, atomics::detail::bitwise_cast< uintptr_storage_type >(v), order))); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + // Boost.Atomic extensions + BOOST_FORCEINLINE value_type add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(extra_operations::add(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order))); + } + + BOOST_FORCEINLINE value_type sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(extra_operations::sub(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order))); + } + + BOOST_FORCEINLINE void opaque_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_add(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order); + } + + BOOST_FORCEINLINE void opaque_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_sub(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool add_and_test(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::add_and_test(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool sub_and_test(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::sub_and_test(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order); + } + + // Operators + BOOST_FORCEINLINE value_type operator++(int) volatile BOOST_NOEXCEPT + { + return fetch_add(1); + } + + BOOST_FORCEINLINE value_type operator++() volatile BOOST_NOEXCEPT + { + return add(1); + } + + BOOST_FORCEINLINE value_type operator--(int) volatile BOOST_NOEXCEPT + { + return fetch_sub(1); + } + + BOOST_FORCEINLINE value_type operator--() volatile BOOST_NOEXCEPT + { + return sub(1); + } + + BOOST_FORCEINLINE value_type operator+=(difference_type v) volatile BOOST_NOEXCEPT + { + return add(v); + } + + BOOST_FORCEINLINE value_type operator-=(difference_type v) volatile BOOST_NOEXCEPT + { + return sub(v); + } + + BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&)) + BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&)) + +private: + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_strong(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< uintptr_storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::bitwise_cast< uintptr_storage_type >(expected); + const bool res = operations::compare_exchange_strong(m_storage.value, old_value, atomics::detail::bitwise_cast< uintptr_storage_type >(desired), success_order, failure_order); + expected = atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(old_value)); + return res; + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_weak(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< uintptr_storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::bitwise_cast< uintptr_storage_type >(expected); + const bool res = operations::compare_exchange_weak(m_storage.value, old_value, atomics::detail::bitwise_cast< uintptr_storage_type >(desired), success_order, failure_order); + expected = atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(old_value)); + return res; + } +}; + +} // namespace detail + +template< typename T > +class atomic : + public atomics::detail::base_atomic< T, typename atomics::detail::classify< T >::type > +{ +private: + typedef atomics::detail::base_atomic< T, typename atomics::detail::classify< T >::type > base_type; + typedef typename base_type::value_arg_type value_arg_type; + +public: + typedef typename base_type::value_type value_type; + typedef typename base_type::storage_type storage_type; + +public: + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = base_type::operations::is_always_lock_free; + +public: + BOOST_DEFAULTED_FUNCTION(atomic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR atomic(value_arg_type v) BOOST_NOEXCEPT : base_type(v) {} + + BOOST_FORCEINLINE value_type operator= (value_arg_type v) BOOST_NOEXCEPT + { + this->store(v); + return v; + } + + BOOST_FORCEINLINE value_type operator= (value_arg_type v) volatile BOOST_NOEXCEPT + { + this->store(v); + return v; + } + + BOOST_FORCEINLINE operator value_type() const volatile BOOST_NOEXCEPT + { + return this->load(); + } + + BOOST_FORCEINLINE bool is_lock_free() const volatile BOOST_NOEXCEPT + { + // C++17 requires all instances of atomic<> return a value consistent with is_always_lock_free here + return is_always_lock_free; + } + + BOOST_FORCEINLINE storage_type& storage() BOOST_NOEXCEPT { return this->m_storage.value; } + BOOST_FORCEINLINE storage_type volatile& storage() volatile BOOST_NOEXCEPT { return this->m_storage.value; } + BOOST_FORCEINLINE storage_type const& storage() const BOOST_NOEXCEPT { return this->m_storage.value; } + BOOST_FORCEINLINE storage_type const volatile& storage() const volatile BOOST_NOEXCEPT { return this->m_storage.value; } + + BOOST_DELETED_FUNCTION(atomic(atomic const&)) + BOOST_DELETED_FUNCTION(atomic& operator= (atomic const&)) + BOOST_DELETED_FUNCTION(atomic& operator= (atomic const&) volatile) +}; + +template< typename T > +BOOST_CONSTEXPR_OR_CONST bool atomic< T >::is_always_lock_free; + +#undef BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL +#undef BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL + +typedef atomic< char > atomic_char; +typedef atomic< unsigned char > atomic_uchar; +typedef atomic< signed char > atomic_schar; +typedef atomic< uint8_t > atomic_uint8_t; +typedef atomic< int8_t > atomic_int8_t; +typedef atomic< unsigned short > atomic_ushort; +typedef atomic< short > atomic_short; +typedef atomic< uint16_t > atomic_uint16_t; +typedef atomic< int16_t > atomic_int16_t; +typedef atomic< unsigned int > atomic_uint; +typedef atomic< int > atomic_int; +typedef atomic< uint32_t > atomic_uint32_t; +typedef atomic< int32_t > atomic_int32_t; +typedef atomic< unsigned long > atomic_ulong; +typedef atomic< long > atomic_long; +typedef atomic< uint64_t > atomic_uint64_t; +typedef atomic< int64_t > atomic_int64_t; +#ifdef BOOST_HAS_LONG_LONG +typedef atomic< boost::ulong_long_type > atomic_ullong; +typedef atomic< boost::long_long_type > atomic_llong; +#endif +typedef atomic< void* > atomic_address; +typedef atomic< bool > atomic_bool; +typedef atomic< wchar_t > atomic_wchar_t; +#if !defined(BOOST_NO_CXX11_CHAR16_T) +typedef atomic< char16_t > atomic_char16_t; +#endif +#if !defined(BOOST_NO_CXX11_CHAR32_T) +typedef atomic< char32_t > atomic_char32_t; +#endif + +typedef atomic< int_least8_t > atomic_int_least8_t; +typedef atomic< uint_least8_t > atomic_uint_least8_t; +typedef atomic< int_least16_t > atomic_int_least16_t; +typedef atomic< uint_least16_t > atomic_uint_least16_t; +typedef atomic< int_least32_t > atomic_int_least32_t; +typedef atomic< uint_least32_t > atomic_uint_least32_t; +typedef atomic< int_least64_t > atomic_int_least64_t; +typedef atomic< uint_least64_t > atomic_uint_least64_t; +typedef atomic< int_fast8_t > atomic_int_fast8_t; +typedef atomic< uint_fast8_t > atomic_uint_fast8_t; +typedef atomic< int_fast16_t > atomic_int_fast16_t; +typedef atomic< uint_fast16_t > atomic_uint_fast16_t; +typedef atomic< int_fast32_t > atomic_int_fast32_t; +typedef atomic< uint_fast32_t > atomic_uint_fast32_t; +typedef atomic< int_fast64_t > atomic_int_fast64_t; +typedef atomic< uint_fast64_t > atomic_uint_fast64_t; +typedef atomic< intmax_t > atomic_intmax_t; +typedef atomic< uintmax_t > atomic_uintmax_t; + +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +typedef atomic< float > atomic_float_t; +typedef atomic< double > atomic_double_t; +typedef atomic< long double > atomic_long_double_t; +#endif + +typedef atomic< std::size_t > atomic_size_t; +typedef atomic< std::ptrdiff_t > atomic_ptrdiff_t; + +#if defined(BOOST_HAS_INTPTR_T) +typedef atomic< intptr_t > atomic_intptr_t; +typedef atomic< uintptr_t > atomic_uintptr_t; +#endif + +} // namespace atomics +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_ATOMIC_DETAIL_ATOMIC_TEMPLATE_HPP_INCLUDED_ diff --git a/boost/atomic/detail/bitwise_cast.hpp b/boost/atomic/detail/bitwise_cast.hpp new file mode 100644 index 0000000..10d165e --- /dev/null +++ b/boost/atomic/detail/bitwise_cast.hpp @@ -0,0 +1,68 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2013 - 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/bitwise_cast.hpp + * + * This header defines \c bitwise_cast used to convert between storage and value types + */ + +#ifndef BOOST_ATOMIC_DETAIL_BITWISE_CAST_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_BITWISE_CAST_HPP_INCLUDED_ + +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< std::size_t FromSize, typename To > +BOOST_FORCEINLINE void clear_padding(To& to, atomics::detail::true_type) BOOST_NOEXCEPT +{ + BOOST_ATOMIC_DETAIL_MEMSET(reinterpret_cast< unsigned char* >(atomics::detail::addressof(to)) + FromSize, 0, sizeof(To) - FromSize); +} + +template< std::size_t FromSize, typename To > +BOOST_FORCEINLINE void clear_padding(To&, atomics::detail::false_type) BOOST_NOEXCEPT +{ +} + +template< typename To, std::size_t FromSize, typename From > +BOOST_FORCEINLINE To bitwise_cast(From const& from) BOOST_NOEXCEPT +{ + To to; + BOOST_ATOMIC_DETAIL_MEMCPY + ( + atomics::detail::addressof(to), + atomics::detail::addressof(from), + (FromSize < sizeof(To) ? FromSize : sizeof(To)) + ); + atomics::detail::clear_padding< FromSize >(to, atomics::detail::integral_constant< bool, FromSize < sizeof(To) >()); + return to; +} + +template< typename To, typename From > +BOOST_FORCEINLINE To bitwise_cast(From const& from) BOOST_NOEXCEPT +{ + return atomics::detail::bitwise_cast< To, sizeof(From) >(from); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_BITWISE_CAST_HPP_INCLUDED_ diff --git a/boost/atomic/detail/bitwise_fp_cast.hpp b/boost/atomic/detail/bitwise_fp_cast.hpp new file mode 100644 index 0000000..a74b20b --- /dev/null +++ b/boost/atomic/detail/bitwise_fp_cast.hpp @@ -0,0 +1,86 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/bitwise_fp_cast.hpp + * + * This header defines \c bitwise_fp_cast used to convert between storage and floating point value types + */ + +#ifndef BOOST_ATOMIC_DETAIL_BITWISE_FP_CAST_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_BITWISE_FP_CAST_HPP_INCLUDED_ + +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +/*! + * \brief The type trait returns the size of the value of the specified floating point type + * + * This size may be less than sizeof(T) if the implementation uses padding bytes for a particular FP type. This is + * often the case with 80-bit extended double, which is stored in 12 or 16 bytes with padding filled with garbage. + */ +template< typename T > +struct value_sizeof +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t value = sizeof(T); +}; + +#if defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE) +template< > +struct value_sizeof< float > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t value = BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE; +}; +#endif + +#if defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE) +template< > +struct value_sizeof< double > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t value = BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE; +}; +#endif + +#if defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE) +template< > +struct value_sizeof< long double > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t value = BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE; +}; +#endif + +template< typename T > +struct value_sizeof< const T > : value_sizeof< T > {}; + +template< typename T > +struct value_sizeof< volatile T > : value_sizeof< T > {}; + +template< typename T > +struct value_sizeof< const volatile T > : value_sizeof< T > {}; + + +template< typename To, typename From > +BOOST_FORCEINLINE To bitwise_fp_cast(From const& from) BOOST_NOEXCEPT +{ + return atomics::detail::bitwise_cast< To, atomics::detail::value_sizeof< From >::value >(from); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_BITWISE_FP_CAST_HPP_INCLUDED_ diff --git a/boost/atomic/detail/caps_gcc_alpha.hpp b/boost/atomic/detail/caps_gcc_alpha.hpp new file mode 100644 index 0000000..861432f --- /dev/null +++ b/boost/atomic/detail/caps_gcc_alpha.hpp @@ -0,0 +1,34 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_alpha.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_ALPHA_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_ALPHA_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_ALPHA_HPP_INCLUDED_ diff --git a/boost/atomic/detail/caps_gcc_arm.hpp b/boost/atomic/detail/caps_gcc_arm.hpp new file mode 100644 index 0000000..a26ea56 --- /dev/null +++ b/boost/atomic/detail/caps_gcc_arm.hpp @@ -0,0 +1,39 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2009 Phil Endecott + * Copyright (c) 2013 Tim Blechmann + * ARM Code by Phil Endecott, based on other architectures. + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_arm.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_ARM_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD) +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#endif +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_ARM_HPP_INCLUDED_ diff --git a/boost/atomic/detail/caps_gcc_atomic.hpp b/boost/atomic/detail/caps_gcc_atomic.hpp new file mode 100644 index 0000000..3b518cf --- /dev/null +++ b/boost/atomic/detail/caps_gcc_atomic.hpp @@ -0,0 +1,133 @@ +/* + * 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) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_atomic.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_ATOMIC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_ATOMIC_HPP_INCLUDED_ + +#include +#include +#if defined(__i386__) || defined(__x86_64__) +#include +#elif defined(__arm__) +#include +#elif defined(__POWERPC__) || defined(__PPC__) +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) && (defined(BOOST_HAS_INT128) || !defined(BOOST_NO_ALIGNMENT)) +#define BOOST_ATOMIC_INT128_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_INT128_LOCK_FREE 0 +#endif + +#if (__GCC_ATOMIC_LLONG_LOCK_FREE == 2) || (defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) && BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 8) +#define BOOST_ATOMIC_LLONG_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_LLONG_LOCK_FREE BOOST_ATOMIC_INT128_LOCK_FREE +#endif + +#if (__GCC_ATOMIC_LONG_LOCK_FREE == 2) || (defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) && BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 8) +#define BOOST_ATOMIC_LONG_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_LONG_LOCK_FREE BOOST_ATOMIC_LLONG_LOCK_FREE +#endif + +#if __GCC_ATOMIC_INT_LOCK_FREE == 2 +#define BOOST_ATOMIC_INT_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_INT_LOCK_FREE BOOST_ATOMIC_LONG_LOCK_FREE +#endif + +#if __GCC_ATOMIC_SHORT_LOCK_FREE == 2 +#define BOOST_ATOMIC_SHORT_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_SHORT_LOCK_FREE BOOST_ATOMIC_INT_LOCK_FREE +#endif + +#if __GCC_ATOMIC_CHAR_LOCK_FREE == 2 +#define BOOST_ATOMIC_CHAR_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_CHAR_LOCK_FREE BOOST_ATOMIC_SHORT_LOCK_FREE +#endif + +#if __GCC_ATOMIC_POINTER_LOCK_FREE == 2 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_POINTER_LOCK_FREE 0 +#endif + + +#define BOOST_ATOMIC_INT8_LOCK_FREE BOOST_ATOMIC_CHAR_LOCK_FREE + +#if BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE BOOST_ATOMIC_SHORT_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE BOOST_ATOMIC_INT_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE BOOST_ATOMIC_LONG_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE BOOST_ATOMIC_LLONG_LOCK_FREE +#else +#define BOOST_ATOMIC_INT16_LOCK_FREE 0 +#endif + +#if BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 4 +#define BOOST_ATOMIC_INT32_LOCK_FREE BOOST_ATOMIC_SHORT_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 4 +#define BOOST_ATOMIC_INT32_LOCK_FREE BOOST_ATOMIC_INT_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 4 +#define BOOST_ATOMIC_INT32_LOCK_FREE BOOST_ATOMIC_LONG_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 4 +#define BOOST_ATOMIC_INT32_LOCK_FREE BOOST_ATOMIC_LLONG_LOCK_FREE +#else +#define BOOST_ATOMIC_INT32_LOCK_FREE 0 +#endif + +#if BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 8 +#define BOOST_ATOMIC_INT64_LOCK_FREE BOOST_ATOMIC_SHORT_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 8 +#define BOOST_ATOMIC_INT64_LOCK_FREE BOOST_ATOMIC_INT_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 8 +#define BOOST_ATOMIC_INT64_LOCK_FREE BOOST_ATOMIC_LONG_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 8 +#define BOOST_ATOMIC_INT64_LOCK_FREE BOOST_ATOMIC_LLONG_LOCK_FREE +#else +#define BOOST_ATOMIC_INT64_LOCK_FREE 0 +#endif + + +#if __GCC_ATOMIC_WCHAR_T_LOCK_FREE == 2 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 2 +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 8 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 4 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 2 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 1 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#else +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 0 +#endif + +#define BOOST_ATOMIC_CHAR32_T_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#define BOOST_ATOMIC_CHAR16_T_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_ATOMIC_HPP_INCLUDED_ diff --git a/boost/atomic/detail/caps_gcc_ppc.hpp b/boost/atomic/detail/caps_gcc_ppc.hpp new file mode 100644 index 0000000..3e20fde --- /dev/null +++ b/boost/atomic/detail/caps_gcc_ppc.hpp @@ -0,0 +1,37 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_ppc.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_PPC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_PPC_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX) +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#endif +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_PPC_HPP_INCLUDED_ diff --git a/boost/atomic/detail/caps_gcc_sparc.hpp b/boost/atomic/detail/caps_gcc_sparc.hpp new file mode 100644 index 0000000..5806684 --- /dev/null +++ b/boost/atomic/detail/caps_gcc_sparc.hpp @@ -0,0 +1,34 @@ +/* + * 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) + * + * Copyright (c) 2010 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_sparc.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_SPARC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_SPARC_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_SPARC_HPP_INCLUDED_ diff --git a/boost/atomic/detail/caps_gcc_sync.hpp b/boost/atomic/detail/caps_gcc_sync.hpp new file mode 100644 index 0000000..ffbe605 --- /dev/null +++ b/boost/atomic/detail/caps_gcc_sync.hpp @@ -0,0 +1,61 @@ +/* + * 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) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_sync.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_SYNC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_SYNC_HPP_INCLUDED_ + +#include +#if defined(__i386__) || defined(__x86_64__) +#include +#elif defined(__arm__) +#include +#elif defined(__POWERPC__) || defined(__PPC__) +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#endif +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#endif +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#endif +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#endif +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define BOOST_ATOMIC_INT128_LOCK_FREE 2 +#endif + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_SYNC_HPP_INCLUDED_ diff --git a/boost/atomic/detail/caps_gcc_x86.hpp b/boost/atomic/detail/caps_gcc_x86.hpp new file mode 100644 index 0000000..70c6462 --- /dev/null +++ b/boost/atomic/detail/caps_gcc_x86.hpp @@ -0,0 +1,40 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2013 - 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_x86.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_X86_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#if defined(__x86_64__) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#endif +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) && (defined(BOOST_HAS_INT128) || !defined(BOOST_NO_ALIGNMENT)) +#define BOOST_ATOMIC_INT128_LOCK_FREE 2 +#endif +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_X86_HPP_INCLUDED_ diff --git a/boost/atomic/detail/caps_linux_arm.hpp b/boost/atomic/detail/caps_linux_arm.hpp new file mode 100644 index 0000000..abe6fb8 --- /dev/null +++ b/boost/atomic/detail/caps_linux_arm.hpp @@ -0,0 +1,35 @@ +/* + * 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) + * + * Copyright (c) 2009, 2011 Helge Bahmann + * Copyright (c) 2009 Phil Endecott + * Copyright (c) 2013 Tim Blechmann + * Linux-specific code by Phil Endecott + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_linux_arm.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_LINUX_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_LINUX_ARM_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_LINUX_ARM_HPP_INCLUDED_ diff --git a/boost/atomic/detail/caps_msvc_arm.hpp b/boost/atomic/detail/caps_msvc_arm.hpp new file mode 100644 index 0000000..6b3c61f --- /dev/null +++ b/boost/atomic/detail/caps_msvc_arm.hpp @@ -0,0 +1,34 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2012 - 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_msvc_arm.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_MSVC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_MSVC_ARM_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_MSVC_ARM_HPP_INCLUDED_ diff --git a/boost/atomic/detail/caps_msvc_x86.hpp b/boost/atomic/detail/caps_msvc_x86.hpp new file mode 100644 index 0000000..07c8451 --- /dev/null +++ b/boost/atomic/detail/caps_msvc_x86.hpp @@ -0,0 +1,59 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2012 - 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_msvc_x86.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_MSVC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_MSVC_X86_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(_M_IX86) && _M_IX86 >= 500 +#define BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B 1 +#endif + +#if !defined(BOOST_ATOMIC_NO_CMPXCHG16B) +#if defined(__clang__) && (defined(_M_AMD64) || defined(__x86_64__)) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B 1 +#elif _MSC_VER >= 1500 && defined(_M_AMD64) +#define BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B 1 +#endif +#endif + +#if defined(_MSC_VER) && (defined(_M_AMD64) || (defined(_M_IX86) && defined(_M_IX86_FP) && _M_IX86_FP >= 2)) +// Use mfence only if SSE2 is available +#define BOOST_ATOMIC_DETAIL_X86_HAS_MFENCE 1 +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 + +#if defined(_M_AMD64) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#endif + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) && (defined(BOOST_HAS_INT128) || !defined(BOOST_NO_ALIGNMENT)) +#define BOOST_ATOMIC_INT128_LOCK_FREE 2 +#endif + +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_MSVC_X86_HPP_INCLUDED_ diff --git a/boost/atomic/detail/caps_windows.hpp b/boost/atomic/detail/caps_windows.hpp new file mode 100644 index 0000000..1cc0ded --- /dev/null +++ b/boost/atomic/detail/caps_windows.hpp @@ -0,0 +1,33 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2012 - 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_windows.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_WINDOWS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_WINDOWS_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_WINDOWS_HPP_INCLUDED_ diff --git a/boost/atomic/detail/config.hpp b/boost/atomic/detail/config.hpp new file mode 100644 index 0000000..d2a6afd --- /dev/null +++ b/boost/atomic/detail/config.hpp @@ -0,0 +1,150 @@ +/* + * 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) + * + * Copyright (c) 2012 Hartmut Kaiser + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/config.hpp + * + * This header defines configuraion macros for Boost.Atomic + */ + +#ifndef BOOST_ATOMIC_DETAIL_CONFIG_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CONFIG_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__CUDACC__) +// nvcc does not support alternatives ("q,m") in asm statement constraints +#define BOOST_ATOMIC_DETAIL_NO_ASM_CONSTRAINT_ALTERNATIVES +// nvcc does not support condition code register ("cc") clobber in asm statements +#define BOOST_ATOMIC_DETAIL_NO_ASM_CLOBBER_CC +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_NO_ASM_CLOBBER_CC) +#define BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC "cc" +#define BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "cc", +#else +#define BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC +#define BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA +#endif + +#if (defined(__i386__) || defined(__x86_64__)) && (defined(__clang__) || (defined(BOOST_GCC) && (BOOST_GCC+0) < 40500) || defined(__SUNPRO_CC)) +// This macro indicates that the compiler does not support allocating eax:edx or rax:rdx register pairs ("A") in asm blocks +#define BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS +#endif + +#if defined(__i386__) && (defined(__PIC__) || defined(__PIE__)) && !(defined(__clang__) || (defined(BOOST_GCC) && (BOOST_GCC+0) >= 50100)) +// This macro indicates that asm blocks should preserve ebx value unchanged. Some compilers are able to maintain ebx themselves +// around the asm blocks. For those compilers we don't need to save/restore ebx in asm blocks. +#define BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX +#endif + +#if defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) +#if !(defined(BOOST_LIBSTDCXX11) && (BOOST_LIBSTDCXX_VERSION+0) >= 40700) /* libstdc++ from gcc >= 4.7 in C++11 mode */ +// This macro indicates that there is not even a basic standard header that is sufficient for most Boost.Atomic needs. +#define BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS +#endif +#endif // defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) + +// Enable pointer/reference casts between storage and value when possible. +// Note: Despite that MSVC does not employ strict aliasing rules for optimizations +// and does not require an explicit markup for types that may alias, we still don't +// enable the optimization for this compiler because at least MSVC-8 and 9 are known +// to generate broken code sometimes when casts are used. +#define BOOST_ATOMIC_DETAIL_MAY_ALIAS BOOST_MAY_ALIAS +#if !defined(BOOST_NO_MAY_ALIAS) +#define BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS +#endif + +#if defined(__GCC_ASM_FLAG_OUTPUTS__) +// The compiler supports output values in flag registers. +// See: https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html, Section 6.44.3. +#define BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS +#endif + +#if defined(__has_builtin) +#if __has_builtin(__builtin_constant_p) +#define BOOST_ATOMIC_DETAIL_IS_CONSTANT(x) __builtin_constant_p(x) +#endif +#elif defined(__GNUC__) +#define BOOST_ATOMIC_DETAIL_IS_CONSTANT(x) __builtin_constant_p(x) +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_IS_CONSTANT) +#define BOOST_ATOMIC_DETAIL_IS_CONSTANT(x) false +#endif + +#if (defined(__BYTE_ORDER__) && defined(__FLOAT_WORD_ORDER__) && (__BYTE_ORDER__+0) == (__FLOAT_WORD_ORDER__+0)) ||\ + defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) +// This macro indicates that integer and floating point endianness is the same +#define BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH +#endif + +// Deprecated symbols markup +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) && defined(_MSC_VER) +#if (_MSC_VER) >= 1400 +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) __declspec(deprecated(msg)) +#else +// MSVC 7.1 only supports the attribute without a message +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) __declspec(deprecated) +#endif +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) && defined(__has_extension) +#if __has_extension(attribute_deprecated_with_message) +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) __attribute__((deprecated(msg))) +#endif +#endif + +// gcc since 4.5 supports deprecated attribute with a message; older versions support the attribute without a message. +// Oracle Studio 12.4 supports deprecated attribute with a message; this is the first release that supports the attribute. +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) && (\ + (defined(__GNUC__) && ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0)) >= 405) ||\ + (defined(__SUNPRO_CC) && (__SUNPRO_CC + 0) >= 0x5130)) +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) __attribute__((deprecated(msg))) +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) && __cplusplus >= 201402 +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) [[deprecated(msg)]] +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) && defined(__GNUC__) +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) __attribute__((deprecated)) +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) && defined(__has_attribute) +#if __has_attribute(deprecated) +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) __attribute__((deprecated)) +#endif +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) +#endif + +// In Boost.Atomic 1.67 we changed (op)_and_test methods to return true when the result is non-zero. This would be more consistent +// with the other names used in Boost.Atomic and the C++ standard library. Since the methods were announced as experimental and +// the previous behavior was released only in Boost 1.66, it was decided to change the result without changing the method names. +// By defining BOOST_ATOMIC_HIGHLIGHT_OP_AND_TEST the user has a way to highlight all uses of the affected functions so +// that it is easier to find and update the affected code (which is typically adding or removing negation of the result). This +// highlighting functionality is a temporary measure to help users upgrade from Boost 1.66 to newer Boost versions. It will +// be removed eventually. +// +// More info at: +// https://github.com/boostorg/atomic/issues/11 +// http://boost.2283326.n4.nabble.com/atomic-op-and-test-naming-tc4701445.html +#if defined(BOOST_ATOMIC_HIGHLIGHT_OP_AND_TEST) +#define BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST BOOST_ATOMIC_DETAIL_DEPRECATED("Boost.Atomic 1.67 has changed (op)_and_test result to the opposite. The functions now return true when the result is non-zero. Please, verify your use of the operation and undefine BOOST_ATOMIC_HIGHLIGHT_OP_AND_TEST.") +#else +#define BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST +#endif + +#endif // BOOST_ATOMIC_DETAIL_CONFIG_HPP_INCLUDED_ diff --git a/boost/atomic/detail/extra_fp_operations.hpp b/boost/atomic/detail/extra_fp_operations.hpp new file mode 100644 index 0000000..854d8c9 --- /dev/null +++ b/boost/atomic/detail/extra_fp_operations.hpp @@ -0,0 +1,28 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_fp_operations.hpp + * + * This header defines extra floating point atomic operations, including the generic version. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_HPP_INCLUDED_ + +#include +#include + +#if !defined(BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND_GENERIC) +#include BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND_HEADER(boost/atomic/detail/extra_fp_ops_) +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_HPP_INCLUDED_ diff --git a/boost/atomic/detail/extra_fp_operations_fwd.hpp b/boost/atomic/detail/extra_fp_operations_fwd.hpp new file mode 100644 index 0000000..79bca9d --- /dev/null +++ b/boost/atomic/detail/extra_fp_operations_fwd.hpp @@ -0,0 +1,35 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_fp_operations_fwd.hpp + * + * This header contains forward declaration of the \c extra_fp_operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_FWD_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_FWD_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base, typename Value, std::size_t Size, bool = Base::is_always_lock_free > +struct extra_fp_operations; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_FWD_HPP_INCLUDED_ diff --git a/boost/atomic/detail/extra_fp_ops_emulated.hpp b/boost/atomic/detail/extra_fp_ops_emulated.hpp new file mode 100644 index 0000000..e04b2f5 --- /dev/null +++ b/boost/atomic/detail/extra_fp_ops_emulated.hpp @@ -0,0 +1,107 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_fp_ops_emulated.hpp + * + * This header contains emulated (lock-based) implementation of the extra floating point atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_EMULATED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_EMULATED_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +//! Generic implementation of extra floating point operations +template< typename Base, typename Value, std::size_t Size > +struct emulated_extra_fp_operations : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef Value value_type; + + static BOOST_FORCEINLINE value_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); + value_type new_val = -old_val; + s = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + return old_val; + } + + static BOOST_FORCEINLINE value_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); + value_type new_val = -old_val; + s = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + return new_val; + } + + static BOOST_FORCEINLINE value_type add(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); + value_type new_val = old_val + v; + s = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + return new_val; + } + + static BOOST_FORCEINLINE value_type sub(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); + value_type new_val = old_val - v; + s = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + return new_val; + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_negate(storage, order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_add(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_sub(storage, v, order); + } +}; + +template< typename Base, typename Value, std::size_t Size > +struct extra_fp_operations< Base, Value, Size, false > : + public emulated_extra_fp_operations< Base, Value, Size > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_EMULATED_HPP_INCLUDED_ diff --git a/boost/atomic/detail/extra_fp_ops_generic.hpp b/boost/atomic/detail/extra_fp_ops_generic.hpp new file mode 100644 index 0000000..34902c4 --- /dev/null +++ b/boost/atomic/detail/extra_fp_ops_generic.hpp @@ -0,0 +1,189 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_fp_ops_generic.hpp + * + * This header contains generic implementation of the extra floating point atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_GENERIC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_GENERIC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_GCC) && (BOOST_GCC+0) >= 60000 +#pragma GCC diagnostic push +// ignoring attributes on template argument X - this warning is because we need to pass storage_type as a template argument; no problem in this case +#pragma GCC diagnostic ignored "-Wignored-attributes" +#endif + +namespace boost { +namespace atomics { +namespace detail { + +//! Negate implementation +template< + typename Base, + typename Value, + std::size_t Size +#if defined(BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH) + , bool = atomics::detail::is_iec559< Value >::value && atomics::detail::is_integral< typename Base::storage_type >::value +#endif +> +struct generic_extra_fp_negate : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef Value value_type; + + static BOOST_FORCEINLINE value_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type old_storage, new_storage; + value_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_storage); + do + { + old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); + new_val = -old_val; + new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + } + while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); + return old_val; + } + + static BOOST_FORCEINLINE value_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type old_storage, new_storage; + value_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_storage); + do + { + old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); + new_val = -old_val; + new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + } + while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_negate(storage, order); + } +}; + +#if defined(BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH) + +//! Negate implementation for IEEE 754 / IEC 559 floating point types. We leverage the fact that the sign bit is the most significant bit in the value. +template< typename Base, typename Value, std::size_t Size > +struct generic_extra_fp_negate< Base, Value, Size, true > : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef Value value_type; + + //! The mask with only one sign bit set to 1 + static BOOST_CONSTEXPR_OR_CONST storage_type sign_mask = static_cast< storage_type >(1u) << (atomics::detail::value_sizeof< value_type >::value * 8u - 1u); + + static BOOST_FORCEINLINE value_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return atomics::detail::bitwise_fp_cast< value_type >(base_type::fetch_xor(storage, sign_mask, order)); + } + + static BOOST_FORCEINLINE value_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return atomics::detail::bitwise_fp_cast< value_type >(base_type::bitwise_xor(storage, sign_mask, order)); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::opaque_xor(storage, sign_mask, order); + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH) + +//! Generic implementation of floating point operations +template< typename Base, typename Value, std::size_t Size > +struct generic_extra_fp_operations : + public generic_extra_fp_negate< Base, Value, Size > +{ + typedef generic_extra_fp_negate< Base, Value, Size > base_type; + typedef typename base_type::storage_type storage_type; + typedef Value value_type; + + static BOOST_FORCEINLINE value_type add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_storage, new_storage; + value_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_storage); + do + { + old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); + new_val = old_val + v; + new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + } + while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE value_type sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_storage, new_storage; + value_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_storage); + do + { + old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); + new_val = old_val - v; + new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + } + while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_add(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_sub(storage, v, order); + } +}; + +// Default extra_fp_operations template definition will be used unless specialized for a specific platform +template< typename Base, typename Value, std::size_t Size > +struct extra_fp_operations< Base, Value, Size, true > : + public generic_extra_fp_operations< Base, Value, Size > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#if defined(BOOST_GCC) && (BOOST_GCC+0) >= 60000 +#pragma GCC diagnostic pop +#endif + +#endif // BOOST_ATOMIC_DETAIL_FP_OPS_GENERIC_HPP_INCLUDED_ diff --git a/boost/atomic/detail/extra_operations.hpp b/boost/atomic/detail/extra_operations.hpp new file mode 100644 index 0000000..c04f55c --- /dev/null +++ b/boost/atomic/detail/extra_operations.hpp @@ -0,0 +1,28 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_operations.hpp + * + * This header defines extra atomic operations, including the generic version. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPERATIONS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPERATIONS_HPP_INCLUDED_ + +#include +#include + +#if !defined(BOOST_ATOMIC_DETAIL_EXTRA_BACKEND_GENERIC) +#include BOOST_ATOMIC_DETAIL_EXTRA_BACKEND_HEADER(boost/atomic/detail/extra_ops_) +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPERATIONS_HPP_INCLUDED_ diff --git a/boost/atomic/detail/extra_operations_fwd.hpp b/boost/atomic/detail/extra_operations_fwd.hpp new file mode 100644 index 0000000..399a823 --- /dev/null +++ b/boost/atomic/detail/extra_operations_fwd.hpp @@ -0,0 +1,35 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_operations_fwd.hpp + * + * This header contains forward declaration of the \c extra_operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPERATIONS_FWD_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPERATIONS_FWD_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base, std::size_t Size, bool Signed, bool = Base::is_always_lock_free > +struct extra_operations; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPERATIONS_FWD_HPP_INCLUDED_ diff --git a/boost/atomic/detail/extra_ops_emulated.hpp b/boost/atomic/detail/extra_ops_emulated.hpp new file mode 100644 index 0000000..c0e4832 --- /dev/null +++ b/boost/atomic/detail/extra_ops_emulated.hpp @@ -0,0 +1,238 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_emulated.hpp + * + * This header contains emulated (lock-based) implementation of the extra atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_EMULATED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_EMULATED_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// unary minus operator applied to unsigned type, result still unsigned +#pragma warning(disable: 4146) +#endif + +namespace boost { +namespace atomics { +namespace detail { + +//! Generic implementation of extra operations +template< typename Base, std::size_t Size, bool Signed > +struct emulated_extra_operations : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s = static_cast< storage_type >(-old_val); + return old_val; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = static_cast< storage_type >(-s); + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = s; + new_val += v; + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = s; + new_val -= v; + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = s; + new_val &= v; + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = s; + new_val |= v; + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = s; + new_val ^= v; + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s = static_cast< storage_type >(~old_val); + return old_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = static_cast< storage_type >(~s); + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + Base::fetch_add(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + Base::fetch_sub(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_negate(storage, order); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + Base::fetch_and(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + Base::fetch_or(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + Base::fetch_xor(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_complement(storage, order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!add(storage, v, order); + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!sub(storage, v, order); + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_and(storage, v, order); + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_or(storage, v, order); + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_xor(storage, v, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_complement(storage, order); + } + + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + storage_type mask = static_cast< storage_type >(static_cast< storage_type >(1u) << bit_number); + storage_type old_val = Base::fetch_or(storage, mask, order); + return !!(old_val & mask); + } + + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + storage_type mask = static_cast< storage_type >(static_cast< storage_type >(1u) << bit_number); + storage_type old_val = Base::fetch_and(storage, ~mask, order); + return !!(old_val & mask); + } + + static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + storage_type mask = static_cast< storage_type >(static_cast< storage_type >(1u) << bit_number); + storage_type old_val = Base::fetch_xor(storage, mask, order); + return !!(old_val & mask); + } +}; + +template< typename Base, std::size_t Size, bool Signed > +struct extra_operations< Base, Size, Signed, false > : + public emulated_extra_operations< Base, Size, Signed > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_EMULATED_HPP_INCLUDED_ diff --git a/boost/atomic/detail/extra_ops_gcc_arm.hpp b/boost/atomic/detail/extra_ops_gcc_arm.hpp new file mode 100644 index 0000000..e84f177 --- /dev/null +++ b/boost/atomic/detail/extra_ops_gcc_arm.hpp @@ -0,0 +1,1111 @@ +/* + * 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) + * + * Copyright (c) 2017 - 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_gcc_arm.hpp + * + * This header contains implementation of the extra atomic operations for ARM. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_ARM_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base > +struct gcc_arm_extra_operations_common : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_negate(storage, order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_complement(storage, order); + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::negate(storage, order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::add(storage, v, order); + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::sub(storage, v, order); + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_and(storage, v, order); + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_or(storage, v, order); + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_xor(storage, v, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_complement(storage, order); + } +}; + +template< typename Base, std::size_t Size, bool Signed > +struct gcc_arm_extra_operations; + +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) + +template< typename Base, bool Signed > +struct gcc_arm_extra_operations< Base, 1u, Signed > : + public generic_extra_operations< Base, 1u, Signed > +{ + typedef generic_extra_operations< Base, 1u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 4u >::type extended_storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "rsb %[result], %[original], #0\n" // result = 0 - original + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "rsb %[result], %[original], #0\n" // result = 0 - original + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "add %[result], %[original], %[value]\n" // result = original + value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "sub %[result], %[original], %[value]\n" // result = original - value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "and %[result], %[original], %[value]\n" // result = original & value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "orr %[result], %[original], %[value]\n" // result = original | value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "eor %[result], %[original], %[value]\n" // result = original ^ value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "mvn %[result], %[original]\n" // result = NOT original + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "mvn %[result], %[original]\n" // result = NOT original + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 1u, Signed, true > : + public gcc_arm_extra_operations_common< gcc_arm_extra_operations< Base, 1u, Signed > > +{ +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) + +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) + +template< typename Base, bool Signed > +struct gcc_arm_extra_operations< Base, 2u, Signed > : + public generic_extra_operations< Base, 2u, Signed > +{ + typedef generic_extra_operations< Base, 2u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 4u >::type extended_storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "rsb %[result], %[original], #0\n" // result = 0 - original + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "rsb %[result], %[original], #0\n" // result = 0 - original + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "add %[result], %[original], %[value]\n" // result = original + value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "sub %[result], %[original], %[value]\n" // result = original - value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "and %[result], %[original], %[value]\n" // result = original & value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "orr %[result], %[original], %[value]\n" // result = original | value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "eor %[result], %[original], %[value]\n" // result = original ^ value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "mvn %[result], %[original]\n" // result = NOT original + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "mvn %[result], %[original]\n" // result = NOT original + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 2u, Signed, true > : + public gcc_arm_extra_operations_common< gcc_arm_extra_operations< Base, 2u, Signed > > +{ +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) + +template< typename Base, bool Signed > +struct gcc_arm_extra_operations< Base, 4u, Signed > : + public generic_extra_operations< Base, 4u, Signed > +{ + typedef generic_extra_operations< Base, 4u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "rsb %[result], %[original], #0\n" // result = 0 - original + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "rsb %[result], %[original], #0\n" // result = 0 - original + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "add %[result], %[original], %[value]\n" // result = original + value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "sub %[result], %[original], %[value]\n" // result = original - value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "and %[result], %[original], %[value]\n" // result = original & value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "orr %[result], %[original], %[value]\n" // result = original | value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "eor %[result], %[original], %[value]\n" // result = original ^ value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "mvn %[result], %[original]\n" // result = NOT original + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "mvn %[result], %[original]\n" // result = NOT original + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 4u, Signed, true > : + public gcc_arm_extra_operations_common< gcc_arm_extra_operations< Base, 4u, Signed > > +{ +}; + +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD) + +template< typename Base, bool Signed > +struct gcc_arm_extra_operations< Base, 8u, Signed > : + public generic_extra_operations< Base, 8u, Signed > +{ + typedef generic_extra_operations< Base, 8u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "mvn %2, %1\n" // result = NOT original + "mvn %H2, %H1\n" + "adds %2, %2, #1\n" // result = result + 1 + "adc %H2, %H2, #0\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "mvn %2, %1\n" // result = NOT original + "mvn %H2, %H1\n" + "adds %2, %2, #1\n" // result = result + 1 + "adc %H2, %H2, #0\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "adds %2, %1, %4\n" // result = original + value + "adc %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "subs %2, %1, %4\n" // result = original - value + "sbc %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "and %2, %1, %4\n" // result = original & value + "and %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "orr %2, %1, %4\n" // result = original | value + "orr %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "eor %2, %1, %4\n" // result = original ^ value + "eor %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "mvn %2, %1\n" // result = NOT original + "mvn %H2, %H1\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "mvn %2, %1\n" // result = NOT original + "mvn %H2, %H1\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 8u, Signed, true > : + public gcc_arm_extra_operations_common< gcc_arm_extra_operations< Base, 8u, Signed > > +{ +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_ARM_HPP_INCLUDED_ diff --git a/boost/atomic/detail/extra_ops_gcc_ppc.hpp b/boost/atomic/detail/extra_ops_gcc_ppc.hpp new file mode 100644 index 0000000..dc4bbdb --- /dev/null +++ b/boost/atomic/detail/extra_ops_gcc_ppc.hpp @@ -0,0 +1,840 @@ +/* + * 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) + * + * Copyright (c) 2017 - 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_gcc_ppc.hpp + * + * This header contains implementation of the extra atomic operations for PowerPC. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_PPC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_PPC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base > +struct gcc_ppc_extra_operations_common : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_negate(storage, order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_complement(storage, order); + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::negate(storage, order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::add(storage, v, order); + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::sub(storage, v, order); + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_and(storage, v, order); + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_or(storage, v, order); + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_xor(storage, v, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_complement(storage, order); + } +}; + +template< typename Base, std::size_t Size, bool Signed > +struct gcc_ppc_extra_operations; + +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX) + +template< typename Base, bool Signed > +struct gcc_ppc_extra_operations< Base, 1u, Signed > : + public generic_extra_operations< Base, 1u, Signed > +{ + typedef generic_extra_operations< Base, 1u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "neg %1,%0\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "neg %1,%0\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 1u, Signed, true > : + public gcc_ppc_extra_operations_common< gcc_ppc_extra_operations< Base, 1u, Signed > > +{ +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX) + +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX) + +template< typename Base, bool Signed > +struct gcc_ppc_extra_operations< Base, 2u, Signed > : + public generic_extra_operations< Base, 2u, Signed > +{ + typedef generic_extra_operations< Base, 2u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "neg %1,%0\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "neg %1,%0\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX) + +template< typename Base, bool Signed > +struct gcc_ppc_extra_operations< Base, 4u, Signed > : + public generic_extra_operations< Base, 4u, Signed > +{ + typedef generic_extra_operations< Base, 4u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "neg %1,%0\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "neg %1,%0\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 4u, Signed, true > : + public gcc_ppc_extra_operations_common< gcc_ppc_extra_operations< Base, 4u, Signed > > +{ +}; + +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX) + +template< typename Base, bool Signed > +struct gcc_ppc_extra_operations< Base, 8u, Signed > : + public generic_extra_operations< Base, 8u, Signed > +{ + typedef generic_extra_operations< Base, 8u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "neg %1,%0\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "neg %1,%0\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 8u, Signed, true > : + public gcc_ppc_extra_operations_common< gcc_ppc_extra_operations< Base, 8u, Signed > > +{ +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_ARM_PPC_INCLUDED_ diff --git a/boost/atomic/detail/extra_ops_gcc_x86.hpp b/boost/atomic/detail/extra_ops_gcc_x86.hpp new file mode 100644 index 0000000..ee2cd02 --- /dev/null +++ b/boost/atomic/detail/extra_ops_gcc_x86.hpp @@ -0,0 +1,1656 @@ +/* + * 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) + * + * Copyright (c) 2015 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_gcc_x86.hpp + * + * This header contains implementation of the extra atomic operations for x86. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_X86_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base > +struct gcc_x86_extra_operations_common : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(Base::fetch_add(storage, v, order) + v); + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(Base::fetch_sub(storage, v, order) - v); + } + + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; bts %[bit_number], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccc" (res) + : [bit_number] "Kq" (bit_number) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; bts %[bit_number], %[storage]\n\t" + "setc %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [bit_number] "Kq" (bit_number) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; btr %[bit_number], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccc" (res) + : [bit_number] "Kq" (bit_number) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; btr %[bit_number], %[storage]\n\t" + "setc %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [bit_number] "Kq" (bit_number) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; btc %[bit_number], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccc" (res) + : [bit_number] "Kq" (bit_number) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; btc %[bit_number], %[storage]\n\t" + "setc %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [bit_number] "Kq" (bit_number) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 1u, Signed, true > : + public gcc_x86_extra_operations_common< Base > +{ + typedef gcc_x86_extra_operations_common< Base > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 4u >::type temp_storage_type; + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: movzbl %[orig], %2\n\t"\ + op " %b2\n\t"\ + "lock; cmpxchgb %b2, %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), "=&q" (result)\ + : \ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negb", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notb", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negb", original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notb", original, result); + return static_cast< storage_type >(result); + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %2\n\t"\ + op " %%al, %b2\n\t"\ + "lock; cmpxchgb %b2, %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), "=&q" (result)\ + : [arg] "ir" ((temp_storage_type)argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andb", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orb", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorb", v, original, result); + return static_cast< storage_type >(result); + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_complement(storage, order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incb %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addb %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decb %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subb %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; negb %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; andb %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; orb %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xorb %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; notb %[storage]\n\t" + : [storage] "+m" (storage) + : + : "memory" + ); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incb %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addb %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incb %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addb %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decb %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subb %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decb %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subb %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; andb %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; andb %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; orb %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; orb %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; xorb %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; xorb %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 2u, Signed, true > : + public gcc_x86_extra_operations_common< Base > +{ + typedef gcc_x86_extra_operations_common< Base > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 4u >::type temp_storage_type; + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: movzwl %[orig], %2\n\t"\ + op " %w2\n\t"\ + "lock; cmpxchgw %w2, %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), "=&q" (result)\ + : \ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negw", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notw", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negw", original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notw", original, result); + return static_cast< storage_type >(result); + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %2\n\t"\ + op " %%ax, %w2\n\t"\ + "lock; cmpxchgw %w2, %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), "=&q" (result)\ + : [arg] "ir" ((temp_storage_type)argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andw", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orw", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorw", v, original, result); + return static_cast< storage_type >(result); + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_complement(storage, order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incw %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addw %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decw %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subw %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; negw %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; andw %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; orw %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xorw %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; notw %[storage]\n\t" + : [storage] "+m" (storage) + : + : "memory" + ); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incw %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addw %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incw %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addw %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decw %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subw %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decw %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subw %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; andw %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; andw %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; orw %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; orw %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; xorw %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; xorw %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 4u, Signed, true > : + public gcc_x86_extra_operations_common< Base > +{ + typedef gcc_x86_extra_operations_common< Base > base_type; + typedef typename base_type::storage_type storage_type; + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[orig], %[res]\n\t"\ + op " %[res]\n\t"\ + "lock; cmpxchgl %[res], %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), [res] "=&r" (result)\ + : \ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negl", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notl", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negl", original, result); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notl", original, result); + return result; + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %[res]\n\t"\ + op " %%eax, %[res]\n\t"\ + "lock; cmpxchgl %[res], %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), [res] "=&r" (result)\ + : [arg] "ir" (argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andl", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orl", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorl", v, original, result); + return static_cast< storage_type >(result); + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_complement(storage, order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incl %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addl %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decl %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subl %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; negl %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; andl %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; orl %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xorl %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; notl %[storage]\n\t" + : [storage] "+m" (storage) + : + : "memory" + ); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incl %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addl %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "ir" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incl %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addl %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decl %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subl %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "ir" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decl %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subl %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; andl %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "ir" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; andl %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; orl %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "ir" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; orl %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; xorl %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "ir" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; xorl %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } +}; + +#if defined(__x86_64__) + +template< typename Base, bool Signed > +struct extra_operations< Base, 8u, Signed, true > : + public gcc_x86_extra_operations_common< Base > +{ + typedef gcc_x86_extra_operations_common< Base > base_type; + typedef typename base_type::storage_type storage_type; + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[orig], %[res]\n\t"\ + op " %[res]\n\t"\ + "lock; cmpxchgq %[res], %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), [res] "=&r" (result)\ + : \ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negq", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notq", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negq", original, result); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notq", original, result); + return result; + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %[res]\n\t"\ + op " %%rax, %[res]\n\t"\ + "lock; cmpxchgq %[res], %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), [res] "=&r" (result)\ + : [arg] "r" (argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andq", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orq", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorq", v, original, result); + return static_cast< storage_type >(result); + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_complement(storage, order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incq %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addq %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decq %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subq %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; negq %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; andq %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; orq %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xorq %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; notq %[storage]\n\t" + : [storage] "+m" (storage) + : + : "memory" + ); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incq %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addq %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "er" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incq %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addq %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decq %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subq %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "er" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decq %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subq %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; andq %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "er" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; andq %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; orq %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "er" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; orq %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; xorq %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "er" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; xorq %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } +}; + +#endif // defined(__x86_64__) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_X86_HPP_INCLUDED_ diff --git a/boost/atomic/detail/extra_ops_generic.hpp b/boost/atomic/detail/extra_ops_generic.hpp new file mode 100644 index 0000000..4384262 --- /dev/null +++ b/boost/atomic/detail/extra_ops_generic.hpp @@ -0,0 +1,402 @@ +/* + * 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) + * + * Copyright (c) 2015 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_generic.hpp + * + * This header contains generic implementation of the extra atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_GENERIC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_GENERIC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// unary minus operator applied to unsigned type, result still unsigned +#pragma warning(disable: 4146) +#endif + +namespace boost { +namespace atomics { +namespace detail { + +//! Generic implementation of extra operations +template< typename Base, std::size_t Size, bool Signed, bool = Base::full_cas_based > +struct generic_extra_operations : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< Size >::type emulated_storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!base_type::compare_exchange_weak(storage, old_val, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val)), order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_add(storage, v, order) + v; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_sub(storage, v, order) - v; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_and(storage, v, order) & v; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_or(storage, v, order) | v; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_xor(storage, v, order) ^ v; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_xor(storage, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u))), order); + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u))); + return base_type::fetch_xor(storage, mask, order) ^ mask; + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_add(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_sub(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_negate(storage, order); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_and(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_or(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_xor(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_complement(storage, order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!static_cast< emulated_storage_type >(add(storage, v, order)); + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!static_cast< emulated_storage_type >(sub(storage, v, order)); + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_and(storage, v, order); + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_or(storage, v, order); + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_xor(storage, v, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!static_cast< emulated_storage_type >(bitwise_complement(storage, order)); + } + + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number)); + storage_type old_val = base_type::fetch_or(storage, mask, order); + return !!(old_val & mask); + } + + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number)); + storage_type old_val = base_type::fetch_and(storage, ~mask, order); + return !!(old_val & mask); + } + + static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number)); + storage_type old_val = base_type::fetch_xor(storage, mask, order); + return !!(old_val & mask); + } +}; + +//! Specialization for cases when the platform only natively supports CAS +template< typename Base, std::size_t Size, bool Signed > +struct generic_extra_operations< Base, Size, Signed, true > : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< Size >::type emulated_storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!base_type::compare_exchange_weak(storage, old_val, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val)), order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val + v)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val - v)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val & v)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val | v)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val ^ v)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_xor(storage, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u))), order); + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return bitwise_xor(storage, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u))), order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_add(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_sub(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_negate(storage, order); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_and(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_or(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_xor(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_complement(storage, order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!static_cast< emulated_storage_type >(add(storage, v, order)); + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!static_cast< emulated_storage_type >(sub(storage, v, order)); + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_and(storage, v, order); + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_or(storage, v, order); + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_xor(storage, v, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!static_cast< emulated_storage_type >(bitwise_complement(storage, order)); + } + + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number)); + storage_type old_val = base_type::fetch_or(storage, mask, order); + return !!(old_val & mask); + } + + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number)); + storage_type old_val = base_type::fetch_and(storage, ~mask, order); + return !!(old_val & mask); + } + + static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number)); + storage_type old_val = base_type::fetch_xor(storage, mask, order); + return !!(old_val & mask); + } +}; + +// Default extra_operations template definition will be used unless specialized for a specific platform +template< typename Base, std::size_t Size, bool Signed > +struct extra_operations< Base, Size, Signed, true > : + public generic_extra_operations< Base, Size, Signed > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_GENERIC_HPP_INCLUDED_ diff --git a/boost/atomic/detail/extra_ops_msvc_arm.hpp b/boost/atomic/detail/extra_ops_msvc_arm.hpp new file mode 100644 index 0000000..b8eb5bc --- /dev/null +++ b/boost/atomic/detail/extra_ops_msvc_arm.hpp @@ -0,0 +1,106 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_msvc_arm.hpp + * + * This header contains implementation of the extra atomic operations for ARM. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_MSVC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_MSVC_ARM_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if defined(BOOST_ATOMIC_INTERLOCKED_BTS) && defined(BOOST_ATOMIC_INTERLOCKED_BTR) + +template< typename Base, std::size_t Size, bool Signed > +struct extra_operations< Base, 4u, Signed, true > : + public generic_extra_operations< Base, 4u, Signed > +{ + typedef generic_extra_operations< Base, 4u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_INTERLOCKED_BTS_RELAXED) && defined(BOOST_ATOMIC_INTERLOCKED_BTS_ACQUIRE) && defined(BOOST_ATOMIC_INTERLOCKED_BTS_RELEASE) + bool result; + switch (order) + { + case memory_order_relaxed: + result = !!BOOST_ATOMIC_INTERLOCKED_BTS_RELAXED(&storage, bit_number); + break; + case memory_order_consume: + case memory_order_acquire: + result = !!BOOST_ATOMIC_INTERLOCKED_BTS_ACQUIRE(&storage, bit_number); + break; + case memory_order_release: + result = !!BOOST_ATOMIC_INTERLOCKED_BTS_RELEASE(&storage, bit_number); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + result = !!BOOST_ATOMIC_INTERLOCKED_BTS(&storage, bit_number); + break; + } + return result; +#else + return !!BOOST_ATOMIC_INTERLOCKED_BTS(&storage, bit_number); +#endif + } + + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_INTERLOCKED_BTR_RELAXED) && defined(BOOST_ATOMIC_INTERLOCKED_BTR_ACQUIRE) && defined(BOOST_ATOMIC_INTERLOCKED_BTR_RELEASE) + bool result; + switch (order) + { + case memory_order_relaxed: + result = !!BOOST_ATOMIC_INTERLOCKED_BTR_RELAXED(&storage, bit_number); + break; + case memory_order_consume: + case memory_order_acquire: + result = !!BOOST_ATOMIC_INTERLOCKED_BTR_ACQUIRE(&storage, bit_number); + break; + case memory_order_release: + result = !!BOOST_ATOMIC_INTERLOCKED_BTR_RELEASE(&storage, bit_number); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + result = !!BOOST_ATOMIC_INTERLOCKED_BTR(&storage, bit_number); + break; + } + return result; +#else + return !!BOOST_ATOMIC_INTERLOCKED_BTR(&storage, bit_number); +#endif + } +}; + +#endif // defined(BOOST_ATOMIC_INTERLOCKED_BTS) && defined(BOOST_ATOMIC_INTERLOCKED_BTR) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_MSVC_ARM_HPP_INCLUDED_ diff --git a/boost/atomic/detail/extra_ops_msvc_x86.hpp b/boost/atomic/detail/extra_ops_msvc_x86.hpp new file mode 100644 index 0000000..17451a8 --- /dev/null +++ b/boost/atomic/detail/extra_ops_msvc_x86.hpp @@ -0,0 +1,1301 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_msvc_x86.hpp + * + * This header contains implementation of the extra atomic operations for x86. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_MSVC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_MSVC_X86_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// frame pointer register 'ebx' modified by inline assembly code +#pragma warning(disable: 4731) +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if defined(_M_IX86) || (defined(BOOST_ATOMIC_INTERLOCKED_BTS) && defined(BOOST_ATOMIC_INTERLOCKED_BTR)) + +template< typename Base, std::size_t Size, bool Signed > +struct msvc_x86_extra_operations_common : + public generic_extra_operations< Base, Size, Signed > +{ + typedef generic_extra_operations< Base, Size, Signed > base_type; + typedef typename base_type::storage_type storage_type; + +#if defined(BOOST_ATOMIC_INTERLOCKED_BTS) + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order) BOOST_NOEXCEPT + { + return !!BOOST_ATOMIC_INTERLOCKED_BTS(&storage, bit_number); + } +#else + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, bit_number + lock bts [edx], eax + setc result + }; + base_type::fence_after(order); + return result; + } +#endif + +#if defined(BOOST_ATOMIC_INTERLOCKED_BTR) + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order) BOOST_NOEXCEPT + { + return !!BOOST_ATOMIC_INTERLOCKED_BTR(&storage, bit_number); + } +#else + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, bit_number + lock btr [edx], eax + setc result + }; + base_type::fence_after(order); + return result; + } +#endif + +#if defined(_M_IX86) + static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, bit_number + lock btc [edx], eax + setc result + }; + base_type::fence_after(order); + return result; + } +#endif +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 1u, Signed, true > : + public msvc_x86_extra_operations_common< Base, 1u, Signed > +{ + typedef msvc_x86_extra_operations_common< Base, 1u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + +#if defined(_M_IX86) + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type old_val; + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + neg dl + lock cmpxchg byte ptr [ecx], dl + jne again + mov old_val, al + }; + base_type::fence_after(order); + return old_val; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type new_val; + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + neg dl + lock cmpxchg byte ptr [ecx], dl + jne again + mov new_val, dl + }; + base_type::fence_after(order); + return new_val; + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + neg dl + lock cmpxchg byte ptr [ecx], dl + jne again + test dl, dl + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + neg dl + lock cmpxchg byte ptr [ecx], dl + jne again + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, byte ptr [edi] + align 16 + again: + mov dl, al + and dl, cl + lock cmpxchg byte ptr [edi], dl + jne again + mov v, dl + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, byte ptr [edi] + align 16 + again: + mov dl, al + or dl, cl + lock cmpxchg byte ptr [edi], dl + jne again + mov v, dl + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, byte ptr [edi] + align 16 + again: + mov dl, al + xor dl, cl + lock cmpxchg byte ptr [edi], dl + jne again + mov v, dl + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type old_val; + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + not dl + lock cmpxchg byte ptr [ecx], dl + jne again + mov old_val, al + }; + base_type::fence_after(order); + return old_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type new_val; + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + not dl + lock cmpxchg byte ptr [ecx], dl + jne again + mov new_val, dl + }; + base_type::fence_after(order); + return new_val; + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + not dl + lock cmpxchg byte ptr [ecx], dl + jne again + test dl, dl + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + not dl + lock cmpxchg byte ptr [ecx], dl + jne again + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock add byte ptr [edx], al + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock sub byte ptr [edx], al + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + lock neg byte ptr [edx] + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock and byte ptr [edx], al + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock or byte ptr [edx], al + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock xor byte ptr [edx], al + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + lock not byte ptr [edx] + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock add byte ptr [edx], al + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock sub byte ptr [edx], al + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock and byte ptr [edx], al + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock or byte ptr [edx], al + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock xor byte ptr [edx], al + setnz result + }; + base_type::fence_after(order); + return result; + } +#endif // defined(_M_IX86) +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 2u, Signed, true > : + public msvc_x86_extra_operations_common< Base, 2u, Signed > +{ + typedef msvc_x86_extra_operations_common< Base, 2u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + +#if defined(_M_IX86) + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type old_val; + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + neg dx + lock cmpxchg word ptr [ecx], dx + jne again + mov old_val, ax + }; + base_type::fence_after(order); + return old_val; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type new_val; + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + neg dx + lock cmpxchg word ptr [ecx], dx + jne again + mov new_val, dx + }; + base_type::fence_after(order); + return new_val; + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + neg dx + lock cmpxchg word ptr [ecx], dx + jne again + test dx, dx + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + neg dx + lock cmpxchg word ptr [ecx], dx + jne again + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, word ptr [edi] + align 16 + again: + mov dx, ax + and dx, cx + lock cmpxchg word ptr [edi], dx + jne again + mov v, dx + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, word ptr [edi] + align 16 + again: + mov dx, ax + or dx, cx + lock cmpxchg word ptr [edi], dx + jne again + mov v, dx + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, word ptr [edi] + align 16 + again: + mov dx, ax + xor dx, cx + lock cmpxchg word ptr [edi], dx + jne again + mov v, dx + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type old_val; + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + not dx + lock cmpxchg word ptr [ecx], dx + jne again + mov old_val, ax + }; + base_type::fence_after(order); + return old_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type new_val; + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + not dx + lock cmpxchg word ptr [ecx], dx + jne again + mov new_val, dx + }; + base_type::fence_after(order); + return new_val; + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + not dx + lock cmpxchg word ptr [ecx], dx + jne again + test dx, dx + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + not dx + lock cmpxchg word ptr [ecx], dx + jne again + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock add word ptr [edx], ax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock sub word ptr [edx], ax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + lock neg word ptr [edx] + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock and word ptr [edx], ax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock or word ptr [edx], ax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock xor word ptr [edx], ax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + lock not word ptr [edx] + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock add word ptr [edx], ax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock sub word ptr [edx], ax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock and word ptr [edx], ax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock or word ptr [edx], ax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock xor word ptr [edx], ax + setnz result + }; + base_type::fence_after(order); + return result; + } +#endif // defined(_M_IX86) +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 4u, Signed, true > : + public msvc_x86_extra_operations_common< Base, 4u, Signed > +{ + typedef msvc_x86_extra_operations_common< Base, 4u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + +#if defined(_M_IX86) + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type old_val; + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + neg edx + lock cmpxchg dword ptr [ecx], edx + jne again + mov old_val, eax + }; + base_type::fence_after(order); + return old_val; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type new_val; + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + neg edx + lock cmpxchg dword ptr [ecx], edx + jne again + mov new_val, edx + }; + base_type::fence_after(order); + return new_val; + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + neg edx + lock cmpxchg dword ptr [ecx], edx + jne again + test edx, edx + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + neg edx + lock cmpxchg dword ptr [ecx], edx + jne again + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + mov ecx, v + xor edx, edx + mov eax, dword ptr [edi] + align 16 + again: + mov edx, eax + and edx, ecx + lock cmpxchg dword ptr [edi], edx + jne again + mov v, edx + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + mov ecx, v + xor edx, edx + mov eax, dword ptr [edi] + align 16 + again: + mov edx, eax + or edx, ecx + lock cmpxchg dword ptr [edi], edx + jne again + mov v, edx + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + mov ecx, v + xor edx, edx + mov eax, dword ptr [edi] + align 16 + again: + mov edx, eax + xor edx, ecx + lock cmpxchg dword ptr [edi], edx + jne again + mov v, edx + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type old_val; + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + not edx + lock cmpxchg dword ptr [ecx], edx + jne again + mov old_val, eax + }; + base_type::fence_after(order); + return old_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type new_val; + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + not edx + lock cmpxchg dword ptr [ecx], edx + jne again + mov new_val, edx + }; + base_type::fence_after(order); + return new_val; + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + not edx + lock cmpxchg dword ptr [ecx], edx + jne again + test edx, edx + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + not edx + lock cmpxchg dword ptr [ecx], edx + jne again + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + mov eax, v + lock add dword ptr [edx], eax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + mov eax, v + lock sub dword ptr [edx], eax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + lock neg dword ptr [edx] + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + mov eax, v + lock and dword ptr [edx], eax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + mov eax, v + lock or dword ptr [edx], eax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + mov eax, v + lock xor dword ptr [edx], eax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + lock not dword ptr [edx] + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, v + lock add dword ptr [edx], eax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, v + lock sub dword ptr [edx], eax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, v + lock and dword ptr [edx], eax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, v + lock or dword ptr [edx], eax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, v + lock xor dword ptr [edx], eax + setnz result + }; + base_type::fence_after(order); + return result; + } +#endif // defined(_M_IX86) +}; + +#endif // defined(_M_IX86) || (defined(BOOST_ATOMIC_INTERLOCKED_BTS) && defined(BOOST_ATOMIC_INTERLOCKED_BTR)) + +#if defined(BOOST_ATOMIC_INTERLOCKED_BTS64) && defined(BOOST_ATOMIC_INTERLOCKED_BTR64) + +template< typename Base, bool Signed > +struct extra_operations< Base, 8u, Signed, true > : + public generic_extra_operations< Base, 8u, Signed > +{ + typedef generic_extra_operations< Base, 8u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + return !!BOOST_ATOMIC_INTERLOCKED_BTS64(&storage, bit_number); + } + + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + return !!BOOST_ATOMIC_INTERLOCKED_BTR64(&storage, bit_number); + } +}; + +#endif // defined(BOOST_ATOMIC_INTERLOCKED_BTS64) && defined(BOOST_ATOMIC_INTERLOCKED_BTR64) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_MSVC_X86_HPP_INCLUDED_ diff --git a/boost/atomic/detail/float_sizes.hpp b/boost/atomic/detail/float_sizes.hpp new file mode 100644 index 0000000..4c3a346 --- /dev/null +++ b/boost/atomic/detail/float_sizes.hpp @@ -0,0 +1,142 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/float_sizes.hpp + * + * This header defines macros for testing buitin floating point type sizes + */ + +#ifndef BOOST_ATOMIC_DETAIL_FLOAT_SIZES_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_FLOAT_SIZES_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// Detect value sizes of the different floating point types. The value sizes may be less than the corresponding type sizes +// if the type contains padding bits. This is typical e.g. with 80-bit extended float types, which are often represented as 128-bit types. +// See: https://en.wikipedia.org/wiki/IEEE_754 +// For Intel x87 extended double see: https://en.wikipedia.org/wiki/Extended_precision#x86_Architecture_Extended_Precision_Format +// For IBM extended double (a.k.a. double-double) see: https://en.wikipedia.org/wiki/Long_double#Implementations, https://gcc.gnu.org/wiki/Ieee128PowerPC +#if (FLT_RADIX+0) == 2 + +#if ((FLT_MANT_DIG+0) == 11) && ((FLT_MAX_EXP+0) == 16) // IEEE 754 binary16 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 2 +#elif ((FLT_MANT_DIG+0) == 24) && ((FLT_MAX_EXP+0) == 128) // IEEE 754 binary32 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 4 +#elif ((FLT_MANT_DIG+0) == 53) && ((FLT_MAX_EXP+0) == 1024) // IEEE 754 binary64 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 8 +#elif ((FLT_MANT_DIG+0) == 64) && ((FLT_MAX_EXP+0) == 16384) // x87 extended double +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 10 +#elif ((FLT_MANT_DIG+0) == 106) && ((FLT_MAX_EXP+0) == 1024) // IBM extended double +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 16 +#elif ((FLT_MANT_DIG+0) == 113) && ((FLT_MAX_EXP+0) == 16384) // IEEE 754 binary128 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 16 +#elif ((FLT_MANT_DIG+0) == 237) && ((FLT_MAX_EXP+0) == 262144) // IEEE 754 binary256 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 32 +#endif + +#if ((DBL_MANT_DIG+0) == 11) && ((DBL_MAX_EXP+0) == 16) // IEEE 754 binary16 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 2 +#elif ((DBL_MANT_DIG+0) == 24) && ((DBL_MAX_EXP+0) == 128) // IEEE 754 binary32 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 4 +#elif ((DBL_MANT_DIG+0) == 53) && ((DBL_MAX_EXP+0) == 1024) // IEEE 754 binary64 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 8 +#elif ((DBL_MANT_DIG+0) == 64) && ((DBL_MAX_EXP+0) == 16384) // x87 extended double +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 10 +#elif ((DBL_MANT_DIG+0) == 106) && ((DBL_MAX_EXP+0) == 1024) // IBM extended double +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 16 +#elif ((DBL_MANT_DIG+0) == 113) && ((DBL_MAX_EXP+0) == 16384) // IEEE 754 binary128 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 16 +#elif ((DBL_MANT_DIG+0) == 237) && ((DBL_MAX_EXP+0) == 262144) // IEEE 754 binary256 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 32 +#endif + +#if ((LDBL_MANT_DIG+0) == 11) && ((LDBL_MAX_EXP+0) == 16) // IEEE 754 binary16 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 2 +#elif ((LDBL_MANT_DIG+0) == 24) && ((LDBL_MAX_EXP+0) == 128) // IEEE 754 binary32 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 4 +#elif ((LDBL_MANT_DIG+0) == 53) && ((LDBL_MAX_EXP+0) == 1024) // IEEE 754 binary64 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 8 +#elif ((LDBL_MANT_DIG+0) == 64) && ((LDBL_MAX_EXP+0) == 16384) // x87 extended double +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 10 +#elif ((LDBL_MANT_DIG+0) == 106) && ((LDBL_MAX_EXP+0) == 1024) // IBM extended double +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 16 +#elif ((LDBL_MANT_DIG+0) == 113) && ((LDBL_MAX_EXP+0) == 16384) // IEEE 754 binary128 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 16 +#elif ((LDBL_MANT_DIG+0) == 237) && ((LDBL_MAX_EXP+0) == 262144) // IEEE 754 binary256 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 32 +#endif + +#elif (FLT_RADIX+0) == 10 + +#if ((FLT_MANT_DIG+0) == 7) && ((FLT_MAX_EXP+0) == 97) // IEEE 754 decimal32 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 4 +#elif ((FLT_MANT_DIG+0) == 16) && ((FLT_MAX_EXP+0) == 385) // IEEE 754 decimal64 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 8 +#elif ((FLT_MANT_DIG+0) == 34) && ((FLT_MAX_EXP+0) == 6145) // IEEE 754 decimal128 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 16 +#endif + +#if ((DBL_MANT_DIG+0) == 7) && ((DBL_MAX_EXP+0) == 97) // IEEE 754 decimal32 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 4 +#elif ((DBL_MANT_DIG+0) == 16) && ((DBL_MAX_EXP+0) == 385) // IEEE 754 decimal64 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 8 +#elif ((DBL_MANT_DIG+0) == 34) && ((DBL_MAX_EXP+0) == 6145) // IEEE 754 decimal128 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 16 +#endif + +#if ((LDBL_MANT_DIG+0) == 7) && ((LDBL_MAX_EXP+0) == 97) // IEEE 754 decimal32 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 4 +#elif ((LDBL_MANT_DIG+0) == 16) && ((LDBL_MAX_EXP+0) == 385) // IEEE 754 decimal64 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 8 +#elif ((LDBL_MANT_DIG+0) == 34) && ((LDBL_MAX_EXP+0) == 6145) // IEEE 754 decimal128 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 16 +#endif + +#endif + +// GCC and compatible compilers define internal macros with builtin type traits +#if defined(__SIZEOF_FLOAT__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT __SIZEOF_FLOAT__ +#endif +#if defined(__SIZEOF_DOUBLE__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE __SIZEOF_DOUBLE__ +#endif +#if defined(__SIZEOF_LONG_DOUBLE__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE __SIZEOF_LONG_DOUBLE__ +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE) + +#define BOOST_ATOMIC_DETAIL_ALIGN_SIZE_TO_POWER_OF_2(x)\ + ((x) == 1u ? 1u : ((x) == 2u ? 2u : ((x) <= 4u ? 4u : ((x) <= 8u ? 8u : ((x) <= 16u ? 16u : ((x) <= 32u ? 32u : (x))))))) + +// Make our best guess. These sizes may not be accurate, but they are good enough to estimate the size of the storage required to hold these types. +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE) +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT BOOST_ATOMIC_DETAIL_ALIGN_SIZE_TO_POWER_OF_2(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE) +#endif +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE) +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE BOOST_ATOMIC_DETAIL_ALIGN_SIZE_TO_POWER_OF_2(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE) +#endif +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE) +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE BOOST_ATOMIC_DETAIL_ALIGN_SIZE_TO_POWER_OF_2(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE) +#endif + +#endif // !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE) + +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) ||\ + !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) ||\ + !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE) +#error Boost.Atomic: Failed to determine builtin floating point type sizes, the target platform is not supported. Please, report to the developers (patches are welcome). +#endif + +#endif // BOOST_ATOMIC_DETAIL_FLOAT_SIZES_HPP_INCLUDED_ diff --git a/boost/atomic/detail/fp_operations.hpp b/boost/atomic/detail/fp_operations.hpp new file mode 100644 index 0000000..69cb0d1 --- /dev/null +++ b/boost/atomic/detail/fp_operations.hpp @@ -0,0 +1,28 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/fp_operations.hpp + * + * This header defines floating point atomic operations, including the generic version. + */ + +#ifndef BOOST_ATOMIC_DETAIL_FP_OPERATIONS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_FP_OPERATIONS_HPP_INCLUDED_ + +#include +#include + +#if !defined(BOOST_ATOMIC_DETAIL_FP_BACKEND_GENERIC) +#include BOOST_ATOMIC_DETAIL_FP_BACKEND_HEADER(boost/atomic/detail/fp_ops_) +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif // BOOST_ATOMIC_DETAIL_FP_OPERATIONS_HPP_INCLUDED_ diff --git a/boost/atomic/detail/fp_operations_fwd.hpp b/boost/atomic/detail/fp_operations_fwd.hpp new file mode 100644 index 0000000..8696de3 --- /dev/null +++ b/boost/atomic/detail/fp_operations_fwd.hpp @@ -0,0 +1,35 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/fp_operations_fwd.hpp + * + * This header contains forward declaration of the \c fp_operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_FP_OPERATIONS_FWD_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_FP_OPERATIONS_FWD_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base, typename Value, std::size_t Size, bool = Base::is_always_lock_free > +struct fp_operations; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_FP_OPERATIONS_FWD_HPP_INCLUDED_ diff --git a/boost/atomic/detail/fp_ops_emulated.hpp b/boost/atomic/detail/fp_ops_emulated.hpp new file mode 100644 index 0000000..a87f181 --- /dev/null +++ b/boost/atomic/detail/fp_ops_emulated.hpp @@ -0,0 +1,72 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/fp_ops_emulated.hpp + * + * This header contains emulated (lock-based) implementation of the floating point atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_FP_OPS_EMULATED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_FP_OPS_EMULATED_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +//! Generic implementation of floating point operations +template< typename Base, typename Value, std::size_t Size > +struct emulated_fp_operations : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef Value value_type; + + static BOOST_FORCEINLINE value_type fetch_add(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); + value_type new_val = old_val + v; + s = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + return old_val; + } + + static BOOST_FORCEINLINE value_type fetch_sub(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); + value_type new_val = old_val - v; + s = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + return old_val; + } +}; + +template< typename Base, typename Value, std::size_t Size > +struct fp_operations< Base, Value, Size, false > : + public emulated_fp_operations< Base, Value, Size > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_FP_OPS_EMULATED_HPP_INCLUDED_ diff --git a/boost/atomic/detail/fp_ops_generic.hpp b/boost/atomic/detail/fp_ops_generic.hpp new file mode 100644 index 0000000..b83e85a --- /dev/null +++ b/boost/atomic/detail/fp_ops_generic.hpp @@ -0,0 +1,83 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/fp_ops_generic.hpp + * + * This header contains generic implementation of the floating point atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_FP_OPS_GENERIC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_FP_OPS_GENERIC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +//! Generic implementation of floating point operations +template< typename Base, typename Value, std::size_t Size > +struct generic_fp_operations : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef Value value_type; + + static BOOST_FORCEINLINE value_type fetch_add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_storage, new_storage; + value_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_storage); + do + { + old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); + new_val = old_val + v; + new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + } + while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); + return old_val; + } + + static BOOST_FORCEINLINE value_type fetch_sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_storage, new_storage; + value_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_storage); + do + { + old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); + new_val = old_val - v; + new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + } + while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); + return old_val; + } +}; + +// Default fp_operations template definition will be used unless specialized for a specific platform +template< typename Base, typename Value, std::size_t Size > +struct fp_operations< Base, Value, Size, true > : + public generic_fp_operations< Base, Value, Size > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_FP_OPS_GENERIC_HPP_INCLUDED_ diff --git a/boost/atomic/detail/hwcaps_gcc_arm.hpp b/boost/atomic/detail/hwcaps_gcc_arm.hpp new file mode 100644 index 0000000..6d0c338 --- /dev/null +++ b/boost/atomic/detail/hwcaps_gcc_arm.hpp @@ -0,0 +1,67 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/hwcaps_gcc_arm.hpp + * + * This header defines hardware capabilities macros for ARM + */ + +#ifndef BOOST_ATOMIC_DETAIL_HWCAPS_GCC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_HWCAPS_GCC_ARM_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__GNUC__) && defined(__arm__) && (BOOST_ATOMIC_DETAIL_ARM_ARCH+0) >= 6 + +#if BOOST_ATOMIC_DETAIL_ARM_ARCH > 6 +// ARMv7 and later have dmb instruction +#define BOOST_ATOMIC_DETAIL_ARM_HAS_DMB 1 +#endif + +#if defined(__ARM_FEATURE_LDREX) + +#if (__ARM_FEATURE_LDREX & 1) +#define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB 1 +#endif +#if (__ARM_FEATURE_LDREX & 2) +#define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH 1 +#endif +#if (__ARM_FEATURE_LDREX & 8) +#define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD 1 +#endif + +#else // defined(__ARM_FEATURE_LDREX) + +#if !(defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6Z__)) + +// ARMv6k and ARMv7 have 8 and 16-bit ldrex/strex variants, but at least GCC 4.7 fails to compile them. GCC 4.9 is known to work. +#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 409 +#define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB 1 +#define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH 1 +#endif + +#if !(((defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__)) && defined(__thumb__)) || defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7M__)) +// ARMv6k and ARMv7 except ARMv7-M have 64-bit ldrex/strex variants. +// Unfortunately, GCC (at least 4.7.3 on Ubuntu) does not allocate register pairs properly when targeting ARMv6k Thumb, +// which is required for ldrexd/strexd instructions, so we disable 64-bit support. When targeting ARMv6k ARM +// or ARMv7 (both ARM and Thumb 2) it works as expected. +#define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD 1 +#endif + +#endif // !(defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6Z__)) + +#endif // defined(__ARM_FEATURE_LDREX) + +#endif // defined(__GNUC__) && defined(__arm__) && (BOOST_ATOMIC_DETAIL_ARM_ARCH+0) >= 6 + +#endif // BOOST_ATOMIC_DETAIL_HWCAPS_GCC_ARM_HPP_INCLUDED_ diff --git a/boost/atomic/detail/hwcaps_gcc_ppc.hpp b/boost/atomic/detail/hwcaps_gcc_ppc.hpp new file mode 100644 index 0000000..2ec1e32 --- /dev/null +++ b/boost/atomic/detail/hwcaps_gcc_ppc.hpp @@ -0,0 +1,42 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/hwcaps_gcc_ppc.hpp + * + * This header defines hardware capabilities macros for PowerPC + */ + +#ifndef BOOST_ATOMIC_DETAIL_HWCAPS_GCC_PPC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_HWCAPS_GCC_PPC_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__POWERPC__) || defined(__PPC__) + +#if defined(_ARCH_PWR8) +// Power8 and later architectures have 8 and 16-bit instructions +#define BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX +#define BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX +#endif + +#if defined(__powerpc64__) || defined(__PPC64__) +// Power7 and later architectures in 64-bit mode have 64-bit instructions +#define BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX +#if defined(_ARCH_PWR8) +// Power8 also has 128-bit instructions +#define BOOST_ATOMIC_DETAIL_PPC_HAS_LQARX_STQCX +#endif +#endif + +#endif // defined(__POWERPC__) || defined(__PPC__) + +#endif // BOOST_ATOMIC_DETAIL_HWCAPS_GCC_PPC_HPP_INCLUDED_ diff --git a/boost/atomic/detail/hwcaps_gcc_x86.hpp b/boost/atomic/detail/hwcaps_gcc_x86.hpp new file mode 100644 index 0000000..91a1aee --- /dev/null +++ b/boost/atomic/detail/hwcaps_gcc_x86.hpp @@ -0,0 +1,58 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/hwcaps_gcc_x86.hpp + * + * This header defines hardware capabilities macros for x86 + */ + +#ifndef BOOST_ATOMIC_DETAIL_HWCAPS_GCC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_HWCAPS_GCC_X86_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__GNUC__) + +#if defined(__i386__) &&\ + (\ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) ||\ + defined(__i586__) || defined(__i686__) || defined(__SSE__)\ + ) +#define BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B 1 +#endif + +#if defined(__x86_64__) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B 1 +#endif + +#if defined(__x86_64__) || defined(__SSE2__) +// Use mfence only if SSE2 is available +#define BOOST_ATOMIC_DETAIL_X86_HAS_MFENCE 1 +#endif + +#else // defined(__GNUC__) + +#if defined(__i386__) && !defined(BOOST_ATOMIC_NO_CMPXCHG8B) +#define BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B 1 +#endif + +#if defined(__x86_64__) && !defined(BOOST_ATOMIC_NO_CMPXCHG16B) +#define BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B 1 +#endif + +#if !defined(BOOST_ATOMIC_NO_MFENCE) +#define BOOST_ATOMIC_DETAIL_X86_HAS_MFENCE 1 +#endif + +#endif // defined(__GNUC__) + +#endif // BOOST_ATOMIC_DETAIL_HWCAPS_GCC_X86_HPP_INCLUDED_ diff --git a/boost/atomic/detail/int_sizes.hpp b/boost/atomic/detail/int_sizes.hpp new file mode 100644 index 0000000..2a9757c --- /dev/null +++ b/boost/atomic/detail/int_sizes.hpp @@ -0,0 +1,140 @@ +/* + * 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) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/int_sizes.hpp + * + * This header defines macros for testing buitin integer type sizes + */ + +#ifndef BOOST_ATOMIC_DETAIL_INT_SIZES_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_INT_SIZES_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// GCC and compatible compilers define internal macros with builtin type traits +#if defined(__SIZEOF_SHORT__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_SHORT __SIZEOF_SHORT__ +#endif +#if defined(__SIZEOF_INT__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_INT __SIZEOF_INT__ +#endif +#if defined(__SIZEOF_LONG__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG __SIZEOF_LONG__ +#endif +#if defined(__SIZEOF_LONG_LONG__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_LLONG __SIZEOF_LONG_LONG__ +#endif +#if defined(__SIZEOF_WCHAR_T__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T __SIZEOF_WCHAR_T__ +#endif +#if defined(__SIZEOF_POINTER__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_POINTER __SIZEOF_POINTER__ +#elif defined(_MSC_VER) +#if defined(_M_AMD64) || defined(_M_ARM64) || defined(_M_IA64) +#define BOOST_ATOMIC_DETAIL_SIZEOF_POINTER 8 +#else +#define BOOST_ATOMIC_DETAIL_SIZEOF_POINTER 4 +#endif +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_SHORT) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_INT) ||\ + !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LLONG) + +// Try to deduce sizes from limits +#include +#include + +#if (USHRT_MAX + 0) == 0xff +#define BOOST_ATOMIC_DETAIL_SIZEOF_SHORT 1 +#elif (USHRT_MAX + 0) == 0xffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_SHORT 2 +#elif (USHRT_MAX + 0) == 0xffffffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_SHORT 4 +#elif (USHRT_MAX + 0) == UINT64_C(0xffffffffffffffff) +#define BOOST_ATOMIC_DETAIL_SIZEOF_SHORT 8 +#endif + +#if (UINT_MAX + 0) == 0xff +#define BOOST_ATOMIC_DETAIL_SIZEOF_INT 1 +#elif (UINT_MAX + 0) == 0xffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_INT 2 +#elif (UINT_MAX + 0) == 0xffffffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_INT 4 +#elif (UINT_MAX + 0) == UINT64_C(0xffffffffffffffff) +#define BOOST_ATOMIC_DETAIL_SIZEOF_INT 8 +#endif + +#if (ULONG_MAX + 0) == 0xff +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG 1 +#elif (ULONG_MAX + 0) == 0xffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG 2 +#elif (ULONG_MAX + 0) == 0xffffffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG 4 +#elif (ULONG_MAX + 0) == UINT64_C(0xffffffffffffffff) +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG 8 +#endif + +#if defined(__hpux) // HP-UX's value of ULONG_LONG_MAX is unusable in preprocessor expressions +#define BOOST_ATOMIC_DETAIL_SIZEOF_LLONG 8 +#else + +// The list of the non-standard macros (the ones except ULLONG_MAX) is taken from cstdint.hpp +#if defined(ULLONG_MAX) +#define BOOST_ATOMIC_DETAIL_ULLONG_MAX ULLONG_MAX +#elif defined(ULONG_LONG_MAX) +#define BOOST_ATOMIC_DETAIL_ULLONG_MAX ULONG_LONG_MAX +#elif defined(ULONGLONG_MAX) +#define BOOST_ATOMIC_DETAIL_ULLONG_MAX ULONGLONG_MAX +#elif defined(_LLONG_MAX) // strangely enough, this one seems to be holding the limit for the unsigned integer +#define BOOST_ATOMIC_DETAIL_ULLONG_MAX _LLONG_MAX +#endif + +#if (BOOST_ATOMIC_DETAIL_ULLONG_MAX + 0) == 0xff +#define BOOST_ATOMIC_DETAIL_SIZEOF_LLONG 1 +#elif (BOOST_ATOMIC_DETAIL_ULLONG_MAX + 0) == 0xffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_LLONG 2 +#elif (BOOST_ATOMIC_DETAIL_ULLONG_MAX + 0) == 0xffffffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_LLONG 4 +#elif (BOOST_ATOMIC_DETAIL_ULLONG_MAX + 0) == UINT64_C(0xffffffffffffffff) +#define BOOST_ATOMIC_DETAIL_SIZEOF_LLONG 8 +#endif + +#endif // defined(__hpux) + +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T) + +#include +#include + +#if defined(_MSC_VER) && (_MSC_VER <= 1310 || defined(UNDER_CE) && _MSC_VER <= 1500) +// MSVC 7.1 and MSVC 8 (arm) define WCHAR_MAX to a value not suitable for constant expressions +#define BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T 2 +#elif (WCHAR_MAX + 0) == 0xff || (WCHAR_MAX + 0) == 0x7f +#define BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T 1 +#elif (WCHAR_MAX + 0) == 0xffff || (WCHAR_MAX + 0) == 0x7fff +#define BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T 2 +#elif (WCHAR_MAX + 0) == 0xffffffff || (WCHAR_MAX + 0) == 0x7fffffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T 4 +#elif (WCHAR_MAX + 0) == UINT64_C(0xffffffffffffffff) || (WCHAR_MAX + 0) == INT64_C(0x7fffffffffffffff) +#define BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T 8 +#endif +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_SHORT) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_INT) ||\ + !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LLONG) ||\ + !defined(BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T) +#error Boost.Atomic: Failed to determine builtin integer sizes, the target platform is not supported. Please, report to the developers (patches are welcome). +#endif + +#endif // BOOST_ATOMIC_DETAIL_INT_SIZES_HPP_INCLUDED_ diff --git a/boost/atomic/detail/integral_extend.hpp b/boost/atomic/detail/integral_extend.hpp new file mode 100644 index 0000000..dea48ac --- /dev/null +++ b/boost/atomic/detail/integral_extend.hpp @@ -0,0 +1,105 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/integral_extend.hpp + * + * This header defines sign/zero extension utilities for Boost.Atomic. The tools assume two's complement signed integer representation. + */ + +#ifndef BOOST_ATOMIC_DETAIL_INTEGRAL_EXTEND_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_INTEGRAL_EXTEND_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Output, typename Input > +BOOST_FORCEINLINE Output zero_extend_impl(Input input, atomics::detail::true_type) BOOST_NOEXCEPT +{ + // Note: If we are casting with truncation or to the same-sized output, don't cause signed integer overflow by this chain of conversions + return atomics::detail::bitwise_cast< Output >(static_cast< typename atomics::detail::make_unsigned< Output >::type >( + static_cast< typename atomics::detail::make_unsigned< Input >::type >(input))); +} + +template< typename Output, typename Input > +BOOST_FORCEINLINE Output zero_extend_impl(Input input, atomics::detail::false_type) BOOST_NOEXCEPT +{ + return static_cast< Output >(static_cast< typename atomics::detail::make_unsigned< Input >::type >(input)); +} + +//! Zero-extends or truncates (wraps) input operand to fit in the output type +template< typename Output, typename Input > +BOOST_FORCEINLINE Output zero_extend(Input input) BOOST_NOEXCEPT +{ + return atomics::detail::zero_extend_impl< Output >(input, atomics::detail::integral_constant< bool, atomics::detail::is_signed< Output >::value >()); +} + +//! Truncates (wraps) input operand to fit in the output type +template< typename Output, typename Input > +BOOST_FORCEINLINE Output integral_truncate(Input input) BOOST_NOEXCEPT +{ + // zero_extend does the truncation + return atomics::detail::zero_extend< Output >(input); +} + +template< typename Output, typename Input > +BOOST_FORCEINLINE Output sign_extend_impl(Input input, atomics::detail::true_type) BOOST_NOEXCEPT +{ + return atomics::detail::integral_truncate< Output >(input); +} + +template< typename Output, typename Input > +BOOST_FORCEINLINE Output sign_extend_impl(Input input, atomics::detail::false_type) BOOST_NOEXCEPT +{ + return static_cast< Output >(atomics::detail::bitwise_cast< typename atomics::detail::make_signed< Input >::type >(input)); +} + +//! Sign-extends or truncates (wraps) input operand to fit in the output type +template< typename Output, typename Input > +BOOST_FORCEINLINE Output sign_extend(Input input) BOOST_NOEXCEPT +{ + return atomics::detail::sign_extend_impl< Output >(input, atomics::detail::integral_constant< bool, sizeof(Output) <= sizeof(Input) >()); +} + +//! Sign-extends or truncates (wraps) input operand to fit in the output type +template< typename Output, typename Input > +BOOST_FORCEINLINE Output integral_extend(Input input, atomics::detail::true_type) BOOST_NOEXCEPT +{ + return atomics::detail::sign_extend< Output >(input); +} + +//! Zero-extends or truncates (wraps) input operand to fit in the output type +template< typename Output, typename Input > +BOOST_FORCEINLINE Output integral_extend(Input input, atomics::detail::false_type) BOOST_NOEXCEPT +{ + return atomics::detail::zero_extend< Output >(input); +} + +//! Sign- or zero-extends or truncates (wraps) input operand to fit in the output type +template< bool Signed, typename Output, typename Input > +BOOST_FORCEINLINE Output integral_extend(Input input) BOOST_NOEXCEPT +{ + return atomics::detail::integral_extend< Output >(input, atomics::detail::integral_constant< bool, Signed >()); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_INTEGRAL_EXTEND_HPP_INCLUDED_ diff --git a/boost/atomic/detail/interlocked.hpp b/boost/atomic/detail/interlocked.hpp new file mode 100644 index 0000000..774354f --- /dev/null +++ b/boost/atomic/detail/interlocked.hpp @@ -0,0 +1,522 @@ +#ifndef BOOST_ATOMIC_DETAIL_INTERLOCKED_HPP +#define BOOST_ATOMIC_DETAIL_INTERLOCKED_HPP + +// Copyright (c) 2009 Helge Bahmann +// Copyright (c) 2012 - 2014, 2017 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(_WIN32_WCE) + +#if _WIN32_WCE >= 0x600 + +extern "C" long __cdecl _InterlockedCompareExchange( long volatile *, long, long ); +extern "C" long __cdecl _InterlockedExchangeAdd( long volatile *, long ); +extern "C" long __cdecl _InterlockedExchange( long volatile *, long ); + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) _InterlockedCompareExchange((long*)(dest), exchange, compare) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) _InterlockedExchangeAdd((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) _InterlockedExchange((long*)(dest), (long)(newval)) + +#else // _WIN32_WCE >= 0x600 + +extern "C" long __cdecl InterlockedCompareExchange( long*, long, long ); +extern "C" long __cdecl InterlockedExchangeAdd( long*, long ); +extern "C" long __cdecl InterlockedExchange( long*, long ); + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) InterlockedCompareExchange((long*)(dest), exchange, compare) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) InterlockedExchangeAdd((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) InterlockedExchange((long*)(dest), (long)(newval)) + +#endif // _WIN32_WCE >= 0x600 + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) ((void*)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE((long*)(dest), (long)(exchange), (long)(compare))) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, exchange) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE((long*)(dest), (long)(exchange))) + +#elif defined(_MSC_VER) && _MSC_VER >= 1310 + +#if _MSC_VER < 1400 + +extern "C" long __cdecl _InterlockedCompareExchange( long volatile *, long, long ); +extern "C" long __cdecl _InterlockedExchangeAdd( long volatile *, long ); +extern "C" long __cdecl _InterlockedExchange( long volatile *, long ); + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange) +#pragma intrinsic(_InterlockedExchangeAdd) +#pragma intrinsic(_InterlockedExchange) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) _InterlockedCompareExchange((long*)(dest), exchange, compare) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) _InterlockedExchangeAdd((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) _InterlockedExchange((long*)(dest), (long)(newval)) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) ((void*)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE((long*)(dest), (long)(exchange), (long)(compare))) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, exchange) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE((long*)(dest), (long)(exchange))) + +#else // _MSC_VER < 1400 + +#include + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange) +#pragma intrinsic(_InterlockedExchangeAdd) +#pragma intrinsic(_InterlockedExchange) +#pragma intrinsic(_InterlockedAnd) +#pragma intrinsic(_InterlockedOr) +#pragma intrinsic(_InterlockedXor) +#pragma intrinsic(_interlockedbittestandset) +#pragma intrinsic(_interlockedbittestandreset) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) _InterlockedCompareExchange((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) _InterlockedExchangeAdd((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) _InterlockedExchange((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_AND(dest, arg) _InterlockedAnd((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR(dest, arg) _InterlockedOr((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR(dest, arg) _InterlockedXor((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTS(dest, arg) _interlockedbittestandset((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTR(dest, arg) _interlockedbittestandreset((long*)(dest), (long)(arg)) + +#if defined(_M_AMD64) +#if defined(BOOST_MSVC) +#pragma intrinsic(_interlockedbittestandset64) +#pragma intrinsic(_interlockedbittestandreset64) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_BTS64(dest, arg) _interlockedbittestandset64((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTR64(dest, arg) _interlockedbittestandreset64((__int64*)(dest), (__int64)(arg)) +#endif // defined(_M_AMD64) + +#if (defined(_M_IX86) && _M_IX86 >= 500) || defined(_M_AMD64) || defined(_M_IA64) +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange64) +#endif +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(dest, exchange, compare) _InterlockedCompareExchange64((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#endif + +#if _MSC_VER >= 1500 && defined(_M_AMD64) +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange128) +#endif +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE128(dest, exchange, compare) _InterlockedCompareExchange128((__int64*)(dest), ((const __int64*)(&exchange))[1], ((const __int64*)(&exchange))[0], (__int64*)(compare)) +#endif + +#if _MSC_VER >= 1600 + +// MSVC 2010 and later provide intrinsics for 8 and 16 bit integers. +// Note that for each bit count these macros must be either all defined or all not defined. +// Otherwise atomic<> operations will be implemented inconsistently. + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange8) +#pragma intrinsic(_InterlockedExchangeAdd8) +#pragma intrinsic(_InterlockedExchange8) +#pragma intrinsic(_InterlockedAnd8) +#pragma intrinsic(_InterlockedOr8) +#pragma intrinsic(_InterlockedXor8) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8(dest, exchange, compare) _InterlockedCompareExchange8((char*)(dest), (char)(exchange), (char)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8(dest, addend) _InterlockedExchangeAdd8((char*)(dest), (char)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE8(dest, newval) _InterlockedExchange8((char*)(dest), (char)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_AND8(dest, arg) _InterlockedAnd8((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR8(dest, arg) _InterlockedOr8((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR8(dest, arg) _InterlockedXor8((char*)(dest), (char)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange16) +#pragma intrinsic(_InterlockedExchangeAdd16) +#pragma intrinsic(_InterlockedExchange16) +#pragma intrinsic(_InterlockedAnd16) +#pragma intrinsic(_InterlockedOr16) +#pragma intrinsic(_InterlockedXor16) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16(dest, exchange, compare) _InterlockedCompareExchange16((short*)(dest), (short)(exchange), (short)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16(dest, addend) _InterlockedExchangeAdd16((short*)(dest), (short)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE16(dest, newval) _InterlockedExchange16((short*)(dest), (short)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_AND16(dest, arg) _InterlockedAnd16((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR16(dest, arg) _InterlockedOr16((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR16(dest, arg) _InterlockedXor16((short*)(dest), (short)(arg)) + +#endif // _MSC_VER >= 1600 + +#if defined(_M_AMD64) || defined(_M_IA64) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedExchangeAdd64) +#pragma intrinsic(_InterlockedExchange64) +#pragma intrinsic(_InterlockedAnd64) +#pragma intrinsic(_InterlockedOr64) +#pragma intrinsic(_InterlockedXor64) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, addend) _InterlockedExchangeAdd64((__int64*)(dest), (__int64)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(dest, newval) _InterlockedExchange64((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_AND64(dest, arg) _InterlockedAnd64((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR64(dest, arg) _InterlockedOr64((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR64(dest, arg) _InterlockedXor64((__int64*)(dest), (__int64)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchangePointer) +#pragma intrinsic(_InterlockedExchangePointer) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) _InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) _InterlockedExchangePointer((void**)(dest), (void*)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64((long*)(dest), byte_offset)) + +#elif defined(_M_IX86) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) ((void*)_InterlockedCompareExchange((long*)(dest), (long)(exchange), (long)(compare))) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) ((void*)_InterlockedExchange((long*)(dest), (long)(newval))) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD((long*)(dest), byte_offset)) + +#endif + +#if _MSC_VER >= 1700 && (defined(_M_ARM) || defined(_M_ARM64)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedExchangeAdd64) +#pragma intrinsic(_InterlockedExchange64) +#pragma intrinsic(_InterlockedAnd64) +#pragma intrinsic(_InterlockedOr64) +#pragma intrinsic(_InterlockedXor64) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, addend) _InterlockedExchangeAdd64((__int64*)(dest), (__int64)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(dest, newval) _InterlockedExchange64((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_AND64(dest, arg) _InterlockedAnd64((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR64(dest, arg) _InterlockedOr64((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR64(dest, arg) _InterlockedXor64((__int64*)(dest), (__int64)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange8_nf) +#pragma intrinsic(_InterlockedCompareExchange8_acq) +#pragma intrinsic(_InterlockedCompareExchange8_rel) +#pragma intrinsic(_InterlockedCompareExchange16_nf) +#pragma intrinsic(_InterlockedCompareExchange16_acq) +#pragma intrinsic(_InterlockedCompareExchange16_rel) +#pragma intrinsic(_InterlockedCompareExchange_nf) +#pragma intrinsic(_InterlockedCompareExchange_acq) +#pragma intrinsic(_InterlockedCompareExchange_rel) +#pragma intrinsic(_InterlockedCompareExchange64) +#pragma intrinsic(_InterlockedCompareExchange64_nf) +#pragma intrinsic(_InterlockedCompareExchange64_acq) +#pragma intrinsic(_InterlockedCompareExchange64_rel) +#pragma intrinsic(_InterlockedCompareExchangePointer) +#pragma intrinsic(_InterlockedCompareExchangePointer_nf) +#pragma intrinsic(_InterlockedCompareExchangePointer_acq) +#pragma intrinsic(_InterlockedCompareExchangePointer_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8_RELAXED(dest, exchange, compare) _InterlockedCompareExchange8_nf((char*)(dest), (char)(exchange), (char)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8_ACQUIRE(dest, exchange, compare) _InterlockedCompareExchange8_acq((char*)(dest), (char)(exchange), (char)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8_RELEASE(dest, exchange, compare) _InterlockedCompareExchange8_rel((char*)(dest), (char)(exchange), (char)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16_RELAXED(dest, exchange, compare) _InterlockedCompareExchange16_nf((short*)(dest), (short)(exchange), (short)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16_ACQUIRE(dest, exchange, compare) _InterlockedCompareExchange16_acq((short*)(dest), (short)(exchange), (short)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16_RELEASE(dest, exchange, compare) _InterlockedCompareExchange16_rel((short*)(dest), (short)(exchange), (short)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_RELAXED(dest, exchange, compare) _InterlockedCompareExchange_nf((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_ACQUIRE(dest, exchange, compare) _InterlockedCompareExchange_acq((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_RELEASE(dest, exchange, compare) _InterlockedCompareExchange_rel((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(dest, exchange, compare) _InterlockedCompareExchange64((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64_RELAXED(dest, exchange, compare) _InterlockedCompareExchange64_nf((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64_ACQUIRE(dest, exchange, compare) _InterlockedCompareExchange64_acq((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64_RELEASE(dest, exchange, compare) _InterlockedCompareExchange64_rel((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) _InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER_RELAXED(dest, exchange, compare) _InterlockedCompareExchangePointer_nf((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER_ACQUIRE(dest, exchange, compare) _InterlockedCompareExchangePointer_acq((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER_RELEASE(dest, exchange, compare) _InterlockedCompareExchangePointer_rel((void**)(dest), (void*)(exchange), (void*)(compare)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedExchangeAdd8_nf) +#pragma intrinsic(_InterlockedExchangeAdd8_acq) +#pragma intrinsic(_InterlockedExchangeAdd8_rel) +#pragma intrinsic(_InterlockedExchangeAdd16_nf) +#pragma intrinsic(_InterlockedExchangeAdd16_acq) +#pragma intrinsic(_InterlockedExchangeAdd16_rel) +#pragma intrinsic(_InterlockedExchangeAdd_nf) +#pragma intrinsic(_InterlockedExchangeAdd_acq) +#pragma intrinsic(_InterlockedExchangeAdd_rel) +#pragma intrinsic(_InterlockedExchangeAdd64_nf) +#pragma intrinsic(_InterlockedExchangeAdd64_acq) +#pragma intrinsic(_InterlockedExchangeAdd64_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8_RELAXED(dest, addend) _InterlockedExchangeAdd8_nf((char*)(dest), (char)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8_ACQUIRE(dest, addend) _InterlockedExchangeAdd8_acq((char*)(dest), (char)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8_RELEASE(dest, addend) _InterlockedExchangeAdd8_rel((char*)(dest), (char)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16_RELAXED(dest, addend) _InterlockedExchangeAdd16_nf((short*)(dest), (short)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16_ACQUIRE(dest, addend) _InterlockedExchangeAdd16_acq((short*)(dest), (short)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16_RELEASE(dest, addend) _InterlockedExchangeAdd16_rel((short*)(dest), (short)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_RELAXED(dest, addend) _InterlockedExchangeAdd_nf((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_ACQUIRE(dest, addend) _InterlockedExchangeAdd_acq((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_RELEASE(dest, addend) _InterlockedExchangeAdd_rel((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_RELAXED(dest, addend) _InterlockedExchangeAdd64_nf((__int64*)(dest), (__int64)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_ACQUIRE(dest, addend) _InterlockedExchangeAdd64_acq((__int64*)(dest), (__int64)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_RELEASE(dest, addend) _InterlockedExchangeAdd64_rel((__int64*)(dest), (__int64)(addend)) + +#if defined(_M_ARM64) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64((__int64*)(dest), byte_offset)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER_RELAXED(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_RELAXED((__int64*)(dest), byte_offset)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER_ACQUIRE(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_ACQUIRE((__int64*)(dest), byte_offset)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER_RELEASE(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_RELEASE((__int64*)(dest), byte_offset)) +#else +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD((long*)(dest), byte_offset)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER_RELAXED(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_RELAXED((long*)(dest), byte_offset)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER_ACQUIRE(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_ACQUIRE((long*)(dest), byte_offset)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER_RELEASE(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_RELEASE((long*)(dest), byte_offset)) +#endif + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedExchange8_nf) +#pragma intrinsic(_InterlockedExchange8_acq) +#pragma intrinsic(_InterlockedExchange16_nf) +#pragma intrinsic(_InterlockedExchange16_acq) +#pragma intrinsic(_InterlockedExchange_nf) +#pragma intrinsic(_InterlockedExchange_acq) +#pragma intrinsic(_InterlockedExchange64_nf) +#pragma intrinsic(_InterlockedExchange64_acq) +#pragma intrinsic(_InterlockedExchangePointer) +#pragma intrinsic(_InterlockedExchangePointer_nf) +#pragma intrinsic(_InterlockedExchangePointer_acq) +#if _MSC_VER >= 1800 +#pragma intrinsic(_InterlockedExchange8_rel) +#pragma intrinsic(_InterlockedExchange16_rel) +#pragma intrinsic(_InterlockedExchange_rel) +#pragma intrinsic(_InterlockedExchange64_rel) +#pragma intrinsic(_InterlockedExchangePointer_rel) +#endif +#endif + +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_RELAXED(dest, newval) _InterlockedExchange8_nf((char*)(dest), (char)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_ACQUIRE(dest, newval) _InterlockedExchange8_acq((char*)(dest), (char)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_RELAXED(dest, newval) _InterlockedExchange16_nf((short*)(dest), (short)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_ACQUIRE(dest, newval) _InterlockedExchange16_acq((short*)(dest), (short)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_RELAXED(dest, newval) _InterlockedExchange_nf((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ACQUIRE(dest, newval) _InterlockedExchange_acq((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_RELAXED(dest, newval) _InterlockedExchange64_nf((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_ACQUIRE(dest, newval) _InterlockedExchange64_acq((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) _InterlockedExchangePointer((void**)(dest), (void*)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER_RELAXED(dest, newval) _InterlockedExchangePointer_nf((void**)(dest), (void*)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER_ACQUIRE(dest, newval) _InterlockedExchangePointer_acq((void**)(dest), (void*)(newval)) + +#if _MSC_VER >= 1800 +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_RELEASE(dest, newval) _InterlockedExchange8_rel((char*)(dest), (char)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_RELEASE(dest, newval) _InterlockedExchange16_rel((short*)(dest), (short)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_RELEASE(dest, newval) _InterlockedExchange_rel((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_RELEASE(dest, newval) _InterlockedExchange64_rel((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER_RELEASE(dest, newval) _InterlockedExchangePointer_rel((void**)(dest), (void*)(newval)) +#else +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_RELEASE(dest, newval) BOOST_ATOMIC_INTERLOCKED_EXCHANGE8(dest, newval) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_RELEASE(dest, newval) BOOST_ATOMIC_INTERLOCKED_EXCHANGE16(dest, newval) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_RELEASE(dest, newval) BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_RELEASE(dest, newval) BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(dest, newval) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER_RELEASE(dest, newval) BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) +#endif + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedAnd8_nf) +#pragma intrinsic(_InterlockedAnd8_acq) +#pragma intrinsic(_InterlockedAnd8_rel) +#pragma intrinsic(_InterlockedAnd16_nf) +#pragma intrinsic(_InterlockedAnd16_acq) +#pragma intrinsic(_InterlockedAnd16_rel) +#pragma intrinsic(_InterlockedAnd_nf) +#pragma intrinsic(_InterlockedAnd_acq) +#pragma intrinsic(_InterlockedAnd_rel) +#pragma intrinsic(_InterlockedAnd64_nf) +#pragma intrinsic(_InterlockedAnd64_acq) +#pragma intrinsic(_InterlockedAnd64_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_AND8_RELAXED(dest, arg) _InterlockedAnd8_nf((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND8_ACQUIRE(dest, arg) _InterlockedAnd8_acq((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND8_RELEASE(dest, arg) _InterlockedAnd8_rel((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND16_RELAXED(dest, arg) _InterlockedAnd16_nf((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND16_ACQUIRE(dest, arg) _InterlockedAnd16_acq((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND16_RELEASE(dest, arg) _InterlockedAnd16_rel((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND_RELAXED(dest, arg) _InterlockedAnd_nf((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND_ACQUIRE(dest, arg) _InterlockedAnd_acq((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND_RELEASE(dest, arg) _InterlockedAnd_rel((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND64_RELAXED(dest, arg) _InterlockedAnd64_nf((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND64_ACQUIRE(dest, arg) _InterlockedAnd64_acq((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND64_RELEASE(dest, arg) _InterlockedAnd64_rel((__int64*)(dest), (__int64)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedOr8_nf) +#pragma intrinsic(_InterlockedOr8_acq) +#pragma intrinsic(_InterlockedOr8_rel) +#pragma intrinsic(_InterlockedOr16_nf) +#pragma intrinsic(_InterlockedOr16_acq) +#pragma intrinsic(_InterlockedOr16_rel) +#pragma intrinsic(_InterlockedOr_nf) +#pragma intrinsic(_InterlockedOr_acq) +#pragma intrinsic(_InterlockedOr_rel) +#pragma intrinsic(_InterlockedOr64_nf) +#pragma intrinsic(_InterlockedOr64_acq) +#pragma intrinsic(_InterlockedOr64_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_OR8_RELAXED(dest, arg) _InterlockedOr8_nf((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR8_ACQUIRE(dest, arg) _InterlockedOr8_acq((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR8_RELEASE(dest, arg) _InterlockedOr8_rel((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR16_RELAXED(dest, arg) _InterlockedOr16_nf((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR16_ACQUIRE(dest, arg) _InterlockedOr16_acq((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR16_RELEASE(dest, arg) _InterlockedOr16_rel((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR_RELAXED(dest, arg) _InterlockedOr_nf((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR_ACQUIRE(dest, arg) _InterlockedOr_acq((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR_RELEASE(dest, arg) _InterlockedOr_rel((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR64_RELAXED(dest, arg) _InterlockedOr64_nf((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR64_ACQUIRE(dest, arg) _InterlockedOr64_acq((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR64_RELEASE(dest, arg) _InterlockedOr64_rel((__int64*)(dest), (__int64)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedXor8_nf) +#pragma intrinsic(_InterlockedXor8_acq) +#pragma intrinsic(_InterlockedXor8_rel) +#pragma intrinsic(_InterlockedXor16_nf) +#pragma intrinsic(_InterlockedXor16_acq) +#pragma intrinsic(_InterlockedXor16_rel) +#pragma intrinsic(_InterlockedXor_nf) +#pragma intrinsic(_InterlockedXor_acq) +#pragma intrinsic(_InterlockedXor_rel) +#pragma intrinsic(_InterlockedXor64_nf) +#pragma intrinsic(_InterlockedXor64_acq) +#pragma intrinsic(_InterlockedXor64_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_XOR8_RELAXED(dest, arg) _InterlockedXor8_nf((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR8_ACQUIRE(dest, arg) _InterlockedXor8_acq((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR8_RELEASE(dest, arg) _InterlockedXor8_rel((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR16_RELAXED(dest, arg) _InterlockedXor16_nf((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR16_ACQUIRE(dest, arg) _InterlockedXor16_acq((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR16_RELEASE(dest, arg) _InterlockedXor16_rel((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR_RELAXED(dest, arg) _InterlockedXor_nf((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR_ACQUIRE(dest, arg) _InterlockedXor_acq((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR_RELEASE(dest, arg) _InterlockedXor_rel((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR64_RELAXED(dest, arg) _InterlockedXor64_nf((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR64_ACQUIRE(dest, arg) _InterlockedXor64_acq((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR64_RELEASE(dest, arg) _InterlockedXor64_rel((__int64*)(dest), (__int64)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_interlockedbittestandset_nf) +#pragma intrinsic(_interlockedbittestandset_acq) +#pragma intrinsic(_interlockedbittestandset_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_BTS_RELAXED(dest, arg) _interlockedbittestandset_nf((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTS_ACQUIRE(dest, arg) _interlockedbittestandset_acq((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTS_RELEASE(dest, arg) _interlockedbittestandset_rel((long*)(dest), (long)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_interlockedbittestandreset_nf) +#pragma intrinsic(_interlockedbittestandreset_acq) +#pragma intrinsic(_interlockedbittestandreset_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_BTR_RELAXED(dest, arg) _interlockedbittestandreset_nf((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTR_ACQUIRE(dest, arg) _interlockedbittestandreset_acq((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTR_RELEASE(dest, arg) _interlockedbittestandreset_rel((long*)(dest), (long)(arg)) + +#endif // _MSC_VER >= 1700 && defined(_M_ARM) + +#endif // _MSC_VER < 1400 + +#else // defined(_MSC_VER) && _MSC_VER >= 1310 + +#if defined(BOOST_USE_WINDOWS_H) + +#include + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) InterlockedCompareExchange((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) InterlockedExchange((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) InterlockedExchangeAdd((long*)(dest), (long)(addend)) + +#if defined(_WIN64) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(dest, exchange, compare) InterlockedCompareExchange64((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(dest, newval) InterlockedExchange64((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, addend) InterlockedExchangeAdd64((__int64*)(dest), (__int64)(addend)) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) InterlockedExchangePointer((void**)(dest), (void*)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, byte_offset)) + +#else // defined(_WIN64) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) ((void*)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, byte_offset)) + +#endif // defined(_WIN64) + +#else // defined(BOOST_USE_WINDOWS_H) + +#if defined(__MINGW64__) +#define BOOST_ATOMIC_INTERLOCKED_IMPORT +#else +#define BOOST_ATOMIC_INTERLOCKED_IMPORT __declspec(dllimport) +#endif + +namespace boost { +namespace atomics { +namespace detail { + +extern "C" { + +BOOST_ATOMIC_INTERLOCKED_IMPORT long __stdcall InterlockedCompareExchange(long volatile*, long, long); +BOOST_ATOMIC_INTERLOCKED_IMPORT long __stdcall InterlockedExchange(long volatile*, long); +BOOST_ATOMIC_INTERLOCKED_IMPORT long __stdcall InterlockedExchangeAdd(long volatile*, long); + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) boost::atomics::detail::InterlockedCompareExchange((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) boost::atomics::detail::InterlockedExchange((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) boost::atomics::detail::InterlockedExchangeAdd((long*)(dest), (long)(addend)) + +#if defined(_WIN64) + +BOOST_ATOMIC_INTERLOCKED_IMPORT __int64 __stdcall InterlockedCompareExchange64(__int64 volatile*, __int64, __int64); +BOOST_ATOMIC_INTERLOCKED_IMPORT __int64 __stdcall InterlockedExchange64(__int64 volatile*, __int64); +BOOST_ATOMIC_INTERLOCKED_IMPORT __int64 __stdcall InterlockedExchangeAdd64(__int64 volatile*, __int64); + +BOOST_ATOMIC_INTERLOCKED_IMPORT void* __stdcall InterlockedCompareExchangePointer(void* volatile *, void*, void*); +BOOST_ATOMIC_INTERLOCKED_IMPORT void* __stdcall InterlockedExchangePointer(void* volatile *, void*); + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(dest, exchange, compare) boost::atomics::detail::InterlockedCompareExchange64((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(dest, newval) boost::atomics::detail::InterlockedExchange64((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, addend) boost::atomics::detail::InterlockedExchangeAdd64((__int64*)(dest), (__int64)(addend)) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) boost::atomics::detail::InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) boost::atomics::detail::InterlockedExchangePointer((void**)(dest), (void*)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, byte_offset)) + +#else // defined(_WIN64) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) ((void*)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, byte_offset)) + +#endif // defined(_WIN64) + +} // extern "C" + +} // namespace detail +} // namespace atomics +} // namespace boost + +#undef BOOST_ATOMIC_INTERLOCKED_IMPORT + +#endif // defined(BOOST_USE_WINDOWS_H) + +#endif // defined(_MSC_VER) + +#endif diff --git a/boost/atomic/detail/link.hpp b/boost/atomic/detail/link.hpp new file mode 100644 index 0000000..4f522ac --- /dev/null +++ b/boost/atomic/detail/link.hpp @@ -0,0 +1,58 @@ +/* + * 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) + * + * Copyright (c) 2012 Hartmut Kaiser + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/config.hpp + * + * This header defines macros for linking with compiled library of Boost.Atomic + */ + +#ifndef BOOST_ATOMIC_DETAIL_LINK_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_LINK_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Set up dll import/export options +#if (defined(BOOST_ATOMIC_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)) && \ + !defined(BOOST_ATOMIC_STATIC_LINK) + +#if defined(BOOST_ATOMIC_SOURCE) +#define BOOST_ATOMIC_DECL BOOST_SYMBOL_EXPORT +#define BOOST_ATOMIC_BUILD_DLL +#else +#define BOOST_ATOMIC_DECL BOOST_SYMBOL_IMPORT +#endif + +#endif // building a shared library + +#ifndef BOOST_ATOMIC_DECL +#define BOOST_ATOMIC_DECL +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Auto library naming +#if !defined(BOOST_ATOMIC_SOURCE) && !defined(BOOST_ALL_NO_LIB) && \ + !defined(BOOST_ATOMIC_NO_LIB) + +#define BOOST_LIB_NAME boost_atomic + +// tell the auto-link code to select a dll when required: +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_ATOMIC_DYN_LINK) +#define BOOST_DYN_LINK +#endif + +#include + +#endif // auto-linking disabled + +#endif diff --git a/boost/atomic/detail/lockpool.hpp b/boost/atomic/detail/lockpool.hpp new file mode 100644 index 0000000..4e249aa --- /dev/null +++ b/boost/atomic/detail/lockpool.hpp @@ -0,0 +1,51 @@ +/* + * 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) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013-2014 Andrey Semashev + */ +/*! + * \file atomic/detail/lockpool.hpp + * + * This header contains declaration of the lockpool used to emulate atomic ops. + */ + +#ifndef BOOST_ATOMIC_DETAIL_LOCKPOOL_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_LOCKPOOL_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +struct lockpool +{ + class scoped_lock + { + void* m_lock; + + public: + explicit BOOST_ATOMIC_DECL scoped_lock(const volatile void* addr) BOOST_NOEXCEPT; + BOOST_ATOMIC_DECL ~scoped_lock() BOOST_NOEXCEPT; + + BOOST_DELETED_FUNCTION(scoped_lock(scoped_lock const&)) + BOOST_DELETED_FUNCTION(scoped_lock& operator=(scoped_lock const&)) + }; + + static BOOST_ATOMIC_DECL void thread_fence() BOOST_NOEXCEPT; + static BOOST_ATOMIC_DECL void signal_fence() BOOST_NOEXCEPT; +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_LOCKPOOL_HPP_INCLUDED_ diff --git a/boost/atomic/detail/operations.hpp b/boost/atomic/detail/operations.hpp new file mode 100644 index 0000000..d81399a --- /dev/null +++ b/boost/atomic/detail/operations.hpp @@ -0,0 +1,24 @@ +/* + * 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) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/operations.hpp + * + * This header defines atomic operations, including the emulated version. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPERATIONS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPERATIONS_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif // BOOST_ATOMIC_DETAIL_OPERATIONS_HPP_INCLUDED_ diff --git a/boost/atomic/detail/operations_fwd.hpp b/boost/atomic/detail/operations_fwd.hpp new file mode 100644 index 0000000..efd4970 --- /dev/null +++ b/boost/atomic/detail/operations_fwd.hpp @@ -0,0 +1,35 @@ +/* + * 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) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/operations_fwd.hpp + * + * This header contains forward declaration of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPERATIONS_FWD_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPERATIONS_FWD_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< std::size_t Size, bool Signed > +struct operations; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPERATIONS_FWD_HPP_INCLUDED_ diff --git a/boost/atomic/detail/operations_lockfree.hpp b/boost/atomic/detail/operations_lockfree.hpp new file mode 100644 index 0000000..62b4583 --- /dev/null +++ b/boost/atomic/detail/operations_lockfree.hpp @@ -0,0 +1,30 @@ +/* + * 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) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/operations_lockfree.hpp + * + * This header defines lockfree atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPERATIONS_LOCKFREE_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPERATIONS_LOCKFREE_HPP_INCLUDED_ + +#include +#include + +#if !defined(BOOST_ATOMIC_EMULATED) +#include BOOST_ATOMIC_DETAIL_BACKEND_HEADER(boost/atomic/detail/ops_) +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif // BOOST_ATOMIC_DETAIL_OPERATIONS_LOCKFREE_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_cas_based.hpp b/boost/atomic/detail/ops_cas_based.hpp new file mode 100644 index 0000000..e2e18aa --- /dev/null +++ b/boost/atomic/detail/ops_cas_based.hpp @@ -0,0 +1,107 @@ +/* + * 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) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_cas_based.hpp + * + * This header contains CAS-based implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_CAS_BASED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_CAS_BASED_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base > +struct cas_based_exchange : + public Base +{ + typedef typename Base::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!Base::compare_exchange_weak(storage, old_val, v, order, memory_order_relaxed)) {} + return old_val; + } +}; + +template< typename Base > +struct cas_based_operations : + public Base +{ + typedef typename Base::storage_type storage_type; + + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!Base::compare_exchange_weak(storage, old_val, old_val + v, order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!Base::compare_exchange_weak(storage, old_val, old_val - v, order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!Base::compare_exchange_weak(storage, old_val, old_val & v, order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!Base::compare_exchange_weak(storage, old_val, old_val | v, order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!Base::compare_exchange_weak(storage, old_val, old_val ^ v, order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!Base::exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + Base::store(storage, (storage_type)0, order); + } +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_CAS_BASED_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_emulated.hpp b/boost/atomic/detail/ops_emulated.hpp new file mode 100644 index 0000000..f30fbda --- /dev/null +++ b/boost/atomic/detail/ops_emulated.hpp @@ -0,0 +1,162 @@ +/* + * 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) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_emulated.hpp + * + * This header contains lockpool-based implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_EMULATED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_EMULATED_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< std::size_t Size, bool Signed > +struct emulated_operations +{ + typedef typename make_storage_type< Size >::type storage_type; + typedef typename make_storage_type< Size >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = false; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + lockpool::scoped_lock lock(&storage); + const_cast< storage_type& >(storage) = v; + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT + { + lockpool::scoped_lock lock(&storage); + return const_cast< storage_type const& >(storage); + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s += v; + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s -= v; + return old_val; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s = v; + return old_val; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + const bool res = old_val == expected; + if (res) + s = desired; + expected = old_val; + + return res; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + // Note: This function is the exact copy of compare_exchange_strong. The reason we're not just forwarding the call + // is that MSVC-12 ICEs in this case. + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + const bool res = old_val == expected; + if (res) + s = desired; + expected = old_val; + + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s &= v; + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s |= v; + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s ^= v; + return old_val; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, (storage_type)0, order); + } +}; + +template< std::size_t Size, bool Signed > +struct operations : + public emulated_operations< Size, Signed > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_EMULATED_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_extending_cas_based.hpp b/boost/atomic/detail/ops_extending_cas_based.hpp new file mode 100644 index 0000000..5f197ce --- /dev/null +++ b/boost/atomic/detail/ops_extending_cas_based.hpp @@ -0,0 +1,69 @@ +/* + * 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) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_extending_cas_based.hpp + * + * This header contains a boilerplate of the \c operations template implementation that requires sign/zero extension in arithmetic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_EXTENDING_CAS_BASED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_EXTENDING_CAS_BASED_HPP_INCLUDED_ + +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base, std::size_t Size, bool Signed > +struct extending_cas_based_operations : + public Base +{ + typedef typename Base::storage_type storage_type; + typedef typename make_storage_type< Size >::type emulated_storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + storage_type new_val; + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val + v)); + } + while (!Base::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + storage_type new_val; + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val - v)); + } + while (!Base::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return old_val; + } +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_EXTENDING_CAS_BASED_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_gcc_alpha.hpp b/boost/atomic/detail/ops_gcc_alpha.hpp new file mode 100644 index 0000000..85b1342 --- /dev/null +++ b/boost/atomic/detail/ops_gcc_alpha.hpp @@ -0,0 +1,876 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_alpha.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_ALPHA_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_ALPHA_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +/* + Refer to http://h71000.www7.hp.com/doc/82final/5601/5601pro_004.html + (HP OpenVMS systems documentation) and the Alpha Architecture Reference Manual. + */ + +/* + NB: The most natural thing would be to write the increment/decrement + operators along the following lines: + + __asm__ __volatile__ + ( + "1: ldl_l %0,%1 \n" + "addl %0,1,%0 \n" + "stl_c %0,%1 \n" + "beq %0,1b\n" + : "=&b" (tmp) + : "m" (value) + : "cc" + ); + + However according to the comments on the HP website and matching + comments in the Linux kernel sources this defies branch prediction, + as the cpu assumes that backward branches are always taken; so + instead copy the trick from the Linux kernel, introduce a forward + branch and back again. + + I have, however, had a hard time measuring the difference between + the two versions in microbenchmarks -- I am leaving it in nevertheless + as it apparently does not hurt either. +*/ + +struct gcc_alpha_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __asm__ __volatile__ ("mb" ::: "memory"); + } + + static BOOST_FORCEINLINE void fence_after(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + __asm__ __volatile__ ("mb" ::: "memory"); + } + + static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("mb" ::: "memory"); + } +}; + + +template< bool Signed > +struct operations< 4u, Signed > : + public gcc_alpha_operations_base +{ + typedef typename make_storage_type< 4u >::type storage_type; + typedef typename make_storage_type< 4u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, tmp; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "mov %3, %1\n" + "ldl_l %0, %2\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (tmp) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + int success; + storage_type current; + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %2, %4\n" // current = *(&storage) + "cmpeq %2, %0, %3\n" // success = current == expected + "mov %2, %0\n" // expected = current + "beq %3, 2f\n" // if (success == 0) goto end + "stl_c %1, %4\n" // storage = desired; desired = store succeeded + "mov %1, %3\n" // success = desired + "2:\n" + : "+&r" (expected), // %0 + "+&r" (desired), // %1 + "=&r" (current), // %2 + "=&r" (success) // %3 + : "m" (storage) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + storage_type current, tmp; + fence_before(success_order); + __asm__ __volatile__ + ( + "1:\n" + "mov %5, %1\n" // tmp = desired + "ldl_l %2, %4\n" // current = *(&storage) + "cmpeq %2, %0, %3\n" // success = current == expected + "mov %2, %0\n" // expected = current + "beq %3, 2f\n" // if (success == 0) goto end + "stl_c %1, %4\n" // storage = tmp; tmp = store succeeded + "beq %1, 3f\n" // if (tmp == 0) goto retry + "mov %1, %3\n" // success = tmp + "2:\n" + + ".subsection 2\n" + "3: br 1b\n" + ".previous\n" + + : "+&r" (expected), // %0 + "=&r" (tmp), // %1 + "=&r" (current), // %2 + "=&r" (success) // %3 + : "m" (storage), // %4 + "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "addl %0, %3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "subl %0, %3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "and %0, %3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "bis %0, %3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "xor %0, %3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + + +template< > +struct operations< 1u, false > : + public operations< 4u, false > +{ + typedef operations< 4u, false > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "addl %0, %3, %1\n" + "zapnot %1, #1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "subl %0, %3, %1\n" + "zapnot %1, #1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +template< > +struct operations< 1u, true > : + public operations< 4u, true > +{ + typedef operations< 4u, true > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "addl %0, %3, %1\n" + "sextb %1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "subl %0, %3, %1\n" + "sextb %1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + + +template< > +struct operations< 2u, false > : + public operations< 4u, false > +{ + typedef operations< 4u, false > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "addl %0, %3, %1\n" + "zapnot %1, #3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "subl %0, %3, %1\n" + "zapnot %1, #3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +template< > +struct operations< 2u, true > : + public operations< 4u, true > +{ + typedef operations< 4u, true > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "addl %0, %3, %1\n" + "sextw %1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "subl %0, %3, %1\n" + "sextw %1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + + +template< bool Signed > +struct operations< 8u, Signed > : + public gcc_alpha_operations_base +{ + typedef typename make_storage_type< 8u >::type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, tmp; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "mov %3, %1\n" + "ldq_l %0, %2\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (tmp) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + int success; + storage_type current; + __asm__ __volatile__ + ( + "1:\n" + "ldq_l %2, %4\n" // current = *(&storage) + "cmpeq %2, %0, %3\n" // success = current == expected + "mov %2, %0\n" // expected = current + "beq %3, 2f\n" // if (success == 0) goto end + "stq_c %1, %4\n" // storage = desired; desired = store succeeded + "mov %1, %3\n" // success = desired + "2:\n" + : "+&r" (expected), // %0 + "+&r" (desired), // %1 + "=&r" (current), // %2 + "=&r" (success) // %3 + : "m" (storage) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + storage_type current, tmp; + fence_before(success_order); + __asm__ __volatile__ + ( + "1:\n" + "mov %5, %1\n" // tmp = desired + "ldq_l %2, %4\n" // current = *(&storage) + "cmpeq %2, %0, %3\n" // success = current == expected + "mov %2, %0\n" // expected = current + "beq %3, 2f\n" // if (success == 0) goto end + "stq_c %1, %4\n" // storage = tmp; tmp = store succeeded + "beq %1, 3f\n" // if (tmp == 0) goto retry + "mov %1, %3\n" // success = tmp + "2:\n" + + ".subsection 2\n" + "3: br 1b\n" + ".previous\n" + + : "+&r" (expected), // %0 + "=&r" (tmp), // %1 + "=&r" (current), // %2 + "=&r" (success) // %3 + : "m" (storage), // %4 + "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldq_l %0, %2\n" + "addq %0, %3, %1\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldq_l %0, %2\n" + "subq %0, %3, %1\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldq_l %0, %2\n" + "and %0, %3, %1\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldq_l %0, %2\n" + "bis %0, %3, %1\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldq_l %0, %2\n" + "xor %0, %3, %1\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("mb" ::: "memory"); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("" ::: "memory"); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_ALPHA_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_gcc_arm.hpp b/boost/atomic/detail/ops_gcc_arm.hpp new file mode 100644 index 0000000..b321595 --- /dev/null +++ b/boost/atomic/detail/ops_gcc_arm.hpp @@ -0,0 +1,1397 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_arm.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +// From the ARM Architecture Reference Manual for architecture v6: +// +// LDREX{} , [] +// Specifies the destination register for the memory word addressed by +// Specifies the register containing the address. +// +// STREX{} , , [] +// Specifies the destination register for the returned status value. +// 0 if the operation updates memory +// 1 if the operation fails to update memory +// Specifies the register containing the word to be stored to memory. +// Specifies the register containing the address. +// Rd must not be the same register as Rm or Rn. +// +// ARM v7 is like ARM v6 plus: +// There are half-word and byte versions of the LDREX and STREX instructions, +// LDREXH, LDREXB, STREXH and STREXB. +// There are also double-word versions, LDREXD and STREXD. +// (Actually it looks like these are available from version 6k onwards.) +// FIXME these are not yet used; should be mostly a matter of copy-and-paste. +// I think you can supply an immediate offset to the address. + +template< bool Signed > +struct operations< 4u, Signed > : + public gcc_arm_operations_base +{ + typedef typename make_storage_type< 4u >::type storage_type; + typedef typename make_storage_type< 4u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + fence_before(order); + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // load the original value + "strex %[tmp], %[value], %[storage]\n" // store the replacement, tmp = store failed + "teq %[tmp], #0\n" // check if store succeeded + "bne 1b\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [tmp] "=&l" (tmp), [original] "=&r" (original), [storage] "+Q" (storage) + : [value] "r" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t success; + uint32_t tmp; + storage_type original; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "mov %[success], #0\n" // success = 0 + "ldrex %[original], %[storage]\n" // original = *(&storage) + "cmp %[original], %[expected]\n" // flags = original==expected + "itt eq\n" // [hint that the following 2 instructions are conditional on flags.equal] + "strexeq %[success], %[desired], %[storage]\n" // if (flags.equal) *(&storage) = desired, success = store failed + "eoreq %[success], %[success], #1\n" // if (flags.equal) success ^= 1 (i.e. make it 1 if store succeeded) + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [success] "=&r" (success), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [expected] "Ir" (expected), // %4 + [desired] "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = original; + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t success; + uint32_t tmp; + storage_type original; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "mov %[success], #0\n" // success = 0 + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "cmp %[original], %[expected]\n" // flags = original==expected + "bne 2f\n" // if (!flags.equal) goto end + "strex %[success], %[desired], %[storage]\n" // *(&storage) = desired, success = store failed + "eors %[success], %[success], #1\n" // success ^= 1 (i.e. make it 1 if store succeeded); flags.equal = success == 0 + "beq 1b\n" // if (flags.equal) goto retry + "2:\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [success] "=&r" (success), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [expected] "Ir" (expected), // %4 + [desired] "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = original; + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "add %[result], %[original], %[value]\n" // result = original + value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "sub %[result], %[original], %[value]\n" // result = original - value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "and %[result], %[original], %[value]\n" // result = original & value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "orr %[result], %[original], %[value]\n" // result = original | value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "eor %[result], %[original], %[value]\n" // result = original ^ value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) + +template< bool Signed > +struct operations< 1u, Signed > : + public gcc_arm_operations_base +{ + typedef typename make_storage_type< 1u >::type storage_type; + typedef typename make_storage_type< 1u >::aligned aligned_storage_type; + typedef typename make_storage_type< 4u >::type extended_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 1u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + extended_storage_type original; + fence_before(order); + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // load the original value and zero-extend to 32 bits + "strexb %[tmp], %[value], %[storage]\n" // store the replacement, tmp = store failed + "teq %[tmp], #0\n" // check if store succeeded + "bne 1b\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [tmp] "=&l" (tmp), [original] "=&r" (original), [storage] "+Q" (storage) + : [value] "r" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t success; + uint32_t tmp; + extended_storage_type original; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "mov %[success], #0\n" // success = 0 + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "cmp %[original], %[expected]\n" // flags = original==expected + "itt eq\n" // [hint that the following 2 instructions are conditional on flags.equal] + "strexbeq %[success], %[desired], %[storage]\n" // if (flags.equal) *(&storage) = desired, success = store failed + "eoreq %[success], %[success], #1\n" // if (flags.equal) success ^= 1 (i.e. make it 1 if store succeeded) + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [success] "=&r" (success), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [expected] "Ir" (atomics::detail::zero_extend< extended_storage_type >(expected)), // %4 + [desired] "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = static_cast< storage_type >(original); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t success; + uint32_t tmp; + extended_storage_type original; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "mov %[success], #0\n" // success = 0 + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "cmp %[original], %[expected]\n" // flags = original==expected + "bne 2f\n" // if (!flags.equal) goto end + "strexb %[success], %[desired], %[storage]\n" // *(&storage) = desired, success = store failed + "eors %[success], %[success], #1\n" // success ^= 1 (i.e. make it 1 if store succeeded); flags.equal = success == 0 + "beq 1b\n" // if (flags.equal) goto retry + "2:\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [success] "=&r" (success), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [expected] "Ir" (atomics::detail::zero_extend< extended_storage_type >(expected)), // %4 + [desired] "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = static_cast< storage_type >(original); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "add %[result], %[original], %[value]\n" // result = original + value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "sub %[result], %[original], %[value]\n" // result = original - value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "and %[result], %[original], %[value]\n" // result = original & value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "orr %[result], %[original], %[value]\n" // result = original | value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "eor %[result], %[original], %[value]\n" // result = original ^ value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#else // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) + +template< > +struct operations< 1u, false > : + public operations< 4u, false > +{ + typedef operations< 4u, false > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "add %[result], %[original], %[value]\n" // result = original + value + "uxtb %[result], %[result]\n" // zero extend result from 8 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "sub %[result], %[original], %[value]\n" // result = original - value + "uxtb %[result], %[result]\n" // zero extend result from 8 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +template< > +struct operations< 1u, true > : + public operations< 4u, true > +{ + typedef operations< 4u, true > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "add %[result], %[original], %[value]\n" // result = original + value + "sxtb %[result], %[result]\n" // sign extend result from 8 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "sub %[result], %[original], %[value]\n" // result = original - value + "sxtb %[result], %[result]\n" // sign extend result from 8 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) + +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) + +template< bool Signed > +struct operations< 2u, Signed > : + public gcc_arm_operations_base +{ + typedef typename make_storage_type< 2u >::type storage_type; + typedef typename make_storage_type< 2u >::aligned aligned_storage_type; + typedef typename make_storage_type< 4u >::type extended_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 2u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + extended_storage_type original; + fence_before(order); + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // load the original value and zero-extend to 32 bits + "strexh %[tmp], %[value], %[storage]\n" // store the replacement, tmp = store failed + "teq %[tmp], #0\n" // check if store succeeded + "bne 1b\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [tmp] "=&l" (tmp), [original] "=&r" (original), [storage] "+Q" (storage) + : [value] "r" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t success; + uint32_t tmp; + extended_storage_type original; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "mov %[success], #0\n" // success = 0 + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "cmp %[original], %[expected]\n" // flags = original==expected + "itt eq\n" // [hint that the following 2 instructions are conditional on flags.equal] + "strexheq %[success], %[desired], %[storage]\n" // if (flags.equal) *(&storage) = desired, success = store failed + "eoreq %[success], %[success], #1\n" // if (flags.equal) success ^= 1 (i.e. make it 1 if store succeeded) + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [success] "=&r" (success), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [expected] "Ir" (atomics::detail::zero_extend< extended_storage_type >(expected)), // %4 + [desired] "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = static_cast< storage_type >(original); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t success; + uint32_t tmp; + extended_storage_type original; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "mov %[success], #0\n" // success = 0 + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "cmp %[original], %[expected]\n" // flags = original==expected + "bne 2f\n" // if (!flags.equal) goto end + "strexh %[success], %[desired], %[storage]\n" // *(&storage) = desired, success = store failed + "eors %[success], %[success], #1\n" // success ^= 1 (i.e. make it 1 if store succeeded); flags.equal = success == 0 + "beq 1b\n" // if (flags.equal) goto retry + "2:\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [success] "=&r" (success), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [expected] "Ir" (atomics::detail::zero_extend< extended_storage_type >(expected)), // %4 + [desired] "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = static_cast< storage_type >(original); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "add %[result], %[original], %[value]\n" // result = original + value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "sub %[result], %[original], %[value]\n" // result = original - value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "and %[result], %[original], %[value]\n" // result = original & value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "orr %[result], %[original], %[value]\n" // result = original | value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "eor %[result], %[original], %[value]\n" // result = original ^ value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#else // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) + +template< > +struct operations< 2u, false > : + public operations< 4u, false > +{ + typedef operations< 4u, false > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "add %[result], %[original], %[value]\n" // result = original + value + "uxth %[result], %[result]\n" // zero extend result from 16 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "sub %[result], %[original], %[value]\n" // result = original - value + "uxth %[result], %[result]\n" // zero extend result from 16 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +template< > +struct operations< 2u, true > : + public operations< 4u, true > +{ + typedef operations< 4u, true > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "add %[result], %[original], %[value]\n" // result = original + value + "sxth %[result], %[result]\n" // sign extend result from 16 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "sub %[result], %[original], %[value]\n" // result = original - value + "sxth %[result], %[result]\n" // sign extend result from 16 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) + +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD) + +// Unlike 32-bit operations, for 64-bit loads and stores we must use ldrexd/strexd. +// Any other instructions result in a non-atomic sequence of 32-bit accesses. +// See "ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition", +// Section A3.5.3 "Atomicity in the ARM architecture". + +// In the asm blocks below we have to use 32-bit register pairs to compose 64-bit values. +// In order to pass the 64-bit operands to/from asm blocks, we use undocumented gcc feature: +// the lower half (Rt) of the operand is accessible normally, via the numbered placeholder (e.g. %0), +// and the upper half (Rt2) - via the same placeholder with an 'H' after the '%' sign (e.g. %H0). +// See: http://hardwarebug.org/2010/07/06/arm-inline-asm-secrets/ + +template< bool Signed > +struct operations< 8u, Signed > : + public gcc_arm_operations_base +{ + typedef typename make_storage_type< 8u >::type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + exchange(storage, v, order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "ldrexd %1, %H1, [%2]\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original) // %1 + : "r" (&storage) // %2 + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + fence_before(order); + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // load the original value + "strexd %0, %2, %H2, [%3]\n" // store the replacement, tmp = store failed + "teq %0, #0\n" // check if store succeeded + "bne 1b\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original) // %1 + : "r" (v), // %2 + "r" (&storage) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t tmp; + storage_type original, old_val = expected; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "cmp %1, %2\n" // flags = original.lo==old_val.lo + "ittt eq\n" // [hint that the following 3 instructions are conditional on flags.equal] + "cmpeq %H1, %H2\n" // if (flags.equal) flags = original.hi==old_val.hi + "strexdeq %0, %4, %H4, [%3]\n" // if (flags.equal) *(&storage) = desired, tmp = store failed + "teqeq %0, #0\n" // if (flags.equal) flags = tmp==0 + "ite eq\n" // [hint that the following 2 instructions are conditional on flags.equal] + "moveq %2, #1\n" // if (flags.equal) old_val.lo = 1 + "movne %2, #0\n" // if (!flags.equal) old_val.lo = 0 + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "+r" (old_val) // %2 + : "r" (&storage), // %3 + "r" (desired) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + const uint32_t success = (uint32_t)old_val; + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = original; + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t tmp; + storage_type original, old_val = expected; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "cmp %1, %2\n" // flags = original.lo==old_val.lo + "it eq\n" // [hint that the following instruction is conditional on flags.equal] + "cmpeq %H1, %H2\n" // if (flags.equal) flags = original.hi==old_val.hi + "bne 2f\n" // if (!flags.equal) goto end + "strexd %0, %4, %H4, [%3]\n" // *(&storage) = desired, tmp = store failed + "teq %0, #0\n" // flags.equal = tmp == 0 + "bne 1b\n" // if (flags.equal) goto retry + "2:\n" + "ite eq\n" // [hint that the following 2 instructions are conditional on flags.equal] + "moveq %2, #1\n" // if (flags.equal) old_val.lo = 1 + "movne %2, #0\n" // if (!flags.equal) old_val.lo = 0 + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "+r" (old_val) // %2 + : "r" (&storage), // %3 + "r" (desired) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + const uint32_t success = (uint32_t)old_val; + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = original; + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "adds %2, %1, %4\n" // result = original + value + "adc %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "subs %2, %1, %4\n" // result = original - value + "sbc %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "and %2, %1, %4\n" // result = original & value + "and %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "orr %2, %1, %4\n" // result = original | value + "orr %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "eor %2, %1, %4\n" // result = original ^ value + "eor %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD) + + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + gcc_arm_operations_base::hardware_full_fence(); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("" ::: "memory"); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_gcc_arm_common.hpp b/boost/atomic/detail/ops_gcc_arm_common.hpp new file mode 100644 index 0000000..73c04ff --- /dev/null +++ b/boost/atomic/detail/ops_gcc_arm_common.hpp @@ -0,0 +1,134 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_arm_common.hpp + * + * This header contains basic utilities for gcc ARM backend. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_COMMON_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_COMMON_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +// A memory barrier is effected using a "co-processor 15" instruction, +// though a separate assembler mnemonic is available for it in v7. +// +// "Thumb 1" is a subset of the ARM instruction set that uses a 16-bit encoding. It +// doesn't include all instructions and in particular it doesn't include the co-processor +// instruction used for the memory barrier or the load-locked/store-conditional +// instructions. So, if we're compiling in "Thumb 1" mode, we need to wrap all of our +// asm blocks with code to temporarily change to ARM mode. +// +// You can only change between ARM and Thumb modes when branching using the bx instruction. +// bx takes an address specified in a register. The least significant bit of the address +// indicates the mode, so 1 is added to indicate that the destination code is Thumb. +// A temporary register is needed for the address and is passed as an argument to these +// macros. It must be one of the "low" registers accessible to Thumb code, specified +// using the "l" attribute in the asm statement. +// +// Architecture v7 introduces "Thumb 2", which does include (almost?) all of the ARM +// instruction set. (Actually, there was an extension of v6 called v6T2 which supported +// "Thumb 2" mode, but its architecture manual is no longer available, referring to v7.) +// So in v7 we don't need to change to ARM mode; we can write "universal +// assembler" which will assemble to Thumb 2 or ARM code as appropriate. The only thing +// we need to do to make this "universal" assembler mode work is to insert "IT" instructions +// to annotate the conditional instructions. These are ignored in other modes (e.g. v6), +// so they can always be present. + +// A note about memory_order_consume. Technically, this architecture allows to avoid +// unnecessary memory barrier after consume load since it supports data dependency ordering. +// However, some compiler optimizations may break a seemingly valid code relying on data +// dependency tracking by injecting bogus branches to aid out of order execution. +// This may happen not only in Boost.Atomic code but also in user's code, which we have no +// control of. See this thread: http://lists.boost.org/Archives/boost/2014/06/213890.php. +// For this reason we promote memory_order_consume to memory_order_acquire. + +#if defined(__thumb__) && !defined(__thumb2__) +#define BOOST_ATOMIC_DETAIL_ARM_ASM_START(TMPREG) "adr " #TMPREG ", 8f\n" "bx " #TMPREG "\n" ".arm\n" ".align 4\n" "8:\n" +#define BOOST_ATOMIC_DETAIL_ARM_ASM_END(TMPREG) "adr " #TMPREG ", 9f + 1\n" "bx " #TMPREG "\n" ".thumb\n" ".align 2\n" "9:\n" +#define BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(var) "=&l" (var) +#else +// The tmpreg may be wasted in this case, which is non-optimal. +#define BOOST_ATOMIC_DETAIL_ARM_ASM_START(TMPREG) +#define BOOST_ATOMIC_DETAIL_ARM_ASM_END(TMPREG) +#define BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(var) "=&r" (var) +#endif + +struct gcc_arm_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + hardware_full_fence(); + } + + static BOOST_FORCEINLINE void fence_after(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + hardware_full_fence(); + } + + static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + hardware_full_fence(); + } + + static BOOST_FORCEINLINE void hardware_full_fence() BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_DMB) + // Older binutils (supposedly, older than 2.21.1) didn't support symbolic or numeric arguments of the "dmb" instruction such as "ish" or "#11". + // As a workaround we have to inject encoded bytes of the instruction. There are two encodings for the instruction: ARM and Thumb. See ARM Architecture Reference Manual, A8.8.43. + // Since we cannot detect binutils version at compile time, we'll have to always use this hack. + __asm__ __volatile__ + ( +#if defined(__thumb2__) + ".short 0xF3BF, 0x8F5B\n" // dmb ish +#else + ".word 0xF57FF05B\n" // dmb ish +#endif + : + : + : "memory" + ); +#else + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "mcr\tp15, 0, r0, c7, c10, 5\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : "=&l" (tmp) + : + : "memory" + ); +#endif + } +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_COMMON_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_gcc_atomic.hpp b/boost/atomic/detail/ops_gcc_atomic.hpp new file mode 100644 index 0000000..ce40e3b --- /dev/null +++ b/boost/atomic/detail/ops_gcc_atomic.hpp @@ -0,0 +1,392 @@ +/* + * 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) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_atomic.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_ATOMIC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_ATOMIC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#if (defined(__clang__) || (defined(BOOST_GCC) && (BOOST_GCC+0) >= 70000)) && (defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B)) +#include +#include +#endif + +#if __GCC_ATOMIC_LLONG_LOCK_FREE != BOOST_ATOMIC_LLONG_LOCK_FREE || __GCC_ATOMIC_LONG_LOCK_FREE != BOOST_ATOMIC_LONG_LOCK_FREE ||\ + __GCC_ATOMIC_INT_LOCK_FREE != BOOST_ATOMIC_INT_LOCK_FREE || __GCC_ATOMIC_SHORT_LOCK_FREE != BOOST_ATOMIC_SHORT_LOCK_FREE ||\ + __GCC_ATOMIC_CHAR_LOCK_FREE != BOOST_ATOMIC_CHAR_LOCK_FREE || __GCC_ATOMIC_BOOL_LOCK_FREE != BOOST_ATOMIC_BOOL_LOCK_FREE ||\ + __GCC_ATOMIC_WCHAR_T_LOCK_FREE != BOOST_ATOMIC_WCHAR_T_LOCK_FREE +// There are platforms where we need to use larger storage types +#include +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__INTEL_COMPILER) +// This is used to suppress warning #32013 described below for Intel Compiler. +// In debug builds the compiler does not inline any functions, so basically +// every atomic function call results in this warning. I don't know any other +// way to selectively disable just this one warning. +#pragma system_header +#endif + +namespace boost { +namespace atomics { +namespace detail { + +/*! + * The function converts \c boost::memory_order values to the compiler-specific constants. + * + * NOTE: The intention is that the function is optimized away by the compiler, and the + * compiler-specific constants are passed to the intrinsics. Unfortunately, constexpr doesn't + * work in this case because the standard atomics interface require memory ordering + * constants to be passed as function arguments, at which point they stop being constexpr. + * However, it is crucial that the compiler sees constants and not runtime values, + * because otherwise it just ignores the ordering value and always uses seq_cst. + * This is the case with Intel C++ Compiler 14.0.3 (Composer XE 2013 SP1, update 3) and + * gcc 4.8.2. Intel Compiler issues a warning in this case: + * + * warning #32013: Invalid memory order specified. Defaulting to seq_cst memory order. + * + * while gcc acts silently. + * + * To mitigate the problem ALL functions, including the atomic<> members must be + * declared with BOOST_FORCEINLINE. In this case the compilers are able to see that + * all functions are called with constant orderings and call intrinstcts properly. + * + * Unfortunately, this still doesn't work in debug mode as the compiler doesn't + * propagate constants even when functions are marked with BOOST_FORCEINLINE. In this case + * all atomic operaions will be executed with seq_cst semantics. + */ +BOOST_FORCEINLINE BOOST_CONSTEXPR int convert_memory_order_to_gcc(memory_order order) BOOST_NOEXCEPT +{ + return (order == memory_order_relaxed ? __ATOMIC_RELAXED : (order == memory_order_consume ? __ATOMIC_CONSUME : + (order == memory_order_acquire ? __ATOMIC_ACQUIRE : (order == memory_order_release ? __ATOMIC_RELEASE : + (order == memory_order_acq_rel ? __ATOMIC_ACQ_REL : __ATOMIC_SEQ_CST))))); +} + +template< std::size_t Size, bool Signed > +struct gcc_atomic_operations +{ + typedef typename make_storage_type< Size >::type storage_type; + typedef typename make_storage_type< Size >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + + // Note: In the current implementation, gcc_atomic_operations are used only when the particularly sized __atomic + // intrinsics are always lock-free (i.e. the corresponding LOCK_FREE macro is 2). Therefore it is safe to + // always set is_always_lock_free to true here. + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + __atomic_store_n(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return __atomic_load_n(&storage, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return __atomic_fetch_add(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return __atomic_fetch_sub(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return __atomic_exchange_n(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return __atomic_compare_exchange_n + ( + &storage, &expected, desired, false, + atomics::detail::convert_memory_order_to_gcc(success_order), + atomics::detail::convert_memory_order_to_gcc(failure_order) + ); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return __atomic_compare_exchange_n + ( + &storage, &expected, desired, true, + atomics::detail::convert_memory_order_to_gcc(success_order), + atomics::detail::convert_memory_order_to_gcc(failure_order) + ); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return __atomic_fetch_and(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return __atomic_fetch_or(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return __atomic_fetch_xor(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return __atomic_test_and_set(&storage, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + __atomic_clear(const_cast< storage_type* >(&storage), atomics::detail::convert_memory_order_to_gcc(order)); + } +}; + +#if BOOST_ATOMIC_INT128_LOCK_FREE > 0 +#if (defined(__clang__) || (defined(BOOST_GCC) && (BOOST_GCC+0) >= 70000)) && defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +// Workaround for clang bug: http://llvm.org/bugs/show_bug.cgi?id=19149 +// Clang 3.4 does not implement 128-bit __atomic* intrinsics even though it defines __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 +// A similar problem exists with gcc 7 as well, as it requires to link with libatomic to use 16-byte intrinsics: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80878 +template< bool Signed > +struct operations< 16u, Signed > : + public cas_based_operations< gcc_dcas_x86_64< Signed > > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 16u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; +}; + +#else + +template< bool Signed > +struct operations< 16u, Signed > : + public gcc_atomic_operations< 16u, Signed > +{ +}; + +#endif +#endif + + +#if BOOST_ATOMIC_INT64_LOCK_FREE > 0 +#if defined(__clang__) && defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) + +// Workaround for clang bug http://llvm.org/bugs/show_bug.cgi?id=19355 +template< bool Signed > +struct operations< 8u, Signed > : + public cas_based_operations< gcc_dcas_x86< Signed > > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; +}; + +#elif (BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 8 && __GCC_ATOMIC_LLONG_LOCK_FREE != BOOST_ATOMIC_LLONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 8 && __GCC_ATOMIC_LONG_LOCK_FREE != BOOST_ATOMIC_LONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_INT == 8 && __GCC_ATOMIC_INT_LOCK_FREE != BOOST_ATOMIC_INT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 8 && __GCC_ATOMIC_SHORT_LOCK_FREE != BOOST_ATOMIC_SHORT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 8 && __GCC_ATOMIC_WCHAR_T_LOCK_FREE != BOOST_ATOMIC_WCHAR_T_LOCK_FREE) + +#define BOOST_ATOMIC_DETAIL_INT64_EXTENDED + +template< bool Signed > +struct operations< 8u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed >, 8u, Signed > +{ +}; + +#else + +template< bool Signed > +struct operations< 8u, Signed > : + public gcc_atomic_operations< 8u, Signed > +{ +}; + +#endif +#endif + +#if BOOST_ATOMIC_INT32_LOCK_FREE > 0 +#if (BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 4 && __GCC_ATOMIC_LLONG_LOCK_FREE != BOOST_ATOMIC_LLONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 4 && __GCC_ATOMIC_LONG_LOCK_FREE != BOOST_ATOMIC_LONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_INT == 4 && __GCC_ATOMIC_INT_LOCK_FREE != BOOST_ATOMIC_INT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 4 && __GCC_ATOMIC_SHORT_LOCK_FREE != BOOST_ATOMIC_SHORT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 4 && __GCC_ATOMIC_WCHAR_T_LOCK_FREE != BOOST_ATOMIC_WCHAR_T_LOCK_FREE) + +#define BOOST_ATOMIC_DETAIL_INT32_EXTENDED + +#if !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) + +template< bool Signed > +struct operations< 4u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 8u, Signed >, 4u, Signed > +{ +}; + +#else // !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) + +template< bool Signed > +struct operations< 4u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed >, 4u, Signed > +{ +}; + +#endif // !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) + +#else + +template< bool Signed > +struct operations< 4u, Signed > : + public gcc_atomic_operations< 4u, Signed > +{ +}; + +#endif +#endif + +#if BOOST_ATOMIC_INT16_LOCK_FREE > 0 +#if (BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 2 && __GCC_ATOMIC_LLONG_LOCK_FREE != BOOST_ATOMIC_LLONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 2 && __GCC_ATOMIC_LONG_LOCK_FREE != BOOST_ATOMIC_LONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_INT == 2 && __GCC_ATOMIC_INT_LOCK_FREE != BOOST_ATOMIC_INT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 2 && __GCC_ATOMIC_SHORT_LOCK_FREE != BOOST_ATOMIC_SHORT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 2 && __GCC_ATOMIC_WCHAR_T_LOCK_FREE != BOOST_ATOMIC_WCHAR_T_LOCK_FREE) + +#define BOOST_ATOMIC_DETAIL_INT16_EXTENDED + +#if !defined(BOOST_ATOMIC_DETAIL_INT32_EXTENDED) + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 4u, Signed >, 2u, Signed > +{ +}; + +#elif !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 8u, Signed >, 2u, Signed > +{ +}; + +#else + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed >, 2u, Signed > +{ +}; + +#endif + +#else + +template< bool Signed > +struct operations< 2u, Signed > : + public gcc_atomic_operations< 2u, Signed > +{ +}; + +#endif +#endif + +#if BOOST_ATOMIC_INT8_LOCK_FREE > 0 +#if (BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 1 && __GCC_ATOMIC_LLONG_LOCK_FREE != BOOST_ATOMIC_LLONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 1 && __GCC_ATOMIC_LONG_LOCK_FREE != BOOST_ATOMIC_LONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_INT == 1 && __GCC_ATOMIC_INT_LOCK_FREE != BOOST_ATOMIC_INT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 1 && __GCC_ATOMIC_SHORT_LOCK_FREE != BOOST_ATOMIC_SHORT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 1 && __GCC_ATOMIC_WCHAR_T_LOCK_FREE != BOOST_ATOMIC_WCHAR_T_LOCK_FREE) ||\ + (__GCC_ATOMIC_CHAR_LOCK_FREE != BOOST_ATOMIC_CHAR_LOCK_FREE) ||\ + (__GCC_ATOMIC_BOOL_LOCK_FREE != BOOST_ATOMIC_BOOL_LOCK_FREE) + +#if !defined(BOOST_ATOMIC_DETAIL_INT16_EXTENDED) + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 2u, Signed >, 1u, Signed > +{ +}; + +#elif !defined(BOOST_ATOMIC_DETAIL_INT32_EXTENDED) + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 4u, Signed >, 1u, Signed > +{ +}; + +#elif !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 8u, Signed >, 1u, Signed > +{ +}; + +#else + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed >, 1u, Signed > +{ +}; + +#endif + +#else + +template< bool Signed > +struct operations< 1u, Signed > : + public gcc_atomic_operations< 1u, Signed > +{ +}; + +#endif +#endif + +#undef BOOST_ATOMIC_DETAIL_INT16_EXTENDED +#undef BOOST_ATOMIC_DETAIL_INT32_EXTENDED +#undef BOOST_ATOMIC_DETAIL_INT64_EXTENDED + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + __atomic_thread_fence(atomics::detail::convert_memory_order_to_gcc(order)); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + __atomic_signal_fence(atomics::detail::convert_memory_order_to_gcc(order)); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_ATOMIC_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_gcc_ppc.hpp b/boost/atomic/detail/ops_gcc_ppc.hpp new file mode 100644 index 0000000..a826736 --- /dev/null +++ b/boost/atomic/detail/ops_gcc_ppc.hpp @@ -0,0 +1,1232 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_ppc.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +// The implementation below uses information from this document: +// http://www.rdrop.com/users/paulmck/scalability/paper/N2745r.2010.02.19a.html + +/* + Refer to: Motorola: "Programming Environments Manual for 32-Bit + Implementations of the PowerPC Architecture", Appendix E: + "Synchronization Programming Examples" for an explanation of what is + going on here (can be found on the web at various places by the + name "MPCFPE32B.pdf", Google is your friend...) + + Most of the atomic operations map to instructions in a relatively + straight-forward fashion, but "load"s may at first glance appear + a bit strange as they map to: + + lwz %rX, addr + cmpw %rX, %rX + bne- 1f + 1: + + That is, the CPU is forced to perform a branch that "formally" depends + on the value retrieved from memory. This scheme has an overhead of + about 1-2 clock cycles per load, but it allows to map "acquire" to + the "isync" instruction instead of "sync" uniformly and for all type + of atomic operations. Since "isync" has a cost of about 15 clock + cycles, while "sync" hast a cost of about 50 clock cycles, the small + penalty to atomic loads more than compensates for this. + + Byte- and halfword-sized atomic values are implemented in two ways. + When 8 and 16-bit instructions are available (in Power8 and later), + they are used. Otherwise operations are realized by encoding the + value to be represented into a word, performing sign/zero extension + as appropriate. This means that after add/sub operations the value + needs fixing up to accurately preserve the wrap-around semantic of + the smaller type. (Nothing special needs to be done for the bit-wise + and the "exchange type" operators as the compiler already sees to + it that values carried in registers are extended appropriately and + everything falls into place naturally). + + The register constraint "b" instructs gcc to use any register + except r0; this is sometimes required because the encoding for + r0 is used to signify "constant zero" in a number of instructions, + making r0 unusable in this place. For simplicity this constraint + is used everywhere since I am to lazy to look this up on a + per-instruction basis, and ppc has enough registers for this not + to pose a problem. +*/ + +template< bool Signed > +struct operations< 4u, Signed > : + public gcc_ppc_operations_base +{ + typedef typename make_storage_type< 4u >::type storage_type; + typedef typename make_storage_type< 4u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + __asm__ __volatile__ + ( + "stw %1, %0\n\t" + : "+m" (storage) + : "r" (v) + ); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v; + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("sync" ::: "memory"); + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + { + __asm__ __volatile__ + ( + "lwz %0, %1\n\t" + "cmpw %0, %0\n\t" + "bne- 1f\n\t" + "1:\n\t" + "isync\n\t" + : "=&r" (v) + : "m" (storage) + : "cr0", "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lwz %0, %1\n\t" + : "=&r" (v) + : "m" (storage) + ); + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y1\n\t" + "stwcx. %2,%y1\n\t" + "bne- 1b\n\t" + : "=&b" (original), "+Z" (storage) + : "b" (v) + : "cr0" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "lwarx %0,%y2\n\t" + "cmpw %0, %3\n\t" + "bne- 1f\n\t" + "stwcx. %4,%y2\n\t" + "bne- 1f\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "0: lwarx %0,%y2\n\t" + "cmpw %0, %3\n\t" + "bne- 1f\n\t" + "stwcx. %4,%y2\n\t" + "bne- 0b\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX) + +template< bool Signed > +struct operations< 1u, Signed > : + public gcc_ppc_operations_base +{ + typedef typename make_storage_type< 1u >::type storage_type; + typedef typename make_storage_type< 1u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 1u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + __asm__ __volatile__ + ( + "stb %1, %0\n\t" + : "+m" (storage) + : "r" (v) + ); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v; + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("sync" ::: "memory"); + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + { + __asm__ __volatile__ + ( + "lbz %0, %1\n\t" + "cmpw %0, %0\n\t" + "bne- 1f\n\t" + "1:\n\t" + "isync\n\t" + : "=&r" (v) + : "m" (storage) + : "cr0", "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lbz %0, %1\n\t" + : "=&r" (v) + : "m" (storage) + ); + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y1\n\t" + "stbcx. %2,%y1\n\t" + "bne- 1b\n\t" + : "=&b" (original), "+Z" (storage) + : "b" (v) + : "cr0" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "lbarx %0,%y2\n\t" + "cmpw %0, %3\n\t" + "bne- 1f\n\t" + "stbcx. %4,%y2\n\t" + "bne- 1f\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "0: lbarx %0,%y2\n\t" + "cmpw %0, %3\n\t" + "bne- 1f\n\t" + "stbcx. %4,%y2\n\t" + "bne- 0b\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#else // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX) + +template< > +struct operations< 1u, false > : + public operations< 4u, false > +{ + typedef operations< 4u, false > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "rlwinm %1, %1, 0, 0xff\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "rlwinm %1, %1, 0, 0xff\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +template< > +struct operations< 1u, true > : + public operations< 4u, true > +{ + typedef operations< 4u, true > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "extsb %1, %1\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "extsb %1, %1\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX) + +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX) + +template< bool Signed > +struct operations< 2u, Signed > : + public gcc_ppc_operations_base +{ + typedef typename make_storage_type< 2u >::type storage_type; + typedef typename make_storage_type< 2u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 2u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + __asm__ __volatile__ + ( + "sth %1, %0\n\t" + : "+m" (storage) + : "r" (v) + ); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v; + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("sync" ::: "memory"); + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + { + __asm__ __volatile__ + ( + "lhz %0, %1\n\t" + "cmpw %0, %0\n\t" + "bne- 1f\n\t" + "1:\n\t" + "isync\n\t" + : "=&r" (v) + : "m" (storage) + : "cr0", "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lhz %0, %1\n\t" + : "=&r" (v) + : "m" (storage) + ); + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y1\n\t" + "sthcx. %2,%y1\n\t" + "bne- 1b\n\t" + : "=&b" (original), "+Z" (storage) + : "b" (v) + : "cr0" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "lharx %0,%y2\n\t" + "cmpw %0, %3\n\t" + "bne- 1f\n\t" + "sthcx. %4,%y2\n\t" + "bne- 1f\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "0: lharx %0,%y2\n\t" + "cmpw %0, %3\n\t" + "bne- 1f\n\t" + "sthcx. %4,%y2\n\t" + "bne- 0b\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#else // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX) + +template< > +struct operations< 2u, false > : + public operations< 4u, false > +{ + typedef operations< 4u, false > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "rlwinm %1, %1, 0, 0xffff\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "rlwinm %1, %1, 0, 0xffff\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +template< > +struct operations< 2u, true > : + public operations< 4u, true > +{ + typedef operations< 4u, true > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "extsh %1, %1\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "extsh %1, %1\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX) + +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX) + +template< bool Signed > +struct operations< 8u, Signed > : + public gcc_ppc_operations_base +{ + typedef typename make_storage_type< 8u >::type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + __asm__ __volatile__ + ( + "std %1, %0\n\t" + : "+m" (storage) + : "r" (v) + ); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v; + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("sync" ::: "memory"); + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + { + __asm__ __volatile__ + ( + "ld %0, %1\n\t" + "cmpd %0, %0\n\t" + "bne- 1f\n\t" + "1:\n\t" + "isync\n\t" + : "=&b" (v) + : "m" (storage) + : "cr0", "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "ld %0, %1\n\t" + : "=&b" (v) + : "m" (storage) + ); + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y1\n\t" + "stdcx. %2,%y1\n\t" + "bne- 1b\n\t" + : "=&b" (original), "+Z" (storage) + : "b" (v) + : "cr0" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "ldarx %0,%y2\n\t" + "cmpd %0, %3\n\t" + "bne- 1f\n\t" + "stdcx. %4,%y2\n\t" + "bne- 1f\n\t" + "li %1, 1\n\t" + "1:" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "0: ldarx %0,%y2\n\t" + "cmpd %0, %3\n\t" + "bne- 1f\n\t" + "stdcx. %4,%y2\n\t" + "bne- 0b\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX) + + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + { +#if defined(__powerpc64__) || defined(__PPC64__) + if (order != memory_order_seq_cst) + __asm__ __volatile__ ("lwsync" ::: "memory"); + else + __asm__ __volatile__ ("sync" ::: "memory"); +#else + __asm__ __volatile__ ("sync" ::: "memory"); +#endif + } +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) +#if defined(__ibmxl__) || defined(__IBMCPP__) + __fence(); +#else + __asm__ __volatile__ ("" ::: "memory"); +#endif +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_gcc_ppc_common.hpp b/boost/atomic/detail/ops_gcc_ppc_common.hpp new file mode 100644 index 0000000..e5c9303 --- /dev/null +++ b/boost/atomic/detail/ops_gcc_ppc_common.hpp @@ -0,0 +1,70 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_ppc_common.hpp + * + * This header contains basic utilities for gcc PowerPC backend. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_COMMON_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_COMMON_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +// The implementation below uses information from this document: +// http://www.rdrop.com/users/paulmck/scalability/paper/N2745r.2010.02.19a.html + +// A note about memory_order_consume. Technically, this architecture allows to avoid +// unnecessary memory barrier after consume load since it supports data dependency ordering. +// However, some compiler optimizations may break a seemingly valid code relying on data +// dependency tracking by injecting bogus branches to aid out of order execution. +// This may happen not only in Boost.Atomic code but also in user's code, which we have no +// control of. See this thread: http://lists.boost.org/Archives/boost/2014/06/213890.php. +// For this reason we promote memory_order_consume to memory_order_acquire. + +struct gcc_ppc_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before(memory_order order) BOOST_NOEXCEPT + { +#if defined(__powerpc64__) || defined(__PPC64__) + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("sync" ::: "memory"); + else if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __asm__ __volatile__ ("lwsync" ::: "memory"); +#else + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __asm__ __volatile__ ("sync" ::: "memory"); +#endif + } + + static BOOST_FORCEINLINE void fence_after(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + __asm__ __volatile__ ("isync" ::: "memory"); + } +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_COMMON_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_gcc_sparc.hpp b/boost/atomic/detail/ops_gcc_sparc.hpp new file mode 100644 index 0000000..19b9b1f --- /dev/null +++ b/boost/atomic/detail/ops_gcc_sparc.hpp @@ -0,0 +1,240 @@ +/* + * 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) + * + * Copyright (c) 2010 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_sparc.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_SPARC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_SPARC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +struct gcc_sparc_cas_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("membar #Sync" ::: "memory"); + else if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __asm__ __volatile__ ("membar #StoreStore | #LoadStore" ::: "memory"); + } + + static BOOST_FORCEINLINE void fence_after(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("membar #Sync" ::: "memory"); + else if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + __asm__ __volatile__ ("membar #StoreStore | #LoadStore" ::: "memory"); + } + + static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("membar #Sync" ::: "memory"); + } +}; + +template< bool Signed > +struct gcc_sparc_cas32 : + public gcc_sparc_cas_base +{ + typedef typename make_storage_type< 4u >::type storage_type; + typedef typename make_storage_type< 4u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + storage_type previous = expected; + __asm__ __volatile__ + ( + "cas [%1], %2, %0" + : "+r" (desired) + : "r" (&storage), "r" (previous) + : "memory" + ); + const bool success = (desired == previous); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = desired; + return success; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + __asm__ __volatile__ + ( + "swap [%1], %0" + : "+r" (v) + : "r" (&storage) + : "memory" + ); + fence_after(order); + return v; + } +}; + +template< bool Signed > +struct operations< 4u, Signed > : + public cas_based_operations< gcc_sparc_cas32< Signed > > +{ +}; + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< operations< 4u, Signed >, 1u, Signed > +{ +}; + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< operations< 4u, Signed >, 2u, Signed > +{ +}; + +template< bool Signed > +struct gcc_sparc_cas64 : + public gcc_sparc_cas_base +{ + typedef typename make_storage_type< 8u >::type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + storage_type previous = expected; + __asm__ __volatile__ + ( + "casx [%1], %2, %0" + : "+r" (desired) + : "r" (&storage), "r" (previous) + : "memory" + ); + const bool success = (desired == previous); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = desired; + return success; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } +}; + +template< bool Signed > +struct operations< 8u, Signed > : + public cas_based_operations< cas_based_exchange< gcc_sparc_cas64< Signed > > > +{ +}; + + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + switch (order) + { + case memory_order_release: + __asm__ __volatile__ ("membar #StoreStore | #LoadStore" ::: "memory"); + break; + case memory_order_consume: + case memory_order_acquire: + __asm__ __volatile__ ("membar #LoadLoad | #LoadStore" ::: "memory"); + break; + case memory_order_acq_rel: + __asm__ __volatile__ ("membar #LoadLoad | #LoadStore | #StoreStore" ::: "memory"); + break; + case memory_order_seq_cst: + __asm__ __volatile__ ("membar #Sync" ::: "memory"); + break; + case memory_order_relaxed: + default: + break; + } +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("" ::: "memory"); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_SPARC_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_gcc_sync.hpp b/boost/atomic/detail/ops_gcc_sync.hpp new file mode 100644 index 0000000..1597de8 --- /dev/null +++ b/boost/atomic/detail/ops_gcc_sync.hpp @@ -0,0 +1,240 @@ +/* + * 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) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_sync.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_SYNC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_SYNC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +struct gcc_sync_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before_store(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __sync_synchronize(); + } + + static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + __sync_synchronize(); + } + + static BOOST_FORCEINLINE void fence_after_load(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_acquire) | static_cast< unsigned int >(memory_order_consume))) != 0u) + __sync_synchronize(); + } +}; + +template< std::size_t Size, bool Signed > +struct gcc_sync_operations : + public gcc_sync_operations_base +{ + typedef typename make_storage_type< Size >::type storage_type; + typedef typename make_storage_type< Size >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before_store(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return __sync_fetch_and_add(&storage, v); + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return __sync_fetch_and_sub(&storage, v); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + // GCC docs mention that not all architectures may support full exchange semantics for this intrinsic. However, GCC's implementation of + // std::atomic<> uses this intrinsic unconditionally. We do so as well. In case if some architectures actually don't support this, we can always + // add a check here and fall back to a CAS loop. + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __sync_synchronize(); + return __sync_lock_test_and_set(&storage, v); + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type expected2 = expected; + storage_type old_val = __sync_val_compare_and_swap(&storage, expected2, desired); + + if (old_val == expected2) + { + return true; + } + else + { + expected = old_val; + return false; + } + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return __sync_fetch_and_and(&storage, v); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return __sync_fetch_and_or(&storage, v); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return __sync_fetch_and_xor(&storage, v); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __sync_synchronize(); + return !!__sync_lock_test_and_set(&storage, 1); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + __sync_lock_release(&storage); + if (order == memory_order_seq_cst) + __sync_synchronize(); + } +}; + +#if BOOST_ATOMIC_INT8_LOCK_FREE > 0 +template< bool Signed > +struct operations< 1u, Signed > : +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) + public gcc_sync_operations< 1u, Signed > +#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) + public extending_cas_based_operations< gcc_sync_operations< 2u, Signed >, 1u, Signed > +#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) + public extending_cas_based_operations< gcc_sync_operations< 4u, Signed >, 1u, Signed > +#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) + public extending_cas_based_operations< gcc_sync_operations< 8u, Signed >, 1u, Signed > +#else + public extending_cas_based_operations< gcc_sync_operations< 16u, Signed >, 1u, Signed > +#endif +{ +}; +#endif + +#if BOOST_ATOMIC_INT16_LOCK_FREE > 0 +template< bool Signed > +struct operations< 2u, Signed > : +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) + public gcc_sync_operations< 2u, Signed > +#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) + public extending_cas_based_operations< gcc_sync_operations< 4u, Signed >, 2u, Signed > +#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) + public extending_cas_based_operations< gcc_sync_operations< 8u, Signed >, 2u, Signed > +#else + public extending_cas_based_operations< gcc_sync_operations< 16u, Signed >, 2u, Signed > +#endif +{ +}; +#endif + +#if BOOST_ATOMIC_INT32_LOCK_FREE > 0 +template< bool Signed > +struct operations< 4u, Signed > : +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) + public gcc_sync_operations< 4u, Signed > +#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) + public extending_cas_based_operations< gcc_sync_operations< 8u, Signed >, 4u, Signed > +#else + public extending_cas_based_operations< gcc_sync_operations< 16u, Signed >, 4u, Signed > +#endif +{ +}; +#endif + +#if BOOST_ATOMIC_INT64_LOCK_FREE > 0 +template< bool Signed > +struct operations< 8u, Signed > : +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) + public gcc_sync_operations< 8u, Signed > +#else + public extending_cas_based_operations< gcc_sync_operations< 16u, Signed >, 8u, Signed > +#endif +{ +}; +#endif + +#if BOOST_ATOMIC_INT128_LOCK_FREE > 0 +template< bool Signed > +struct operations< 16u, Signed > : + public gcc_sync_operations< 16u, Signed > +{ +}; +#endif + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __sync_synchronize(); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("" ::: "memory"); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_SYNC_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_gcc_x86.hpp b/boost/atomic/detail/ops_gcc_x86.hpp new file mode 100644 index 0000000..007d4ee --- /dev/null +++ b/boost/atomic/detail/ops_gcc_x86.hpp @@ -0,0 +1,563 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_x86.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_X86_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) +#include +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +struct gcc_x86_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __asm__ __volatile__ ("" ::: "memory"); + } + + static BOOST_FORCEINLINE void fence_after(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + __asm__ __volatile__ ("" ::: "memory"); + } +}; + +template< std::size_t Size, bool Signed, typename Derived > +struct gcc_x86_operations : + public gcc_x86_operations_base +{ + typedef typename make_storage_type< Size >::type storage_type; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + if (order != memory_order_seq_cst) + { + fence_before(order); + storage = v; + fence_after(order); + } + else + { + Derived::exchange(storage, v, order); + } + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return Derived::fetch_add(storage, -v, order); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return Derived::compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!Derived::exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, (storage_type)0, order); + } +}; + +template< bool Signed > +struct operations< 1u, Signed > : + public gcc_x86_operations< 1u, Signed, operations< 1u, Signed > > +{ + typedef gcc_x86_operations< 1u, Signed, operations< 1u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 1u >::aligned aligned_storage_type; + typedef typename make_storage_type< 4u >::type temp_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 1u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xaddb %0, %1" + : "+q" (v), "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "xchgb %0, %1" + : "+q" (v), "+m" (storage) + : + : "memory" + ); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + bool success; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgb %3, %1" + : "+a" (previous), "+m" (storage), "=@ccz" (success) + : "q" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgb %3, %1\n\t" + "sete %2" + : "+a" (previous), "+m" (storage), "=q" (success) + : "q" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + expected = previous; + return success; + } + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, result)\ + temp_storage_type new_val;\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %2\n\t"\ + op " %%al, %b2\n\t"\ + "lock; cmpxchgb %b2, %[storage]\n\t"\ + "jne 1b"\ + : [res] "+a" (result), [storage] "+m" (storage), "=&q" (new_val)\ + : [arg] "ir" ((temp_storage_type)argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andb", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orb", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorb", v, res); + return res; + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP +}; + +template< bool Signed > +struct operations< 2u, Signed > : + public gcc_x86_operations< 2u, Signed, operations< 2u, Signed > > +{ + typedef gcc_x86_operations< 2u, Signed, operations< 2u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 2u >::aligned aligned_storage_type; + typedef typename make_storage_type< 4u >::type temp_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 2u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xaddw %0, %1" + : "+q" (v), "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "xchgw %0, %1" + : "+q" (v), "+m" (storage) + : + : "memory" + ); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + bool success; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgw %3, %1" + : "+a" (previous), "+m" (storage), "=@ccz" (success) + : "q" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgw %3, %1\n\t" + "sete %2" + : "+a" (previous), "+m" (storage), "=q" (success) + : "q" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + expected = previous; + return success; + } + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, result)\ + temp_storage_type new_val;\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %2\n\t"\ + op " %%ax, %w2\n\t"\ + "lock; cmpxchgw %w2, %[storage]\n\t"\ + "jne 1b"\ + : [res] "+a" (result), [storage] "+m" (storage), "=&q" (new_val)\ + : [arg] "ir" ((temp_storage_type)argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andw", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orw", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorw", v, res); + return res; + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP +}; + +template< bool Signed > +struct operations< 4u, Signed > : + public gcc_x86_operations< 4u, Signed, operations< 4u, Signed > > +{ + typedef gcc_x86_operations< 4u, Signed, operations< 4u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 4u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xaddl %0, %1" + : "+r" (v), "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "xchgl %0, %1" + : "+r" (v), "+m" (storage) + : + : "memory" + ); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + bool success; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgl %3, %1" + : "+a" (previous), "+m" (storage), "=@ccz" (success) + : "r" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgl %3, %1\n\t" + "sete %2" + : "+a" (previous), "+m" (storage), "=q" (success) + : "r" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + expected = previous; + return success; + } + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, result)\ + storage_type new_val;\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %[new_val]\n\t"\ + op " %%eax, %[new_val]\n\t"\ + "lock; cmpxchgl %[new_val], %[storage]\n\t"\ + "jne 1b"\ + : [res] "+a" (result), [storage] "+m" (storage), [new_val] "=&r" (new_val)\ + : [arg] "ir" (argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andl", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orl", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorl", v, res); + return res; + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP +}; + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) + +template< bool Signed > +struct operations< 8u, Signed > : + public cas_based_operations< gcc_dcas_x86< Signed > > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; +}; + +#elif defined(__x86_64__) + +template< bool Signed > +struct operations< 8u, Signed > : + public gcc_x86_operations< 8u, Signed, operations< 8u, Signed > > +{ + typedef gcc_x86_operations< 8u, Signed, operations< 8u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xaddq %0, %1" + : "+r" (v), "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "xchgq %0, %1" + : "+r" (v), "+m" (storage) + : + : "memory" + ); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + bool success; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgq %3, %1" + : "+a" (previous), "+m" (storage), "=@ccz" (success) + : "r" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgq %3, %1\n\t" + "sete %2" + : "+a" (previous), "+m" (storage), "=q" (success) + : "r" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + expected = previous; + return success; + } + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, result)\ + storage_type new_val;\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: movq %[arg], %[new_val]\n\t"\ + op " %%rax, %[new_val]\n\t"\ + "lock; cmpxchgq %[new_val], %[storage]\n\t"\ + "jne 1b"\ + : [res] "+a" (result), [storage] "+m" (storage), [new_val] "=&r" (new_val)\ + : [arg] "r" (argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andq", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orq", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorq", v, res); + return res; + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP +}; + +#endif + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +template< bool Signed > +struct operations< 16u, Signed > : + public cas_based_operations< gcc_dcas_x86_64< Signed > > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 16u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order == memory_order_seq_cst) + { + __asm__ __volatile__ + ( +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_MFENCE) + "mfence\n" +#else + "lock; addl $0, (%%esp)\n" +#endif + ::: "memory" + ); + } + else if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_acquire) | static_cast< unsigned int >(memory_order_release))) != 0u) + { + __asm__ __volatile__ ("" ::: "memory"); + } +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("" ::: "memory"); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_X86_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_gcc_x86_dcas.hpp b/boost/atomic/detail/ops_gcc_x86_dcas.hpp new file mode 100644 index 0000000..4206bb3 --- /dev/null +++ b/boost/atomic/detail/ops_gcc_x86_dcas.hpp @@ -0,0 +1,556 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2014 - 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_x86_dcas.hpp + * + * This header contains implementation of the double-width CAS primitive for x86. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_X86_DCAS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_X86_DCAS_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +// Note: In the 32-bit PIC code guarded with BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX below we have to avoid using memory +// operand constraints because the compiler may choose to use ebx as the base register for that operand. At least, clang +// is known to do that. For this reason we have to pre-compute a pointer to storage and pass it in edi. For the same reason +// we cannot save ebx to the stack with a mov instruction, so we use esi as a scratch register and restore it afterwards. +// Alternatively, we could push/pop the register to the stack, but exchanging the registers is faster. +// The need to pass a pointer in edi is a bit wasteful because normally the memory operand would use a base pointer +// with an offset (e.g. `this` + offset). But unfortunately, there seems to be no way around it. + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) + +template< bool Signed > +struct gcc_dcas_x86 +{ + typedef typename make_storage_type< 8u >::type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + typedef uint32_t BOOST_ATOMIC_DETAIL_MAY_ALIAS aliasing_uint32_t; + + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_LIKELY((((uint32_t)&storage) & 0x00000007) == 0u)) + { +#if defined(__SSE__) + typedef float xmm_t __attribute__((__vector_size__(16))); + xmm_t xmm_scratch; + __asm__ __volatile__ + ( +#if defined(__AVX__) + "vmovq %[value], %[xmm_scratch]\n\t" + "vmovq %[xmm_scratch], %[storage]\n\t" +#elif defined(__SSE2__) + "movq %[value], %[xmm_scratch]\n\t" + "movq %[xmm_scratch], %[storage]\n\t" +#else + "xorps %[xmm_scratch], %[xmm_scratch]\n\t" + "movlps %[value], %[xmm_scratch]\n\t" + "movlps %[xmm_scratch], %[storage]\n\t" +#endif + : [storage] "=m" (storage), [xmm_scratch] "=x" (xmm_scratch) + : [value] "m" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "fildll %[value]\n\t" + "fistpll %[storage]\n\t" + : [storage] "=m" (storage) + : [value] "m" (v) + : "memory" + ); +#endif + } + else + { +#if defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + __asm__ __volatile__ + ( + "xchgl %%ebx, %%esi\n\t" + "movl %%eax, %%ebx\n\t" + "movl (%[dest]), %%eax\n\t" + "movl 4(%[dest]), %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b (%[dest])\n\t" + "jne 1b\n\t" + "xchgl %%ebx, %%esi\n\t" + : + : "a" ((uint32_t)v), "c" ((uint32_t)(v >> 32)), [dest] "D" (&storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "edx", "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + __asm__ __volatile__ + ( + "movl %[dest_lo], %%eax\n\t" + "movl %[dest_hi], %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b %[dest_lo]\n\t" + "jne 1b\n\t" + : [dest_lo] "=m" (storage), [dest_hi] "=m" (reinterpret_cast< volatile aliasing_uint32_t* >(&storage)[1]) + : [value_lo] "b" ((uint32_t)v), "c" ((uint32_t)(v >> 32)) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "eax", "edx", "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + } + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type value; + + if (BOOST_LIKELY((((uint32_t)&storage) & 0x00000007) == 0u)) + { +#if defined(__SSE__) + typedef float xmm_t __attribute__((__vector_size__(16))); + xmm_t xmm_scratch; + __asm__ __volatile__ + ( +#if defined(__AVX__) + "vmovq %[storage], %[xmm_scratch]\n\t" + "vmovq %[xmm_scratch], %[value]\n\t" +#elif defined(__SSE2__) + "movq %[storage], %[xmm_scratch]\n\t" + "movq %[xmm_scratch], %[value]\n\t" +#else + "xorps %[xmm_scratch], %[xmm_scratch]\n\t" + "movlps %[storage], %[xmm_scratch]\n\t" + "movlps %[xmm_scratch], %[value]\n\t" +#endif + : [value] "=m" (value), [xmm_scratch] "=x" (xmm_scratch) + : [storage] "m" (storage) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "fildll %[storage]\n\t" + "fistpll %[value]\n\t" + : [value] "=m" (value) + : [storage] "m" (storage) + : "memory" + ); +#endif + } + else + { + // Note that despite const qualification cmpxchg8b below may issue a store to the storage. The storage value + // will not change, but this prevents the storage to reside in read-only memory. + +#if defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + uint32_t value_bits[2]; + + // We don't care for comparison result here; the previous value will be stored into value anyway. + // Also we don't care for ebx and ecx values, they just have to be equal to eax and edx before cmpxchg8b. + __asm__ __volatile__ + ( + "movl %%ebx, %%eax\n\t" + "movl %%ecx, %%edx\n\t" + "lock; cmpxchg8b %[storage]\n\t" + : "=&a" (value_bits[0]), "=&d" (value_bits[1]) + : [storage] "m" (storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + BOOST_ATOMIC_DETAIL_MEMCPY(&value, value_bits, sizeof(value)); + +#else // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + // We don't care for comparison result here; the previous value will be stored into value anyway. + // Also we don't care for ebx and ecx values, they just have to be equal to eax and edx before cmpxchg8b. + __asm__ __volatile__ + ( + "movl %%ebx, %%eax\n\t" + "movl %%ecx, %%edx\n\t" + "lock; cmpxchg8b %[storage]\n\t" + : "=&A" (value) + : [storage] "m" (storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + } + + return value; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { +#if defined(__clang__) + + // Clang cannot allocate eax:edx register pairs but it has sync intrinsics + storage_type old_expected = expected; + expected = __sync_val_compare_and_swap(&storage, old_expected, desired); + return expected == old_expected; + +#elif defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + + bool success; + +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "xchgl %%ebx, %%esi\n\t" + "lock; cmpxchg8b (%[dest])\n\t" + "xchgl %%ebx, %%esi\n\t" + : "+A" (expected), [success] "=@ccz" (success) + : "S" ((uint32_t)desired), "c" ((uint32_t)(desired >> 32)), [dest] "D" (&storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "xchgl %%ebx, %%esi\n\t" + "lock; cmpxchg8b (%[dest])\n\t" + "xchgl %%ebx, %%esi\n\t" + "sete %[success]\n\t" + : "+A" (expected), [success] "=qm" (success) + : "S" ((uint32_t)desired), "c" ((uint32_t)(desired >> 32)), [dest] "D" (&storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + + return success; + +#else // defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + + bool success; + +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchg8b %[dest]\n\t" + : "+A" (expected), [dest] "+m" (storage), [success] "=@ccz" (success) + : "b" ((uint32_t)desired), "c" ((uint32_t)(desired >> 32)) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchg8b %[dest]\n\t" + "sete %[success]\n\t" + : "+A" (expected), [dest] "+m" (storage), [success] "=qm" (success) + : "b" ((uint32_t)desired), "c" ((uint32_t)(desired >> 32)) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + + return success; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) +#if defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + uint32_t old_bits[2]; + __asm__ __volatile__ + ( + "xchgl %%ebx, %%esi\n\t" + "movl (%[dest]), %%eax\n\t" + "movl 4(%[dest]), %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b (%[dest])\n\t" + "jne 1b\n\t" + "xchgl %%ebx, %%esi\n\t" + : "=a" (old_bits[0]), "=d" (old_bits[1]) + : "S" ((uint32_t)v), "c" ((uint32_t)(v >> 32)), [dest] "D" (&storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + storage_type old_value; + BOOST_ATOMIC_DETAIL_MEMCPY(&old_value, old_bits, sizeof(old_value)); + return old_value; + +#else // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + storage_type old_value; + __asm__ __volatile__ + ( + "xchgl %%ebx, %%esi\n\t" + "movl (%[dest]), %%eax\n\t" + "movl 4(%[dest]), %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b (%[dest])\n\t" + "jne 1b\n\t" + "xchgl %%ebx, %%esi\n\t" + : "=A" (old_value) + : "S" ((uint32_t)v), "c" ((uint32_t)(v >> 32)), [dest] "D" (&storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + return old_value; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) +#else // defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) +#if defined(__MINGW32__) && ((__GNUC__+0) * 100 + (__GNUC_MINOR__+0)) < 407 + + // MinGW gcc up to 4.6 has problems with allocating registers in the asm blocks below + uint32_t old_bits[2]; + __asm__ __volatile__ + ( + "movl (%[dest]), %%eax\n\t" + "movl 4(%[dest]), %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b (%[dest])\n\t" + "jne 1b\n\t" + : "=&a" (old_bits[0]), "=&d" (old_bits[1]) + : "b" ((uint32_t)v), "c" ((uint32_t)(v >> 32)), [dest] "DS" (&storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + storage_type old_value; + BOOST_ATOMIC_DETAIL_MEMCPY(&old_value, old_bits, sizeof(old_value)); + return old_value; + +#elif defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + uint32_t old_bits[2]; + __asm__ __volatile__ + ( + "movl %[dest_lo], %%eax\n\t" + "movl %[dest_hi], %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b %[dest_lo]\n\t" + "jne 1b\n\t" + : "=&a" (old_bits[0]), "=&d" (old_bits[1]), [dest_lo] "+m" (storage), [dest_hi] "+m" (reinterpret_cast< volatile aliasing_uint32_t* >(&storage)[1]) + : "b" ((uint32_t)v), "c" ((uint32_t)(v >> 32)) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + storage_type old_value; + BOOST_ATOMIC_DETAIL_MEMCPY(&old_value, old_bits, sizeof(old_value)); + return old_value; + +#else // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + storage_type old_value; + __asm__ __volatile__ + ( + "movl %[dest_lo], %%eax\n\t" + "movl %[dest_hi], %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b %[dest_lo]\n\t" + "jne 1b\n\t" + : "=&A" (old_value), [dest_lo] "+m" (storage), [dest_hi] "+m" (reinterpret_cast< volatile aliasing_uint32_t* >(&storage)[1]) + : "b" ((uint32_t)v), "c" ((uint32_t)(v >> 32)) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + return old_value; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) +#endif // defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +template< bool Signed > +struct gcc_dcas_x86_64 +{ + typedef typename make_storage_type< 16u >::type storage_type; + typedef typename make_storage_type< 16u >::aligned aligned_storage_type; + typedef uint64_t BOOST_ATOMIC_DETAIL_MAY_ALIAS aliasing_uint64_t; + + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "movq %[dest_lo], %%rax\n\t" + "movq %[dest_hi], %%rdx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg16b %[dest_lo]\n\t" + "jne 1b\n\t" + : [dest_lo] "=m" (storage), [dest_hi] "=m" (reinterpret_cast< volatile aliasing_uint64_t* >(&storage)[1]) + : "b" (reinterpret_cast< const aliasing_uint64_t* >(&v)[0]), "c" (reinterpret_cast< const aliasing_uint64_t* >(&v)[1]) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "rax", "rdx", "memory" + ); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT + { + // Note that despite const qualification cmpxchg16b below may issue a store to the storage. The storage value + // will not change, but this prevents the storage to reside in read-only memory. + +#if defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + uint64_t value_bits[2]; + + // We don't care for comparison result here; the previous value will be stored into value anyway. + // Also we don't care for rbx and rcx values, they just have to be equal to rax and rdx before cmpxchg16b. + __asm__ __volatile__ + ( + "movq %%rbx, %%rax\n\t" + "movq %%rcx, %%rdx\n\t" + "lock; cmpxchg16b %[storage]\n\t" + : "=&a" (value_bits[0]), "=&d" (value_bits[1]) + : [storage] "m" (storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + storage_type value; + BOOST_ATOMIC_DETAIL_MEMCPY(&value, value_bits, sizeof(value)); + return value; + +#else // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + storage_type value; + + // We don't care for comparison result here; the previous value will be stored into value anyway. + // Also we don't care for rbx and rcx values, they just have to be equal to rax and rdx before cmpxchg16b. + __asm__ __volatile__ + ( + "movq %%rbx, %%rax\n\t" + "movq %%rcx, %%rdx\n\t" + "lock; cmpxchg16b %[storage]\n\t" + : "=&A" (value) + : [storage] "m" (storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + return value; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { +#if defined(__clang__) + + // Clang cannot allocate rax:rdx register pairs but it has sync intrinsics + storage_type old_expected = expected; + expected = __sync_val_compare_and_swap(&storage, old_expected, desired); + return expected == old_expected; + +#elif defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + // Some compilers can't allocate rax:rdx register pair either but also don't support 128-bit __sync_val_compare_and_swap + bool success; + __asm__ __volatile__ + ( + "lock; cmpxchg16b %[dest]\n\t" + "sete %[success]\n\t" + : [dest] "+m" (storage), "+a" (reinterpret_cast< aliasing_uint64_t* >(&expected)[0]), "+d" (reinterpret_cast< aliasing_uint64_t* >(&expected)[1]), [success] "=q" (success) + : "b" (reinterpret_cast< const aliasing_uint64_t* >(&desired)[0]), "c" (reinterpret_cast< const aliasing_uint64_t* >(&desired)[1]) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + return success; + +#else // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + bool success; + +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchg16b %[dest]\n\t" + : "+A" (expected), [dest] "+m" (storage), "=@ccz" (success) + : "b" (reinterpret_cast< const aliasing_uint64_t* >(&desired)[0]), "c" (reinterpret_cast< const aliasing_uint64_t* >(&desired)[1]) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchg16b %[dest]\n\t" + "sete %[success]\n\t" + : "+A" (expected), [dest] "+m" (storage), [success] "=qm" (success) + : "b" (reinterpret_cast< const aliasing_uint64_t* >(&desired)[0]), "c" (reinterpret_cast< const aliasing_uint64_t* >(&desired)[1]) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + + return success; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + uint64_t old_bits[2]; + __asm__ __volatile__ + ( + "movq %[dest_lo], %%rax\n\t" + "movq %[dest_hi], %%rdx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg16b %[dest_lo]\n\t" + "jne 1b\n\t" + : [dest_lo] "+m" (storage), [dest_hi] "+m" (reinterpret_cast< volatile aliasing_uint64_t* >(&storage)[1]), "=&a" (old_bits[0]), "=&d" (old_bits[1]) + : "b" (reinterpret_cast< const aliasing_uint64_t* >(&v)[0]), "c" (reinterpret_cast< const aliasing_uint64_t* >(&v)[1]) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + storage_type old_value; + BOOST_ATOMIC_DETAIL_MEMCPY(&old_value, old_bits, sizeof(old_value)); + return old_value; +#else // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + storage_type old_value; + __asm__ __volatile__ + ( + "movq %[dest_lo], %%rax\n\t" + "movq %[dest_hi], %%rdx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg16b %[dest_lo]\n\t" + "jne 1b\n\t" + : "=&A" (old_value), [dest_lo] "+m" (storage), [dest_hi] "+m" (reinterpret_cast< volatile aliasing_uint64_t* >(&storage)[1]) + : "b" (reinterpret_cast< const aliasing_uint64_t* >(&v)[0]), "c" (reinterpret_cast< const aliasing_uint64_t* >(&v)[1]) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + return old_value; +#endif // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_X86_DCAS_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_linux_arm.hpp b/boost/atomic/detail/ops_linux_arm.hpp new file mode 100644 index 0000000..16af173 --- /dev/null +++ b/boost/atomic/detail/ops_linux_arm.hpp @@ -0,0 +1,180 @@ +/* + * 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) + * + * Copyright (c) 2009, 2011 Helge Bahmann + * Copyright (c) 2009 Phil Endecott + * Copyright (c) 2013 Tim Blechmann + * Linux-specific code by Phil Endecott + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_linux_arm.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_LINUX_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_LINUX_ARM_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +// Different ARM processors have different atomic instructions. In particular, +// architecture versions before v6 (which are still in widespread use, e.g. the +// Intel/Marvell XScale chips like the one in the NSLU2) have only atomic swap. +// On Linux the kernel provides some support that lets us abstract away from +// these differences: it provides emulated CAS and barrier functions at special +// addresses that are guaranteed not to be interrupted by the kernel. Using +// this facility is slightly slower than inline assembler would be, but much +// faster than a system call. +// +// While this emulated CAS is "strong" in the sense that it does not fail +// "spuriously" (i.e.: it never fails to perform the exchange when the value +// found equals the value expected), it does not return the found value on +// failure. To satisfy the atomic API, compare_exchange_{weak|strong} must +// return the found value on failure, and we have to manually load this value +// after the emulated CAS reports failure. This in turn introduces a race +// between the CAS failing (due to the "wrong" value being found) and subsequently +// loading (which might turn up the "right" value). From an application's +// point of view this looks like "spurious failure", and therefore the +// emulated CAS is only good enough to provide compare_exchange_weak +// semantics. + +struct linux_arm_cas_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before_store(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + hardware_full_fence(); + } + + static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + hardware_full_fence(); + } + + static BOOST_FORCEINLINE void fence_after_load(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + hardware_full_fence(); + } + + static BOOST_FORCEINLINE void hardware_full_fence() BOOST_NOEXCEPT + { + typedef void (*kernel_dmb_t)(void); + ((kernel_dmb_t)0xffff0fa0)(); + } +}; + +template< bool Signed > +struct linux_arm_cas : + public linux_arm_cas_base +{ + typedef typename make_storage_type< 4u >::type storage_type; + typedef typename make_storage_type< 4u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before_store(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + while (true) + { + storage_type tmp = expected; + if (compare_exchange_weak(storage, tmp, desired, success_order, failure_order)) + return true; + if (tmp != expected) + { + expected = tmp; + return false; + } + } + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + typedef storage_type (*kernel_cmpxchg32_t)(storage_type oldval, storage_type newval, volatile storage_type* ptr); + + if (((kernel_cmpxchg32_t)0xffff0fc0)(expected, desired, &storage) == 0) + { + return true; + } + else + { + expected = storage; + return false; + } + } +}; + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< cas_based_operations< cas_based_exchange< linux_arm_cas< Signed > > >, 1u, Signed > +{ +}; + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< cas_based_operations< cas_based_exchange< linux_arm_cas< Signed > > >, 2u, Signed > +{ +}; + +template< bool Signed > +struct operations< 4u, Signed > : + public cas_based_operations< cas_based_exchange< linux_arm_cas< Signed > > > +{ +}; + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + linux_arm_cas_base::hardware_full_fence(); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("" ::: "memory"); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_LINUX_ARM_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_msvc_arm.hpp b/boost/atomic/detail/ops_msvc_arm.hpp new file mode 100644 index 0000000..608c6fd --- /dev/null +++ b/boost/atomic/detail/ops_msvc_arm.hpp @@ -0,0 +1,824 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_msvc_arm.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_MSVC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_MSVC_ARM_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_DETAIL_ARM_LOAD8(p) __iso_volatile_load8((const volatile __int8*)(p)) +#define BOOST_ATOMIC_DETAIL_ARM_LOAD16(p) __iso_volatile_load16((const volatile __int16*)(p)) +#define BOOST_ATOMIC_DETAIL_ARM_LOAD32(p) __iso_volatile_load32((const volatile __int32*)(p)) +#define BOOST_ATOMIC_DETAIL_ARM_LOAD64(p) __iso_volatile_load64((const volatile __int64*)(p)) +#define BOOST_ATOMIC_DETAIL_ARM_STORE8(p, v) __iso_volatile_store8((volatile __int8*)(p), (__int8)(v)) +#define BOOST_ATOMIC_DETAIL_ARM_STORE16(p, v) __iso_volatile_store16((volatile __int16*)(p), (__int16)(v)) +#define BOOST_ATOMIC_DETAIL_ARM_STORE32(p, v) __iso_volatile_store32((volatile __int32*)(p), (__int32)(v)) +#define BOOST_ATOMIC_DETAIL_ARM_STORE64(p, v) __iso_volatile_store64((volatile __int64*)(p), (__int64)(v)) + +namespace boost { +namespace atomics { +namespace detail { + +// A note about memory_order_consume. Technically, this architecture allows to avoid +// unnecessary memory barrier after consume load since it supports data dependency ordering. +// However, some compiler optimizations may break a seemingly valid code relying on data +// dependency tracking by injecting bogus branches to aid out of order execution. +// This may happen not only in Boost.Atomic code but also in user's code, which we have no +// control of. See this thread: http://lists.boost.org/Archives/boost/2014/06/213890.php. +// For this reason we promote memory_order_consume to memory_order_acquire. + +struct msvc_arm_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void hardware_full_fence() BOOST_NOEXCEPT + { + __dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later + } + + static BOOST_FORCEINLINE void fence_before_store(memory_order order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + hardware_full_fence(); + + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + if (order == memory_order_seq_cst) + hardware_full_fence(); + + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE void fence_after_load(memory_order order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + hardware_full_fence(); + + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE BOOST_CONSTEXPR memory_order cas_common_order(memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + // Combine order flags together and promote memory_order_consume to memory_order_acquire + return static_cast< memory_order >(((static_cast< unsigned int >(failure_order) | static_cast< unsigned int >(success_order)) & ~static_cast< unsigned int >(memory_order_consume)) + | (((static_cast< unsigned int >(failure_order) | static_cast< unsigned int >(success_order)) & static_cast< unsigned int >(memory_order_consume)) << 1u)); + } +}; + +template< std::size_t Size, bool Signed, typename Derived > +struct msvc_arm_operations : + public msvc_arm_operations_base +{ + typedef typename make_storage_type< Size >::type storage_type; + typedef typename make_storage_type< Size >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + typedef typename boost::atomics::detail::make_signed< storage_type >::type signed_storage_type; + return Derived::fetch_add(storage, static_cast< storage_type >(-static_cast< signed_storage_type >(v)), order); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return Derived::compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!Derived::exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + Derived::store(storage, (storage_type)0, order); + } +}; + +template< bool Signed > +struct operations< 1u, Signed > : + public msvc_arm_operations< 1u, Signed, operations< 1u, Signed > > +{ + typedef msvc_arm_operations< 1u, Signed, operations< 1u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before_store(order); + BOOST_ATOMIC_DETAIL_ARM_STORE8(&storage, v); + base_type::fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = BOOST_ATOMIC_DETAIL_ARM_LOAD8(&storage); + base_type::fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE8(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + storage_type previous = expected, old_val; + + switch (cas_common_order(success_order, failure_order)) + { + case memory_order_relaxed: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8_RELAXED(&storage, desired, previous)); + break; + case memory_order_consume: + case memory_order_acquire: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8_ACQUIRE(&storage, desired, previous)); + break; + case memory_order_release: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8_RELEASE(&storage, desired, previous)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8(&storage, desired, previous)); + break; + } + expected = old_val; + + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND8_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND8_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND8_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND8(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR8_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR8_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR8_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR8(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR8_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR8_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR8_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR8(&storage, v)); + break; + } + return v; + } +}; + +template< bool Signed > +struct operations< 2u, Signed > : + public msvc_arm_operations< 2u, Signed, operations< 2u, Signed > > +{ + typedef msvc_arm_operations< 2u, Signed, operations< 2u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before_store(order); + BOOST_ATOMIC_DETAIL_ARM_STORE16(&storage, v); + base_type::fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = BOOST_ATOMIC_DETAIL_ARM_LOAD16(&storage); + base_type::fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE16(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + storage_type previous = expected, old_val; + + switch (cas_common_order(success_order, failure_order)) + { + case memory_order_relaxed: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16_RELAXED(&storage, desired, previous)); + break; + case memory_order_consume: + case memory_order_acquire: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16_ACQUIRE(&storage, desired, previous)); + break; + case memory_order_release: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16_RELEASE(&storage, desired, previous)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16(&storage, desired, previous)); + break; + } + expected = old_val; + + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND16_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND16_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND16_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND16(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR16_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR16_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR16_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR16(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR16_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR16_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR16_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR16(&storage, v)); + break; + } + return v; + } +}; + +template< bool Signed > +struct operations< 4u, Signed > : + public msvc_arm_operations< 4u, Signed, operations< 4u, Signed > > +{ + typedef msvc_arm_operations< 4u, Signed, operations< 4u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before_store(order); + BOOST_ATOMIC_DETAIL_ARM_STORE32(&storage, v); + base_type::fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = BOOST_ATOMIC_DETAIL_ARM_LOAD32(&storage); + base_type::fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + storage_type previous = expected, old_val; + + switch (cas_common_order(success_order, failure_order)) + { + case memory_order_relaxed: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_RELAXED(&storage, desired, previous)); + break; + case memory_order_consume: + case memory_order_acquire: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_ACQUIRE(&storage, desired, previous)); + break; + case memory_order_release: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_RELEASE(&storage, desired, previous)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&storage, desired, previous)); + break; + } + expected = old_val; + + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR(&storage, v)); + break; + } + return v; + } +}; + +template< bool Signed > +struct operations< 8u, Signed > : + public msvc_arm_operations< 8u, Signed, operations< 8u, Signed > > +{ + typedef msvc_arm_operations< 8u, Signed, operations< 8u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before_store(order); + BOOST_ATOMIC_DETAIL_ARM_STORE64(&storage, v); + base_type::fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = BOOST_ATOMIC_DETAIL_ARM_LOAD64(&storage); + base_type::fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + storage_type previous = expected, old_val; + + switch (cas_common_order(success_order, failure_order)) + { + case memory_order_relaxed: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64_RELAXED(&storage, desired, previous)); + break; + case memory_order_consume: + case memory_order_acquire: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64_ACQUIRE(&storage, desired, previous)); + break; + case memory_order_release: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64_RELEASE(&storage, desired, previous)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(&storage, desired, previous)); + break; + } + expected = old_val; + + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND64_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND64_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND64_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND64(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR64_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR64_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR64_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR64(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR64_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR64_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR64_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR64(&storage, v)); + break; + } + return v; + } +}; + + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + if (order != memory_order_relaxed) + msvc_arm_operations_base::hardware_full_fence(); + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#undef BOOST_ATOMIC_DETAIL_ARM_LOAD8 +#undef BOOST_ATOMIC_DETAIL_ARM_LOAD16 +#undef BOOST_ATOMIC_DETAIL_ARM_LOAD32 +#undef BOOST_ATOMIC_DETAIL_ARM_LOAD64 +#undef BOOST_ATOMIC_DETAIL_ARM_STORE8 +#undef BOOST_ATOMIC_DETAIL_ARM_STORE16 +#undef BOOST_ATOMIC_DETAIL_ARM_STORE32 +#undef BOOST_ATOMIC_DETAIL_ARM_STORE64 + +#endif // BOOST_ATOMIC_DETAIL_OPS_MSVC_ARM_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_msvc_common.hpp b/boost/atomic/detail/ops_msvc_common.hpp new file mode 100644 index 0000000..8c51207 --- /dev/null +++ b/boost/atomic/detail/ops_msvc_common.hpp @@ -0,0 +1,40 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2014, 2019 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_msvc_common.hpp + * + * This header contains common tools for MSVC implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_MSVC_COMMON_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_MSVC_COMMON_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// Define compiler barriers +#if defined(__INTEL_COMPILER) +#define BOOST_ATOMIC_DETAIL_COMPILER_BARRIER() __memory_barrier() +#elif defined(__clang__) +#define BOOST_ATOMIC_DETAIL_COMPILER_BARRIER() __atomic_signal_fence(__ATOMIC_SEQ_CST) +#elif defined(_MSC_VER) && !defined(_WIN32_WCE) +extern "C" void _ReadWriteBarrier(void); +#pragma intrinsic(_ReadWriteBarrier) +#define BOOST_ATOMIC_DETAIL_COMPILER_BARRIER() _ReadWriteBarrier() +#endif + +#ifndef BOOST_ATOMIC_DETAIL_COMPILER_BARRIER +#define BOOST_ATOMIC_DETAIL_COMPILER_BARRIER() +#endif + +#endif // BOOST_ATOMIC_DETAIL_OPS_MSVC_COMMON_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_msvc_x86.hpp b/boost/atomic/detail/ops_msvc_x86.hpp new file mode 100644 index 0000000..70b0ea9 --- /dev/null +++ b/boost/atomic/detail/ops_msvc_x86.hpp @@ -0,0 +1,908 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_msvc_x86.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_MSVC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_MSVC_X86_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) +#include +#include +#endif +#include +#if !defined(_M_IX86) && !(defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8) && defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16)) +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// frame pointer register 'ebx' modified by inline assembly code. See the note below. +#pragma warning(disable: 4731) +#endif + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_MFENCE) +extern "C" void _mm_mfence(void); +#if defined(BOOST_MSVC) +#pragma intrinsic(_mm_mfence) +#endif +#endif + +namespace boost { +namespace atomics { +namespace detail { + +/* + * Implementation note for asm blocks. + * + * http://msdn.microsoft.com/en-us/data/k1a8ss06%28v=vs.105%29 + * + * Some SSE types require eight-byte stack alignment, forcing the compiler to emit dynamic stack-alignment code. + * To be able to access both the local variables and the function parameters after the alignment, the compiler + * maintains two frame pointers. If the compiler performs frame pointer omission (FPO), it will use EBP and ESP. + * If the compiler does not perform FPO, it will use EBX and EBP. To ensure code runs correctly, do not modify EBX + * in asm code if the function requires dynamic stack alignment as it could modify the frame pointer. + * Either move the eight-byte aligned types out of the function, or avoid using EBX. + * + * Since we have no way of knowing that the compiler uses FPO, we have to always save and restore ebx + * whenever we have to clobber it. Additionally, we disable warning C4731 above so that the compiler + * doesn't spam about ebx use. + */ + +struct msvc_x86_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void hardware_full_fence() BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_MFENCE) + _mm_mfence(); +#else + long tmp; + BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&tmp, 0); +#endif + } + + static BOOST_FORCEINLINE void fence_before(memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE void fence_after(memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE void fence_after_load(memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + // On x86 and x86_64 there is no need for a hardware barrier, + // even if seq_cst memory order is requested, because all + // seq_cst writes are implemented with lock-prefixed operations + // or xchg which has implied lock prefix. Therefore normal loads + // are already ordered with seq_cst stores on these architectures. + } +}; + +template< std::size_t Size, bool Signed, typename Derived > +struct msvc_x86_operations : + public msvc_x86_operations_base +{ + typedef typename make_storage_type< Size >::type storage_type; + typedef typename make_storage_type< Size >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + if (order != memory_order_seq_cst) + { + fence_before(order); + storage = v; + fence_after(order); + } + else + { + Derived::exchange(storage, v, order); + } + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + typedef typename boost::atomics::detail::make_signed< storage_type >::type signed_storage_type; + return Derived::fetch_add(storage, static_cast< storage_type >(-static_cast< signed_storage_type >(v)), order); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return Derived::compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!Derived::exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, (storage_type)0, order); + } +}; + +template< bool Signed > +struct operations< 4u, Signed > : + public msvc_x86_operations< 4u, Signed, operations< 4u, Signed > > +{ + typedef msvc_x86_operations< 4u, Signed, operations< 4u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&storage, v)); + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&storage, desired, previous)); + expected = old_val; + return (previous == old_val); + } + +#if defined(BOOST_ATOMIC_INTERLOCKED_AND) + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND(&storage, v)); + } +#else + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type res = storage; + while (!compare_exchange_strong(storage, res, res & v, order, memory_order_relaxed)) {} + return res; + } +#endif + +#if defined(BOOST_ATOMIC_INTERLOCKED_OR) + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR(&storage, v)); + } +#else + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type res = storage; + while (!compare_exchange_strong(storage, res, res | v, order, memory_order_relaxed)) {} + return res; + } +#endif + +#if defined(BOOST_ATOMIC_INTERLOCKED_XOR) + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR(&storage, v)); + } +#else + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type res = storage; + while (!compare_exchange_strong(storage, res, res ^ v, order, memory_order_relaxed)) {} + return res; + } +#endif +}; + +#if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8) + +template< bool Signed > +struct operations< 1u, Signed > : + public msvc_x86_operations< 1u, Signed, operations< 1u, Signed > > +{ + typedef msvc_x86_operations< 1u, Signed, operations< 1u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE8(&storage, v)); + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8(&storage, desired, previous)); + expected = old_val; + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND8(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR8(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR8(&storage, v)); + } +}; + +#elif defined(_M_IX86) + +template< bool Signed > +struct operations< 1u, Signed > : + public msvc_x86_operations< 1u, Signed, operations< 1u, Signed > > +{ + typedef msvc_x86_operations< 1u, Signed, operations< 1u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock xadd byte ptr [edx], al + mov v, al + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + xchg byte ptr [edx], al + mov v, al + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order) BOOST_NOEXCEPT + { + base_type::fence_before(success_order); + bool success; + __asm + { + mov esi, expected + mov edi, storage + movzx eax, byte ptr [esi] + movzx edx, desired + lock cmpxchg byte ptr [edi], dl + mov byte ptr [esi], al + sete success + }; + // The success and failure fences are equivalent anyway + base_type::fence_after(success_order); + return success; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, byte ptr [edi] + align 16 + again: + mov dl, al + and dl, cl + lock cmpxchg byte ptr [edi], dl + jne again + mov v, al + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, byte ptr [edi] + align 16 + again: + mov dl, al + or dl, cl + lock cmpxchg byte ptr [edi], dl + jne again + mov v, al + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, byte ptr [edi] + align 16 + again: + mov dl, al + xor dl, cl + lock cmpxchg byte ptr [edi], dl + jne again + mov v, al + }; + base_type::fence_after(order); + return v; + } +}; + +#else + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< operations< 4u, Signed >, 1u, Signed > +{ +}; + +#endif + +#if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16) + +template< bool Signed > +struct operations< 2u, Signed > : + public msvc_x86_operations< 2u, Signed, operations< 2u, Signed > > +{ + typedef msvc_x86_operations< 2u, Signed, operations< 2u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE16(&storage, v)); + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16(&storage, desired, previous)); + expected = old_val; + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND16(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR16(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR16(&storage, v)); + } +}; + +#elif defined(_M_IX86) + +template< bool Signed > +struct operations< 2u, Signed > : + public msvc_x86_operations< 2u, Signed, operations< 2u, Signed > > +{ + typedef msvc_x86_operations< 2u, Signed, operations< 2u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock xadd word ptr [edx], ax + mov v, ax + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + xchg word ptr [edx], ax + mov v, ax + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order) BOOST_NOEXCEPT + { + base_type::fence_before(success_order); + bool success; + __asm + { + mov esi, expected + mov edi, storage + movzx eax, word ptr [esi] + movzx edx, desired + lock cmpxchg word ptr [edi], dx + mov word ptr [esi], ax + sete success + }; + // The success and failure fences are equivalent anyway + base_type::fence_after(success_order); + return success; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, word ptr [edi] + align 16 + again: + mov dx, ax + and dx, cx + lock cmpxchg word ptr [edi], dx + jne again + mov v, ax + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, word ptr [edi] + align 16 + again: + mov dx, ax + or dx, cx + lock cmpxchg word ptr [edi], dx + jne again + mov v, ax + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, word ptr [edi] + align 16 + again: + mov dx, ax + xor dx, cx + lock cmpxchg word ptr [edi], dx + jne again + mov v, ax + }; + base_type::fence_after(order); + return v; + } +}; + +#else + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< operations< 4u, Signed >, 2u, Signed > +{ +}; + +#endif + + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) + +template< bool Signed > +struct msvc_dcas_x86 +{ + typedef typename make_storage_type< 8u >::type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + // Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 3A, 8.1.1. Guaranteed Atomic Operations: + // + // The Pentium processor (and newer processors since) guarantees that the following additional memory operations will always be carried out atomically: + // * Reading or writing a quadword aligned on a 64-bit boundary + // + // Luckily, the memory is almost always 8-byte aligned in our case because atomic<> uses 64 bit native types for storage and dynamic memory allocations + // have at least 8 byte alignment. The only unfortunate case is when atomic is placed on the stack and it is not 8-byte aligned (like on 32 bit Windows). + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + storage_type volatile* p = &storage; + if (((uint32_t)p & 0x00000007) == 0) + { +#if defined(_M_IX86_FP) && _M_IX86_FP >= 2 +#if defined(__AVX__) + __asm + { + mov edx, p + vmovq xmm4, v + vmovq qword ptr [edx], xmm4 + }; +#else + __asm + { + mov edx, p + movq xmm4, v + movq qword ptr [edx], xmm4 + }; +#endif +#else + __asm + { + mov edx, p + fild v + fistp qword ptr [edx] + }; +#endif + } + else + { + uint32_t backup; + __asm + { + mov backup, ebx + mov edi, p + mov ebx, dword ptr [v] + mov ecx, dword ptr [v + 4] + mov eax, dword ptr [edi] + mov edx, dword ptr [edi + 4] + align 16 + again: + lock cmpxchg8b qword ptr [edi] + jne again + mov ebx, backup + }; + } + + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + storage_type const volatile* p = &storage; + storage_type value; + + if (((uint32_t)p & 0x00000007) == 0) + { +#if defined(_M_IX86_FP) && _M_IX86_FP >= 2 +#if defined(__AVX__) + __asm + { + mov edx, p + vmovq xmm4, qword ptr [edx] + vmovq value, xmm4 + }; +#else + __asm + { + mov edx, p + movq xmm4, qword ptr [edx] + movq value, xmm4 + }; +#endif +#else + __asm + { + mov edx, p + fild qword ptr [edx] + fistp value + }; +#endif + } + else + { + // We don't care for comparison result here; the previous value will be stored into value anyway. + // Also we don't care for ebx and ecx values, they just have to be equal to eax and edx before cmpxchg8b. + __asm + { + mov edi, p + mov eax, ebx + mov edx, ecx + lock cmpxchg8b qword ptr [edi] + mov dword ptr [value], eax + mov dword ptr [value + 4], edx + }; + } + + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + return value; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + // MSVC-11 in 32-bit mode sometimes generates messed up code without compiler barriers, + // even though the _InterlockedCompareExchange64 intrinsic already provides one. + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + storage_type volatile* p = &storage; +#if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64) + const storage_type old_val = (storage_type)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(p, desired, expected); + const bool result = (old_val == expected); + expected = old_val; +#else + bool result; + uint32_t backup; + __asm + { + mov backup, ebx + mov edi, p + mov esi, expected + mov ebx, dword ptr [desired] + mov ecx, dword ptr [desired + 4] + mov eax, dword ptr [esi] + mov edx, dword ptr [esi + 4] + lock cmpxchg8b qword ptr [edi] + mov dword ptr [esi], eax + mov dword ptr [esi + 4], edx + mov ebx, backup + sete result + }; +#endif + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + return result; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + storage_type volatile* p = &storage; + uint32_t backup; + __asm + { + mov backup, ebx + mov edi, p + mov ebx, dword ptr [v] + mov ecx, dword ptr [v + 4] + mov eax, dword ptr [edi] + mov edx, dword ptr [edi + 4] + align 16 + again: + lock cmpxchg8b qword ptr [edi] + jne again + mov ebx, backup + mov dword ptr [v], eax + mov dword ptr [v + 4], edx + }; + + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + return v; + } +}; + +template< bool Signed > +struct operations< 8u, Signed > : + public cas_based_operations< msvc_dcas_x86< Signed > > +{ +}; + +#elif defined(_M_AMD64) + +template< bool Signed > +struct operations< 8u, Signed > : + public msvc_x86_operations< 8u, Signed, operations< 8u, Signed > > +{ + typedef msvc_x86_operations< 8u, Signed, operations< 8u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(&storage, v)); + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(&storage, desired, previous)); + expected = old_val; + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND64(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR64(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR64(&storage, v)); + } +}; + +#endif + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +template< bool Signed > +struct msvc_dcas_x86_64 +{ + typedef typename make_storage_type< 16u >::type storage_type; + typedef typename make_storage_type< 16u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 16u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type value = const_cast< storage_type& >(storage); + while (!BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE128(&storage, v, &value)) {} + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type value = storage_type(); + BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE128(&storage, value, &value); + return value; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + return !!BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE128(&storage, desired, &expected); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } +}; + +template< bool Signed > +struct operations< 16u, Signed > : + public cas_based_operations< cas_based_exchange< msvc_dcas_x86_64< Signed > > > +{ +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + if (order == memory_order_seq_cst) + msvc_x86_operations_base::hardware_full_fence(); + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_ATOMIC_DETAIL_OPS_MSVC_X86_HPP_INCLUDED_ diff --git a/boost/atomic/detail/ops_windows.hpp b/boost/atomic/detail/ops_windows.hpp new file mode 100644 index 0000000..d4ce6d9 --- /dev/null +++ b/boost/atomic/detail/ops_windows.hpp @@ -0,0 +1,218 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_windows.hpp + * + * This header contains implementation of the \c operations template. + * + * This implementation is the most basic version for Windows. It should + * work for any non-MSVC-like compilers as long as there are Interlocked WinAPI + * functions available. This version is also used for WinCE. + * + * Notably, this implementation is not as efficient as other + * versions based on compiler intrinsics. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_WINDOWS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_WINDOWS_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +struct windows_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void hardware_full_fence() BOOST_NOEXCEPT + { + long tmp; + BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&tmp, 0); + } + + static BOOST_FORCEINLINE void fence_before(memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE void fence_after(memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } +}; + +template< std::size_t Size, bool Signed, typename Derived > +struct windows_operations : + public windows_operations_base +{ + typedef typename make_storage_type< Size >::type storage_type; + typedef typename make_storage_type< Size >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + Derived::exchange(storage, v, order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return Derived::fetch_add(const_cast< storage_type volatile& >(storage), (storage_type)0, order); + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + typedef typename boost::atomics::detail::make_signed< storage_type >::type signed_storage_type; + return Derived::fetch_add(storage, static_cast< storage_type >(-static_cast< signed_storage_type >(v)), order); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return Derived::compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!Derived::exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, (storage_type)0, order); + } +}; + +template< bool Signed > +struct operations< 4u, Signed > : + public windows_operations< 4u, Signed, operations< 4u, Signed > > +{ + typedef windows_operations< 4u, Signed, operations< 4u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(&storage, v)); + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&storage, v)); + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + base_type::fence_before(success_order); + storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&storage, desired, previous)); + expected = old_val; + // The success and failure fences are the same anyway + base_type::fence_after(success_order); + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_INTERLOCKED_AND) + base_type::fence_before(order); + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND(&storage, v)); + base_type::fence_after(order); + return v; +#else + storage_type res = storage; + while (!compare_exchange_strong(storage, res, res & v, order, memory_order_relaxed)) {} + return res; +#endif + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_INTERLOCKED_OR) + base_type::fence_before(order); + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR(&storage, v)); + base_type::fence_after(order); + return v; +#else + storage_type res = storage; + while (!compare_exchange_strong(storage, res, res | v, order, memory_order_relaxed)) {} + return res; +#endif + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_INTERLOCKED_XOR) + base_type::fence_before(order); + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR(&storage, v)); + base_type::fence_after(order); + return v; +#else + storage_type res = storage; + while (!compare_exchange_strong(storage, res, res ^ v, order, memory_order_relaxed)) {} + return res; +#endif + } +}; + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< operations< 4u, Signed >, 1u, Signed > +{ +}; + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< operations< 4u, Signed >, 2u, Signed > +{ +}; + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + if (order == memory_order_seq_cst) + windows_operations_base::hardware_full_fence(); + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_WINDOWS_HPP_INCLUDED_ diff --git a/boost/atomic/detail/pause.hpp b/boost/atomic/detail/pause.hpp new file mode 100644 index 0000000..37aa5ca --- /dev/null +++ b/boost/atomic/detail/pause.hpp @@ -0,0 +1,43 @@ +/* + * 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) + * + * (C) Copyright 2013 Tim Blechmann + * (C) Copyright 2013 Andrey Semashev + */ + +#ifndef BOOST_ATOMIC_DETAIL_PAUSE_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_PAUSE_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_IX86)) +extern "C" void _mm_pause(void); +#if defined(BOOST_MSVC) +#pragma intrinsic(_mm_pause) +#endif +#endif + +namespace boost { +namespace atomics { +namespace detail { + +BOOST_FORCEINLINE void pause() BOOST_NOEXCEPT +{ +#if defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_IX86)) + _mm_pause(); +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + __asm__ __volatile__("pause;"); +#endif +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_PAUSE_HPP_INCLUDED_ diff --git a/boost/atomic/detail/platform.hpp b/boost/atomic/detail/platform.hpp new file mode 100644 index 0000000..df4cc30 --- /dev/null +++ b/boost/atomic/detail/platform.hpp @@ -0,0 +1,163 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/platform.hpp + * + * This header defines macros for the target platform detection + */ + +#ifndef BOOST_ATOMIC_DETAIL_PLATFORM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_PLATFORM_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__GNUC__) && defined(__arm__) + +// Newer gcc versions define __ARM_ARCH. Older ones don't, so we have to deduce ARM arch version from a bunch of version-specific macros. +#if defined(__ARM_ARCH) +#define BOOST_ATOMIC_DETAIL_ARM_ARCH __ARM_ARCH +#elif defined(__ARM_ARCH_8A__) +#define BOOST_ATOMIC_DETAIL_ARM_ARCH 8 +#elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) ||\ + defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) ||\ + defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7S__) +#define BOOST_ATOMIC_DETAIL_ARM_ARCH 7 +#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) ||\ + defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) ||\ + defined(__ARM_ARCH_6ZK__) +#define BOOST_ATOMIC_DETAIL_ARM_ARCH 6 +#else +// We are not interested in older versions - they don't support atomic ops +#define BOOST_ATOMIC_DETAIL_ARM_ARCH 0 +#endif + +#endif // defined(__GNUC__) && defined(__arm__) + +#if !defined(BOOST_ATOMIC_FORCE_FALLBACK) + +// Determine the target platform. +// The target platform describes the compiler and target architecture. It can be used by more generic backends, such as the ones +// based on compiler intrinsics, to implement specialized operations in a non-generic way. + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +#define BOOST_ATOMIC_DETAIL_PLATFORM gcc_x86 +#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND gcc_x86 + +#elif defined(__GNUC__) && (defined(__POWERPC__) || defined(__PPC__)) + +#define BOOST_ATOMIC_DETAIL_PLATFORM gcc_ppc +#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND gcc_ppc + +#elif defined(__GNUC__) && defined(__arm__) && (BOOST_ATOMIC_DETAIL_ARM_ARCH+0) >= 6 + +#define BOOST_ATOMIC_DETAIL_PLATFORM gcc_arm +#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND gcc_arm + +#elif (defined(__GNUC__) || defined(__SUNPRO_CC)) && (defined(__sparcv8plus) || defined(__sparc_v9__)) + +#define BOOST_ATOMIC_DETAIL_PLATFORM gcc_sparc + +#elif defined(__GNUC__) && defined(__alpha__) + +#define BOOST_ATOMIC_DETAIL_PLATFORM gcc_alpha + +#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) + +#define BOOST_ATOMIC_DETAIL_PLATFORM msvc_x86 + +#elif defined(_MSC_VER) && _MSC_VER >= 1700 && (defined(_M_ARM) || defined(_M_ARM64)) + +#define BOOST_ATOMIC_DETAIL_PLATFORM msvc_arm + +#endif + +// Compiler-based backends + +// IBM XL C++ Compiler has to be checked before GCC/Clang as it pretends to be one but does not support __atomic* intrinsics. +// It does support GCC inline assembler though. +#if !(defined(__ibmxl__) || defined(__IBMCPP__)) &&\ + ((defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 407)) ||\ + (defined(BOOST_CLANG) && ((__clang_major__ * 100 + __clang_minor__) >= 302))) &&\ + (\ + (__GCC_ATOMIC_BOOL_LOCK_FREE + 0) == 2 ||\ + (__GCC_ATOMIC_CHAR_LOCK_FREE + 0) == 2 ||\ + (__GCC_ATOMIC_SHORT_LOCK_FREE + 0) == 2 ||\ + (__GCC_ATOMIC_INT_LOCK_FREE + 0) == 2 ||\ + (__GCC_ATOMIC_LONG_LOCK_FREE + 0) == 2 ||\ + (__GCC_ATOMIC_LLONG_LOCK_FREE + 0) == 2\ + ) + +#define BOOST_ATOMIC_DETAIL_BACKEND gcc_atomic + +#elif defined(BOOST_ATOMIC_DETAIL_PLATFORM) + +#define BOOST_ATOMIC_DETAIL_BACKEND BOOST_ATOMIC_DETAIL_PLATFORM + +#elif defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 401) &&\ + (\ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) ||\ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) ||\ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) ||\ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) ||\ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16)\ + ) + +#define BOOST_ATOMIC_DETAIL_BACKEND gcc_sync + +#endif + +// OS-based backends + +#if !defined(BOOST_ATOMIC_DETAIL_BACKEND) + +#if defined(__linux__) && defined(__arm__) + +#define BOOST_ATOMIC_DETAIL_BACKEND linux_arm + +#elif defined(BOOST_WINDOWS) || defined(_WIN32_CE) + +#define BOOST_ATOMIC_DETAIL_BACKEND windows + +#endif + +#endif // !defined(BOOST_ATOMIC_DETAIL_BACKEND) + +#endif // !defined(BOOST_ATOMIC_FORCE_FALLBACK) + +#if !defined(BOOST_ATOMIC_DETAIL_BACKEND) +#define BOOST_ATOMIC_DETAIL_BACKEND emulated +#define BOOST_ATOMIC_EMULATED +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_FP_BACKEND) +#define BOOST_ATOMIC_DETAIL_FP_BACKEND generic +#define BOOST_ATOMIC_DETAIL_FP_BACKEND_GENERIC +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_EXTRA_BACKEND) +#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND generic +#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND_GENERIC +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND) +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND generic +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND_GENERIC +#endif + +#define BOOST_ATOMIC_DETAIL_BACKEND_HEADER(prefix) +#define BOOST_ATOMIC_DETAIL_FP_BACKEND_HEADER(prefix) +#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND_HEADER(prefix) +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND_HEADER(prefix) + +#endif // BOOST_ATOMIC_DETAIL_PLATFORM_HPP_INCLUDED_ diff --git a/boost/atomic/detail/storage_type.hpp b/boost/atomic/detail/storage_type.hpp new file mode 100644 index 0000000..5d824d3 --- /dev/null +++ b/boost/atomic/detail/storage_type.hpp @@ -0,0 +1,207 @@ +/* + * 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) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2013 - 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/storage_type.hpp + * + * This header defines underlying types used as storage + */ + +#ifndef BOOST_ATOMIC_DETAIL_STORAGE_TYPE_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_STORAGE_TYPE_HPP_INCLUDED_ + +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename T > +BOOST_FORCEINLINE void non_atomic_load(T const volatile& from, T& to) BOOST_NOEXCEPT +{ + to = from; +} + +template< std::size_t Size > +struct BOOST_ATOMIC_DETAIL_MAY_ALIAS buffer_storage +{ + BOOST_ALIGNMENT(16) unsigned char data[Size]; + + BOOST_FORCEINLINE bool operator! () const BOOST_NOEXCEPT + { + return (data[0] == 0u && BOOST_ATOMIC_DETAIL_MEMCMP(data, data + 1, Size - 1) == 0); + } + + BOOST_FORCEINLINE bool operator== (buffer_storage const& that) const BOOST_NOEXCEPT + { + return BOOST_ATOMIC_DETAIL_MEMCMP(data, that.data, Size) == 0; + } + + BOOST_FORCEINLINE bool operator!= (buffer_storage const& that) const BOOST_NOEXCEPT + { + return BOOST_ATOMIC_DETAIL_MEMCMP(data, that.data, Size) != 0; + } +}; + +template< std::size_t Size > +BOOST_FORCEINLINE void non_atomic_load(buffer_storage< Size > const volatile& from, buffer_storage< Size >& to) BOOST_NOEXCEPT +{ + BOOST_ATOMIC_DETAIL_MEMCPY(to.data, const_cast< unsigned char const* >(from.data), Size); +} + +template< std::size_t Size > +struct make_storage_type +{ + typedef buffer_storage< Size > type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type const& v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +template< > +struct make_storage_type< 1u > +{ + typedef boost::uint8_t BOOST_ATOMIC_DETAIL_MAY_ALIAS type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +template< > +struct make_storage_type< 2u > +{ + typedef boost::uint16_t BOOST_ATOMIC_DETAIL_MAY_ALIAS type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + BOOST_ALIGNMENT(2) type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +template< > +struct make_storage_type< 4u > +{ + typedef boost::uint32_t BOOST_ATOMIC_DETAIL_MAY_ALIAS type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + BOOST_ALIGNMENT(4) type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +template< > +struct make_storage_type< 8u > +{ + typedef boost::uint64_t BOOST_ATOMIC_DETAIL_MAY_ALIAS type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + BOOST_ALIGNMENT(8) type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +#if defined(BOOST_HAS_INT128) + +template< > +struct make_storage_type< 16u > +{ + typedef boost::uint128_type BOOST_ATOMIC_DETAIL_MAY_ALIAS type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + BOOST_ALIGNMENT(16) type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +#elif !defined(BOOST_NO_ALIGNMENT) + +struct BOOST_ATOMIC_DETAIL_MAY_ALIAS storage128_t +{ + typedef boost::uint64_t BOOST_ATOMIC_DETAIL_MAY_ALIAS element_type; + + element_type data[2]; + + BOOST_FORCEINLINE bool operator! () const BOOST_NOEXCEPT + { + return (data[0] | data[1]) == 0u; + } +}; + +BOOST_FORCEINLINE bool operator== (storage128_t const& left, storage128_t const& right) BOOST_NOEXCEPT +{ + return ((left.data[0] ^ right.data[0]) | (left.data[1] ^ right.data[1])) == 0u; +} +BOOST_FORCEINLINE bool operator!= (storage128_t const& left, storage128_t const& right) BOOST_NOEXCEPT +{ + return !(left == right); +} + +BOOST_FORCEINLINE void non_atomic_load(storage128_t const volatile& from, storage128_t& to) BOOST_NOEXCEPT +{ + to.data[0] = from.data[0]; + to.data[1] = from.data[1]; +} + +template< > +struct make_storage_type< 16u > +{ + typedef storage128_t type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + BOOST_ALIGNMENT(16) type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type const& v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +#endif + +template< typename T > +struct storage_size_of +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t size = sizeof(T); + static BOOST_CONSTEXPR_OR_CONST std::size_t value = (size == 3u ? 4u : (size >= 5u && size <= 7u ? 8u : (size >= 9u && size <= 15u ? 16u : size))); +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_STORAGE_TYPE_HPP_INCLUDED_ diff --git a/boost/atomic/detail/string_ops.hpp b/boost/atomic/detail/string_ops.hpp new file mode 100644 index 0000000..ce145b9 --- /dev/null +++ b/boost/atomic/detail/string_ops.hpp @@ -0,0 +1,61 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/string_ops.hpp + * + * This header defines string operations for Boost.Atomic + */ + +#ifndef BOOST_ATOMIC_DETAIL_STRING_OPS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_STRING_OPS_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__has_builtin) +#if __has_builtin(__builtin_memcpy) +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCPY +#endif +#if __has_builtin(__builtin_memcmp) +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCMP +#endif +#if __has_builtin(__builtin_memset) +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMSET +#endif +#elif defined(BOOST_GCC) +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCPY +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCMP +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMSET +#endif + +#if defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCPY) +#define BOOST_ATOMIC_DETAIL_MEMCPY __builtin_memcpy +#else +#define BOOST_ATOMIC_DETAIL_MEMCPY std::memcpy +#endif + +#if defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCMP) +#define BOOST_ATOMIC_DETAIL_MEMCMP __builtin_memcmp +#else +#define BOOST_ATOMIC_DETAIL_MEMCMP std::memcmp +#endif + +#if defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMSET) +#define BOOST_ATOMIC_DETAIL_MEMSET __builtin_memset +#else +#define BOOST_ATOMIC_DETAIL_MEMSET std::memset +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCPY) || !defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCMP) || !defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMSET) +#include +#endif + +#endif // BOOST_ATOMIC_DETAIL_STRING_OPS_HPP_INCLUDED_ diff --git a/boost/atomic/detail/type_traits/conditional.hpp b/boost/atomic/detail/type_traits/conditional.hpp new file mode 100644 index 0000000..6b9e896 --- /dev/null +++ b/boost/atomic/detail/type_traits/conditional.hpp @@ -0,0 +1,42 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/conditional.hpp + * + * This header defines \c conditional type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_CONDITIONAL_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_CONDITIONAL_HPP_INCLUDED_ + +#include +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +using std::conditional; +#else +using boost::conditional; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_CONDITIONAL_HPP_INCLUDED_ diff --git a/boost/atomic/detail/type_traits/integral_constant.hpp b/boost/atomic/detail/type_traits/integral_constant.hpp new file mode 100644 index 0000000..eac8649 --- /dev/null +++ b/boost/atomic/detail/type_traits/integral_constant.hpp @@ -0,0 +1,46 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/integral_constant.hpp + * + * This header defines \c integral_constant wrapper + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_INTEGRAL_CONSTANT_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_INTEGRAL_CONSTANT_HPP_INCLUDED_ + +#include +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +using std::integral_constant; +using std::true_type; +using std::false_type; +#else +using boost::integral_constant; +using boost::true_type; +using boost::false_type; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_INTEGRAL_CONSTANT_HPP_INCLUDED_ diff --git a/boost/atomic/detail/type_traits/is_floating_point.hpp b/boost/atomic/detail/type_traits/is_floating_point.hpp new file mode 100644 index 0000000..46e2ab8 --- /dev/null +++ b/boost/atomic/detail/type_traits/is_floating_point.hpp @@ -0,0 +1,43 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/is_floating_point.hpp + * + * This header defines \c is_floating_point type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FLOATING_POINT_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FLOATING_POINT_HPP_INCLUDED_ + +#include +// Some versions of libstdc++ don't consider __float128 a floating point type. Use Boost.TypeTraits because of that. +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_FLOAT128) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_FLOAT128) +using std::is_floating_point; +#else +using boost::is_floating_point; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FLOATING_POINT_HPP_INCLUDED_ diff --git a/boost/atomic/detail/type_traits/is_function.hpp b/boost/atomic/detail/type_traits/is_function.hpp new file mode 100644 index 0000000..e720535 --- /dev/null +++ b/boost/atomic/detail/type_traits/is_function.hpp @@ -0,0 +1,42 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/is_function.hpp + * + * This header defines \c is_function type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FUNCTION_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FUNCTION_HPP_INCLUDED_ + +#include +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +using std::is_function; +#else +using boost::is_function; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FUNCTION_HPP_INCLUDED_ diff --git a/boost/atomic/detail/type_traits/is_iec559.hpp b/boost/atomic/detail/type_traits/is_iec559.hpp new file mode 100644 index 0000000..299c4f0 --- /dev/null +++ b/boost/atomic/detail/type_traits/is_iec559.hpp @@ -0,0 +1,47 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/is_iec559.hpp + * + * This header defines \c is_iec559 type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_IEC559_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_IEC559_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename T > +struct is_iec559 +{ + static BOOST_CONSTEXPR_OR_CONST bool value = !!std::numeric_limits< T >::is_iec559; +}; + +#if defined(BOOST_HAS_FLOAT128) +// libstdc++ does not specialize numeric_limits for __float128 +template< > +struct is_iec559< boost::float128_type > +{ + static BOOST_CONSTEXPR_OR_CONST bool value = true; +}; +#endif // defined(BOOST_HAS_FLOAT128) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_IEC559_HPP_INCLUDED_ diff --git a/boost/atomic/detail/type_traits/is_integral.hpp b/boost/atomic/detail/type_traits/is_integral.hpp new file mode 100644 index 0000000..ef3e2e3 --- /dev/null +++ b/boost/atomic/detail/type_traits/is_integral.hpp @@ -0,0 +1,43 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/is_integral.hpp + * + * This header defines \c is_integral type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_INTEGRAL_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_INTEGRAL_HPP_INCLUDED_ + +#include +// Some versions of libstdc++ don't consider __int128 an integral type. Use Boost.TypeTraits because of that. +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +using std::is_integral; +#else +using boost::is_integral; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_INTEGRAL_HPP_INCLUDED_ diff --git a/boost/atomic/detail/type_traits/is_signed.hpp b/boost/atomic/detail/type_traits/is_signed.hpp new file mode 100644 index 0000000..2dc1df7 --- /dev/null +++ b/boost/atomic/detail/type_traits/is_signed.hpp @@ -0,0 +1,43 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/is_signed.hpp + * + * This header defines \c is_signed type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_SIGNED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_SIGNED_HPP_INCLUDED_ + +#include +// Some versions of libstdc++ don't consider __int128 an integral type. Use Boost.TypeTraits because of that. +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +using std::is_signed; +#else +using boost::is_signed; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_SIGNED_HPP_INCLUDED_ diff --git a/boost/atomic/detail/type_traits/is_trivially_default_constructible.hpp b/boost/atomic/detail/type_traits/is_trivially_default_constructible.hpp new file mode 100644 index 0000000..5f88b88 --- /dev/null +++ b/boost/atomic/detail/type_traits/is_trivially_default_constructible.hpp @@ -0,0 +1,46 @@ +/* + * 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) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/is_trivially_default_constructible.hpp + * + * This header defines \c is_trivially_default_constructible type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_TRIVIALLY_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_TRIVIALLY_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_ + +#include +#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) +using std::is_trivially_default_constructible; +#elif !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) +template< typename T > +using is_trivially_default_constructible = boost::has_trivial_constructor< T >; +#else +template< typename T > +struct is_trivially_default_constructible : public boost::has_trivial_constructor< T > {}; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_TRIVIALLY_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_ diff --git a/boost/atomic/detail/type_traits/make_signed.hpp b/boost/atomic/detail/type_traits/make_signed.hpp new file mode 100644 index 0000000..82f61b3 --- /dev/null +++ b/boost/atomic/detail/type_traits/make_signed.hpp @@ -0,0 +1,43 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/make_signed.hpp + * + * This header defines \c make_signed type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_MAKE_SIGNED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_MAKE_SIGNED_HPP_INCLUDED_ + +#include +// Some versions of libstdc++ don't consider __int128 an integral type. Use Boost.TypeTraits because of that. +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +using std::make_signed; +#else +using boost::make_signed; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_MAKE_SIGNED_HPP_INCLUDED_ diff --git a/boost/atomic/detail/type_traits/make_unsigned.hpp b/boost/atomic/detail/type_traits/make_unsigned.hpp new file mode 100644 index 0000000..573a161 --- /dev/null +++ b/boost/atomic/detail/type_traits/make_unsigned.hpp @@ -0,0 +1,43 @@ +/* + * 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) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/make_unsigned.hpp + * + * This header defines \c make_unsigned type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_MAKE_UNSIGNED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_MAKE_UNSIGNED_HPP_INCLUDED_ + +#include +// Some versions of libstdc++ don't consider __int128 an integral type. Use Boost.TypeTraits because of that. +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +using std::make_unsigned; +#else +using boost::make_unsigned; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_MAKE_UNSIGNED_HPP_INCLUDED_ diff --git a/boost/atomic/fences.hpp b/boost/atomic/fences.hpp new file mode 100644 index 0000000..31e3040 --- /dev/null +++ b/boost/atomic/fences.hpp @@ -0,0 +1,67 @@ +/* + * 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) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/fences.hpp + * + * This header contains definition of \c atomic_thread_fence and \c atomic_signal_fence functions. + */ + +#ifndef BOOST_ATOMIC_FENCES_HPP_INCLUDED_ +#define BOOST_ATOMIC_FENCES_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +/* + * IMPLEMENTATION NOTE: All interface functions MUST be declared with BOOST_FORCEINLINE, + * see comment for convert_memory_order_to_gcc in ops_gcc_atomic.hpp. + */ + +namespace boost { + +namespace atomics { + +#if BOOST_ATOMIC_THREAD_FENCE > 0 +BOOST_FORCEINLINE void atomic_thread_fence(memory_order order) BOOST_NOEXCEPT +{ + detail::thread_fence(order); +} +#else +BOOST_FORCEINLINE void atomic_thread_fence(memory_order) BOOST_NOEXCEPT +{ + detail::lockpool::thread_fence(); +} +#endif + +#if BOOST_ATOMIC_SIGNAL_FENCE > 0 +BOOST_FORCEINLINE void atomic_signal_fence(memory_order order) BOOST_NOEXCEPT +{ + detail::signal_fence(order); +} +#else +BOOST_FORCEINLINE void atomic_signal_fence(memory_order) BOOST_NOEXCEPT +{ + detail::lockpool::signal_fence(); +} +#endif + +} // namespace atomics + +using atomics::atomic_thread_fence; +using atomics::atomic_signal_fence; + +} // namespace boost + +#endif // BOOST_ATOMIC_FENCES_HPP_INCLUDED_ diff --git a/boost/chrono.hpp b/boost/chrono.hpp new file mode 100644 index 0000000..a3a3522 --- /dev/null +++ b/boost/chrono.hpp @@ -0,0 +1,20 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2010. +// 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/libs/stm for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CHRONO_HPP +#define BOOST_CHRONO_HPP + +//----------------------------------------------------------------------------- +#include +//----------------------------------------------------------------------------- + +#endif // BOOST_CHRONO_HPP diff --git a/boost/chrono/ceil.hpp b/boost/chrono/ceil.hpp new file mode 100644 index 0000000..7fbf9dd --- /dev/null +++ b/boost/chrono/ceil.hpp @@ -0,0 +1,36 @@ +// boost/chrono/round.hpp ------------------------------------------------------------// + +// (C) Copyright Howard Hinnant +// Copyright 2011 Vicente J. Botet Escriba + +// 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/libs/chrono for documentation. + +#ifndef BOOST_CHRONO_CEIL_HPP +#define BOOST_CHRONO_CEIL_HPP + +#include + +namespace boost +{ + namespace chrono + { + + /** + * rounds up + */ + template + To ceil(const duration& d) + { + To t = duration_cast(d); + if (t < d) + ++t; + return t; + } + + } // namespace chrono +} // namespace boost + +#endif diff --git a/boost/chrono/chrono_io.hpp b/boost/chrono/chrono_io.hpp new file mode 100644 index 0000000..ebd18a3 --- /dev/null +++ b/boost/chrono/chrono_io.hpp @@ -0,0 +1,34 @@ + +// chrono_io +// +// (C) Copyright Howard Hinnant +// (C) Copyright 2010-2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o under lvm/libc++ to Boost + +#ifndef BOOST_CHRONO_CHRONO_IO_HPP +#define BOOST_CHRONO_CHRONO_IO_HPP + +#include + +//#if BOOST_CHRONO_VERSION == 2 +//#include +//#include +//#elif BOOST_CHRONO_VERSION == 1 +//#include +//#endif + +#if defined BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 +#include +#include +#else +#include +#endif + +#include + +#endif // BOOST_CHRONO_CHRONO_IO_HPP diff --git a/boost/chrono/detail/no_warning/signed_unsigned_cmp.hpp b/boost/chrono/detail/no_warning/signed_unsigned_cmp.hpp new file mode 100644 index 0000000..94936c8 --- /dev/null +++ b/boost/chrono/detail/no_warning/signed_unsigned_cmp.hpp @@ -0,0 +1,54 @@ +// is_evenly_divisible_by.hpp --------------------------------------------------------------// + +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHRONO_DETAIL_NO_WARNING_SIGNED_UNSIGNED_CMP_HPP +#define BOOST_CHRONO_DETAIL_NO_WARNING_SIGNED_UNSIGNED_CMP_HPP + +// +// We simply cannot include this header on gcc without getting copious warnings of the kind: +// +//../../../boost/chrono/detail/no_warning/signed_unsigned_cmp.hpp:37: warning: comparison between signed and unsigned integer expressions +// +// And yet there is no other reasonable implementation, so we declare this a system header +// to suppress these warnings. +// + +#if defined(__GNUC__) && (__GNUC__ >= 4) +#pragma GCC system_header +#elif defined __SUNPRO_CC +#pragma disable_warn +#elif defined _MSC_VER +#pragma warning(push, 1) +#endif + +namespace boost { +namespace chrono { +namespace detail { + + template + bool lt(T t, U u) + { + return t < u; + } + + template + bool gt(T t, U u) + { + return t > u; + } + +} // namespace detail +} // namespace detail +} // namespace chrono + +#if defined __SUNPRO_CC +#pragma enable_warn +#elif defined _MSC_VER +#pragma warning(pop) +#endif + +#endif // BOOST_CHRONO_DETAIL_NO_WARNING_SIGNED_UNSIGNED_CMP_HPP diff --git a/boost/chrono/detail/scan_keyword.hpp b/boost/chrono/detail/scan_keyword.hpp new file mode 100644 index 0000000..aa4e2e8 --- /dev/null +++ b/boost/chrono/detail/scan_keyword.hpp @@ -0,0 +1,163 @@ +// scan_keyword.hpp --------------------------------------------------------------// +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Adaptation to Boost of the libcxx + +// Copyright 2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHRONO_DETAIL_SCAN_KEYWORD_HPP +#define BOOST_CHRONO_DETAIL_SCAN_KEYWORD_HPP + +#include + +#include +#include +#include +#include +#include + +namespace boost { + using movelib::unique_ptr; + +namespace chrono { +namespace chrono_detail { + +inline void free_aux(void* ptr) { free(ptr); } + +// scan_keyword +// Scans [b, e) until a match is found in the basic_strings range +// [kb, ke) or until it can be shown that there is no match in [kb, ke). +// b will be incremented (visibly), consuming CharT until a match is found +// or proved to not exist. A keyword may be "", in which will match anything. +// If one keyword is a prefix of another, and the next CharT in the input +// might match another keyword, the algorithm will attempt to find the longest +// matching keyword. If the longer matching keyword ends up not matching, then +// no keyword match is found. If no keyword match is found, ke is returned +// and failbit is set in err. +// Else an iterator pointing to the matching keyword is found. If more than +// one keyword matches, an iterator to the first matching keyword is returned. +// If on exit b == e, eofbit is set in err. +// Examples: +// Keywords: "a", "abb" +// If the input is "a", the first keyword matches and eofbit is set. +// If the input is "abc", no match is found and "ab" are consumed. + +template +ForwardIterator +scan_keyword(InputIterator& b, InputIterator e, + ForwardIterator kb, ForwardIterator ke, + std::ios_base::iostate& err + ) +{ + typedef typename std::iterator_traits::value_type CharT; + size_t nkw = std::distance(kb, ke); + const unsigned char doesnt_match = '\0'; + const unsigned char might_match = '\1'; + const unsigned char does_match = '\2'; + unsigned char statbuf[100]; + unsigned char* status = statbuf; + // Change free by free_aux to avoid + // Error: Could not find a match for boost::interprocess::unique_ptr::unique_ptr(int, extern "C" void(void*)) + unique_ptr stat_hold(0, free_aux); + if (nkw > sizeof(statbuf)) + { + status = (unsigned char*)malloc(nkw); + if (status == 0) + throw_exception(std::bad_alloc()); + stat_hold.reset(status); + } + size_t n_might_match = nkw; // At this point, any keyword might match + size_t n_does_match = 0; // but none of them definitely do + // Initialize all statuses to might_match, except for "" keywords are does_match + unsigned char* st = status; + for (ForwardIterator ky = kb; ky != ke; ++ky, ++st) + { + if (!ky->empty()) + *st = might_match; + else + { + *st = does_match; + --n_might_match; + ++n_does_match; + } + } + // While there might be a match, test keywords against the next CharT + for (size_t indx = 0; b != e && n_might_match > 0; ++indx) + { + // Peek at the next CharT but don't consume it + CharT c = *b; + bool consume = false; + // For each keyword which might match, see if the indx character is c + // If a match if found, consume c + // If a match is found, and that is the last character in the keyword, + // then that keyword matches. + // If the keyword doesn't match this character, then change the keyword + // to doesn't match + st = status; + for (ForwardIterator ky = kb; ky != ke; ++ky, ++st) + { + if (*st == might_match) + { + CharT kc = (*ky)[indx]; + if (c == kc) + { + consume = true; + if (ky->size() == indx+1) + { + *st = does_match; + --n_might_match; + ++n_does_match; + } + } + else + { + *st = doesnt_match; + --n_might_match; + } + } + } + // consume if we matched a character + if (consume) + { + ++b; + // If we consumed a character and there might be a matched keyword that + // was marked matched on a previous iteration, then such keywords + // which are now marked as not matching. + if (n_might_match + n_does_match > 1) + { + st = status; + for (ForwardIterator ky = kb; ky != ke; ++ky, ++st) + { + if (*st == does_match && ky->size() != indx+1) + { + *st = doesnt_match; + --n_does_match; + } + } + } + } + } + // We've exited the loop because we hit eof and/or we have no more "might matches". + if (b == e) + err |= std::ios_base::eofbit; + // Return the first matching result + for (st = status; kb != ke; ++kb, ++st) + if (*st == does_match) + break; + if (kb == ke) + err |= std::ios_base::failbit; + return kb; +} +} +} +} +#endif // BOOST_CHRONO_DETAIL_SCAN_KEYWORD_HPP diff --git a/boost/chrono/floor.hpp b/boost/chrono/floor.hpp new file mode 100644 index 0000000..eb85fa7 --- /dev/null +++ b/boost/chrono/floor.hpp @@ -0,0 +1,36 @@ +// boost/chrono/round.hpp ------------------------------------------------------------// + +// (C) Copyright Howard Hinnant +// Copyright 2011 Vicente J. Botet Escriba + +// 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/libs/chrono for documentation. + +#ifndef BOOST_CHRONO_FLOOR_HPP +#define BOOST_CHRONO_FLOOR_HPP + +#include + +namespace boost +{ + namespace chrono + { + + /** + * rounds down + */ + template + To floor(const duration& d) + { + To t = duration_cast(d); + if (t>d) --t; + return t; + } + + + } // namespace chrono +} // namespace boost + +#endif diff --git a/boost/chrono/include.hpp b/boost/chrono/include.hpp new file mode 100644 index 0000000..b58f76b --- /dev/null +++ b/boost/chrono/include.hpp @@ -0,0 +1,23 @@ + +// include +// +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o under lvm/libc++ to Boost + +#ifndef BOOST_CHRONO_INCLUDE_HPP +#define BOOST_CHRONO_INCLUDE_HPP + +#include +#include +#include +#include +#include +#include +#include + +#endif // BOOST_CHRONO_INCLUDE_HPP diff --git a/boost/chrono/io/duration_get.hpp b/boost/chrono/io/duration_get.hpp new file mode 100644 index 0000000..081f071 --- /dev/null +++ b/boost/chrono/io/duration_get.hpp @@ -0,0 +1,591 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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_CHRONO_IO_DURATION_GET_HPP +#define BOOST_CHRONO_IO_DURATION_GET_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/** + * Duration formatting facet for input. + */ +namespace boost +{ + namespace chrono + { + + namespace detail + { + template ::value> + struct duration_io_intermediate + { + typedef Rep type; + }; + + template + struct duration_io_intermediate + { + typedef typename mpl::if_c::value, long double, typename mpl::if_c< + is_signed::value, long long, unsigned long long>::type>::type type; + }; + + template + struct duration_io_intermediate, false> + { + typedef process_times::type> type; + }; + + template + typename enable_if , bool>::type reduce(intermediate_type& r, + unsigned long long& den, std::ios_base::iostate& err) + { + typedef typename common_type::type common_type_t; + + // Reduce r * num / den + common_type_t t = integer::gcd(common_type_t(r), common_type_t(den)); + r /= t; + den /= t; + if (den != 1) + { + // Conversion to Period is integral and not exact + err |= std::ios_base::failbit; + return false; + } + return true; + } + template + typename disable_if , bool>::type reduce(intermediate_type&, unsigned long long&, + std::ios_base::iostate&) + { + return true; + } + + } + + /** + * @c duration_get is used to parse a character sequence, extracting + * components of a duration into a class duration. + * Each get member parses a format as produced by a corresponding format specifier to time_put<>::put. + * If the sequence being parsed matches the correct format, the + * corresponding member of the class duration argument are set to the + * value used to produce the sequence; + * otherwise either an error is reported or unspecified values are assigned. + * In other words, user confirmation is required for reliable parsing of + * user-entered durations, but machine-generated formats can be parsed + * reliably. This allows parsers to be aggressive about interpreting user + * variations on standard formats. + * + * If the end iterator is reached during parsing of the get() member + * function, the member sets std::ios_base::eofbit in err. + */ + template > + class duration_get: public std::locale::facet + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string passed to member functions. + */ + typedef std::basic_string string_type; + /** + * Type of iterator used to scan the character buffer. + */ + typedef InputIterator iter_type; + + /** + * Construct a @c duration_get facet. + * @param refs + * @Effects Construct a @c duration_get facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + + explicit duration_get(size_t refs = 0) : + std::locale::facet(refs) + { + } + + /** + * @param s start input stream iterator + * @param end end input stream iterator + * @param ios a reference to a ios_base + * @param err the ios_base state + * @param d the duration + * @param pattern begin of the formatting pattern + * @param pat_end end of the formatting pattern + * + * Requires: [pattern,pat_end) shall be a valid range. + * + * Effects: The function starts by evaluating err = std::ios_base::goodbit. + * It then enters a loop, reading zero or more characters from s at + * each iteration. Unless otherwise specified below, the loop + * terminates when the first of the following conditions holds: + * - The expression pattern == pat_end evaluates to true. + * - The expression err == std::ios_base::goodbit evaluates to false. + * - The expression s == end evaluates to true, in which case the + * function evaluates err = std::ios_base::eofbit | std::ios_base::failbit. + * - The next element of pattern is equal to '%', followed by a conversion + * specifier character, format. + * If the number of elements in the range [pattern,pat_end) is not + * sufficient to unambiguously determine whether the conversion + * specification is complete and valid, the function evaluates + * err = std::ios_base::failbit. Otherwise, the function evaluates + * s = get_value(s, end, ios, err, r) when the conversion specification is 'v' and + * s = get_value(s, end, ios, err, rt) when the conversion specification is 'u'. + * If err == std::ios_base::goodbit holds after + * the evaluation of the expression, the function increments pattern to + * point just past the end of the conversion specification and continues + * looping. + * - The expression isspace(*pattern, ios.getloc()) evaluates to true, in + * which case the function first increments pattern until + * pattern == pat_end || !isspace(*pattern, ios.getloc()) evaluates to true, + * then advances s until s == end || !isspace(*s, ios.getloc()) is true, + * and finally resumes looping. + * - The next character read from s matches the element pointed to by + * pattern in a case-insensitive comparison, in which case the function + * evaluates ++pattern, ++s and continues looping. Otherwise, the function + * evaluates err = std::ios_base::failbit. + * + * Once r and rt are retrieved, + * Returns: s + */ + template + iter_type get(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, + duration &d, const char_type *pattern, const char_type *pat_end) const + { + if (std::has_facet >(ios.getloc())) + { + duration_units const&facet = std::use_facet >(ios.getloc()); + return get(facet, s, end, ios, err, d, pattern, pat_end); + } + else + { + duration_units_default facet; + return get(facet, s, end, ios, err, d, pattern, pat_end); + } + } + + template + iter_type get(duration_units const&facet, iter_type s, iter_type end, std::ios_base& ios, + std::ios_base::iostate& err, duration &d, const char_type *pattern, const char_type *pat_end) const + { + + typedef typename detail::duration_io_intermediate::type intermediate_type; + intermediate_type r; + rt_ratio rt; + bool value_found = false, unit_found = false; + + const std::ctype& ct = std::use_facet >(ios.getloc()); + while (pattern != pat_end && err == std::ios_base::goodbit) + { + if (s == end) + { + err |= std::ios_base::eofbit; + break; + } + if (ct.narrow(*pattern, 0) == '%') + { + if (++pattern == pat_end) + { + err |= std::ios_base::failbit; + return s; + } + char cmd = ct.narrow(*pattern, 0); + switch (cmd) + { + case 'v': + { + if (value_found) + { + err |= std::ios_base::failbit; + return s; + } + value_found = true; + s = get_value(s, end, ios, err, r); + if (err & (std::ios_base::badbit | std::ios_base::failbit)) + { + return s; + } + break; + } + case 'u': + { + if (unit_found) + { + err |= std::ios_base::failbit; + return s; + } + unit_found = true; + s = get_unit(facet, s, end, ios, err, rt); + if (err & (std::ios_base::badbit | std::ios_base::failbit)) + { + return s; + } + break; + } + default: + BOOST_ASSERT(false && "Boost::Chrono internal error."); + break; + } + + ++pattern; + } + else if (ct.is(std::ctype_base::space, *pattern)) + { + for (++pattern; pattern != pat_end && ct.is(std::ctype_base::space, *pattern); ++pattern) + ; + for (; s != end && ct.is(std::ctype_base::space, *s); ++s) + ; + } + else if (ct.toupper(*s) == ct.toupper(*pattern)) + { + ++s; + ++pattern; + } + else + { + err |= std::ios_base::failbit; + return s; + } + + } + + unsigned long long num = rt.num; + unsigned long long den = rt.den; + + // r should be multiplied by (num/den) / Period + // Reduce (num/den) / Period to lowest terms + unsigned long long gcd_n1_n2 = integer::gcd(num, Period::num); + unsigned long long gcd_d1_d2 = integer::gcd(den, Period::den); + num /= gcd_n1_n2; + den /= gcd_d1_d2; + unsigned long long n2 = Period::num / gcd_n1_n2; + unsigned long long d2 = Period::den / gcd_d1_d2; + if (num > (std::numeric_limits::max)() / d2 || den + > (std::numeric_limits::max)() / n2) + { + // (num/den) / Period overflows + err |= std::ios_base::failbit; + return s; + } + num *= d2; + den *= n2; + + typedef typename common_type::type common_type_t; + + // num / den is now factor to multiply by r + if (!detail::reduce(r, den, err)) return s; + + if (chrono::detail::gt(r, ( (duration_values::max)() / num))) + { + // Conversion to Period overflowed + err |= std::ios_base::failbit; + return s; + } + common_type_t t = r * num; + t /= den; + if (t > duration_values::zero()) + { + if ( (duration_values::max)() < Rep(t)) + { + // Conversion to Period overflowed + err |= std::ios_base::failbit; + return s; + } + } + // Success! Store it. + d = duration (Rep(t)); + + return s; + } + + /** + * + * @param s start input stream iterator + * @param end end input stream iterator + * @param ios a reference to a ios_base + * @param err the ios_base state + * @param d the duration + * Stores the duration pattern from the @c duration_unit facet in let say @c str. Last as if + * @code + * return get(s, end, ios, err, ios, d, str.data(), str.data() + str.size()); + * @codeend + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name + */ + template + iter_type get(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, + duration & d) const + { + if (std::has_facet >(ios.getloc())) + { + duration_units const&facet = std::use_facet >(ios.getloc()); + std::basic_string str = facet.get_pattern(); + return get(facet, s, end, ios, err, d, str.data(), str.data() + str.size()); + } + else + { + duration_units_default facet; + std::basic_string str = facet.get_pattern(); + return get(facet, s, end, ios, err, d, str.data(), str.data() + str.size()); + } + } + + /** + * + * @param s start input stream iterator + * @param end end input stream iterator + * @param ios a reference to a ios_base + * @param err the ios_base state + * @param r a reference to the duration representation. + * @Effects As if + * @code + * return std::use_facet >(ios.getloc()).get(s, end, ios, err, r); + * @endcode + * + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name + */ + template + iter_type get_value(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, Rep& r) const + { + return std::use_facet >(ios.getloc()).get(s, end, ios, err, r); + } + template + iter_type get_value(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, process_times& r) const + { + if (s == end) { + err |= std::ios_base::eofbit; + return s; + } else if (*s != '{') { // mandatory '{' + err |= std::ios_base::failbit; + return s; + } + ++s; + s = std::use_facet >(ios.getloc()).get(s, end, ios, err, r.real); + if (s == end) { + err |= std::ios_base::eofbit; + return s; + } else if (*s != ';') { // mandatory ';' + err |= std::ios_base::failbit; + return s; + } + ++s; + s = std::use_facet >(ios.getloc()).get(s, end, ios, err, r.user); + if (s == end) { + err |= std::ios_base::eofbit; + return s; + } else if (*s != ';') { // mandatory ';' + err |= std::ios_base::failbit; + return s; + } + ++s; + s = std::use_facet >(ios.getloc()).get(s, end, ios, err, r.system); + if (s == end) { + err |= std::ios_base::eofbit; + return s; + } else if (*s != '}') { // mandatory '}' + err |= std::ios_base::failbit; + return s; + } + return s; + } + + /** + * + * @param s start input stream iterator + * @param e end input stream iterator + * @param ios a reference to a ios_base + * @param err the ios_base state + * @param rt a reference to the duration run-time ratio. + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name + */ + iter_type get_unit(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, rt_ratio &rt) const + { + if (std::has_facet >(is.getloc())) + { + return get_unit(std::use_facet >(is.getloc()), i, e, is, err, rt); + } + else + { + duration_units_default facet; + return get_unit(facet, i, e, is, err, rt); + } + } + + + iter_type get_unit(duration_units const &facet, iter_type i, iter_type e, std::ios_base& is, + std::ios_base::iostate& err, rt_ratio &rt) const + { + + if (*i == '[') + { + // parse [N/D]s or [N/D]second or [N/D]seconds format + ++i; + i = std::use_facet >(is.getloc()).get(i, e, is, err, rt.num); + if ( (err & std::ios_base::failbit) != 0) + { + return i; + } + + if (i == e) + { + err |= std::ios_base::failbit; + return i; + } + CharT x = *i++; + if (x != '/') + { + err |= std::ios_base::failbit; + return i; + } + i = std::use_facet >(is.getloc()).get(i, e, is, err, rt.den); + if ( (err & std::ios_base::failbit) != 0) + { + return i; + } + if (i == e) + { + err |= std::ios_base::failbit; + return i; + } + if (*i != ']') + { + err |= std::ios_base::failbit; + return i; + } + ++i; + if (i == e) + { + err |= std::ios_base::failbit; + return i; + } + // parse s or second or seconds + return do_get_n_d_valid_unit(facet, i, e, is, err); + } + else + { + return do_get_valid_unit(facet, i, e, is, err, rt); + } + } + + /** + * Unique identifier for this type of facet. + */ + static std::locale::id id; + + /** + * @Effects Destroy the facet + */ + ~duration_get() + { + } + + protected: + + /** + * Extracts the run-time ratio associated to the duration when it is given in prefix form. + * + * This is an extension point of this facet so that we can take in account other periods that can have a useful + * translation in other contexts, as e.g. days and weeks. + * + * @param facet the duration_units facet + * @param i start input stream iterator. + * @param e end input stream iterator. + * @param ios a reference to a ios_base. + * @param err the ios_base state. + * @return @c s + */ + iter_type do_get_n_d_valid_unit(duration_units const &facet, iter_type i, iter_type e, + std::ios_base&, std::ios_base::iostate& err) const + { + // parse SI name, short or long + + const string_type* units = facet.get_n_d_valid_units_start(); + const string_type* units_end = facet.get_n_d_valid_units_end(); + + const string_type* k = chrono_detail::scan_keyword(i, e, units, units_end, + //~ std::use_facet >(loc), + err); + if (err & (std::ios_base::badbit | std::ios_base::failbit)) + { + return i; + } + if (!facet.match_n_d_valid_unit(k)) + { + err |= std::ios_base::failbit; + } + return i; + } + + /** + * Extracts the run-time ratio associated to the duration when it is given in prefix form. + * + * This is an extension point of this facet so that we can take in account other periods that can have a useful + * translation in other contexts, as e.g. days and weeks. + * + * @param facet the duration_units facet + * @param i start input stream iterator. + * @param e end input stream iterator. + * @param ios a reference to a ios_base. + * @param err the ios_base state. + * @param rt a reference to the duration run-time ratio. + * @Effects + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name. + */ + iter_type do_get_valid_unit(duration_units const &facet, iter_type i, iter_type e, + std::ios_base&, std::ios_base::iostate& err, rt_ratio &rt) const + { + // parse SI name, short or long + + const string_type* units = facet.get_valid_units_start(); + const string_type* units_end = facet.get_valid_units_end(); + + err = std::ios_base::goodbit; + const string_type* k = chrono_detail::scan_keyword(i, e, units, units_end, + //~ std::use_facet >(loc), + err); + if (err & (std::ios_base::badbit | std::ios_base::failbit)) + { + return i; + } + if (!facet.match_valid_unit(k, rt)) + { + err |= std::ios_base::failbit; + } + return i; + } + }; + + /** + * Unique identifier for this type of facet. + */ + template + std::locale::id duration_get::id; + + } // chrono +} +// boost + +#endif // header diff --git a/boost/chrono/io/duration_io.hpp b/boost/chrono/io/duration_io.hpp new file mode 100644 index 0000000..f3aca6a --- /dev/null +++ b/boost/chrono/io/duration_io.hpp @@ -0,0 +1,295 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o to Boost + +#ifndef BOOST_CHRONO_IO_DURATION_IO_HPP +#define BOOST_CHRONO_IO_DURATION_IO_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace chrono + { + + /** + * duration parameterized manipulator. + */ + + class duration_fmt: public manip + { + duration_style style_; + public: + + /** + * explicit manipulator constructor from a @c duration_style + */ + explicit duration_fmt(duration_style style)BOOST_NOEXCEPT + : style_(style) + {} + + /** + * Change the duration_style ios state; + */ + void operator()(std::ios_base &ios) const + + { + set_duration_style(ios, style_); + } + }; + + /** + * duration_style i/o saver. + * + * See Boost.IO i/o state savers for a motivating compression. + */ + struct duration_style_io_saver + { + + //! the type of the state to restore + typedef std::ios_base state_type; + //! the type of aspect to save + typedef duration_style aspect_type; + + /** + * Explicit construction from an i/o stream. + * + * Store a reference to the i/o stream and the value of the associated @c duration_style. + */ + explicit duration_style_io_saver(state_type &s) : + s_save_(s), a_save_(get_duration_style(s)) + { + } + + /** + * Construction from an i/o stream and a @c duration_style to restore. + * + * Stores a reference to the i/o stream and the value @c new_value @c duration_style to set. + */ + duration_style_io_saver(state_type &s, aspect_type new_value) : + s_save_(s), a_save_(get_duration_style(s)) + { + set_duration_style(s, new_value); + } + + /** + * Destructor. + * + * Restores the i/o stream with the duration_style to be restored. + */ + ~duration_style_io_saver() + { + this->restore(); + } + + /** + * Restores the i/o stream with the duration_style to be restored. + */ + void restore() + { + set_duration_style(s_save_, a_save_); + } + + private: + duration_style_io_saver& operator=(duration_style_io_saver const& rhs) ; + + state_type& s_save_; + aspect_type a_save_; + }; + + template + struct duration_put_enabled + : integral_constant::value || is_floating_point::value + > + {}; + + + /** + * duration stream inserter + * @param os the output stream + * @param d to value to insert + * @return @c os + */ + + template + typename boost::enable_if_c< ! duration_put_enabled::value, std::basic_ostream& >::type + operator<<(std::basic_ostream& os, const duration& d) + { + std::basic_ostringstream ostr; + ostr << d.count(); + duration dd(0); + bool failed = false; + BOOST_TRY + { + std::ios_base::iostate err = std::ios_base::goodbit; + BOOST_TRY + { + typename std::basic_ostream::sentry opfx(os); + if (bool(opfx)) + { + if (!std::has_facet >(os.getloc())) + { + if (duration_put ().put(os, os, os.fill(), dd, ostr.str().c_str()) .failed()) + { + err = std::ios_base::badbit; + } + } + else if (std::use_facet >(os.getloc()) .put(os, os, os.fill(), dd, ostr.str().c_str()) .failed()) + { + err = std::ios_base::badbit; + } + os.width(0); + } + } + BOOST_CATCH(...) + { + bool flag = false; + BOOST_TRY + { + os.setstate(std::ios_base::failbit); + } + BOOST_CATCH (std::ios_base::failure ) + { + flag = true; + } + BOOST_CATCH_END + if (flag) throw; + } + BOOST_CATCH_END + if (err) os.setstate(err); + return os; + } + BOOST_CATCH(...) + { + failed = true; + } + BOOST_CATCH_END + if (failed) os.setstate(std::ios_base::failbit | std::ios_base::badbit); + return os; + + } + + template + typename boost::enable_if_c< duration_put_enabled::value, std::basic_ostream& >::type + operator<<(std::basic_ostream& os, const duration& d) + { + bool failed = false; + BOOST_TRY + { + std::ios_base::iostate err = std::ios_base::goodbit; + BOOST_TRY + { + typename std::basic_ostream::sentry opfx(os); + if (bool(opfx)) + { + if (!std::has_facet >(os.getloc())) + { + if (duration_put ().put(os, os, os.fill(), d) .failed()) + { + err = std::ios_base::badbit; + } + } + else if (std::use_facet >(os.getloc()) .put(os, os, os.fill(), d) .failed()) + { + err = std::ios_base::badbit; + } + os.width(0); + } + } + BOOST_CATCH(...) + { + bool flag = false; + BOOST_TRY + { + os.setstate(std::ios_base::failbit); + } + BOOST_CATCH (std::ios_base::failure ) + { + flag = true; + } + BOOST_CATCH_END + if (flag) throw; + } + BOOST_CATCH_END + if (err) os.setstate(err); + return os; + } + BOOST_CATCH(...) + { + failed = true; + } + BOOST_CATCH_END + if (failed) os.setstate(std::ios_base::failbit | std::ios_base::badbit); + return os; + } + + /** + * + * @param is the input stream + * @param d the duration + * @return @c is + */ + template + std::basic_istream& + operator>>(std::basic_istream& is, duration& d) + { + std::ios_base::iostate err = std::ios_base::goodbit; + + BOOST_TRY + { + typename std::basic_istream::sentry ipfx(is); + if (bool(ipfx)) + { + if (!std::has_facet >(is.getloc())) + { + duration_get ().get(is, std::istreambuf_iterator(), is, err, d); + } + else + { + std::use_facet >(is.getloc()) .get(is, std::istreambuf_iterator(), is, + err, d); + } + } + } + BOOST_CATCH (...) + { + bool flag = false; + BOOST_TRY + { + is.setstate(std::ios_base::failbit); + } + BOOST_CATCH (std::ios_base::failure ) + { + flag = true; + } + BOOST_CATCH_END + if (flag) { BOOST_RETHROW } + } + BOOST_CATCH_END + if (err) is.setstate(err); + return is; + } + + } // chrono + +} + +#endif // header diff --git a/boost/chrono/io/duration_put.hpp b/boost/chrono/io/duration_put.hpp new file mode 100644 index 0000000..623eae1 --- /dev/null +++ b/boost/chrono/io/duration_put.hpp @@ -0,0 +1,317 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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). +// + +/** + * Duration formatting facet for output. + */ +#ifndef BOOST_CHRONO_IO_DURATION_PUT_HPP +#define BOOST_CHRONO_IO_DURATION_PUT_HPP + +#include +#include +#include +#include +#include + +namespace boost +{ + namespace chrono + { + + namespace detail + { + template + struct propagate { + typedef T type; + }; + template <> + struct propagate { + typedef boost::int_least64_t type; + }; + } + /** + * @tparam ChatT a character type + * @tparam OutputIterator a model of @c OutputIterator + * + * The @c duration_put facet provides facilities for formatted output of duration values. + * The member function of @c duration_put take a duration and format it into character string representation. + * + */ + template > + class duration_put: public std::locale::facet + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string passed to member functions. + */ + typedef std::basic_string string_type; + /** + * Type of iterator used to write in the character buffer. + */ + typedef OutputIterator iter_type; + + /** + * Construct a duration_put facet. + * @param refs + * @Effects Construct a duration_put facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + explicit duration_put(size_t refs = 0) : + std::locale::facet(refs) + { + } + + /** + * + * @param s an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param d the duration + * @param pattern begin of the formatting pattern + * @param pat_end end of the formatting pattern + * + * @Effects Steps through the sequence from @c pattern to @c pat_end, + * identifying characters that are part of a pattern sequence. Each character + * that is not part of a pattern sequence is written to @c s immediately, and + * each pattern sequence, as it is identified, results in a call to + * @c put_value or @c put_unit; + * thus, pattern elements and other characters are interleaved in the output + * in the order in which they appear in the pattern. Pattern sequences are + * identified by converting each character @c c to a @c char value as if by + * @c ct.narrow(c,0), where @c ct is a reference to @c ctype obtained from + * @c ios.getloc(). The first character of each sequence is equal to @c '%', + * followed by a pattern specifier character @c spec, which can be @c 'v' for + * the duration value or @c 'u' for the duration unit. . + * For each valid pattern sequence identified, calls + * put_value(s, ios, fill, d) or put_unit(s, ios, fill, d). + * + * @Returns An iterator pointing immediately after the last character produced. + */ + template + iter_type put(iter_type s, std::ios_base& ios, char_type fill, duration const& d, const CharT* pattern, + const CharT* pat_end, const char_type* val = 0) const + { + if (std::has_facet >(ios.getloc())) + { + duration_units const&facet = std::use_facet >( + ios.getloc()); + return put(facet, s, ios, fill, d, pattern, pat_end, val); + } + else + { + duration_units_default facet; + return put(facet, s, ios, fill, d, pattern, pat_end, val); + } + } + + template + iter_type put(duration_units const& units_facet, iter_type s, std::ios_base& ios, char_type fill, + duration const& d, const CharT* pattern, const CharT* pat_end, const char_type* val = 0) const + { + + const std::ctype& ct = std::use_facet >(ios.getloc()); + for (; pattern != pat_end; ++pattern) + { + if (ct.narrow(*pattern, 0) == '%') + { + if (++pattern == pat_end) + { + *s++ = pattern[-1]; + break; + } + char fmt = ct.narrow(*pattern, 0); + switch (fmt) + { + case 'v': + { + s = put_value(s, ios, fill, d, val); + break; + } + case 'u': + { + s = put_unit(units_facet, s, ios, fill, d); + break; + } + default: + BOOST_ASSERT(false && "Boost::Chrono internal error."); + break; + } + } + else + *s++ = *pattern; + } + return s; + } + + /** + * + * @param s an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param d the duration + * @Effects imbue in @c ios the @c duration_units_default facet if not already present. + * Retrieves Stores the duration pattern from the @c duration_unit facet in let say @c str. Last as if + * @code + * return put(s, ios, d, str.data(), str.data() + str.size()); + * @endcode + * @Returns An iterator pointing immediately after the last character produced. + */ + template + iter_type put(iter_type s, std::ios_base& ios, char_type fill, duration const& d, const char_type* val = 0) const + { + if (std::has_facet >(ios.getloc())) + { + duration_units const&facet = std::use_facet >( + ios.getloc()); + std::basic_string str = facet.get_pattern(); + return put(facet, s, ios, fill, d, str.data(), str.data() + str.size(), val); + } + else + { + duration_units_default facet; + std::basic_string str = facet.get_pattern(); + + return put(facet, s, ios, fill, d, str.data(), str.data() + str.size(), val); + } + } + + /** + * + * @param s an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param d the duration + * @Effects As if s=std::use_facet >(ios.getloc()).put(s, ios, fill, static_cast (d.count())). + * @Returns s, iterator pointing immediately after the last character produced. + */ + template + iter_type put_value(iter_type s, std::ios_base& ios, char_type fill, duration const& d, const char_type* val = 0) const + { + if (val) + { + while (*val) { + *s = *val; + s++; val++; + } + return s; + } + return std::use_facet >(ios.getloc()).put(s, ios, fill, + static_cast::type> (d.count())); + } + + template + iter_type put_value(iter_type s, std::ios_base& ios, char_type fill, duration, Period> const& d, const char_type* = 0) const + { + *s++ = CharT('{'); + s = put_value(s, ios, fill, process_real_cpu_clock::duration(d.count().real)); + *s++ = CharT(';'); + s = put_value(s, ios, fill, process_user_cpu_clock::duration(d.count().user)); + *s++ = CharT(';'); + s = put_value(s, ios, fill, process_system_cpu_clock::duration(d.count().system)); + *s++ = CharT('}'); + return s; + } + + /** + * + * @param s an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param d the duration + * @Effects Let facet be the duration_units facet associated to ios. If the associated unit is named, + * as if + * @code + string_type str = facet.get_unit(get_duration_style(ios), d); + s=std::copy(str.begin(), str.end(), s); + * @endcode + * Otherwise, format the unit as "[Period::num/Period::den]" followed by the unit associated to [N/D] obtained using facet.get_n_d_unit(get_duration_style(ios), d) + * @Returns s, iterator pointing immediately after the last character produced. + */ + template + iter_type put_unit(iter_type s, std::ios_base& ios, char_type fill, duration const& d) const + { + if (std::has_facet >(ios.getloc())) + { + duration_units const&facet = std::use_facet >( + ios.getloc()); + return put_unit(facet, s, ios, fill, d); + } + else + { + duration_units_default facet; + return put_unit(facet, s, ios, fill, d); + } + } + + template + iter_type put_unit(duration_units const& facet, iter_type s, std::ios_base& ios, char_type fill, + duration const& d) const + { + if (facet.template is_named_unit()) { + string_type str = facet.get_unit(get_duration_style(ios), d); + s=std::copy(str.begin(), str.end(), s); + } else { + *s++ = CharT('['); + std::use_facet >(ios.getloc()).put(s, ios, fill, Period::num); + *s++ = CharT('/'); + std::use_facet >(ios.getloc()).put(s, ios, fill, Period::den); + *s++ = CharT(']'); + string_type str = facet.get_n_d_unit(get_duration_style(ios), d); + s=std::copy(str.begin(), str.end(), s); + } + return s; + } + template + iter_type put_unit(duration_units const& facet, iter_type s, std::ios_base& ios, char_type fill, + duration, Period> const& d) const + { + duration real(d.count().real); + if (facet.template is_named_unit()) { + string_type str = facet.get_unit(get_duration_style(ios), real); + s=std::copy(str.begin(), str.end(), s); + } else { + *s++ = CharT('['); + std::use_facet >(ios.getloc()).put(s, ios, fill, Period::num); + *s++ = CharT('/'); + std::use_facet >(ios.getloc()).put(s, ios, fill, Period::den); + *s++ = CharT(']'); + string_type str = facet.get_n_d_unit(get_duration_style(ios), real); + s=std::copy(str.begin(), str.end(), s); + } + return s; + } + + /** + * Unique identifier for this type of facet. + */ + static std::locale::id id; + + /** + * @Effects Destroy the facet + */ + ~duration_put() + { + } + + }; + + template + std::locale::id duration_put::id; + + } // chrono +} // boost + +#endif // header diff --git a/boost/chrono/io/duration_style.hpp b/boost/chrono/io/duration_style.hpp new file mode 100644 index 0000000..65b76a9 --- /dev/null +++ b/boost/chrono/io/duration_style.hpp @@ -0,0 +1,35 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o to Boost + +#ifndef BOOST_CHRONO_IO_DURATION_STYLE_HPP +#define BOOST_CHRONO_IO_DURATION_STYLE_HPP + +#include + +namespace boost +{ + namespace chrono + { + /** + * Scoped enumeration emulation stating whether the duration I/O style is long or short. + * prefix means duration::rep with whatever stream/locale settings are set for it followed by a long name representing the unit + * symbol means duration::rep with whatever stream/locale settings are set for it followed by a SI unit abbreviation + */ + BOOST_SCOPED_ENUM_DECLARE_BEGIN(duration_style) + { + prefix, symbol + } + BOOST_SCOPED_ENUM_DECLARE_END(duration_style) + + + } // chrono + +} + +#endif // header diff --git a/boost/chrono/io/duration_units.hpp b/boost/chrono/io/duration_units.hpp new file mode 100644 index 0000000..84faa81 --- /dev/null +++ b/boost/chrono/io/duration_units.hpp @@ -0,0 +1,1003 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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_CHRONO_IO_DURATION_UNITS_HPP +#define BOOST_CHRONO_IO_DURATION_UNITS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace chrono + { + class rt_ratio + { + public: + template + rt_ratio(Period const&) : + num(Period::type::num), den(Period::type::den) + { + } + + rt_ratio(intmax_t n = 0, intmax_t d = 0) : + num(n), den(d) + { + } + + intmax_t num; + intmax_t den; + }; + + /** + * @c duration_units facet gives useful information about the duration units, + * as the number of plural forms, the plural form associated to a duration, + * the text associated to a plural form and a duration's period, + */ + template + class duration_units: public std::locale::facet + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string passed to member functions. + */ + typedef std::basic_string string_type; + + /** + * Unique identifier for this type of facet. + */ + static std::locale::id id; + + /** + * Construct a @c duration_units facet. + * @param refs + * @Effects Construct a @c duration_units facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + explicit duration_units(size_t refs = 0) : + std::locale::facet(refs) + { + } + + /** + * @return pointer to the start of valid [N/D] units. + */ + virtual const string_type* get_n_d_valid_units_start() const =0; + /** + * @effect calls the do_... + * @return pointer to the end of valid [N/D] units. + */ + virtual const string_type* get_n_d_valid_units_end() const=0; + + /** + * @return pointer to the start of valid units, symbol or prefix with its different plural forms. + */ + virtual const string_type* get_valid_units_start() const=0; + /** + * @return pointer to the end of valid units. + */ + virtual const string_type* get_valid_units_end() const=0; + + /** + * @param k the found pointer to the [N/D] unit. + * @return true if @c k matches a valid unit. + */ + virtual bool match_n_d_valid_unit(const string_type* k) const = 0; + /** + * @param k the found pointer to the unit. + * @Effects @c rt is set to the valid Period when the @c k matches a valid unit. + * @return true if @c k matches a valid unit. + */ + virtual bool match_valid_unit(const string_type* k, rt_ratio& rt) const = 0; + + /** + * @effect calls the do_... + * @return the pattern to be used by default. + */ + virtual string_type get_pattern() const=0; + + /** + * @effect calls the do_... + * @return the unit associated to this duration. + */ + template + string_type get_unit(duration_style style, duration const& d) const + { + return do_get_unit(style, rt_ratio(Period()), static_cast(d.count())); + } + /** + * @effect calls the do_... + * @return the [N/D] suffix unit associated to this duration. + */ + template + string_type get_n_d_unit(duration_style style, duration const& d) const + { + return do_get_n_d_unit(style, rt_ratio(Period()), static_cast(d.count())); + } + + /** + * @effect calls the do_... + * @return true if the unit associated to the given Period is named, false otherwise. + */ + template + bool is_named_unit() const + { + return do_is_named_unit(rt_ratio(Period())); + } + + + protected: + + /** + * @Effects Destroys the facet + */ + virtual ~duration_units() + { + } + /** + * @return the [N/D] suffix unit associated to this duration. + */ + virtual string_type do_get_n_d_unit(duration_style style, rt_ratio rt, intmax_t v) const = 0; + /** + * @return the unit associated to this duration. + */ + virtual string_type do_get_unit(duration_style style,rt_ratio rt, intmax_t v) const = 0; + /** + * @return true if the unit associated to the given Period is named, false otherwise. + */ + virtual bool do_is_named_unit(rt_ratio rt) const =0; + + }; + + template + std::locale::id duration_units::id; + + namespace detail + { + template + struct duration_units_default_holder + { + typedef std::basic_string string_type; + static string_type* n_d_valid_units_; + static string_type* valid_units_; + static bool initialized_; + }; + template + typename duration_units_default_holder::string_type* duration_units_default_holder::n_d_valid_units_=0; + template + typename duration_units_default_holder::string_type* duration_units_default_holder::valid_units_=0; + template + bool duration_units_default_holder::initialized_ = false; + } + + /** + * This class is used to define the strings for the default English + */ + template + class duration_units_default: public duration_units + { + protected: + static const std::size_t pfs_ = 2; + + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string passed to member functions. + */ + typedef std::basic_string string_type; + + /** + * Construct a @c duration_units_default facet. + * @param refs + * @Effects Construct a @c duration_units_default facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + explicit duration_units_default(size_t refs = 0) : + duration_units (refs) + { + } + + /** + * Destroys the facet. + */ + ~duration_units_default() + { + } + + public: + + /** + * @param k the found pointer to the [N/D] unit. + * @return true if @c k matches a valid unit. + */ + bool match_n_d_valid_unit(const string_type* k) const + { + std::size_t index = (k - get_n_d_valid_units_start()) / (pfs_ + 1); + switch (index) + { + case 0: + break; + default: + return false; + } + return true; + } + /** + * @param k the found pointer to the unit. + * @Effects @c rt is set to the valid Period when the @c k matches a valid unit. + * @return true if @c k matches a valid unit. + */ + bool match_valid_unit(const string_type* k, rt_ratio& rt) const + { + std::size_t index = (k - get_valid_units_start()) / (pfs_ + 1); + switch (index) + { + case 0: + rt = rt_ratio(atto()); + break; + case 1: + rt = rt_ratio(femto()); + break; + case 2: + rt = rt_ratio(pico()); + break; + case 3: + rt = rt_ratio(nano()); + break; + case 4: + rt = rt_ratio(micro()); + break; + case 5: + rt = rt_ratio(milli()); + break; + case 6: + rt = rt_ratio(centi()); + break; + case 7: + rt = rt_ratio(deci()); + break; + case 8: + rt = rt_ratio(deca()); + break; + case 9: + rt = rt_ratio(hecto()); + break; + case 10: + rt = rt_ratio(kilo()); + break; + case 11: + rt = rt_ratio(mega()); + break; + case 12: + rt = rt_ratio(giga()); + break; + case 13: + rt = rt_ratio(tera()); + break; + case 14: + rt = rt_ratio(peta()); + break; + case 15: + rt = rt_ratio(exa()); + break; + case 16: + rt = rt_ratio(ratio<1> ()); + break; + case 17: + rt = rt_ratio(ratio<60> ()); + break; + case 18: + rt = rt_ratio(ratio<3600> ()); + break; + default: + return false; + } + return true; + } + + /** + * @return pointer to the start of valid [N/D] units. + */ + virtual const string_type* get_n_d_valid_units_start()const + { + return detail::duration_units_default_holder::n_d_valid_units_; + } + /** + * @return pointer to the end of valid [N/D] units. + */ + virtual const string_type* get_n_d_valid_units_end()const + { + return detail::duration_units_default_holder::n_d_valid_units_ + (pfs_ + 1); + } + + /** + * @return pointer to the start of valid units. + */ + virtual const string_type* get_valid_units_start() const + { + return detail::duration_units_default_holder::valid_units_; + } + /** + * @return pointer to the end of valid units. + */ + virtual const string_type* get_valid_units_end() const + { + return detail::duration_units_default_holder::valid_units_ + 19 * (pfs_ + 1); + } + + string_type get_pattern() const + { + static const CharT t[] = + { '%', 'v', ' ', '%', 'u' }; + static const string_type pattern(t, t + sizeof (t) / sizeof (t[0])); + + return pattern; + } + + protected: + /** + * + * This facet names the units associated to the following periods: + * atto,femto,pico,nano,micro,milli,centi,deci,ratio<1>,deca,hecto,kilo,mega,giga,tera,peta,exa,ratio<60> and ratio<3600>. + * @return true if the unit associated to the given Period is named, false otherwise. + */ + bool do_is_named_unit(rt_ratio rt) const + { + if (rt.num==1) { + switch (rt.den) + { + case BOOST_RATIO_INTMAX_C(1): + case BOOST_RATIO_INTMAX_C(10): + case BOOST_RATIO_INTMAX_C(100): + case BOOST_RATIO_INTMAX_C(1000): + case BOOST_RATIO_INTMAX_C(1000000): + case BOOST_RATIO_INTMAX_C(1000000000): + case BOOST_RATIO_INTMAX_C(1000000000000): + case BOOST_RATIO_INTMAX_C(1000000000000000): + case BOOST_RATIO_INTMAX_C(1000000000000000000): + return true; + default: + return false; + } + } else if (rt.den==1) { + switch (rt.num) + { + case BOOST_RATIO_INTMAX_C(10): + case BOOST_RATIO_INTMAX_C(60): + case BOOST_RATIO_INTMAX_C(100): + case BOOST_RATIO_INTMAX_C(1000): + case BOOST_RATIO_INTMAX_C(3600): + case BOOST_RATIO_INTMAX_C(1000000): + case BOOST_RATIO_INTMAX_C(1000000000): + case BOOST_RATIO_INTMAX_C(1000000000000): + case BOOST_RATIO_INTMAX_C(1000000000000000): + case BOOST_RATIO_INTMAX_C(1000000000000000000): + return true; + default: + return false; + } + } + return false; + + } + + /** + * In English the suffix used after [N/D] is the one associated to the period ratio<1>. + * @return the [N/D] suffix unit associated to this duration. + */ + string_type do_get_n_d_unit(duration_style style, rt_ratio, intmax_t v) const + { + return do_get_unit(style, ratio<1>(), do_get_plural_form(v)); + } + + /** + * @return the unit associated to this duration if it is named, "" otherwise. + */ + string_type do_get_unit(duration_style style, rt_ratio rt, intmax_t v) const + { + if (rt.num==1) { + switch (rt.den) + { + case BOOST_RATIO_INTMAX_C(1): + return do_get_unit(style, ratio<1>(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(10): + return do_get_unit(style, deci(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(100): + return do_get_unit(style, centi(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000): + return do_get_unit(style, milli(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000): + return do_get_unit(style, micro(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000): + return do_get_unit(style, nano(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000000): + return do_get_unit(style, pico(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000000000): + return do_get_unit(style, femto(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000000000000): + return do_get_unit(style, atto(), do_get_plural_form(v)); + default: + ; + } + } else if (rt.den==1) { + switch (rt.num) + { + case BOOST_RATIO_INTMAX_C(10): + return do_get_unit(style, deca(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(60): + return do_get_unit(style, ratio<60>(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(100): + return do_get_unit(style, hecto(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000): + return do_get_unit(style, kilo(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(3600): + return do_get_unit(style, ratio<3600>(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000): + return do_get_unit(style, mega(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000): + return do_get_unit(style, giga(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000000): + return do_get_unit(style, tera(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000000000): + return do_get_unit(style, peta(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000000000000): + return do_get_unit(style, exa(), do_get_plural_form(v)); + default: + ; + } + } + BOOST_ASSERT(false&&"ratio parameter can not be translated"); + //throw "exception"; + return string_type(); + } + + protected: + /** + * @return the number of associated plural forms this facet manages. + */ + virtual std::size_t do_get_plural_forms() const + { + return static_get_plural_forms(); + } + static std::size_t static_get_plural_forms() + { + return pfs_; + } + /** + * Gets the associated plural form. + * @param value the duration representation + * @return the plural form associated to the @c value parameter. In English there are 2 plural forms + * 0 singular (-1 or 1) + * 1 plural for all others + */ + virtual std::size_t do_get_plural_form(int_least64_t value) const + { + return static_get_plural_form(value); + } + static std::size_t static_get_plural_form(int_least64_t value) + { + return (value == -1 || value == 1) ? 0 : 1; + } + + /** + * @param style the duration style. + * @param period the period associated to the duration seconds. + * @param pf the requested plural form. + * @return if style is symbol returns "s", otherwise if pf is 0 return "second", if pf is 1 "seconds" + */ + virtual string_type do_get_unit(duration_style style, ratio<1> u, std::size_t pf) const + { + return static_get_unit(style,u,pf); + } + static string_type static_get_unit(duration_style style, ratio<1> , std::size_t pf) + { + static const CharT t[] = + { 's' }; + static const string_type symbol(t, t + sizeof (t) / sizeof (t[0])); + static const CharT u[] = + { 's', 'e', 'c', 'o', 'n', 'd' }; + static const string_type singular(u, u + sizeof (u) / sizeof (u[0])); + static const CharT v[] = + { 's', 'e', 'c', 'o', 'n', 'd', 's' }; + static const string_type plural(v, v + sizeof (v) / sizeof (v[0])); + + if (style == duration_style::symbol) + { + return symbol; + } + if (pf == 0) + { + return singular; + } + if (pf == 1) + { + return plural; + } + BOOST_ASSERT(false&&"style/pf parameters not valid"); + //throw "exception"; + return string_type(); + } + + /** + * @param style the duration style. + * @param period the period associated to the duration minutes. + * @param pf the requested plural form. + * @return if style is symbol returns "min", otherwise if pf is 0 return "minute", if pf is 1 "minutes" + */ + virtual string_type do_get_unit(duration_style style, ratio<60> u, std::size_t pf) const + { + return static_get_unit(style,u,pf); + } + static string_type static_get_unit(duration_style style, ratio<60> , std::size_t pf) + { + static const CharT t[] = + { 'm', 'i', 'n' }; + static const string_type symbol(t, t + sizeof (t) / sizeof (t[0])); + + static const CharT u[] = + { 'm', 'i', 'n', 'u', 't', 'e' }; + static const string_type singular(u, u + sizeof (u) / sizeof (u[0])); + static const CharT v[] = + { 'm', 'i', 'n', 'u', 't', 'e', 's' }; + static const string_type plural(v, v + sizeof (v) / sizeof (v[0])); + + if (style == duration_style::symbol) return symbol; + if (pf == 0) return singular; + if (pf == 1) return plural; + BOOST_ASSERT(false&&"style/pf parameters not valid"); + //throw "exception"; + return string_type(); + + } + + /** + * @param style the duration style. + * @param period the period associated to the duration hours. + * @param pf the requested plural form. + * @return if style is symbol returns "h", otherwise if pf is 0 return "hour", if pf is 1 "hours" + */ + virtual string_type do_get_unit(duration_style style, ratio<3600> u, std::size_t pf) const + { + return static_get_unit(style,u,pf); + } + static string_type static_get_unit(duration_style style, ratio<3600> , std::size_t pf) + { + static const CharT t[] = + { 'h' }; + static const string_type symbol(t, t + sizeof (t) / sizeof (t[0])); + static const CharT u[] = + { 'h', 'o', 'u', 'r' }; + static const string_type singular(u, u + sizeof (u) / sizeof (u[0])); + static const CharT v[] = + { 'h', 'o', 'u', 'r', 's' }; + static const string_type plural(v, v + sizeof (v) / sizeof (v[0])); + + if (style == duration_style::symbol) return symbol; + if (pf == 0) return singular; + if (pf == 1) return plural; + BOOST_ASSERT(false&&"style/pf parameters not valid"); + //throw "exception"; + return string_type(); + + } + /** + * @param style the duration style. + * @param u the period tag atto. + * @param pf the requested plural form. + * @return the concatenation of the prefix associated to @c period + the one associated to seconds. + */ + virtual string_type do_get_unit(duration_style style, atto u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, atto u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + /** + * @param style the duration style. + * @param u the period tag femto. + * @param pf the requested plural form. + * @return the concatenation of the prefix associated to period @c u + the one associated to seconds. + */ + virtual string_type do_get_unit(duration_style style, femto u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, femto u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + /** + * @param style the duration style. + * @param u the period tag femto. + * @param pf the requested plural form. + * @return the concatenation of the prefix associated to period @c u + the one associated to seconds. + */ + virtual string_type do_get_unit(duration_style style, pico u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, pico u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, nano u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, nano u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, micro u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, micro u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, milli u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, milli u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, centi u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, centi u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, deci u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, deci u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, deca u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, deca u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, hecto u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, hecto u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, kilo u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, kilo u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, mega u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, mega u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, giga u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, giga u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, tera u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, tera u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, peta u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, peta u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, exa u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, exa u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + + protected: + + /** + * @param style the duration style. + * @param u the period tag atto. + * @return depending on the value of @c style return the ratio_string symbol or prefix. + */ + virtual string_type do_get_ratio_prefix(duration_style style, atto u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, atto) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, femto u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, femto) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, pico u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, pico) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, nano u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, nano) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, micro u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, micro) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, milli u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, milli) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, centi u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, centi) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, deci u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, deci) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, deca u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, deca) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, hecto u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, hecto) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, kilo u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, kilo) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, mega u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, mega) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, giga u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, giga) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, tera u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, tera) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, peta u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, peta) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, exa u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, exa) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + + protected: + template + string_type* fill_units(string_type* it, Period) const + { + std::size_t pfs = do_get_plural_forms(); + for (std::size_t pf = 0; pf < pfs; ++pf) + { + *it++ = do_get_unit(duration_style::prefix, Period(), pf); + } + *it++ = do_get_unit(duration_style::symbol, Period(), 0); + return it; + } + public: + template + static string_type* static_fill_units(string_type* it, Period) + { + std::size_t pfs = static_get_plural_forms(); + for (std::size_t pf = 0; pf < pfs; ++pf) + { + *it++ = static_get_unit(duration_style::prefix, Period(), pf); + } + *it++ = static_get_unit(duration_style::symbol, Period(), 0); + return it; + } + static string_type* static_init_valid_units(string_type* it) + { + it = static_fill_units(it, atto()); + it = static_fill_units(it, femto()); + it = static_fill_units(it, pico()); + it = static_fill_units(it, nano()); + it = static_fill_units(it, micro()); + it = static_fill_units(it, milli()); + it = static_fill_units(it, centi()); + it = static_fill_units(it, deci()); + it = static_fill_units(it, deca()); + it = static_fill_units(it, hecto()); + it = static_fill_units(it, kilo()); + it = static_fill_units(it, mega()); + it = static_fill_units(it, giga()); + it = static_fill_units(it, tera()); + it = static_fill_units(it, peta()); + it = static_fill_units(it, exa()); + it = static_fill_units(it, ratio<1> ()); + it = static_fill_units(it, ratio<60> ()); + it = static_fill_units(it, ratio<3600> ()); + return it; + } + }; + + namespace detail + { + + template + struct duration_units_default_initializer_t + { + duration_units_default_initializer_t() + { + if (!duration_units_default_holder::initialized_) + { + typedef typename duration_units_default_holder::string_type string_type; + duration_units_default_holder::n_d_valid_units_ = new string_type[3]; + duration_units_default_holder::valid_units_ = new string_type[19 * 3]; + + string_type* it = duration_units_default_holder::n_d_valid_units_; + it = duration_units_default::static_fill_units(it, ratio<1> ()); + it = duration_units_default::static_init_valid_units(duration_units_default_holder::valid_units_); + + duration_units_default_holder::initialized_ = true; + } + } + ~duration_units_default_initializer_t() + { + if (duration_units_default_holder::initialized_) + { + delete[] duration_units_default_holder::n_d_valid_units_; + duration_units_default_holder::n_d_valid_units_ = 0; + delete[] duration_units_default_holder::valid_units_; + duration_units_default_holder::valid_units_ = 0; + duration_units_default_holder::initialized_ = false; + } + } + }; + namespace /**/ + { + duration_units_default_initializer_t duration_units_default_initializer; + duration_units_default_initializer_t wduration_units_default_initializer; + } // namespace + } + } // chrono + +} // boost + +#endif // header diff --git a/boost/chrono/io/ios_base_state.hpp b/boost/chrono/io/ios_base_state.hpp new file mode 100644 index 0000000..1393e2e --- /dev/null +++ b/boost/chrono/io/ios_base_state.hpp @@ -0,0 +1,152 @@ +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o to Boost + +#ifndef BOOST_CHRONO_IO_IOS_BASE_STATE_HPP +#define BOOST_CHRONO_IO_IOS_BASE_STATE_HPP + +#include +#include +#include +#include +#include + +namespace boost +{ + namespace chrono + { + + class fmt_masks : public ios_flags + { + typedef ios_flags base_type; + fmt_masks& operator=(fmt_masks const& rhs) ; + + public: + fmt_masks(std::ios_base& ios): base_type(ios) {} + enum type + { + uses_symbol = 1 << 0, + uses_local = 1 << 1 + }; + + inline duration_style get_duration_style() + { + return (flags() & uses_symbol) ? duration_style::symbol : duration_style::prefix; + } + inline void set_duration_style(duration_style style) + { + if (style == duration_style::symbol) + setf(uses_symbol); + else + unsetf(uses_symbol); + } + + inline timezone get_timezone() + { + return (flags() & uses_local) ? timezone::local : timezone::utc; + } + inline void set_timezone(timezone tz) + { + if (tz == timezone::local) + setf(uses_local); + else + unsetf(uses_local); + } + }; + namespace detail + { + namespace /**/ { + xalloc_key_initializer fmt_masks_xalloc_key_initializer; + } // namespace + } // namespace detail + + inline duration_style get_duration_style(std::ios_base & ios) + { + return fmt_masks(ios).get_duration_style(); + } + inline void set_duration_style(std::ios_base& ios, duration_style style) + { + fmt_masks(ios).set_duration_style(style); + } + inline std::ios_base& symbol_format(std::ios_base& ios) + { + fmt_masks(ios).setf(fmt_masks::uses_symbol); + return ios; + } + inline std::ios_base& name_format(std::ios_base& ios) + { + fmt_masks(ios).unsetf(fmt_masks::uses_symbol); + return ios; + } + + inline timezone get_timezone(std::ios_base & ios) + { + return fmt_masks(ios).get_timezone(); + } + inline void set_timezone(std::ios_base& ios, timezone tz) + { + fmt_masks(ios).set_timezone(tz); + } + inline std::ios_base& local_timezone(std::ios_base& ios) + { + fmt_masks(ios).setf(fmt_masks::uses_local); + return ios; + } + + inline std::ios_base& utc_timezone(std::ios_base& ios) + { + fmt_masks(ios).unsetf(fmt_masks::uses_local); + return ios; + } + + namespace detail + { + + template + struct ios_base_data_aux + { + std::basic_string time_fmt; + std::basic_string duration_fmt; + public: + + ios_base_data_aux() + //: + // time_fmt(""), + // duration_fmt("") + { + } + }; + template + struct ios_base_data {}; + namespace /**/ { + xalloc_key_initializer > ios_base_data_aux_xalloc_key_initializer; + xalloc_key_initializer > wios_base_data_aux_xalloc_key_initializer; +#if BOOST_CHRONO_HAS_UNICODE_SUPPORT + xalloc_key_initializer > u16ios_base_data_aux_xalloc_key_initializer; + xalloc_key_initializer > u32ios_base_data_aux_xalloc_key_initializer; +#endif + } // namespace + } // namespace detail + + template + inline std::basic_string get_time_fmt(std::ios_base & ios) + { + ios_state_not_null_ptr, detail::ios_base_data_aux > ptr(ios); + return ptr->time_fmt; + } + template + inline void set_time_fmt(std::ios_base& ios, std::basic_string< + CharT> const& fmt) + { + ios_state_not_null_ptr, detail::ios_base_data_aux > ptr(ios); + ptr->time_fmt = fmt; + } + + } // chrono +} // boost + +#endif // header diff --git a/boost/chrono/io/time_point_get.hpp b/boost/chrono/io/time_point_get.hpp new file mode 100644 index 0000000..44c641e --- /dev/null +++ b/boost/chrono/io/time_point_get.hpp @@ -0,0 +1,330 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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_CHRONO_IO_TIME_POINT_GET_HPP +#define BOOST_CHRONO_IO_TIME_POINT_GET_HPP + +#include +#include +#include +#include +#include +#include +#include + +/** + * Duration formatting facet for input. + */ +namespace boost +{ + namespace chrono + { + + template > + class time_point_get: public std::locale::facet + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of iterator used to scan the character buffer. + */ + typedef InputIterator iter_type; + + /** + * Construct a @c time_point_get facet. + * @param refs + * @Effects Construct a @c time_point_get facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + + explicit time_point_get(size_t refs = 0) : + std::locale::facet(refs) + { + } + + /** + * @param s start input stream iterator + * @param end end input stream iterator + * @param ios a reference to a ios_base + * @param err the ios_base state + * @param d the duration + * @param pattern begin of the formatting pattern + * @param pat_end end of the formatting pattern + * + * Requires: [pattern,pat_end) shall be a valid range. + * + * Effects: The function starts by evaluating err = std::ios_base::goodbit. + * It then enters a loop, reading zero or more characters from s at + * each iteration. Unless otherwise specified below, the loop + * terminates when the first of the following conditions holds: + * - The expression pattern == pat_end evaluates to true. + * - The expression err == std::ios_base::goodbit evaluates to false. + * - The expression s == end evaluates to true, in which case the + * function evaluates err = std::ios_base::eofbit | std::ios_base::failbit. + * - The next element of pattern is equal to '%', followed by a conversion + * specifier character, the functions @c get_duration or @c get_epoch are called depending on + * whether the format is @c 'd' or @c 'e'. + * If the number of elements in the range [pattern,pat_end) is not + * sufficient to unambiguously determine whether the conversion + * specification is complete and valid, the function evaluates + * err = std::ios_base::failbit. Otherwise, the function evaluates + * s = do_get(s, end, ios, err, d). If err == std::ios_base::goodbit holds after + * the evaluation of the expression, the function increments pattern to + * point just past the end of the conversion specification and continues + * looping. + * - The expression isspace(*pattern, ios.getloc()) evaluates to true, in + * which case the function first increments pattern until + * pattern == pat_end || !isspace(*pattern, ios.getloc()) evaluates to true, + * then advances s until s == end || !isspace(*s, ios.getloc()) is true, + * and finally resumes looping. + * - The next character read from s matches the element pointed to by + * pattern in a case-insensitive comparison, in which case the function + * evaluates ++pattern, ++s and continues looping. Otherwise, the function + * evaluates err = std::ios_base::failbit. + * + * Returns: s + */ + + template + iter_type get(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, + time_point &tp, const char_type *pattern, const char_type *pat_end) const + { + if (std::has_facet >(is.getloc())) + { + time_point_units const &facet = std::use_facet >(is.getloc()); + return get(facet, i, e, is, err, tp, pattern, pat_end); + } + else + { + time_point_units_default facet; + return get(facet, i, e, is, err, tp, pattern, pat_end); + } + } + + template + iter_type get(time_point_units const &facet, iter_type s, iter_type end, std::ios_base& ios, + std::ios_base::iostate& err, time_point &tp, const char_type *pattern, + const char_type *pat_end) const + { + + Duration d; + bool duration_found = false, epoch_found = false; + + const std::ctype& ct = std::use_facet >(ios.getloc()); + err = std::ios_base::goodbit; + while (pattern != pat_end && err == std::ios_base::goodbit) + { + if (s == end) + { + err |= std::ios_base::eofbit; + break; + } + if (ct.narrow(*pattern, 0) == '%') + { + if (++pattern == pat_end) + { + err |= std::ios_base::failbit; + return s; + } + char cmd = ct.narrow(*pattern, 0); + switch (cmd) + { + case 'd': + { + if (duration_found) + { + err |= std::ios_base::failbit; + return s; + } + duration_found = true; + s = get_duration(s, end, ios, err, d); + if (err & (std::ios_base::badbit | std::ios_base::failbit)) + { + return s; + } + break; + } + case 'e': + { + if (epoch_found) + { + err |= std::ios_base::failbit; + return s; + } + epoch_found = true; + s = get_epoch (facet, s, end, ios, err); + if (err & (std::ios_base::badbit | std::ios_base::failbit)) + { + return s; + } + break; + } + default: + BOOST_ASSERT(false && "Boost::Chrono internal error."); + break; + } + + ++pattern; + } + else if (ct.is(std::ctype_base::space, *pattern)) + { + for (++pattern; pattern != pat_end && ct.is(std::ctype_base::space, *pattern); ++pattern) + ; + for (; s != end && ct.is(std::ctype_base::space, *s); ++s) + ; + } + else if (ct.toupper(*s) == ct.toupper(*pattern)) + { + ++s; + ++pattern; + } + else + { + err |= std::ios_base::failbit; + } + } + + // Success! Store it. + tp = time_point (d); + return s; + } + + /** + * + * @param s an input stream iterator + * @param ios a reference to a ios_base + * @param d the duration + * Stores the duration pattern from the @c duration_unit facet in let say @c str. Last as if + * @code + * return get(s, end, ios, err, ios, d, str.data(), str.data() + str.size()); + * @codeend + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name + */ + template + iter_type get(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, + time_point &tp) const + { + if (std::has_facet >(is.getloc())) + { + time_point_units const &facet = std::use_facet >(is.getloc()); + std::basic_string str = facet.get_pattern(); + return get(facet, i, e, is, err, tp, str.data(), str.data() + str.size()); + } + else + { + time_point_units_default facet; + std::basic_string str = facet.get_pattern(); + return get(facet, i, e, is, err, tp, str.data(), str.data() + str.size()); + } + } + + /** + * As if + * @code + * return facet.get(s, end, ios, err, d); + * @endcode + * where @c facet is either the @c duration_get facet associated to the @c ios or an instance of the default @c duration_get facet. + * + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid duration. + */ + template + iter_type get_duration(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, + duration& d) const + { + if (std::has_facet >(is.getloc())) + { + duration_get const &facet = std::use_facet >(is.getloc()); + return get_duration(facet, i, e, is, err, d); + } + else + { + duration_get facet; + return get_duration(facet, i, e, is, err, d); + } + } + + template + iter_type get_duration(duration_get const& facet, iter_type s, iter_type end, std::ios_base& ios, + std::ios_base::iostate& err, duration& d) const + { + return facet.get(s, end, ios, err, d); + } + + /** + * + * @Effects Let @c facet be the @c time_point_units facet associated to @c is or a new instance of the default @c time_point_units_default facet. + * Let @c epoch be the epoch string associated to the Clock using this facet. + * Scans @c i to match @c epoch or @c e is reached. + * + * If not match before the @c e is reached @c std::ios_base::failbit is set in @c err. + * If @c e is reached @c std::ios_base::failbit is set in @c err. + * + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid epoch. + */ + template + iter_type get_epoch(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err) const + { + if (std::has_facet >(is.getloc())) + { + time_point_units const &facet = std::use_facet >(is.getloc()); + return get_epoch(facet, i, e, is, err); + } + else + { + time_point_units_default facet; + return get_epoch(facet, i, e, is, err); + } + } + + template + iter_type get_epoch(time_point_units const &facet, iter_type i, iter_type e, std::ios_base&, + std::ios_base::iostate& err) const + { + const std::basic_string epoch = facet.template get_epoch (); + std::ptrdiff_t k = chrono_detail::scan_keyword(i, e, &epoch, &epoch + 1, + //~ std::use_facet >(ios.getloc()), + err) - &epoch; + if (k == 1) + { + err |= std::ios_base::failbit; + return i; + } + return i; + } + + /** + * Unique identifier for this type of facet. + */ + static std::locale::id id; + + /** + * @Effects Destroy the facet + */ + ~time_point_get() + { + } + }; + + /** + * Unique identifier for this type of facet. + */ + template + std::locale::id time_point_get::id; + + } // chrono +} +// boost + +#endif // header diff --git a/boost/chrono/io/time_point_io.hpp b/boost/chrono/io/time_point_io.hpp new file mode 100644 index 0000000..d0f854c --- /dev/null +++ b/boost/chrono/io/time_point_io.hpp @@ -0,0 +1,1249 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2010-2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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). + +//===-------------------------- locale ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o to Boost and some functions from libc++/locale to emulate the missing time_get::get() + +#ifndef BOOST_CHRONO_IO_TIME_POINT_IO_HPP +#define BOOST_CHRONO_IO_TIME_POINT_IO_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if ( defined BOOST_WINDOWS && ! defined(__CYGWIN__) ) \ + || (defined(sun) || defined(__sun)) \ + || (defined __IBMCPP__) \ + || defined __ANDROID__ \ + || defined __QNXNTO__ \ + || (defined(_AIX) && defined __GNUC__) +#define BOOST_CHRONO_INTERNAL_TIMEGM +#endif + +#if (defined BOOST_WINDOWS && ! defined(__CYGWIN__)) \ + || ( (defined(sun) || defined(__sun)) && defined __GNUC__) \ + || (defined __IBMCPP__) \ + || defined __ANDROID__ \ + || (defined(_AIX) && defined __GNUC__) +#define BOOST_CHRONO_INTERNAL_GMTIME +#endif + +#define BOOST_CHRONO_USES_INTERNAL_TIME_GET + +namespace boost +{ + namespace chrono + { + typedef double fractional_seconds; + namespace detail + { + + + template > + struct time_get + { + std::time_get const &that_; + time_get(std::time_get const& that) : that_(that) {} + + typedef std::time_get facet; + typedef typename facet::iter_type iter_type; + typedef typename facet::char_type char_type; + typedef std::basic_string string_type; + + static int + get_up_to_n_digits( + InputIterator& b, InputIterator e, + std::ios_base::iostate& err, + const std::ctype& ct, + int n) + { + // Precondition: n >= 1 + if (b == e) + { + err |= std::ios_base::eofbit | std::ios_base::failbit; + return 0; + } + // get first digit + CharT c = *b; + if (!ct.is(std::ctype_base::digit, c)) + { + err |= std::ios_base::failbit; + return 0; + } + int r = ct.narrow(c, 0) - '0'; + for (++b, --n; b != e && n > 0; ++b, --n) + { + // get next digit + c = *b; + if (!ct.is(std::ctype_base::digit, c)) + return r; + r = r * 10 + ct.narrow(c, 0) - '0'; + } + if (b == e) + err |= std::ios_base::eofbit; + return r; + } + + + void get_day( + int& d, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 2); + if (!(err & std::ios_base::failbit) && 1 <= t && t <= 31) + d = t; + else + err |= std::ios_base::failbit; + } + + void get_month( + int& m, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 2); + if (!(err & std::ios_base::failbit) && 1 <= t && t <= 12) + m = --t; + else + err |= std::ios_base::failbit; + } + + + void get_year4(int& y, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 4); + if (!(err & std::ios_base::failbit)) + y = t - 1900; + } + + void + get_hour(int& h, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 2); + if (!(err & std::ios_base::failbit) && t <= 23) + h = t; + else + err |= std::ios_base::failbit; + } + + void + get_minute(int& m, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 2); + if (!(err & std::ios_base::failbit) && t <= 59) + m = t; + else + err |= std::ios_base::failbit; + } + + void get_second(int& s, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 2); + if (!(err & std::ios_base::failbit) && t <= 60) + s = t; + else + err |= std::ios_base::failbit; + } + + void get_white_space(iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + for (; b != e && ct.is(std::ctype_base::space, *b); ++b) + ; + if (b == e) + err |= std::ios_base::eofbit; + } + + void get_12_hour(int& h, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 2); + if (!(err & std::ios_base::failbit) && 1 <= t && t <= 12) + h = t; + else + err |= std::ios_base::failbit; + } + + void get_percent(iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + if (b == e) + { + err |= std::ios_base::eofbit | std::ios_base::failbit; + return; + } + if (ct.narrow(*b, 0) != '%') + err |= std::ios_base::failbit; + else if(++b == e) + err |= std::ios_base::eofbit; + } + + void get_day_year_num(int& d, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 3); + if (!(err & std::ios_base::failbit) && 1 <= t && t <= 366) + d = --t; + else + err |= std::ios_base::failbit; + } + + void + get_weekday(int& w, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 1); + if (!(err & std::ios_base::failbit) && t <= 6) + w = t; + else + err |= std::ios_base::failbit; + } +#if 0 + + void + get_am_pm(int& h, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + const string_type* ap = am_pm(); + if (ap[0].size() + ap[1].size() == 0) + { + err |= ios_base::failbit; + return; + } + ptrdiff_t i = detail::scan_keyword(b, e, ap, ap+2, ct, err, false) - ap; + if (i == 0 && h == 12) + h = 0; + else if (i == 1 && h < 12) + h += 12; + } + +#endif + + InputIterator get( + iter_type b, iter_type e, + std::ios_base& iob, + std::ios_base::iostate& err, + std::tm* tm, + char fmt, char) const + { + err = std::ios_base::goodbit; + const std::ctype& ct = std::use_facet >(iob.getloc()); + + switch (fmt) + { + case 'a': + case 'A': + { + std::tm tm2; + std::memset(&tm2, 0, sizeof(std::tm)); + that_.get_weekday(b, e, iob, err, &tm2); + //tm->tm_wday = tm2.tm_wday; + } + break; + case 'b': + case 'B': + case 'h': + { + std::tm tm2; + std::memset(&tm2, 0, sizeof(std::tm)); + that_.get_monthname(b, e, iob, err, &tm2); + //tm->tm_mon = tm2.tm_mon; + } + break; +// case 'c': +// { +// const string_type& fm = c(); +// b = get(b, e, iob, err, tm, fm.data(), fm.data() + fm.size()); +// } +// break; + case 'd': + case 'e': + get_day(tm->tm_mday, b, e, err, ct); + break; + case 'D': + { + const char_type fm[] = {'%', 'm', '/', '%', 'd', '/', '%', 'y'}; + b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); + } + break; + case 'F': + { + const char_type fm[] = {'%', 'Y', '-', '%', 'm', '-', '%', 'd'}; + b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); + } + break; + case 'H': + get_hour(tm->tm_hour, b, e, err, ct); + break; + case 'I': + get_12_hour(tm->tm_hour, b, e, err, ct); + break; + case 'j': + get_day_year_num(tm->tm_yday, b, e, err, ct); + break; + case 'm': + get_month(tm->tm_mon, b, e, err, ct); + break; + case 'M': + get_minute(tm->tm_min, b, e, err, ct); + break; + case 'n': + case 't': + get_white_space(b, e, err, ct); + break; +// case 'p': +// get_am_pm(tm->tm_hour, b, e, err, ct); +// break; + case 'r': + { + const char_type fm[] = {'%', 'I', ':', '%', 'M', ':', '%', 'S', ' ', '%', 'p'}; + b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); + } + break; + case 'R': + { + const char_type fm[] = {'%', 'H', ':', '%', 'M'}; + b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); + } + break; + case 'S': + get_second(tm->tm_sec, b, e, err, ct); + break; + case 'T': + { + const char_type fm[] = {'%', 'H', ':', '%', 'M', ':', '%', 'S'}; + b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); + } + break; + case 'w': + { + get_weekday(tm->tm_wday, b, e, err, ct); + } + break; + case 'x': + return that_.get_date(b, e, iob, err, tm); +// case 'X': +// return that_.get_time(b, e, iob, err, tm); +// { +// const string_type& fm = X(); +// b = that_.get(b, e, iob, err, tm, fm.data(), fm.data() + fm.size()); +// } +// break; +// case 'y': +// get_year(tm->tm_year, b, e, err, ct); + break; + case 'Y': + get_year4(tm->tm_year, b, e, err, ct); + break; + case '%': + get_percent(b, e, err, ct); + break; + default: + err |= std::ios_base::failbit; + } + return b; + } + + + InputIterator get( + iter_type b, iter_type e, + std::ios_base& iob, + std::ios_base::iostate& err, std::tm* tm, + const char_type* fmtb, const char_type* fmte) const + { + const std::ctype& ct = std::use_facet >(iob.getloc()); + err = std::ios_base::goodbit; + while (fmtb != fmte && err == std::ios_base::goodbit) + { + if (b == e) + { + err = std::ios_base::failbit; + break; + } + if (ct.narrow(*fmtb, 0) == '%') + { + if (++fmtb == fmte) + { + err = std::ios_base::failbit; + break; + } + char cmd = ct.narrow(*fmtb, 0); + char opt = '\0'; + if (cmd == 'E' || cmd == '0') + { + if (++fmtb == fmte) + { + err = std::ios_base::failbit; + break; + } + opt = cmd; + cmd = ct.narrow(*fmtb, 0); + } + b = get(b, e, iob, err, tm, cmd, opt); + ++fmtb; + } + else if (ct.is(std::ctype_base::space, *fmtb)) + { + for (++fmtb; fmtb != fmte && ct.is(std::ctype_base::space, *fmtb); ++fmtb) + ; + for ( ; b != e && ct.is(std::ctype_base::space, *b); ++b) + ; + } + else if (ct.toupper(*b) == ct.toupper(*fmtb)) + { + ++b; + ++fmtb; + } + else + err = std::ios_base::failbit; + } + if (b == e) + err |= std::ios_base::eofbit; + return b; + } + + }; + + + template + class time_manip: public manip > + { + std::basic_string fmt_; + timezone tz_; + public: + + time_manip(timezone tz, std::basic_string fmt) + // todo move semantics + : + fmt_(fmt), tz_(tz) + { + } + + /** + * Change the timezone and time format ios state; + */ + void operator()(std::ios_base &ios) const + { + set_time_fmt (ios, fmt_); + set_timezone(ios, tz_); + } + }; + + class time_man: public manip + { + timezone tz_; + public: + + time_man(timezone tz) + // todo move semantics + : + tz_(tz) + { + } + + /** + * Change the timezone and time format ios state; + */ + void operator()(std::ios_base &ios) const + { + //set_time_fmt(ios, ""); + set_timezone(ios, tz_); + } + }; + + } + + template + inline detail::time_manip time_fmt(timezone tz, const CharT* fmt) + { + return detail::time_manip(tz, fmt); + } + + template + inline detail::time_manip time_fmt(timezone tz, std::basic_string fmt) + { + // todo move semantics + return detail::time_manip(tz, fmt); + } + + inline detail::time_man time_fmt(timezone f) + { + return detail::time_man(f); + } + + /** + * time_fmt_io_saver i/o saver. + * + * See Boost.IO i/o state savers for a motivating compression. + */ + template > + struct time_fmt_io_saver + { + + //! the type of the state to restore + //typedef std::basic_ostream state_type; + typedef std::ios_base state_type; + + //! the type of aspect to save + typedef std::basic_string aspect_type; + + /** + * Explicit construction from an i/o stream. + * + * Store a reference to the i/o stream and the value of the associated @c time format . + */ + explicit time_fmt_io_saver(state_type &s) : + s_save_(s), a_save_(get_time_fmt(s_save_)) + { + } + + /** + * Construction from an i/o stream and a @c time format to restore. + * + * Stores a reference to the i/o stream and the value @c new_value to restore given as parameter. + */ + time_fmt_io_saver(state_type &s, aspect_type new_value) : + s_save_(s), a_save_(get_time_fmt(s_save_)) + { + set_time_fmt(s_save_, new_value); + } + + /** + * Destructor. + * + * Restores the i/o stream with the format to be restored. + */ + ~time_fmt_io_saver() + { + this->restore(); + } + + /** + * Restores the i/o stream with the time format to be restored. + */ + void restore() + { + set_time_fmt(s_save_, a_save_); + } + private: + state_type& s_save_; + aspect_type a_save_; + }; + + /** + * timezone_io_saver i/o saver. + * + * See Boost.IO i/o state savers for a motivating compression. + */ + struct timezone_io_saver + { + + //! the type of the state to restore + typedef std::ios_base state_type; + //! the type of aspect to save + typedef timezone aspect_type; + + /** + * Explicit construction from an i/o stream. + * + * Store a reference to the i/o stream and the value of the associated @c timezone. + */ + explicit timezone_io_saver(state_type &s) : + s_save_(s), a_save_(get_timezone(s_save_)) + { + } + + /** + * Construction from an i/o stream and a @c timezone to restore. + * + * Stores a reference to the i/o stream and the value @c new_value to restore given as parameter. + */ + timezone_io_saver(state_type &s, aspect_type new_value) : + s_save_(s), a_save_(get_timezone(s_save_)) + { + set_timezone(s_save_, new_value); + } + + /** + * Destructor. + * + * Restores the i/o stream with the format to be restored. + */ + ~timezone_io_saver() + { + this->restore(); + } + + /** + * Restores the i/o stream with the timezone to be restored. + */ + void restore() + { + set_timezone(s_save_, a_save_); + } + private: + timezone_io_saver& operator=(timezone_io_saver const& rhs) ; + + state_type& s_save_; + aspect_type a_save_; + }; + + /** + * + * @param os + * @param tp + * @Effects Behaves as a formatted output function. After constructing a @c sentry object, if the @ sentry + * converts to true, calls to @c facet.put(os,os,os.fill(),tp) where @c facet is the @c time_point_put + * facet associated to @c os or a new created instance of the default @c time_point_put facet. + * @return @c os. + */ + template + std::basic_ostream& + operator<<(std::basic_ostream& os, const time_point& tp) + { + + bool failed = false; + BOOST_TRY + { + std::ios_base::iostate err = std::ios_base::goodbit; + BOOST_TRY + { + typename std::basic_ostream::sentry opfx(os); + if (bool(opfx)) + { + if (!std::has_facet >(os.getloc())) + { + if (time_point_put ().put(os, os, os.fill(), tp) .failed()) + { + err = std::ios_base::badbit; + } + } + else + { + if (std::use_facet >(os.getloc()) .put(os, os, os.fill(), tp).failed()) + { + err = std::ios_base::badbit; + } + } + os.width(0); + } + } + BOOST_CATCH (...) + { + bool flag = false; + BOOST_TRY + { + os.setstate(std::ios_base::failbit); + } + BOOST_CATCH (std::ios_base::failure ) + { + flag = true; + } + BOOST_CATCH_END + if (flag) throw; + } + BOOST_CATCH_END + if (err) os.setstate(err); + return os; + } + BOOST_CATCH (...) + { + failed = true; + } + BOOST_CATCH_END + if (failed) os.setstate(std::ios_base::failbit | std::ios_base::badbit); + return os; + } + + template + std::basic_istream& + operator>>(std::basic_istream& is, time_point& tp) + { + std::ios_base::iostate err = std::ios_base::goodbit; + + BOOST_TRY + { + typename std::basic_istream::sentry ipfx(is); + if (bool(ipfx)) + { + if (!std::has_facet >(is.getloc())) + { + time_point_get ().get(is, std::istreambuf_iterator(), is, err, tp); + } + else + { + std::use_facet >(is.getloc()).get(is, std::istreambuf_iterator(), is, + err, tp); + } + } + } + BOOST_CATCH (...) + { + bool flag = false; + BOOST_TRY + { + is.setstate(std::ios_base::failbit); + } + BOOST_CATCH (std::ios_base::failure ) + { + flag = true; + } + BOOST_CATCH_END + if (flag) throw; + } + BOOST_CATCH_END + if (err) is.setstate(err); + return is; + } + + + namespace detail + { + +//#if defined BOOST_CHRONO_INTERNAL_TIMEGM + + inline int32_t is_leap(int32_t year) + { + if(year % 400 == 0) + return 1; + if(year % 100 == 0) + return 0; + if(year % 4 == 0) + return 1; + return 0; + } + inline int32_t days_from_0(int32_t year) + { + year--; + return 365 * year + (year / 400) - (year/100) + (year / 4); + } + inline int32_t days_from_1970(int32_t year) + { + static const int32_t days_from_0_to_1970 = days_from_0(1970); + return days_from_0(year) - days_from_0_to_1970; + } + inline int32_t days_from_1jan(int32_t year,int32_t month,int32_t day) + { + static const int32_t days[2][12] = + { + { 0,31,59,90,120,151,181,212,243,273,304,334}, + { 0,31,60,91,121,152,182,213,244,274,305,335} + }; + + return days[is_leap(year)][month-1] + day - 1; + } + + inline time_t internal_timegm(std::tm const *t) + { + int year = t->tm_year + 1900; + int month = t->tm_mon; + if(month > 11) + { + year += month/12; + month %= 12; + } + else if(month < 0) + { + int years_diff = (-month + 11)/12; + year -= years_diff; + month+=12 * years_diff; + } + month++; + int day = t->tm_mday; + int day_of_year = days_from_1jan(year,month,day); + int days_since_epoch = days_from_1970(year) + day_of_year ; + + time_t seconds_in_day = 3600 * 24; + time_t result = seconds_in_day * days_since_epoch + 3600 * t->tm_hour + 60 * t->tm_min + t->tm_sec; + + return result; + } +//#endif + + /** + * from_ymd could be made more efficient by using a table + * day_count_table indexed by the y%400. + * This table could contain the day_count + * by*365 + by/4 - by/100 + by/400 + * + * from_ymd = (by/400)*days_by_400_years+day_count_table[by%400] + + * days_in_year_before[is_leap_table[by%400]][m-1] + d; + */ + inline unsigned days_before_years(int32_t y) + { + return y * 365 + y / 4 - y / 100 + y / 400; + } + + // Returns year/month/day triple in civil calendar + // Preconditions: z is number of days since 1970-01-01 and is in the range: + // [numeric_limits::min(), numeric_limits::max()-719468]. + template + //constexpr + void + inline civil_from_days(Int z, Int& y, unsigned& m, unsigned& d) BOOST_NOEXCEPT + { + BOOST_STATIC_ASSERT_MSG(std::numeric_limits::digits >= 18, + "This algorithm has not been ported to a 16 bit unsigned integer"); + BOOST_STATIC_ASSERT_MSG(std::numeric_limits::digits >= 20, + "This algorithm has not been ported to a 16 bit signed integer"); + z += 719468; + const Int era = (z >= 0 ? z : z - 146096) / 146097; + const unsigned doe = static_cast(z - era * 146097); // [0, 146096] + const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399] + y = static_cast(yoe) + era * 400; + const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365] + const unsigned mp = (5*doy + 2)/153; // [0, 11] + d = doy - (153*mp+2)/5 + 1; // [1, 31] + m = mp + (mp < 10 ? 3 : -9); // [1, 12] + y += (m <= 2); + --m; + } + inline std::tm * internal_gmtime(std::time_t const* t, std::tm *tm) + { + if (t==0) return 0; + if (tm==0) return 0; + +#if 0 + static const unsigned char + day_of_year_month[2][366] = + { + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 }, + + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 + + } }; + + static const int32_t days_in_year_before[2][13] = + { + { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }, + { -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 } + }; +#endif + + const time_t seconds_in_day = 3600 * 24; + int32_t days_since_epoch = static_cast(*t / seconds_in_day); + int32_t hms = static_cast(*t - seconds_in_day*days_since_epoch); + if (hms < 0) { + days_since_epoch-=1; + hms = seconds_in_day+hms; + } + +#if 0 + int32_t x = days_since_epoch; + int32_t y = static_cast (static_cast (x + 2) * 400 + / 146097); + const int32_t ym1 = y - 1; + int32_t doy = x - days_before_years(y); + const int32_t doy1 = x - days_before_years(ym1); + const int32_t N = std::numeric_limits::digits - 1; + const int32_t mask1 = doy >> N; // arithmetic rshift - not portable - but nearly universal + const int32_t mask0 = ~mask1; + doy = (doy & mask0) | (doy1 & mask1); + y = (y & mask0) | (ym1 & mask1); + //y -= 32767 + 2; + y += 70; + tm->tm_year=y; + const int32_t leap = is_leap(y); + tm->tm_mon = day_of_year_month[leap][doy]-1; + tm->tm_mday = doy - days_in_year_before[leap][tm->tm_mon] ; +#else + int32_t y; + unsigned m, d; + civil_from_days(days_since_epoch, y, m, d); + tm->tm_year=y-1900; tm->tm_mon=m; tm->tm_mday=d; +#endif + + tm->tm_hour = hms / 3600; + const int ms = hms % 3600; + tm->tm_min = ms / 60; + tm->tm_sec = ms % 60; + + tm->tm_isdst = -1; + (void)mktime(tm); + return tm; + } + + } // detail +#ifndef BOOST_CHRONO_NO_UTC_TIMEPOINT + +#if defined BOOST_CHRONO_PROVIDES_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT + + template + std::basic_ostream& + operator<<(std::basic_ostream& os, const time_point& tp) + { + typename std::basic_ostream::sentry ok(os); + if (bool(ok)) + { + bool failed = false; + BOOST_TRY + { + const CharT* pb = 0; //nullptr; + const CharT* pe = pb; + std::basic_string fmt = get_time_fmt (os); + pb = fmt.data(); + pe = pb + fmt.size(); + + timezone tz = get_timezone(os); + std::locale loc = os.getloc(); + time_t t = system_clock::to_time_t(time_point_cast(tp)); + std::tm tm; + std::memset(&tm, 0, sizeof(std::tm)); + if (tz == timezone::local) + { +#if defined BOOST_WINDOWS && ! defined(__CYGWIN__) +#if BOOST_MSVC < 1400 // localtime_s doesn't exist in vc7.1 + std::tm *tmp = 0; + if ((tmp=localtime(&t)) == 0) + failed = true; + else + tm =*tmp; +# else + if (localtime_s(&tm, &t) != 0) failed = true; +# endif +#else + if (localtime_r(&t, &tm) == 0) failed = true; +#endif + } + else + { +#if defined BOOST_CHRONO_INTERNAL_GMTIME + if (detail::internal_gmtime(&t, &tm) == 0) failed = true; + +#elif defined BOOST_WINDOWS && ! defined(__CYGWIN__) + std::tm *tmp = 0; + if((tmp = gmtime(&t)) == 0) + failed = true; + else + tm = *tmp; +#else + if (gmtime_r(&t, &tm) == 0) failed = true; + tm.tm_isdst = -1; + (void)mktime(&tm); + +#endif + + } + if (!failed) + { + const std::time_put& tpf = std::use_facet >(loc); + if (pb == pe) + { + CharT pattern[] = + { '%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ', '%', 'H', ':', '%', 'M', ':' }; + pb = pattern; + pe = pb + sizeof (pattern) / sizeof(CharT); + failed = tpf.put(os, os, os.fill(), &tm, pb, pe).failed(); + if (!failed) + { + duration d = tp - system_clock::from_time_t(t) + seconds(tm.tm_sec); + if (d.count() < 10) os << CharT('0'); + //if (! os.good()) { + // throw "exception"; + //} + std::ios::fmtflags flgs = os.flags(); + os.setf(std::ios::fixed, std::ios::floatfield); + //if (! os.good()) { + //throw "exception"; + //} + os.precision(9); + os << d.count(); + //if (! os.good()) { + //throw "exception"; + //} + os.flags(flgs); + if (tz == timezone::local) + { + CharT sub_pattern[] = + { ' ', '%', 'z' }; + pb = sub_pattern; + pe = pb + +sizeof (sub_pattern) / sizeof(CharT); + failed = tpf.put(os, os, os.fill(), &tm, pb, pe).failed(); + } + else + { + CharT sub_pattern[] = + { ' ', '+', '0', '0', '0', '0', 0 }; + os << sub_pattern; + } + } + } + else + { + failed = tpf.put(os, os, os.fill(), &tm, pb, pe).failed(); + } + } + } + BOOST_CATCH (...) + { + failed = true; + } + BOOST_CATCH_END + if (failed) + { + os.setstate(std::ios_base::failbit | std::ios_base::badbit); + } + } + return os; + } +#endif + + namespace detail + { + + template + minutes extract_z(InputIterator& b, InputIterator e, std::ios_base::iostate& err, const std::ctype& ct) + { + int min = 0; + if (b != e) + { + char cn = ct.narrow(*b, 0); + if (cn != '+' && cn != '-') + { + err |= std::ios_base::failbit; + return minutes(0); + } + int sn = cn == '-' ? -1 : 1; + int hr = 0; + for (int i = 0; i < 2; ++i) + { + if (++b == e) + { + err |= std::ios_base::eofbit | std::ios_base::failbit; + return minutes(0); + } + cn = ct.narrow(*b, 0); + if (! ('0' <= cn && cn <= '9')) + { + err |= std::ios_base::failbit; + return minutes(0); + } + hr = hr * 10 + cn - '0'; + } + for (int i = 0; i < 2; ++i) + { + if (++b == e) + { + err |= std::ios_base::eofbit | std::ios_base::failbit; + return minutes(0); + } + cn = ct.narrow(*b, 0); + if (! ('0' <= cn && cn <= '9')) + { + err |= std::ios_base::failbit; + return minutes(0); + } + min = min * 10 + cn - '0'; + } + if (++b == e) { + err |= std::ios_base::eofbit; + } + min += hr * 60; + min *= sn; + } + else + { + err |= std::ios_base::eofbit | std::ios_base::failbit; + } + return minutes(min); + } + + } // detail + +#if defined BOOST_CHRONO_PROVIDES_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT + + template + std::basic_istream& + operator>>(std::basic_istream& is, time_point& tp) + { + typename std::basic_istream::sentry ok(is); + if (bool(ok)) + { + std::ios_base::iostate err = std::ios_base::goodbit; + BOOST_TRY + { + const CharT* pb = 0; //nullptr; + const CharT* pe = pb; + std::basic_string fmt = get_time_fmt (is); + pb = fmt.data(); + pe = pb + fmt.size(); + + timezone tz = get_timezone(is); + std::locale loc = is.getloc(); + const std::time_get& tg = std::use_facet >(loc); + const std::ctype& ct = std::use_facet >(loc); + tm tm; // {0} + std::memset(&tm, 0, sizeof(std::tm)); + + typedef std::istreambuf_iterator It; + if (pb == pe) + { + CharT pattern[] = + { '%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ', '%', 'H', ':', '%', 'M', ':' }; + pb = pattern; + pe = pb + sizeof (pattern) / sizeof(CharT); + +#if defined BOOST_CHRONO_USES_INTERNAL_TIME_GET + const detail::time_get& dtg(tg); + dtg.get(is, 0, is, err, &tm, pb, pe); +#else + tg.get(is, 0, is, err, &tm, pb, pe); +#endif + if (err & std::ios_base::failbit) goto exit; + fractional_seconds sec; + CharT c = CharT(); + std::ios::fmtflags flgs = is.flags(); + is.setf(std::ios::fixed, std::ios::floatfield); + is.precision(9); + is >> sec; + is.flags(flgs); + if (is.fail()) + { + err |= std::ios_base::failbit; + goto exit; + } + It i(is); + It eof; + c = *i; + if (++i == eof || c != ' ') + { + err |= std::ios_base::failbit; + goto exit; + } + minutes min = detail::extract_z(i, eof, err, ct); + + if (err & std::ios_base::failbit) goto exit; + time_t t; + +#if defined BOOST_CHRONO_INTERNAL_TIMEGM + t = detail::internal_timegm(&tm); +#else + t = timegm(&tm); +#endif + tp = time_point_cast( + system_clock::from_time_t(t) - min + round (duration (sec)) + ); + } + else + { + const CharT z[2] = + { '%', 'z' }; + const CharT* fz = std::search(pb, pe, z, z + 2); +#if defined BOOST_CHRONO_USES_INTERNAL_TIME_GET + const detail::time_get& dtg(tg); + dtg.get(is, 0, is, err, &tm, pb, fz); +#else + tg.get(is, 0, is, err, &tm, pb, fz); +#endif + minutes minu(0); + if (fz != pe) + { + if (err != std::ios_base::goodbit) + { + err |= std::ios_base::failbit; + goto exit; + } + It i(is); + It eof; + minu = detail::extract_z(i, eof, err, ct); + if (err & std::ios_base::failbit) goto exit; + if (fz + 2 != pe) + { + if (err != std::ios_base::goodbit) + { + err |= std::ios_base::failbit; + goto exit; + } +#if defined BOOST_CHRONO_USES_INTERNAL_TIME_GET + const detail::time_get& dtg(tg); + dtg.get(is, 0, is, err, &tm, fz + 2, pe); +#else + tg.get(is, 0, is, err, &tm, fz + 2, pe); +#endif + if (err & std::ios_base::failbit) goto exit; + } + } + tm.tm_isdst = -1; + time_t t; + if (tz == timezone::utc || fz != pe) + { +#if defined BOOST_CHRONO_INTERNAL_TIMEGM + t = detail::internal_timegm(&tm); +#else + t = timegm(&tm); +#endif + } + else + { + t = mktime(&tm); + } + tp = time_point_cast( + system_clock::from_time_t(t) - minu + ); + } + } + BOOST_CATCH (...) + { + err |= std::ios_base::badbit | std::ios_base::failbit; + } + BOOST_CATCH_END + exit: is.setstate(err); + } + return is; + } + +#endif +#endif //UTC + } // chrono + +} + +#endif // header diff --git a/boost/chrono/io/time_point_put.hpp b/boost/chrono/io/time_point_put.hpp new file mode 100644 index 0000000..9c8c7ca --- /dev/null +++ b/boost/chrono/io/time_point_put.hpp @@ -0,0 +1,261 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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). +// + +/** + * Duration formatting facet for output. + */ +#ifndef BOOST_CHRONO_IO_TIME_POINT_PUT_HPP +#define BOOST_CHRONO_IO_TIME_POINT_PUT_HPP + +#include +#include +#include +#include +#include + +namespace boost +{ + namespace chrono + { + + /** + * @tparam ChatT a character type + * @tparam OutputIterator a model of @c OutputIterator + * + * The @c time_point_put facet provides facilities for formatted output of @c time_point values. + * The member function of @c time_point_put take a @c time_point and format it into character string representation. + * + */ + template > + class time_point_put: public std::locale::facet + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string passed to member functions. + */ + typedef std::basic_string string_type; + /** + * Type of iterator used to write in the character buffer. + */ + typedef OutputIterator iter_type; + + /** + * Construct a time_point_put facet. + * @param refs + * @Effects Construct a time_point_put facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + explicit time_point_put(size_t refs = 0) : + std::locale::facet(refs) + { + } + + /** + * @param i an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param tp the @c time_point + * @param pattern begin of the formatting pattern + * @param pat_end end of the formatting pattern + * + * @Effects Steps through the sequence from @c pattern to @c pat_end, + * identifying characters that are part of a pattern sequence. Each character + * that is not part of a pattern sequence is written to @c s immediately, and + * each pattern sequence, as it is identified, results in a call to + * @c put_duration or @c put_epoch; + * thus, pattern elements and other characters are interleaved in the output + * in the order in which they appear in the pattern. Pattern sequences are + * identified by converting each character @c c to a @c char value as if by + * @c ct.narrow(c,0), where @c ct is a reference to @c ctype obtained from + * @c ios.getloc(). The first character of each sequence is equal to @c '%', + * followed by a pattern specifier character @c spec, which can be @c 'd' for + * the duration value or @c 'e' for the epoch. + * For each valid pattern sequence identified, calls + * put_duration(s, ios, fill, tp.time_since_epoch()) or put_epoch(s, ios). + * + * @Returns An iterator pointing immediately after the last character produced. + */ + + template + iter_type put(iter_type i, std::ios_base& ios, char_type fill, time_point const& tp, const CharT* pattern, + const CharT* pat_end) const + { + if (std::has_facet >(ios.getloc())) + { + time_point_units const &facet = + std::use_facet >(ios.getloc()); + return put(facet, i, ios, fill, tp, pattern, pat_end); + } + else + { + time_point_units_default facet; + return put(facet, i, ios, fill, tp, pattern, pat_end); + } + } + + template + iter_type put(time_point_units const& units_facet, iter_type s, std::ios_base& ios, char_type fill, + time_point const& tp, const CharT* pattern, const CharT* pat_end) const + { + + const std::ctype& ct = std::use_facet >(ios.getloc()); + for (; pattern != pat_end; ++pattern) + { + if (ct.narrow(*pattern, 0) == '%') + { + if (++pattern == pat_end) + { + *s++ = pattern[-1]; + break; + } + char fmt = ct.narrow(*pattern, 0); + switch (fmt) + { + case 'd': + { + s = put_duration(s, ios, fill, tp.time_since_epoch()); + break; + } + case 'e': + { + s = put_epoch (units_facet, s, ios); + break; + } + default: + BOOST_ASSERT(false && "Boost::Chrono internal error."); + break; + } + } + else + *s++ = *pattern; + } + return s; + } + + /** + * @param i an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param tp the @c time_point + * @param pattern begin of the formatting pattern + * @param pat_end end of the formatting pattern + * + * @Effects Stores the time_point pattern from the @c time_point_unit facet in let say @c str. Last as if + * @code + * return put(s, ios, dill, tp, str.data(), str.data() + str.size()); + * @endcode + * @Returns An iterator pointing immediately after the last character produced. + */ + template + iter_type put(iter_type i, std::ios_base& ios, char_type fill, time_point const& tp) const + { + if (std::has_facet >(ios.getloc())) + { + time_point_units const &facet = + std::use_facet >(ios.getloc()); + std::basic_string str = facet.get_pattern(); + return put(facet, i, ios, fill, tp, str.data(), str.data() + str.size()); + } + else + { + time_point_units_default facet; + std::basic_string str = facet.get_pattern(); + return put(facet, i, ios, fill, tp, str.data(), str.data() + str.size()); + } + } + + /** + * @param i an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param d the @c duration + * @Effects As if facet.put(s, ios, fill, d) where facet is the @c duration_put facet associated + * to the @c ios or a new instance of @c duration_put. + * @Returns An iterator pointing immediately after the last character produced. + */ + template + iter_type put_duration(iter_type i, std::ios_base& ios, char_type fill, duration const& d) const + { + if (std::has_facet >(ios.getloc())) + { + duration_put const &facet = std::use_facet >(ios.getloc()); + return facet.put(i, ios, fill, d); + } + else + { + duration_put facet; + return facet.put(i, ios, fill, d); + } + } + + /** + * + * @param i an output stream iterator + * @param ios a reference to a ios_base + * @Effects As if + * @code + * string_type str = facet.template get_epoch(); + * s=std::copy(str.begin(), str.end(), s); + * @endcode + * where facet is the @c time_point_units facet associated + * to the @c ios or a new instance of @c time_point_units_default. + * @Returns s, iterator pointing immediately after the last character produced. + */ + + template + iter_type put_epoch(iter_type i, std::ios_base& os) const + { + if (std::has_facet >(os.getloc())) + { + time_point_units const &facet = std::use_facet >(os.getloc()); + return put_epoch (facet, i, os); + } + else + { + time_point_units_default facet; + return put_epoch (facet, i, os); + } + } + + template + iter_type put_epoch(time_point_units const& facet, iter_type s, std::ios_base&) const + { + string_type str = facet.template get_epoch(); + s= std::copy(str.begin(), str.end(), s); + return s; + } + + /** + * Unique identifier for this type of facet. + */ + static std::locale::id id; + + /** + * @Effects Destroy the facet + */ + ~time_point_put() + { + } + + }; + + template + std::locale::id time_point_put::id; + + } // chrono +} // boost + +#endif // header diff --git a/boost/chrono/io/time_point_units.hpp b/boost/chrono/io/time_point_units.hpp new file mode 100644 index 0000000..6a4999a --- /dev/null +++ b/boost/chrono/io/time_point_units.hpp @@ -0,0 +1,260 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Copyright (c) Microsoft Corporation 2014 +// Use, modification and distribution are subject to 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_CHRONO_IO_TIME_POINT_UNITS_HPP +#define BOOST_CHRONO_IO_TIME_POINT_UNITS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace chrono + { + /** + * customization point to the epoch associated to the clock @c Clock + * The default calls @c f.do_get_epoch(Clock()). The user can overload this function. + * @return the string epoch associated to the @c Clock + */ + template + std::basic_string get_epoch_custom(Clock, TPUFacet& f) + { + return f.do_get_epoch(Clock()); + } + + /** + * @c time_point_units facet gives useful information about the time_point pattern, + * the text associated to a time_point's epoch, + */ + template + class time_point_units: public std::locale::facet + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string used by member functions. + */ + typedef std::basic_string string_type; + + /** + * Unique identifier for this type of facet. + */ + static std::locale::id id; + + /** + * Construct a @c time_point_units facet. + * @param refs + * @Effects Construct a @c time_point_units facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + explicit time_point_units(size_t refs = 0) : + std::locale::facet(refs) + { + } + + /** + * @return the pattern to be used by default. + */ + virtual string_type get_pattern() const =0; + + /** + * @return the epoch associated to the clock @c Clock calling @c do_get_epoch(Clock()) + */ + template + string_type get_epoch() const + { + return get_epoch_custom(Clock(), *this); + } + + protected: + /** + * Destroy the facet. + */ + virtual ~time_point_units() {} + + public: + + /** + * + * @param c a dummy instance of @c system_clock. + * @return The epoch string associated to the @c system_clock. + */ + virtual string_type do_get_epoch(system_clock) const=0; + + /** + * + * @param c a dummy instance of @c steady_clock. + * @return The epoch string associated to the @c steady_clock. + */ + virtual string_type do_get_epoch(steady_clock) const=0; + +#if defined(BOOST_CHRONO_HAS_PROCESS_CLOCKS) + /** + * + * @param c a dummy instance of @c process_real_cpu_clock. + * @return The epoch string associated to the @c process_real_cpu_clock. + */ + virtual string_type do_get_epoch(process_real_cpu_clock) const=0; +#if ! BOOST_OS_WINDOWS || BOOST_PLAT_WINDOWS_DESKTOP + /** + * + * @param c a dummy instance of @c process_user_cpu_clock. + * @return The epoch string associated to the @c process_user_cpu_clock. + */ + virtual string_type do_get_epoch(process_user_cpu_clock) const=0; + /** + * + * @param c a dummy instance of @c process_system_cpu_clock. + * @return The epoch string associated to the @c process_system_cpu_clock. + */ + virtual string_type do_get_epoch(process_system_cpu_clock) const=0; + /** + * + * @param c a dummy instance of @c process_cpu_clock. + * @return The epoch string associated to the @c process_cpu_clock. + */ + virtual string_type do_get_epoch(process_cpu_clock) const=0; +#endif +#endif +#if defined(BOOST_CHRONO_HAS_THREAD_CLOCK) + /** + * + * @param c a dummy instance of @c thread_clock. + * @return The epoch string associated to the @c thread_clock. + */ + virtual string_type do_get_epoch(thread_clock) const=0; +#endif + + }; + + template + std::locale::id time_point_units::id; + + + // This class is used to define the strings for the default English + template + class time_point_units_default: public time_point_units + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string returned by member functions. + */ + typedef std::basic_string string_type; + + explicit time_point_units_default(size_t refs = 0) : + time_point_units (refs) + { + } + ~time_point_units_default() {} + + /** + * @return the default pattern "%d%e". + */ + string_type get_pattern() const + { + static const CharT t[] = + { '%', 'd', '%', 'e' }; + static const string_type pattern(t, t + sizeof (t) / sizeof (t[0])); + + return pattern; + } + + //protected: + /** + * @param c a dummy instance of @c system_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(system_clock ) const + { + return clock_string::since(); + } + /** + * @param c a dummy instance of @c steady_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(steady_clock ) const + { + return clock_string::since(); + } + +#if defined(BOOST_CHRONO_HAS_PROCESS_CLOCKS) + /** + * @param c a dummy instance of @c process_real_cpu_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(process_real_cpu_clock ) const + { + return clock_string::since(); + } +#if ! BOOST_OS_WINDOWS || BOOST_PLAT_WINDOWS_DESKTOP + /** + * @param c a dummy instance of @c process_user_cpu_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(process_user_cpu_clock ) const + { + return clock_string::since(); + } + /** + * @param c a dummy instance of @c process_system_cpu_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(process_system_cpu_clock ) const + { + return clock_string::since(); + } + /** + * @param c a dummy instance of @c process_cpu_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(process_cpu_clock ) const + { + return clock_string::since(); + } + +#endif +#endif +#if defined(BOOST_CHRONO_HAS_THREAD_CLOCK) + /** + * @param c a dummy instance of @c thread_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(thread_clock ) const + { + return clock_string::since(); + } +#endif + + }; + + + } // chrono + +} // boost + +#endif // header diff --git a/boost/chrono/io/timezone.hpp b/boost/chrono/io/timezone.hpp new file mode 100644 index 0000000..67975da --- /dev/null +++ b/boost/chrono/io/timezone.hpp @@ -0,0 +1,30 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2010-2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o to Boost + +#ifndef BOOST_CHRONO_IO_TIMEZONE_HPP +#define BOOST_CHRONO_IO_TIMEZONE_HPP +#include + +namespace boost +{ + namespace chrono + { + /** + * Scoped enumeration emulation stating whether the time_point for system_clock I/O is UTC or local. + */ + BOOST_SCOPED_ENUM_DECLARE_BEGIN(timezone) + { + utc, local + } + BOOST_SCOPED_ENUM_DECLARE_END(timezone) + + } // chrono +} // boost + +#endif // header diff --git a/boost/chrono/io/utility/ios_base_state_ptr.hpp b/boost/chrono/io/utility/ios_base_state_ptr.hpp new file mode 100644 index 0000000..15c8ac4 --- /dev/null +++ b/boost/chrono/io/utility/ios_base_state_ptr.hpp @@ -0,0 +1,437 @@ +// boost/chrono/utility/ios_base_pword_ptr.hpp ------------------------------------------------------------// + +// Copyright 2011 Vicente J. Botet Escriba + +// 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/libs/chrono for documentation. + +#ifndef BOOST_CHRONO_UTILITY_IOS_BASE_STATE_PTR_HPP +#define BOOST_CHRONO_UTILITY_IOS_BASE_STATE_PTR_HPP + +#include +#include + +/** + * + + + */ +namespace boost +{ + namespace chrono + { + namespace detail + { + + /** + * xalloc key holder. + */ + template + struct xalloc_key_holder + { + static int value; //< the xalloc value associated to T. + static bool initialized; //< whether the value has been initialized or not. + }; + + template + int xalloc_key_holder::value = 0; + + template + bool xalloc_key_holder::initialized = false; + + } + + /** + * xalloc key initialiazer. + * + * Declare a static variable of this type to ensure that the xalloc_key_holder is initialized correctly. + */ + template + struct xalloc_key_initializer + { + xalloc_key_initializer() + { + if (!detail::xalloc_key_holder::initialized) + { + detail::xalloc_key_holder::value = std::ios_base::xalloc(); + detail::xalloc_key_holder::initialized = true; + } + } + }; + /** + * @c ios_state_ptr is a smart pointer to a ios_base specific state. + */ + template + class ios_state_ptr + { + ios_state_ptr& operator=(ios_state_ptr const& rhs) ; + + public: + /** + * The pointee type + */ + typedef T element_type; + /** + * Explicit constructor. + * @param ios the ios + * @Effects Constructs a @c ios_state_ptr by storing the associated @c ios. + */ + explicit ios_state_ptr(std::ios_base& ios) : + ios_(ios) + { + + } + /** + * Nothing to do as xalloc index can not be removed. + */ + ~ios_state_ptr() + { + } + + /** + * @Effects Allocates the index if not already done. + * Registers the callback responsible of maintaining the state pointer coherency, if not already done. + * Retrieves the associated ios pointer + * @return the retrieved pointer statically casted to const. + */ + T const* get() const BOOST_NOEXCEPT + { + register_once(index(), ios_); + void* &pw = ios_.pword(index()); + if (pw == 0) + { + return 0; + } + return static_cast (pw); + } + /** + * @Effects Allocates the index if not already done. + * Registers the callback responsible of maintaining the state pointer coherency, if not already done. + * Retrieves the associated ios pointer + * @return the retrieved pointer. + */ + T * get() BOOST_NOEXCEPT + { + register_once(index(), ios_); + void* &pw = ios_.pword(index()); + if (pw == 0) + { + return 0; + } + return static_cast (pw); + } + /** + * @Effects as if @c return get(); + * @return the retrieved pointer. + */ + T * operator->()BOOST_NOEXCEPT + { + return get(); + } + /** + * @Effects as if @c return get(); + * @return the retrieved pointer. + */ + T const * operator->() const BOOST_NOEXCEPT + { + return get(); + } + + /** + * @Effects as if @c return *get(); + * @return a reference to the retrieved state. + * @Remark The behavior is undefined if @c get()==0. + */ + T & operator*() BOOST_NOEXCEPT + { + return *get(); + } + /** + * @Effects as if @c return *get(); + * @return a reference to the retrieved state. + * @Remark The behavior is undefined if @c get()==0. + */ + T const & operator *() const BOOST_NOEXCEPT + { + return *get(); + } + + /** + * @Effects reset the current pointer after storing in a temporary variable the pointer to the current state. + * @return the stored state pointer. + */ + T * release() BOOST_NOEXCEPT + { + void*& pw = ios_.pword(index()); + T* ptr = static_cast (pw); + pw = 0; + return ptr; + } + + /** + * + * @param new_ptr the new pointer. + * @Effects deletes the current state and replace it with the new one. + */ + void reset(T* new_ptr = 0)BOOST_NOEXCEPT + { + register_once(index(), ios_); + void*& pw = ios_.pword(index()); + delete static_cast (pw); + pw = new_ptr; + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef T* (ios_state_ptr::*bool_type)(); + operator bool_type() const BOOST_NOEXCEPT + { + return (get()!=0)?&ios_state_ptr::release:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return (get()==0)?&ios_state_ptr::release:0; + } +#else + /** + * Explicit conversion to bool. + */ + explicit operator bool() const BOOST_NOEXCEPT + { + return get()!=0; + } +#endif + + std::ios_base& getios()BOOST_NOEXCEPT + { + return ios_; + } + std::ios_base& getios() const BOOST_NOEXCEPT + { + return ios_; + } + /** + * Implicit conversion to the ios_base + */ + operator std::ios_base&() BOOST_NOEXCEPT + { + return ios_; + } + /** + * Implicit conversion to the ios_base const + */ + operator std::ios_base&() const BOOST_NOEXCEPT + { + return ios_; + } + private: + static inline bool is_registerd(std::ios_base& ios) + { + long iw = ios.iword(index()); + return (iw == 1); + } + static inline void set_registered(std::ios_base& ios) + { + long& iw = ios.iword(index()); + iw = 1; + } + static inline void callback(std::ios_base::event evt, std::ios_base& ios, int index) + { + switch (evt) + { + case std::ios_base::erase_event: + { + void*& pw = ios.pword(index); + if (pw != 0) + { + T* ptr = static_cast (pw); + delete ptr; + pw = 0; + } + break; + } + case std::ios_base::copyfmt_event: + { + void*& pw = ios.pword(index); + if (pw != 0) + { + pw = new T(*static_cast (pw)); + } + break; + } + default: + break; + } + } + + static inline int index() + { + return detail::xalloc_key_holder::value; + } + + static inline void register_once(int indx, std::ios_base& ios) + { + // needs a mask registered + if (!is_registerd(ios)) + { + set_registered(ios); + ios.register_callback(callback, indx); + } + } + + + protected: + std::ios_base& ios_; + //static detail::xalloc_key_initializer xalloc_key_initializer_; + + }; + //template + //detail::xalloc_key_initializer ios_state_ptr::xalloc_key_initializer_; + + + /** + * @c ios_state_not_null_ptr is a non null variant of @c ios_state_ptr. + * @tparm T + * @Requires @c T must be @c DefaultConstructible and @c HeapAllocatable + */ + template + class ios_state_not_null_ptr: public ios_state_ptr + { + typedef ios_state_ptr base_type; + public: + explicit ios_state_not_null_ptr(std::ios_base& ios) : + base_type(ios) + { + if (this->get() == 0) + { + this->base_type::reset(new T()); + } + } + ~ios_state_not_null_ptr() + { + } + + void reset(T* new_value) BOOST_NOEXCEPT + { + BOOST_ASSERT(new_value!=0); + this->base_type::reset(new_value); + } + + }; + + /** + * This class is useful to associate some flags to an std::ios_base. + */ + template + class ios_flags + { + public: + /** + * + * @param ios the associated std::ios_base. + * @Postcondition flags()==0 + */ + explicit ios_flags(std::ios_base& ios) : + ios_(ios) + { + } + ~ios_flags() + { + } + /** + * @Returns The format control information. + */ + long flags() const BOOST_NOEXCEPT + { + return value(); + } + + /** + * @param v the new bit mask. + * @Postcondition v == flags(). + * @Returns The previous value of @c flags(). + */ + long flags(long v)BOOST_NOEXCEPT + { + long tmp = flags(); + ref() = v; + return tmp; + } + + /** + * @param v the new value + * @Effects: Sets @c v in @c flags(). + * @Returns: The previous value of @c flags(). + */ + long setf(long v) + { + long tmp = value(); + ref() |= v; + return tmp; + } + + /** + * @param mask the bit mask to clear. + * @Effects: Clears @c mask in @c flags(). + */ + void unsetf(long mask) + { + ref() &= ~mask; + } + + /** + * + * @param v + * @param mask + * @Effects: Clears @c mask in @c flags(), sets v & mask in @c flags(). + * @Returns: The previous value of flags(). + */ + long setf(long v, long mask) + { + long tmp = value(); + unsetf(mask); + ref() |= v & mask; + return tmp; + } + + /** + * implicit conversion to the @c ios_base + */ + operator std::ios_base&()BOOST_NOEXCEPT + { + return ios_; + } + /** + * implicit conversion to the @c ios_base const + */ + operator std::ios_base const&() const BOOST_NOEXCEPT + { + return ios_; + } + private: + long value() const BOOST_NOEXCEPT + { + return ios_.iword(index()); + } + long& ref()BOOST_NOEXCEPT + { + return ios_.iword(index()); + } + static inline int index() + { + return detail::xalloc_key_holder::value; + } + ios_flags& operator=(ios_flags const& rhs) ; + + std::ios_base& ios_; + //static detail::xalloc_key_initializer xalloc_key_initializer_; + + }; + //template + //detail::xalloc_key_initializer ios_flags::xalloc_key_initializer_; + + } // namespace chrono +} // namespace boost + +#endif // header diff --git a/boost/chrono/io/utility/manip_base.hpp b/boost/chrono/io/utility/manip_base.hpp new file mode 100644 index 0000000..f4a5f56 --- /dev/null +++ b/boost/chrono/io/utility/manip_base.hpp @@ -0,0 +1,101 @@ +// boost/chrono/utility/manip_base.hpp ------------------------------------------------------------// + +// Copyright 2011 Vicente J. Botet Escriba + +// 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/libs/chrono for documentation. + +#ifndef BOOST_CHRONO_UTILITY_MANIP_BASE_PTR_HPP +#define BOOST_CHRONO_UTILITY_MANIP_BASE_PTR_HPP + +#include + +/** + * + + */ + +namespace boost +{ + namespace chrono + { + + /** + * manip is a manipulator mixin class following the CRTP. + * @tparam Final the derived from manip and final type + * + * @Example + * @code + + class mendl: public manip + { + public: + explicit mendl(size_t how_many) : + count(how_many) {} + template + void operator()(out_stream &out) const + { + for (size_t line = 0; line < count; ++line) + { + out.put(out.widen('\n')); + } + out.flush(); + } + private: + size_t count; + }; + + * @codeend + */ + template + class manip + { + public: + /** + * + * @param ios the io stream or ios_base. + * @Effects calls to the manipulator final functor. + */ + //template + void operator()(std::ios_base &ios) const + { + (*static_cast (this))(ios); + } + }; + + /** + * @c manip stream inserter + * @param out the io stream or ios_base. + * @param op the manipulator instance. + * @Effects if @c out is good calls to the manipulator functor @op. + * @return @c out + */ + template + out_stream &operator<<(out_stream &out, const manip &op) + { + if (out.good()) + op(out); + return out; + } + + /** + * @c manip stream extractor + * @param in the io stream or ios_base. + * @param op the manipulator instance. + * @Effects if @c in is good calls to the manipulator functor @op. + * @return @c in + */ + template + in_stream &operator>>(in_stream &in, const manip &op) + { + if (in.good()) + op(in); + return in; + } + + } // namespace chrono +} // namespace boost + +#endif // header diff --git a/boost/chrono/io/utility/to_string.hpp b/boost/chrono/io/utility/to_string.hpp new file mode 100644 index 0000000..4717ba6 --- /dev/null +++ b/boost/chrono/io/utility/to_string.hpp @@ -0,0 +1,50 @@ +// boost/chrono/utility/to_string.hpp +// +// Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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_CHRONO_UTILITY_TO_STRING_HPP +#define BOOST_CHRONO_UTILITY_TO_STRING_HPP + +#include +#include +#include + +namespace boost +{ + namespace chrono + { + template + std::basic_string to_basic_string(T const&v) { + std::basic_stringstream sstr; + sstr << v; + return sstr.str(); + } + + template + std::string to_string(T const&v) { + return to_basic_string(v); + } +#ifndef BOOST_NO_STD_WSTRING + template + std::wstring to_wstring(T const&v) { + return to_basic_string(v); + } +#endif +#if BOOST_CHRONO_HAS_UNICODE_SUPPORT + template + std::basic_string to_u16string(T const&v) { + return to_basic_string(v); + } + template + std::basic_string to_u32string(T const&v) { + return to_basic_string(v); + } +#endif + } // chrono + +} // boost + +#endif // header diff --git a/boost/chrono/io_v1/chrono_io.hpp b/boost/chrono/io_v1/chrono_io.hpp new file mode 100644 index 0000000..afcc9ed --- /dev/null +++ b/boost/chrono/io_v1/chrono_io.hpp @@ -0,0 +1,635 @@ + +// chrono_io +// +// (C) Copyright Howard Hinnant +// (C) Copyright 2010 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o under lvm/libc++ to Boost + +#ifndef BOOST_CHRONO_IO_V1_CHRONO_IO_HPP +#define BOOST_CHRONO_IO_V1_CHRONO_IO_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + +namespace chrono +{ + +template +class duration_punct + : public std::locale::facet +{ +public: + typedef std::basic_string string_type; + enum {use_long, use_short}; + +private: + bool use_short_; + string_type long_seconds_; + string_type long_minutes_; + string_type long_hours_; + string_type short_seconds_; + string_type short_minutes_; + string_type short_hours_; + + template + string_type short_name(Period) const + {return ::boost::ratio_string::short_name() + short_seconds_;} + + string_type short_name(ratio<1>) const {return short_seconds_;} + string_type short_name(ratio<60>) const {return short_minutes_;} + string_type short_name(ratio<3600>) const {return short_hours_;} + + template + string_type long_name(Period) const + {return ::boost::ratio_string::long_name() + long_seconds_;} + + string_type long_name(ratio<1>) const {return long_seconds_;} + string_type long_name(ratio<60>) const {return long_minutes_;} + string_type long_name(ratio<3600>) const {return long_hours_;} + + void init_C(); +public: + static std::locale::id id; + + explicit duration_punct(int use = use_long) + : use_short_(use==use_short) {init_C();} + + duration_punct(int use, + const string_type& long_seconds, const string_type& long_minutes, + const string_type& long_hours, const string_type& short_seconds, + const string_type& short_minutes, const string_type& short_hours); + + duration_punct(int use, const duration_punct& d); + + template + string_type short_name() const + {return short_name(typename Period::type());} + + template + string_type long_name() const + {return long_name(typename Period::type());} + + template + string_type plural() const + {return long_name(typename Period::type());} + + template + string_type singular() const + { + return string_type(long_name(typename Period::type()), 0, long_name(typename Period::type()).size()-1); + } + + template + string_type name() const + { + if (use_short_) return short_name(); + else { + return long_name(); + } + } + template + string_type name(D v) const + { + if (use_short_) return short_name(); + else + { + if (v==-1 || v==1) + return singular(); + else + return plural(); + } + } + + bool is_short_name() const {return use_short_;} + bool is_long_name() const {return !use_short_;} +}; + +template +std::locale::id +duration_punct::id; + +template +void +duration_punct::init_C() +{ + short_seconds_ = CharT('s'); + short_minutes_ = CharT('m'); + short_hours_ = CharT('h'); + const CharT s[] = {'s', 'e', 'c', 'o', 'n', 'd', 's'}; + const CharT m[] = {'m', 'i', 'n', 'u', 't', 'e', 's'}; + const CharT h[] = {'h', 'o', 'u', 'r', 's'}; + long_seconds_.assign(s, s + sizeof(s)/sizeof(s[0])); + long_minutes_.assign(m, m + sizeof(m)/sizeof(m[0])); + long_hours_.assign(h, h + sizeof(h)/sizeof(h[0])); +} + +template +duration_punct::duration_punct(int use, + const string_type& long_seconds, const string_type& long_minutes, + const string_type& long_hours, const string_type& short_seconds, + const string_type& short_minutes, const string_type& short_hours) + : use_short_(use==use_short), + long_seconds_(long_seconds), + long_minutes_(long_minutes), + long_hours_(long_hours), + short_seconds_(short_seconds), + short_minutes_(short_minutes), + short_hours_(short_hours) +{} + +template +duration_punct::duration_punct(int use, const duration_punct& d) + : use_short_(use==use_short), + long_seconds_(d.long_seconds_), + long_minutes_(d.long_minutes_), + long_hours_(d.long_hours_), + short_seconds_(d.short_seconds_), + short_minutes_(d.short_minutes_), + short_hours_(d.short_hours_) +{} + +template +std::basic_ostream& +duration_short(std::basic_ostream& os) +{ + typedef duration_punct Facet; + std::locale loc = os.getloc(); + if (std::has_facet(loc)) + { + const Facet& f = std::use_facet(loc); + if (f.is_long_name()) + os.imbue(std::locale(loc, new Facet(Facet::use_short, f))); + } + else + os.imbue(std::locale(loc, new Facet(Facet::use_short))); + return os; +} + +template +std::basic_ostream& +duration_long(std::basic_ostream& os) +{ + typedef duration_punct Facet; + std::locale loc = os.getloc(); + if (std::has_facet(loc)) + { + const Facet& f = std::use_facet(loc); + if (f.is_short_name()) + os.imbue(std::locale(loc, new Facet(Facet::use_long, f))); + } + return os; +} + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const duration& d) +{ + typedef duration_punct Facet; + std::locale loc = os.getloc(); + if (!std::has_facet(loc)) + os.imbue(std::locale(loc, new Facet)); + const Facet& f = std::use_facet(os.getloc()); + return os << d.count() << ' ' << f.template name(d.count()); +} + +namespace chrono_detail { +template ::value> +struct duration_io_intermediate +{ + typedef Rep type; +}; + +template +struct duration_io_intermediate +{ + typedef typename mpl::if_c + < + is_floating_point::value, + long double, + typename mpl::if_c + < + is_signed::value, + long long, + unsigned long long + >::type + >::type type; +}; + +template +typename enable_if, bool>::type +reduce(intermediate_type& r, unsigned long long& den, std::ios_base::iostate& err) +{ + typedef typename common_type::type common_type_t; + + // Reduce r * num / den + common_type_t t = integer::gcd(common_type_t(r), common_type_t(den)); + r /= t; + den /= t; + if (den != 1) + { + // Conversion to Period is integral and not exact + err |= std::ios_base::failbit; + return false; + } + return true; +} +template +typename disable_if, bool>::type +reduce(intermediate_type& , unsigned long long& , std::ios_base::iostate& ) +{ + return true; +} + +} + +template +std::basic_istream& +operator>>(std::basic_istream& is, duration& d) +{ + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + typedef duration_punct Facet; + std::locale loc = is.getloc(); + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + if (!std::has_facet(loc)) { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.imbue(std::locale(loc, new Facet)); + } + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + loc = is.getloc(); + const Facet& f = std::use_facet(loc); + typedef typename chrono_detail::duration_io_intermediate::type intermediate_type; + intermediate_type r; + std::ios_base::iostate err = std::ios_base::goodbit; + // read value into r + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is >> r; + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + if (is.good()) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // now determine unit + typedef std::istreambuf_iterator in_iterator; + in_iterator i(is); + in_iterator e; + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + if (i != e && *i == ' ') // mandatory ' ' after value + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + ++i; + if (i != e) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // unit is num / den (yet to be determined) + unsigned long long num = 0; + unsigned long long den = 0; + if (*i == '[') + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // parse [N/D]s or [N/D]seconds format + ++i; + CharT x; + is >> num >> x >> den; + if (!is.good() || (x != '/')) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(is.failbit); + return is; + } + i = in_iterator(is); + if (*i != ']') + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(is.failbit); + return is; + } + ++i; + const std::basic_string units[] = + { + f.template singular >(), + f.template plural >(), + f.template short_name >() + }; + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + const std::basic_string* k = chrono_detail::scan_keyword(i, e, + units, units + sizeof(units)/sizeof(units[0]), + //~ std::use_facet >(loc), + err); + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(err); + switch ((k - units) / 3) + { + case 0: + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + break; + default: + is.setstate(err); + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + return is; + } + } + else + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // parse SI name, short or long + const std::basic_string units[] = + { + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular >(), + f.template plural >(), + f.template short_name >(), + f.template singular >(), + f.template plural >(), + f.template short_name >(), + f.template singular >(), + f.template plural >(), + f.template short_name >() + }; + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + const std::basic_string* k = chrono_detail::scan_keyword(i, e, + units, units + sizeof(units)/sizeof(units[0]), + //~ std::use_facet >(loc), + err); + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + switch ((k - units) / 3) + { + case 0: + num = 1ULL; + den = 1000000000000000000ULL; + break; + case 1: + num = 1ULL; + den = 1000000000000000ULL; + break; + case 2: + num = 1ULL; + den = 1000000000000ULL; + break; + case 3: + num = 1ULL; + den = 1000000000ULL; + break; + case 4: + num = 1ULL; + den = 1000000ULL; + break; + case 5: + num = 1ULL; + den = 1000ULL; + break; + case 6: + num = 1ULL; + den = 100ULL; + break; + case 7: + num = 1ULL; + den = 10ULL; + break; + case 8: + num = 10ULL; + den = 1ULL; + break; + case 9: + num = 100ULL; + den = 1ULL; + break; + case 10: + num = 1000ULL; + den = 1ULL; + break; + case 11: + num = 1000000ULL; + den = 1ULL; + break; + case 12: + num = 1000000000ULL; + den = 1ULL; + break; + case 13: + num = 1000000000000ULL; + den = 1ULL; + break; + case 14: + num = 1000000000000000ULL; + den = 1ULL; + break; + case 15: + num = 1000000000000000000ULL; + den = 1ULL; + break; + case 16: + num = 1; + den = 1; + break; + case 17: + num = 60; + den = 1; + break; + case 18: + num = 3600; + den = 1; + break; + default: + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(err|is.failbit); + return is; + } + } + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // unit is num/den + // r should be multiplied by (num/den) / Period + // Reduce (num/den) / Period to lowest terms + unsigned long long gcd_n1_n2 = integer::gcd(num, Period::num); + unsigned long long gcd_d1_d2 = integer::gcd(den, Period::den); + num /= gcd_n1_n2; + den /= gcd_d1_d2; + unsigned long long n2 = Period::num / gcd_n1_n2; + unsigned long long d2 = Period::den / gcd_d1_d2; + if (num > (std::numeric_limits::max)() / d2 || + den > (std::numeric_limits::max)() / n2) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // (num/den) / Period overflows + is.setstate(err|is.failbit); + return is; + } + num *= d2; + den *= n2; + + typedef typename common_type::type common_type_t; + + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // num / den is now factor to multiply by r + if (!chrono_detail::reduce(r, den, err)) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(err|is.failbit); + return is; + } + + //if (r > ((duration_values::max)() / num)) + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + if (chrono::detail::gt(r,((duration_values::max)() / num))) + { + // Conversion to Period overflowed + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(err|is.failbit); + return is; + } + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + common_type_t t = r * num; + t /= den; + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + + if (t > duration_values::zero()) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + if ( (duration_values::max)() < Rep(t)) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // Conversion to Period overflowed + is.setstate(err|is.failbit); + return is; + } + } + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // Success! Store it. + d = duration(Rep(t)); + is.setstate(err); + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + return is; + } + else { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(is.failbit | is.eofbit); + return is; + } + } + else + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + if (i == e) + is.setstate(is.failbit|is.eofbit); + else + is.setstate(is.failbit); + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + return is; + } + } + else { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + //is.setstate(is.failbit); + return is; + } +} + + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, + const time_point& tp) +{ + return os << tp.time_since_epoch() << clock_string::since(); +} + +template +std::basic_istream& +operator>>(std::basic_istream& is, + time_point& tp) +{ + Duration d; + is >> d; + if (is.good()) + { + const std::basic_string units=clock_string::since(); + std::ios_base::iostate err = std::ios_base::goodbit; + typedef std::istreambuf_iterator in_iterator; + in_iterator i(is); + in_iterator e; + std::ptrdiff_t k = chrono_detail::scan_keyword(i, e, + &units, &units + 1, + //~ std::use_facet >(is.getloc()), + err) - &units; + is.setstate(err); + if (k == 1) + { + is.setstate(err | is.failbit); + // failed to read epoch string + return is; + } + tp = time_point(d); + } + else + is.setstate(is.failbit); + return is; +} +} // chrono + +} + +#endif // BOOST_CHRONO_CHRONO_IO_HPP diff --git a/boost/chrono/round.hpp b/boost/chrono/round.hpp new file mode 100644 index 0000000..09741fc --- /dev/null +++ b/boost/chrono/round.hpp @@ -0,0 +1,59 @@ +// boost/chrono/round.hpp ------------------------------------------------------------// + +// (C) Copyright Howard Hinnant +// Copyright 2011 Vicente J. Botet Escriba + +// 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/libs/chrono for documentation. + +#ifndef BOOST_CHRONO_ROUND_HPP +#define BOOST_CHRONO_ROUND_HPP + +#include +#include +//#include + +namespace boost +{ + namespace chrono + { + + /** + * rounds to nearest, to even on tie + */ + template + To round(const duration& d) + { + typedef typename common_type >::type result_type; + result_type diff0; + result_type diff1; + + To t0 = duration_cast(d); + To t1 = t0; + if (t0>d) { + --t1; + diff0 = t0 - d; + diff1 = d - t1; + } else { + ++t1; + diff0 = d - t0; + diff1 = t1 - d; + } + + if (diff0 == diff1) + { + if (t0.count() & 1) + return t1; + return t0; + } + else if (diff0 < diff1) + return t0; + return t1; + } + + } // namespace chrono +} // namespace boost + +#endif diff --git a/boost/config/compiler/visualc.hpp b/boost/config/compiler/visualc.hpp index e2ea270..092252e 100644 --- a/boost/config/compiler/visualc.hpp +++ b/boost/config/compiler/visualc.hpp @@ -111,8 +111,8 @@ // TR1 features: // #if (_MSC_VER >= 1700) && defined(_HAS_CXX17) && (_HAS_CXX17 > 0) -// # define BOOST_HAS_TR1_HASH // don't know if this is true yet. -// # define BOOST_HAS_TR1_TYPE_TRAITS // don't know if this is true yet. +// # define BOOST_HAS_TR1_HASH // don't know if this is true yet. +// # define BOOST_HAS_TR1_TYPE_TRAITS // don't know if this is true yet. # define BOOST_HAS_TR1_UNORDERED_MAP # define BOOST_HAS_TR1_UNORDERED_SET #endif diff --git a/boost/config/detail/suffix.hpp b/boost/config/detail/suffix.hpp index 86f6081..47e139b 100644 --- a/boost/config/detail/suffix.hpp +++ b/boost/config/detail/suffix.hpp @@ -943,6 +943,14 @@ namespace std{ using ::type_info; } // ------------------ End of deprecated macros for 1.51 --------------------------- +// +// Helper macro for marking types and methods final +// +#if !defined(BOOST_NO_CXX11_FINAL) +# define BOOST_FINAL final +#else +# define BOOST_FINAL +#endif // // Helper macros BOOST_NOEXCEPT, BOOST_NOEXCEPT_IF, BOOST_NOEXCEPT_EXPR @@ -986,6 +994,15 @@ namespace std{ using ::type_info; } #define BOOST_CXX14_CONSTEXPR constexpr #endif +// +// C++17 inline variables +// +#if !defined(BOOST_NO_CXX17_INLINE_VARIABLES) +#define BOOST_INLINE_VARIABLE inline +#else +#define BOOST_INLINE_VARIABLE +#endif + // // Unused variable/typedef workarounds: // @@ -996,7 +1013,8 @@ namespace std{ using ::type_info; } // [[nodiscard]]: // #ifdef __has_cpp_attribute -#if __has_cpp_attribute(nodiscard) +// clang-6 accepts [[nodiscard]] with -std=c++14, but warns about it -pedantic +#if __has_cpp_attribute(nodiscard) && !(defined(__clang__) && (__cplusplus < 201703L)) # define BOOST_ATTRIBUTE_NODISCARD [[nodiscard]] #endif #if __has_cpp_attribute(no_unique_address) && !(defined(__GNUC__) && (__cplusplus < 201100)) @@ -1041,7 +1059,8 @@ namespace std{ using ::type_info; } #endif // This is a catch all case for obsolete compilers / std libs: -#if !defined(__has_include) +#if !defined(_YVALS) && !defined(_CPPLIB_VER) // msvc std lib already configured +#if (!defined(__has_include) || (__cplusplus < 201700)) # define BOOST_NO_CXX17_HDR_OPTIONAL # define BOOST_NO_CXX17_HDR_STRING_VIEW # define BOOST_NO_CXX17_HDR_VARIANT @@ -1056,6 +1075,7 @@ namespace std{ using ::type_info; } # define BOOST_NO_CXX17_HDR_VARIANT #endif #endif +#endif // // Finish off with checks for macros that are depricated / no longer supported, diff --git a/boost/config/platform/vxworks.hpp b/boost/config/platform/vxworks.hpp index 7718acb..0564b94 100644 --- a/boost/config/platform/vxworks.hpp +++ b/boost/config/platform/vxworks.hpp @@ -318,7 +318,7 @@ namespace std { #ifdef __cplusplus -extern "C" void bzero (void *, size_t); // FD_ZERO uses bzero() but doesn't include strings.h +extern "C" void bzero (void *, size_t); // FD_ZERO uses bzero() but doesn't include strings.h // Put the selfmade functions into the std-namespace, just in case namespace std { diff --git a/boost/config/stdlib/dinkumware.hpp b/boost/config/stdlib/dinkumware.hpp index 19c772c..7d56565 100644 --- a/boost/config/stdlib/dinkumware.hpp +++ b/boost/config/stdlib/dinkumware.hpp @@ -97,7 +97,7 @@ #endif #include #if ( (!_HAS_EXCEPTIONS && !defined(__ghs__)) || (defined(__ghs__) && !_HAS_NAMESPACE) ) && !defined(__TI_COMPILER_VERSION__) && !defined(__VISUALDSPVERSION__) \ - && !defined(__VXWORKS__) + && !defined(__VXWORKS__) # define BOOST_NO_STD_TYPEINFO #endif @@ -136,6 +136,7 @@ # define BOOST_NO_CXX11_HDR_RATIO # define BOOST_NO_CXX11_HDR_THREAD # define BOOST_NO_CXX11_ATOMIC_SMART_PTR +# define BOOST_NO_CXX11_HDR_EXCEPTION #endif // C++0x headers implemented in 610 (as shipped by Microsoft) diff --git a/boost/config/stdlib/libcomo.hpp b/boost/config/stdlib/libcomo.hpp index 75ac2bb..6a8a161 100644 --- a/boost/config/stdlib/libcomo.hpp +++ b/boost/config/stdlib/libcomo.hpp @@ -39,6 +39,7 @@ # define BOOST_NO_CXX11_HDR_CHRONO # define BOOST_NO_CXX11_HDR_CODECVT # define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_EXCEPTION # define BOOST_NO_CXX11_HDR_FORWARD_LIST # define BOOST_NO_CXX11_HDR_FUTURE # define BOOST_NO_CXX11_HDR_INITIALIZER_LIST diff --git a/boost/config/stdlib/libcpp.hpp b/boost/config/stdlib/libcpp.hpp index e5e5c34..e8eea91 100644 --- a/boost/config/stdlib/libcpp.hpp +++ b/boost/config/stdlib/libcpp.hpp @@ -41,6 +41,7 @@ # define BOOST_NO_CXX11_HDR_CODECVT # define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_EXCEPTION # define BOOST_NO_CXX11_HDR_INITIALIZER_LIST # define BOOST_NO_CXX11_HDR_MUTEX # define BOOST_NO_CXX11_HDR_RANDOM diff --git a/boost/config/stdlib/libstdcpp3.hpp b/boost/config/stdlib/libstdcpp3.hpp index 9696515..c4c9996 100644 --- a/boost/config/stdlib/libstdcpp3.hpp +++ b/boost/config/stdlib/libstdcpp3.hpp @@ -125,7 +125,13 @@ // #ifdef __clang__ -#if __has_include() +#if __has_include() +# define BOOST_LIBSTDCXX_VERSION 90100 +#elif __has_include() +# define BOOST_LIBSTDCXX_VERSION 80100 +#elif __has_include() +# define BOOST_LIBSTDCXX_VERSION 70100 +#elif __has_include() # define BOOST_LIBSTDCXX_VERSION 60100 #elif __has_include() # define BOOST_LIBSTDCXX_VERSION 50100 @@ -231,6 +237,7 @@ extern "C" char *gets (char *__s); # define BOOST_NO_CXX11_HDR_RATIO # define BOOST_NO_CXX11_HDR_SYSTEM_ERROR # define BOOST_NO_CXX11_SMART_PTR +# define BOOST_NO_CXX11_HDR_EXCEPTION #else # define BOOST_HAS_TR1_COMPLEX_INVERSE_TRIG # define BOOST_HAS_TR1_COMPLEX_OVERLOADS diff --git a/boost/config/stdlib/modena.hpp b/boost/config/stdlib/modena.hpp index 81919e0..31a26c8 100644 --- a/boost/config/stdlib/modena.hpp +++ b/boost/config/stdlib/modena.hpp @@ -51,6 +51,7 @@ # define BOOST_NO_CXX11_HDR_ATOMIC # define BOOST_NO_CXX11_STD_ALIGN # define BOOST_NO_CXX11_ADDRESSOF +# define BOOST_NO_CXX11_HDR_EXCEPTION #if defined(__has_include) #if !__has_include() diff --git a/boost/config/stdlib/msl.hpp b/boost/config/stdlib/msl.hpp index 0e2e2af..f2f8259 100644 --- a/boost/config/stdlib/msl.hpp +++ b/boost/config/stdlib/msl.hpp @@ -75,6 +75,7 @@ # define BOOST_NO_CXX11_HDR_ATOMIC # define BOOST_NO_CXX11_STD_ALIGN # define BOOST_NO_CXX11_ADDRESSOF +# define BOOST_NO_CXX11_HDR_EXCEPTION #if defined(__has_include) #if !__has_include() diff --git a/boost/config/stdlib/roguewave.hpp b/boost/config/stdlib/roguewave.hpp index df60215..0c5c113 100644 --- a/boost/config/stdlib/roguewave.hpp +++ b/boost/config/stdlib/roguewave.hpp @@ -187,6 +187,7 @@ # define BOOST_NO_CXX11_HDR_ATOMIC # define BOOST_NO_CXX11_STD_ALIGN # define BOOST_NO_CXX11_ADDRESSOF +# define BOOST_NO_CXX11_HDR_EXCEPTION #if defined(__has_include) #if !__has_include() diff --git a/boost/config/stdlib/sgi.hpp b/boost/config/stdlib/sgi.hpp index 0c8ab2e..c49957c 100644 --- a/boost/config/stdlib/sgi.hpp +++ b/boost/config/stdlib/sgi.hpp @@ -145,6 +145,7 @@ # define BOOST_NO_CXX11_HDR_ATOMIC # define BOOST_NO_CXX11_STD_ALIGN # define BOOST_NO_CXX11_ADDRESSOF +# define BOOST_NO_CXX11_HDR_EXCEPTION #if defined(__has_include) #if !__has_include() diff --git a/boost/config/stdlib/stlport.hpp b/boost/config/stdlib/stlport.hpp index 2e304e2..094e27b 100644 --- a/boost/config/stdlib/stlport.hpp +++ b/boost/config/stdlib/stlport.hpp @@ -235,6 +235,7 @@ namespace boost { using std::min; using std::max; } # define BOOST_NO_CXX11_HDR_ATOMIC # define BOOST_NO_CXX11_STD_ALIGN # define BOOST_NO_CXX11_ADDRESSOF +# define BOOST_NO_CXX11_HDR_EXCEPTION #if defined(__has_include) #if !__has_include() diff --git a/boost/config/stdlib/vacpp.hpp b/boost/config/stdlib/vacpp.hpp index c4e1fb1..b14dd65 100644 --- a/boost/config/stdlib/vacpp.hpp +++ b/boost/config/stdlib/vacpp.hpp @@ -51,6 +51,7 @@ # define BOOST_NO_CXX11_HDR_ATOMIC # define BOOST_NO_CXX11_STD_ALIGN # define BOOST_NO_CXX11_ADDRESSOF +# define BOOST_NO_CXX11_HDR_EXCEPTION #if defined(__has_include) #if !__has_include() diff --git a/boost/config/stdlib/xlcpp_zos.hpp b/boost/config/stdlib/xlcpp_zos.hpp index 4d5beb1..a5e02fd 100644 --- a/boost/config/stdlib/xlcpp_zos.hpp +++ b/boost/config/stdlib/xlcpp_zos.hpp @@ -50,6 +50,7 @@ #define BOOST_NO_CXX11_HDR_CHRONO #define BOOST_NO_CXX11_HDR_ATOMIC #define BOOST_NO_CXX11_HDR_ARRAY +#define BOOST_NO_CXX11_HDR_EXCEPTION #define BOOST_NO_CXX11_STD_ALIGN #define BOOST_NO_CXX14_STD_EXCHANGE diff --git a/boost/config/user.hpp b/boost/config/user.hpp index 28e7476..8160fca 100644 --- a/boost/config/user.hpp +++ b/boost/config/user.hpp @@ -1,8 +1,8 @@ // boost/config/user.hpp ---------------------------------------------------// // (C) Copyright John Maddock 2001. -// Use, modification and distribution are subject to the -// Boost Software License, Version 1.0. (See accompanying file +// Use, modification and distribution are subject to 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) // Do not check in modified versions of this file, diff --git a/boost/container/detail/dispatch_uses_allocator.hpp b/boost/container/detail/dispatch_uses_allocator.hpp new file mode 100644 index 0000000..ff88e27 --- /dev/null +++ b/boost/container/detail/dispatch_uses_allocator.hpp @@ -0,0 +1,461 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. 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/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DISPATCH_USES_ALLOCATOR_HPP +#define BOOST_CONTAINER_DISPATCH_USES_ALLOCATOR_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif +#include + +#include + +namespace boost { namespace container { + +namespace dtl { + + +// Check if we can detect is_convertible using advanced SFINAE expressions +#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + //! Code inspired by Mathias Gaunard's is_convertible.cpp found in the Boost mailing list + //! http://boost.2283326.n4.nabble.com/type-traits-is-constructible-when-decltype-is-supported-td3575452.html + //! Thanks Mathias! + + //With variadic templates, we need a single class to implement the trait + template + struct is_constructible + { + typedef char yes_type; + struct no_type + { char padding[2]; }; + + template + struct dummy; + + template + static decltype(X(boost::move_detail::declval()...), true_type()) test(int); + + template + static no_type test(...); + + static const bool value = sizeof(test(0)) == sizeof(yes_type); + }; + + template + struct is_constructible_with_allocator_prefix + : is_constructible + {}; + +#else // #if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + //Without advanced SFINAE expressions, we can't use is_constructible + //so backup to constructible_with_allocator_xxx + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + struct is_constructible_with_allocator_prefix + : constructible_with_allocator_prefix + {}; + + template + struct is_constructible_with_allocator_suffix + : constructible_with_allocator_suffix + {}; + + #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + struct is_constructible_with_allocator_prefix + : constructible_with_allocator_prefix + {}; + + template + struct is_constructible_with_allocator_suffix + : constructible_with_allocator_suffix + {}; + + #endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#endif // #if !defined(BOOST_NO_SFINAE_EXPR) + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +template < typename ConstructAlloc + , typename ArgAlloc + , typename T + , class ...Args + > +inline typename dtl::enable_if_and + < void + , dtl::is_not_pair + , dtl::not_< uses_allocator > + >::type dispatch_uses_allocator + ( ConstructAlloc & construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p, BOOST_FWD_REF(Args)...args) +{ + (void)arg_alloc; + allocator_traits::construct(construct_alloc, p, ::boost::forward(args)...); +} + +// allocator_arg_t +template < typename ConstructAlloc + , typename ArgAlloc + , typename T + , class ...Args + > +inline typename dtl::enable_if_and + < void + , dtl::is_not_pair + , uses_allocator + , is_constructible_with_allocator_prefix + >::type dispatch_uses_allocator + ( ConstructAlloc& construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p, BOOST_FWD_REF(Args) ...args) +{ + allocator_traits::construct + ( construct_alloc, p, allocator_arg + , ::boost::forward(arg_alloc), ::boost::forward(args)...); +} + +// allocator suffix +template < typename ConstructAlloc + , typename ArgAlloc + , typename T + , class ...Args + > +inline typename dtl::enable_if_and + < void + , dtl::is_not_pair + , uses_allocator + , dtl::not_ > + >::type dispatch_uses_allocator + ( ConstructAlloc& construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p, BOOST_FWD_REF(Args)...args) +{ + allocator_traits::construct + (construct_alloc, p, ::boost::forward(args)..., ::boost::forward(arg_alloc)); +} + +#else //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#define BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE(N) \ + template \ + inline typename dtl::enable_if_and\ + < void\ + , dtl::is_not_pair\ + , dtl::not_ >\ + >::type\ + dispatch_uses_allocator\ + (ConstructAlloc &construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + (void)arg_alloc;\ + allocator_traits::construct(construct_alloc, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ +// +BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE) +#undef BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE + +#define BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE(N) \ + template < typename ConstructAlloc, typename ArgAlloc, typename T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ + inline typename dtl::enable_if_and\ + < void\ + , dtl::is_not_pair\ + , uses_allocator\ + , is_constructible_with_allocator_prefix\ + >::type\ + dispatch_uses_allocator\ + (ConstructAlloc& construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + allocator_traits::construct\ + (construct_alloc, p, allocator_arg, ::boost::forward(arg_alloc) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ +// +BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE) +#undef BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE + +#define BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE(N) \ + template < typename ConstructAlloc, typename ArgAlloc, typename T BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ + inline typename dtl::enable_if_and\ + < void\ + , dtl::is_not_pair\ + , uses_allocator\ + , dtl::not_ >\ + >::type\ + dispatch_uses_allocator\ + (ConstructAlloc& construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, T* p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + allocator_traits::construct\ + (construct_alloc, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N, ::boost::forward(arg_alloc));\ + }\ +// +BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE) +#undef BOOST_CONTAINER_SCOPED_ALLOCATOR_DISPATCH_USES_ALLOCATOR_CODE + +#endif //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +template < typename ConstructAlloc + , typename ArgAlloc + , typename Pair + > inline +BOOST_CONTAINER_DOC1ST(void, typename dtl::enable_if BOOST_MOVE_I void >::type) + dispatch_uses_allocator + ( ConstructAlloc & construct_alloc + , BOOST_FWD_REF(ArgAlloc) arg_alloc + , Pair* p) +{ + (dispatch_uses_allocator)(construct_alloc, arg_alloc, dtl::addressof(p->first)); + BOOST_TRY{ + (dispatch_uses_allocator)(construct_alloc, arg_alloc, dtl::addressof(p->second)); + } + BOOST_CATCH(...) { + allocator_traits::destroy(construct_alloc, dtl::addressof(p->first)); + BOOST_RETHROW + } + BOOST_CATCH_END +} + + +template < typename ConstructAlloc + , typename ArgAlloc + , class Pair, class U, class V> +BOOST_CONTAINER_DOC1ST(void, typename dtl::enable_if BOOST_MOVE_I void>::type) + dispatch_uses_allocator + ( ConstructAlloc & construct_alloc + , BOOST_FWD_REF(ArgAlloc) arg_alloc + , Pair* p, BOOST_FWD_REF(U) x, BOOST_FWD_REF(V) y) +{ + (dispatch_uses_allocator)(construct_alloc, arg_alloc, dtl::addressof(p->first), ::boost::forward(x)); + BOOST_TRY{ + (dispatch_uses_allocator)(construct_alloc, arg_alloc, dtl::addressof(p->second), ::boost::forward(y)); + } + BOOST_CATCH(...){ + allocator_traits::destroy(construct_alloc, dtl::addressof(p->first)); + BOOST_RETHROW + } + BOOST_CATCH_END +} + +template < typename ConstructAlloc + , typename ArgAlloc + , class Pair, class Pair2> +BOOST_CONTAINER_DOC1ST(void, typename dtl::enable_if< dtl::is_pair BOOST_MOVE_I void >::type) + dispatch_uses_allocator + (ConstructAlloc & construct_alloc + , BOOST_FWD_REF(ArgAlloc) arg_alloc + , Pair* p, Pair2& x) +{ (dispatch_uses_allocator)(construct_alloc, arg_alloc, p, x.first, x.second); } + +template < typename ConstructAlloc + , typename ArgAlloc + , class Pair, class Pair2> +typename dtl::enable_if_and + < void + , dtl::is_pair + , dtl::not_ > >::type //This is needed for MSVC10 and ambiguous overloads + dispatch_uses_allocator + (ConstructAlloc & construct_alloc + , BOOST_FWD_REF(ArgAlloc) arg_alloc + , Pair* p, BOOST_RV_REF_BEG Pair2 BOOST_RV_REF_END x) +{ (dispatch_uses_allocator)(construct_alloc, arg_alloc, p, ::boost::move(x.first), ::boost::move(x.second)); } + + +//piecewise construction from boost::tuple +#define BOOST_DISPATCH_USES_ALLOCATOR_PIECEWISE_CONSTRUCT_BOOST_TUPLE_CODE(N,M)\ +template< typename ConstructAlloc, typename ArgAlloc, class Pair \ + , template class BoostTuple \ + BOOST_MOVE_I_IF(BOOST_MOVE_OR(N,M)) BOOST_MOVE_CLASS##N BOOST_MOVE_I_IF(BOOST_MOVE_AND(N,M)) BOOST_MOVE_CLASSQ##M > \ +typename dtl::enable_if< dtl::is_pair BOOST_MOVE_I void>::type\ + dispatch_uses_allocator( ConstructAlloc & construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, Pair* pair, piecewise_construct_t\ + , BoostTuple p\ + , BoostTuple q)\ +{\ + (void)p; (void)q;\ + (dispatch_uses_allocator)\ + (construct_alloc, arg_alloc, dtl::addressof(pair->first) BOOST_MOVE_I_IF(N) BOOST_MOVE_TMPL_GET##N);\ + BOOST_TRY{\ + (dispatch_uses_allocator)\ + (construct_alloc, arg_alloc, dtl::addressof(pair->second) BOOST_MOVE_I_IF(M) BOOST_MOVE_TMPL_GETQ##M);\ + }\ + BOOST_CATCH(...) {\ + allocator_traits::destroy(construct_alloc, dtl::addressof(pair->first));\ + BOOST_RETHROW\ + }\ + BOOST_CATCH_END\ +}\ +// +BOOST_MOVE_ITER2D_0TOMAX(9, BOOST_DISPATCH_USES_ALLOCATOR_PIECEWISE_CONSTRUCT_BOOST_TUPLE_CODE) +#undef BOOST_DISPATCH_USES_ALLOCATOR_PIECEWISE_CONSTRUCT_BOOST_TUPLE_CODE + +//piecewise construction from Std Tuple +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template< typename ConstructAlloc, typename ArgAlloc, class Pair + , template class Tuple, class... Args1, class... Args2, size_t... Indexes1, size_t... Indexes2> + void dispatch_uses_allocator_index( ConstructAlloc & construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, Pair* pair + , Tuple& t1, Tuple& t2, index_tuple, index_tuple) + { + (void)t1; (void)t2; + (dispatch_uses_allocator)(construct_alloc, arg_alloc, dtl::addressof(pair->first), ::boost::forward(get(t1))...); + BOOST_TRY{ + (dispatch_uses_allocator)(construct_alloc, arg_alloc, dtl::addressof(pair->second), ::boost::forward(get(t2))...); + } + BOOST_CATCH(...){ + allocator_traits::destroy(construct_alloc, dtl::addressof(pair->first)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template< typename ConstructAlloc, typename ArgAlloc, class Pair + , template class Tuple, class... Args1, class... Args2> + typename dtl::enable_if< dtl::is_pair, void >::type + dispatch_uses_allocator( ConstructAlloc & construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, Pair* pair, piecewise_construct_t + , Tuple t1, Tuple t2) + { + (dispatch_uses_allocator_index)( construct_alloc, arg_alloc, pair, t1, t2 + , typename build_number_seq::type() + , typename build_number_seq::type()); + } + +#elif defined(BOOST_MSVC) && (_CPPLIB_VER == 520) + + //MSVC 2010 tuple implementation + #define BOOST_DISPATCH_USES_ALLOCATOR_PIECEWISE_CONSTRUCT_MSVC2010_TUPLE_CODE(N,M)\ + template< typename ConstructAlloc, typename ArgAlloc, class Pair\ + , template class StdTuple\ + BOOST_MOVE_I_IF(BOOST_MOVE_OR(N,M)) BOOST_MOVE_CLASS##N BOOST_MOVE_I_IF(BOOST_MOVE_AND(N,M)) BOOST_MOVE_CLASSQ##M > \ + typename dtl::enable_if< dtl::is_pair BOOST_MOVE_I void>::type\ + dispatch_uses_allocator(ConstructAlloc & construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, Pair* pair, piecewise_construct_t\ + , StdTuple p\ + , StdTuple q)\ + {\ + (void)p; (void)q;\ + (dispatch_uses_allocator)\ + (construct_alloc, arg_alloc, dtl::addressof(pair->first) BOOST_MOVE_I_IF(N) BOOST_MOVE_GET_IDX##N);\ + BOOST_TRY{\ + (dispatch_uses_allocator)\ + (construct_alloc, arg_alloc, dtl::addressof(pair->second) BOOST_MOVE_I_IF(M) BOOST_MOVE_GET_IDXQ##M);\ + }\ + BOOST_CATCH(...) {\ + allocator_traits::destroy(construct_alloc, dtl::addressof(pair->first));\ + BOOST_RETHROW\ + }\ + BOOST_CATCH_END\ + }\ + // + BOOST_MOVE_ITER2D_0TOMAX(9, BOOST_DISPATCH_USES_ALLOCATOR_PIECEWISE_CONSTRUCT_MSVC2010_TUPLE_CODE) + #undef BOOST_DISPATCH_USES_ALLOCATOR_PIECEWISE_CONSTRUCT_MSVC2010_TUPLE_CODE + +#elif defined(BOOST_MSVC) && (_CPPLIB_VER == 540) + #if _VARIADIC_MAX >= 9 + #define BOOST_DISPATCH_USES_ALLOCATOR_PIECEWISE_CONSTRUCT_MSVC2012_TUPLE_MAX_IT 9 + #else + #define BOOST_DISPATCH_USES_ALLOCATOR_PIECEWISE_CONSTRUCT_MSVC2012_TUPLE_MAX_IT BOOST_MOVE_ADD(_VARIADIC_MAX, 1) + #endif + + //MSVC 2012 tuple implementation + #define BOOST_DISPATCH_USES_ALLOCATOR_PIECEWISE_CONSTRUCT_MSVC2012_TUPLE_CODE(N,M)\ + template< typename ConstructAlloc, typename ArgAlloc, class Pair\ + , template class StdTuple \ + BOOST_MOVE_I_IF(BOOST_MOVE_OR(N,M)) BOOST_MOVE_CLASS##N BOOST_MOVE_I_IF(BOOST_MOVE_AND(N,M)) BOOST_MOVE_CLASSQ##M > \ + typename dtl::enable_if< dtl::is_pair BOOST_MOVE_I void>::type\ + dispatch_uses_allocator\ + ( ConstructAlloc & construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, Pair* pair, piecewise_construct_t\ + , StdTuple p\ + , StdTuple q)\ + {\ + (void)p; (void)q;\ + (dispatch_uses_allocator)\ + (construct_alloc, arg_alloc, dtl::addressof(pair->first) BOOST_MOVE_I_IF(N) BOOST_MOVE_GET_IDX##N);\ + BOOST_TRY{\ + (dispatch_uses_allocator)\ + (construct_alloc, arg_alloc, dtl::addressof(pair->second) BOOST_MOVE_I_IF(M) BOOST_MOVE_GET_IDXQ##M);\ + }\ + BOOST_CATCH(...) {\ + allocator_traits::destroy(construct_alloc, dtl::addressof(pair->first));\ + BOOST_RETHROW\ + }\ + BOOST_CATCH_END\ + }\ + // + BOOST_MOVE_ITER2D_0TOMAX(BOOST_DISPATCH_USES_ALLOCATOR_PIECEWISE_CONSTRUCT_MSVC2012_TUPLE_MAX_IT, BOOST_DISPATCH_USES_ALLOCATOR_PIECEWISE_CONSTRUCT_MSVC2012_TUPLE_CODE) + #undef BOOST_DISPATCH_USES_ALLOCATOR_PIECEWISE_CONSTRUCT_MSVC2010_TUPLE_CODE + #undef BOOST_DISPATCH_USES_ALLOCATOR_PIECEWISE_CONSTRUCT_MSVC2012_TUPLE_MAX_IT + +#endif //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +template < typename ConstructAlloc + , typename ArgAlloc + , class Pair, class KeyType, class ... Args> +typename dtl::enable_if< dtl::is_pair, void >::type + dispatch_uses_allocator + (ConstructAlloc & construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, Pair* p, try_emplace_t, BOOST_FWD_REF(KeyType) k, BOOST_FWD_REF(Args) ...args) +{ + (dispatch_uses_allocator)(construct_alloc, arg_alloc, dtl::addressof(p->first), ::boost::forward(k)); + BOOST_TRY{ + (dispatch_uses_allocator)(construct_alloc, arg_alloc, dtl::addressof(p->second), ::boost::forward(args)...); + } + BOOST_CATCH(...) { + allocator_traits::destroy(construct_alloc, dtl::addressof(p->first)); + BOOST_RETHROW + } + BOOST_CATCH_END +} + +#else + +#define BOOST_CONTAINER_DISPATCH_USES_ALLOCATOR_PAIR_TRY_EMPLACE_CODE(N) \ + template \ + inline typename dtl::enable_if\ + < dtl::is_pair BOOST_MOVE_I void >::type\ + dispatch_uses_allocator\ + (ConstructAlloc &construct_alloc, BOOST_FWD_REF(ArgAlloc) arg_alloc, Pair* p, try_emplace_t, \ + BOOST_FWD_REF(KeyType) k BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + (dispatch_uses_allocator)(construct_alloc, arg_alloc, dtl::addressof(p->first), ::boost::forward(k));\ + BOOST_TRY{\ + (dispatch_uses_allocator)(construct_alloc, arg_alloc, dtl::addressof(p->second) BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + BOOST_CATCH(...) {\ + allocator_traits::destroy(construct_alloc, dtl::addressof(p->first));\ + BOOST_RETHROW\ + }\ + BOOST_CATCH_END\ + }\ +// +BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DISPATCH_USES_ALLOCATOR_PAIR_TRY_EMPLACE_CODE) +#undef BOOST_CONTAINER_DISPATCH_USES_ALLOCATOR_PAIR_TRY_EMPLACE_CODE + +#endif //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +} //namespace dtl + +}} // namespace boost { namespace container { + +#include + +#endif // BOOST_CONTAINER_DISPATCH_USES_ALLOCATOR_HPP diff --git a/boost/container/flat_map.hpp b/boost/container/flat_map.hpp index f1d5ed2..63e7ab1 100644 --- a/boost/container/flat_map.hpp +++ b/boost/container/flat_map.hpp @@ -1199,7 +1199,7 @@ class flat_map //! //! Throws: Nothing unless the comparison object throws. //! - //! Complexity: N log(a.size() + N) (N has the value source.size()) + //! Complexity: N log(size() + N) (N has the value source.size()) template BOOST_CONTAINER_FORCEINLINE void merge(flat_map& source) { m_flat_tree.merge_unique(source.tree()); } @@ -1269,7 +1269,7 @@ class flat_map && boost::container::dtl::is_nothrow_swappable::value ) { m_flat_tree.swap(x.m_flat_tree); } - //! Effects: erase(a.begin(),a.end()). + //! Effects: erase(begin(),end()). //! //! Postcondition: size() == 0. //! @@ -1376,14 +1376,14 @@ class flat_map { return m_flat_tree.find(x) != m_flat_tree.end(); } //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& x) { return dtl::force_copy(m_flat_tree.lower_bound(x)); } //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& x) const @@ -1393,7 +1393,7 @@ class flat_map //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. template @@ -1404,22 +1404,22 @@ class flat_map //! key_compare::is_transparent exists. //! //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. template BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const K& x) const { return dtl::force_copy(m_flat_tree.lower_bound(x)); } - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. BOOST_CONTAINER_FORCEINLINE iterator upper_bound(const key_type& x) { return dtl::force_copy(m_flat_tree.upper_bound(x)); } - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& x) const @@ -1428,7 +1428,7 @@ class flat_map //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. @@ -1439,8 +1439,8 @@ class flat_map //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic. template @@ -2539,7 +2539,7 @@ class flat_multimap //! //! Throws: Nothing unless the comparison object throws. //! - //! Complexity: N log(a.size() + N) (N has the value source.size()) + //! Complexity: N log(size() + N) (N has the value source.size()) template BOOST_CONTAINER_FORCEINLINE void merge(flat_multimap& source) { m_flat_tree.merge_equal(source.tree()); } @@ -2609,7 +2609,7 @@ class flat_multimap && boost::container::dtl::is_nothrow_swappable::value ) { m_flat_tree.swap(x.m_flat_tree); } - //! Effects: erase(a.begin(),a.end()). + //! Effects: erase(begin(),end()). //! //! Postcondition: size() == 0. //! @@ -2714,14 +2714,14 @@ class flat_multimap { return m_flat_tree.find(x) != m_flat_tree.end(); } //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic BOOST_CONTAINER_FORCEINLINE iterator lower_bound(const key_type& x) { return dtl::force_copy(m_flat_tree.lower_bound(x)); } //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const key_type& x) const @@ -2731,7 +2731,7 @@ class flat_multimap //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template @@ -2742,14 +2742,14 @@ class flat_multimap //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template BOOST_CONTAINER_FORCEINLINE const_iterator lower_bound(const K& x) const { return dtl::force_copy(m_flat_tree.lower_bound(x)); } - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic @@ -2757,7 +2757,7 @@ class flat_multimap {return dtl::force_copy(m_flat_tree.upper_bound(x)); } //! Returns: A const iterator pointing to the first element with key - //! not less than x, or end() if such an element is not found. + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic BOOST_CONTAINER_FORCEINLINE const_iterator upper_bound(const key_type& x) const @@ -2766,7 +2766,7 @@ class flat_multimap //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic @@ -2778,7 +2778,7 @@ class flat_multimap //! key_compare::is_transparent exists. //! //! Returns: A const iterator pointing to the first element with key - //! not less than x, or end() if such an element is not found. + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template diff --git a/boost/container/flat_set.hpp b/boost/container/flat_set.hpp index 7cb1d5c..7af8395 100644 --- a/boost/container/flat_set.hpp +++ b/boost/container/flat_set.hpp @@ -808,7 +808,7 @@ class flat_set BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value && boost::container::dtl::is_nothrow_swappable::value ); - //! Effects: erase(a.begin(),a.end()). + //! Effects: erase(begin(),end()). //! //! Postcondition: size() == 0. //! @@ -948,13 +948,13 @@ class flat_set bool contains(const K& x) const; //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator lower_bound(const key_type& x); //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator lower_bound(const key_type& x) const; @@ -963,7 +963,7 @@ class flat_set //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template @@ -973,20 +973,20 @@ class flat_set //! key_compare::is_transparent exists. //! //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template const_iterator lower_bound(const K& x) const; - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator upper_bound(const key_type& x); - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator upper_bound(const key_type& x) const; @@ -994,7 +994,7 @@ class flat_set //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic @@ -1004,8 +1004,8 @@ class flat_set //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template diff --git a/boost/container/map.hpp b/boost/container/map.hpp index 447f4ad..477dcc1 100644 --- a/boost/container/map.hpp +++ b/boost/container/map.hpp @@ -993,7 +993,7 @@ class map //! //! Returns: A node_type owning the element if found, otherwise an empty node_type. //! - //! Complexity: log(a.size()). + //! Complexity: log(size()). node_type extract(const key_type& k) { typename base_t::node_type base_nh(this->base_t::extract(k)); @@ -1026,7 +1026,7 @@ class map //! //! Throws: Nothing unless the comparison object throws. //! - //! Complexity: N log(a.size() + N) (N has the value source.size()) + //! Complexity: N log(size() + N) (N has the value source.size()) template BOOST_CONTAINER_FORCEINLINE void merge(map& source) { @@ -1064,7 +1064,7 @@ class map BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value && boost::container::dtl::is_nothrow_swappable::value ) - //! Effects: erase(a.begin(),a.end()). + //! Effects: erase(begin(),end()). //! //! Postcondition: size() == 0. //! @@ -1152,13 +1152,13 @@ class map bool contains(const K& x) const; //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator lower_bound(const key_type& x); //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator lower_bound(const key_type& x) const; @@ -1167,7 +1167,7 @@ class map //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template @@ -1177,20 +1177,20 @@ class map //! key_compare::is_transparent exists. //! //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template const_iterator lower_bound(const K& x) const; - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator upper_bound(const key_type& x); - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator upper_bound(const key_type& x) const; @@ -1198,7 +1198,7 @@ class map //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic @@ -1208,8 +1208,8 @@ class map //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template @@ -1981,7 +1981,7 @@ class multimap //! //! Throws: Nothing unless the comparison object throws. //! - //! Complexity: N log(a.size() + N) (N has the value source.size()) + //! Complexity: N log(size() + N) (N has the value source.size()) template BOOST_CONTAINER_FORCEINLINE void merge(multimap& source) { @@ -2087,13 +2087,13 @@ class multimap bool contains(const K& x) const; //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator lower_bound(const key_type& x); //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator lower_bound(const key_type& x) const; @@ -2102,7 +2102,7 @@ class multimap //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template @@ -2112,20 +2112,20 @@ class multimap //! key_compare::is_transparent exists. //! //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template const_iterator lower_bound(const K& x) const; - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator upper_bound(const key_type& x); - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator upper_bound(const key_type& x) const; @@ -2133,7 +2133,7 @@ class multimap //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic @@ -2143,8 +2143,8 @@ class multimap //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template diff --git a/boost/container/scoped_allocator.hpp b/boost/container/scoped_allocator.hpp new file mode 100644 index 0000000..6cd69fe --- /dev/null +++ b/boost/container/scoped_allocator.hpp @@ -0,0 +1,907 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Pablo Halpern 2009. 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) +// +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2013. 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/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_ALLOCATOR_SCOPED_ALLOCATOR_HPP +#define BOOST_CONTAINER_ALLOCATOR_SCOPED_ALLOCATOR_HPP + +#if defined (_MSC_VER) +# pragma once +#endif + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif +#include + +#include + +namespace boost { namespace container { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +namespace dtl { + +template +struct is_scoped_allocator_imp +{ + typedef char yes_type; + struct no_type{ char dummy[2]; }; + + template + static yes_type test(typename T::outer_allocator_type*); + + template + static int test(...); + + static const bool value = (sizeof(yes_type) == sizeof(test(0))); +}; + +template::value > +struct outermost_allocator_type_impl +{ + typedef typename MaybeScopedAlloc::outer_allocator_type outer_type; + typedef typename outermost_allocator_type_impl::type type; +}; + +template +struct outermost_allocator_type_impl +{ + typedef MaybeScopedAlloc type; +}; + +template::value > +struct outermost_allocator_imp +{ + typedef MaybeScopedAlloc type; + + static type &get(MaybeScopedAlloc &a) + { return a; } + + static const type &get(const MaybeScopedAlloc &a) + { return a; } +}; + +template +struct outermost_allocator_imp +{ + typedef typename MaybeScopedAlloc::outer_allocator_type outer_type; + typedef typename outermost_allocator_type_impl::type type; + + static type &get(MaybeScopedAlloc &a) + { return outermost_allocator_imp::get(a.outer_allocator()); } + + static const type &get(const MaybeScopedAlloc &a) + { return outermost_allocator_imp::get(a.outer_allocator()); } +}; + +} //namespace dtl { + +template +struct is_scoped_allocator + : dtl::is_scoped_allocator_imp +{}; + +template +struct outermost_allocator + : dtl::outermost_allocator_imp +{}; + +template +typename outermost_allocator::type & + get_outermost_allocator(Allocator &a) +{ return outermost_allocator::get(a); } + +template +const typename outermost_allocator::type & + get_outermost_allocator(const Allocator &a) +{ return outermost_allocator::get(a); } + +namespace dtl { + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +template +class scoped_allocator_adaptor_base + : public OuterAlloc +{ + typedef allocator_traits outer_traits_type; + BOOST_COPYABLE_AND_MOVABLE(scoped_allocator_adaptor_base) + + public: + template + struct rebind_base + { + typedef scoped_allocator_adaptor_base other; + }; + + typedef OuterAlloc outer_allocator_type; + typedef scoped_allocator_adaptor inner_allocator_type; + typedef allocator_traits inner_traits_type; + typedef scoped_allocator_adaptor + scoped_allocator_type; + typedef dtl::bool_< + outer_traits_type::propagate_on_container_copy_assignment::value || + inner_allocator_type::propagate_on_container_copy_assignment::value + > propagate_on_container_copy_assignment; + typedef dtl::bool_< + outer_traits_type::propagate_on_container_move_assignment::value || + inner_allocator_type::propagate_on_container_move_assignment::value + > propagate_on_container_move_assignment; + typedef dtl::bool_< + outer_traits_type::propagate_on_container_swap::value || + inner_allocator_type::propagate_on_container_swap::value + > propagate_on_container_swap; + typedef dtl::bool_< + outer_traits_type::is_always_equal::value && + inner_allocator_type::is_always_equal::value + > is_always_equal; + + scoped_allocator_adaptor_base() + {} + + template + scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc, const InnerAllocs &...args) + : outer_allocator_type(::boost::forward(outerAlloc)) + , m_inner(args...) + {} + + scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other) + : outer_allocator_type(other.outer_allocator()) + , m_inner(other.inner_allocator()) + {} + + scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other) + : outer_allocator_type(::boost::move(other.outer_allocator())) + , m_inner(::boost::move(other.inner_allocator())) + {} + + template + scoped_allocator_adaptor_base + (const scoped_allocator_adaptor_base& other) + : outer_allocator_type(other.outer_allocator()) + , m_inner(other.inner_allocator()) + {} + + template + scoped_allocator_adaptor_base + (BOOST_RV_REF_BEG scoped_allocator_adaptor_base + BOOST_RV_REF_END other) + : outer_allocator_type(other.outer_allocator()) + , m_inner(other.inner_allocator()) + {} + + public: + struct internal_type_t{}; + + template + scoped_allocator_adaptor_base + ( internal_type_t + , BOOST_FWD_REF(OuterA2) outerAlloc + , const inner_allocator_type &inner) + : outer_allocator_type(::boost::forward(outerAlloc)) + , m_inner(inner) + {} + + public: + + scoped_allocator_adaptor_base &operator= + (BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor_base) other) + { + outer_allocator_type::operator=(other.outer_allocator()); + m_inner = other.inner_allocator(); + return *this; + } + + scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other) + { + outer_allocator_type::operator=(boost::move(other.outer_allocator())); + m_inner = ::boost::move(other.inner_allocator()); + return *this; + } + + void swap(scoped_allocator_adaptor_base &r) + { + boost::adl_move_swap(this->outer_allocator(), r.outer_allocator()); + boost::adl_move_swap(this->m_inner, r.inner_allocator()); + } + + friend void swap(scoped_allocator_adaptor_base &l, scoped_allocator_adaptor_base &r) + { l.swap(r); } + + inner_allocator_type& inner_allocator() BOOST_NOEXCEPT_OR_NOTHROW + { return m_inner; } + + inner_allocator_type const& inner_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + { return m_inner; } + + outer_allocator_type & outer_allocator() BOOST_NOEXCEPT_OR_NOTHROW + { return static_cast(*this); } + + const outer_allocator_type &outer_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + { return static_cast(*this); } + + scoped_allocator_type select_on_container_copy_construction() const + { + return scoped_allocator_type + (internal_type_t() + ,outer_traits_type::select_on_container_copy_construction(this->outer_allocator()) + ,inner_traits_type::select_on_container_copy_construction(this->inner_allocator()) + ); + } + + private: + inner_allocator_type m_inner; +}; + +#else //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +//Let's add a dummy first template parameter to allow creating +//specializations up to maximum InnerAlloc count +template +class scoped_allocator_adaptor_base; + +//Specializations for the adaptor with InnerAlloc allocators + +#define BOOST_CONTAINER_SCOPED_ALLOCATOR_ADAPTOR_BASE_CODE(N)\ +template \ +class scoped_allocator_adaptor_base\ + : public OuterAlloc\ +{\ + typedef allocator_traits outer_traits_type;\ + BOOST_COPYABLE_AND_MOVABLE(scoped_allocator_adaptor_base)\ + \ + public:\ + template \ + struct rebind_base\ + {\ + typedef scoped_allocator_adaptor_base other;\ + };\ + \ + typedef OuterAlloc outer_allocator_type;\ + typedef scoped_allocator_adaptor inner_allocator_type;\ + typedef scoped_allocator_adaptor scoped_allocator_type;\ + typedef allocator_traits inner_traits_type;\ + typedef dtl::bool_<\ + outer_traits_type::propagate_on_container_copy_assignment::value ||\ + inner_allocator_type::propagate_on_container_copy_assignment::value\ + > propagate_on_container_copy_assignment;\ + typedef dtl::bool_<\ + outer_traits_type::propagate_on_container_move_assignment::value ||\ + inner_allocator_type::propagate_on_container_move_assignment::value\ + > propagate_on_container_move_assignment;\ + typedef dtl::bool_<\ + outer_traits_type::propagate_on_container_swap::value ||\ + inner_allocator_type::propagate_on_container_swap::value\ + > propagate_on_container_swap;\ + \ + typedef dtl::bool_<\ + outer_traits_type::is_always_equal::value &&\ + inner_allocator_type::is_always_equal::value\ + > is_always_equal;\ + \ + scoped_allocator_adaptor_base(){}\ + \ + template \ + scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc, BOOST_MOVE_CREF##N)\ + : outer_allocator_type(::boost::forward(outerAlloc))\ + , m_inner(BOOST_MOVE_ARG##N)\ + {}\ + \ + scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other)\ + : outer_allocator_type(other.outer_allocator())\ + , m_inner(other.inner_allocator())\ + {}\ + \ + scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other)\ + : outer_allocator_type(::boost::move(other.outer_allocator()))\ + , m_inner(::boost::move(other.inner_allocator()))\ + {}\ + \ + template \ + scoped_allocator_adaptor_base\ + (const scoped_allocator_adaptor_base& other)\ + : outer_allocator_type(other.outer_allocator())\ + , m_inner(other.inner_allocator())\ + {}\ + \ + template \ + scoped_allocator_adaptor_base\ + (BOOST_RV_REF_BEG scoped_allocator_adaptor_base BOOST_RV_REF_END other)\ + : outer_allocator_type(other.outer_allocator())\ + , m_inner(other.inner_allocator())\ + {}\ + \ + public:\ + struct internal_type_t{};\ + \ + template \ + scoped_allocator_adaptor_base\ + ( internal_type_t, BOOST_FWD_REF(OuterA2) outerAlloc, const inner_allocator_type &inner)\ + : outer_allocator_type(::boost::forward(outerAlloc))\ + , m_inner(inner)\ + {}\ + \ + public:\ + scoped_allocator_adaptor_base &operator=\ + (BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor_base) other)\ + {\ + outer_allocator_type::operator=(other.outer_allocator());\ + m_inner = other.inner_allocator();\ + return *this;\ + }\ + \ + scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other)\ + {\ + outer_allocator_type::operator=(boost::move(other.outer_allocator()));\ + m_inner = ::boost::move(other.inner_allocator());\ + return *this;\ + }\ + \ + void swap(scoped_allocator_adaptor_base &r)\ + {\ + boost::adl_move_swap(this->outer_allocator(), r.outer_allocator());\ + boost::adl_move_swap(this->m_inner, r.inner_allocator());\ + }\ + \ + friend void swap(scoped_allocator_adaptor_base &l, scoped_allocator_adaptor_base &r)\ + { l.swap(r); }\ + \ + inner_allocator_type& inner_allocator()\ + { return m_inner; }\ + \ + inner_allocator_type const& inner_allocator() const\ + { return m_inner; }\ + \ + outer_allocator_type & outer_allocator()\ + { return static_cast(*this); }\ + \ + const outer_allocator_type &outer_allocator() const\ + { return static_cast(*this); }\ + \ + scoped_allocator_type select_on_container_copy_construction() const\ + {\ + return scoped_allocator_type\ + (internal_type_t()\ + ,outer_traits_type::select_on_container_copy_construction(this->outer_allocator())\ + ,inner_traits_type::select_on_container_copy_construction(this->inner_allocator())\ + );\ + }\ + private:\ + inner_allocator_type m_inner;\ +};\ +//! +BOOST_MOVE_ITERATE_1TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_ADAPTOR_BASE_CODE) +#undef BOOST_CONTAINER_SCOPED_ALLOCATOR_ADAPTOR_BASE_CODE + +#endif //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + #define BOOST_CONTAINER_SCOPEDALLOC_DUMMYTRUE ,true + #define BOOST_CONTAINER_SCOPEDALLOC_ALLINNER BOOST_MOVE_TARG9 + #define BOOST_CONTAINER_SCOPEDALLOC_ALLINNERCLASS BOOST_MOVE_CLASS9 +#else + #define BOOST_CONTAINER_SCOPEDALLOC_DUMMYTRUE + #define BOOST_CONTAINER_SCOPEDALLOC_ALLINNER InnerAllocs... + #define BOOST_CONTAINER_SCOPEDALLOC_ALLINNERCLASS typename... InnerAllocs +#endif + +//Specialization for adaptor without any InnerAlloc +template +class scoped_allocator_adaptor_base< OuterAlloc BOOST_CONTAINER_SCOPEDALLOC_DUMMYTRUE> + : public OuterAlloc +{ + BOOST_COPYABLE_AND_MOVABLE(scoped_allocator_adaptor_base) + public: + + template + struct rebind_base + { + typedef scoped_allocator_adaptor_base + ::template portable_rebind_alloc::type + BOOST_CONTAINER_SCOPEDALLOC_DUMMYTRUE > other; + }; + + typedef OuterAlloc outer_allocator_type; + typedef allocator_traits outer_traits_type; + typedef scoped_allocator_adaptor inner_allocator_type; + typedef inner_allocator_type scoped_allocator_type; + typedef allocator_traits inner_traits_type; + typedef typename outer_traits_type:: + propagate_on_container_copy_assignment propagate_on_container_copy_assignment; + typedef typename outer_traits_type:: + propagate_on_container_move_assignment propagate_on_container_move_assignment; + typedef typename outer_traits_type:: + propagate_on_container_swap propagate_on_container_swap; + typedef typename outer_traits_type:: + is_always_equal is_always_equal; + + scoped_allocator_adaptor_base() + {} + + template + scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc) + : outer_allocator_type(::boost::forward(outerAlloc)) + {} + + scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other) + : outer_allocator_type(other.outer_allocator()) + {} + + scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other) + : outer_allocator_type(::boost::move(other.outer_allocator())) + {} + + template + scoped_allocator_adaptor_base + (const scoped_allocator_adaptor_base& other) + : outer_allocator_type(other.outer_allocator()) + {} + + template + scoped_allocator_adaptor_base + (BOOST_RV_REF_BEG scoped_allocator_adaptor_base BOOST_RV_REF_END other) + : outer_allocator_type(other.outer_allocator()) + {} + + public: + struct internal_type_t{}; + + template + scoped_allocator_adaptor_base(internal_type_t, BOOST_FWD_REF(OuterA2) outerAlloc, const inner_allocator_type &) + : outer_allocator_type(::boost::forward(outerAlloc)) + {} + + public: + scoped_allocator_adaptor_base &operator=(BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor_base) other) + { + outer_allocator_type::operator=(other.outer_allocator()); + return *this; + } + + scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other) + { + outer_allocator_type::operator=(boost::move(other.outer_allocator())); + return *this; + } + + void swap(scoped_allocator_adaptor_base &r) + { + boost::adl_move_swap(this->outer_allocator(), r.outer_allocator()); + } + + friend void swap(scoped_allocator_adaptor_base &l, scoped_allocator_adaptor_base &r) + { l.swap(r); } + + inner_allocator_type& inner_allocator() + { return static_cast(*this); } + + inner_allocator_type const& inner_allocator() const + { return static_cast(*this); } + + outer_allocator_type & outer_allocator() + { return static_cast(*this); } + + const outer_allocator_type &outer_allocator() const + { return static_cast(*this); } + + scoped_allocator_type select_on_container_copy_construction() const + { + return scoped_allocator_type + (internal_type_t() + ,outer_traits_type::select_on_container_copy_construction(this->outer_allocator()) + //Don't use inner_traits_type::select_on_container_copy_construction(this->inner_allocator()) + //as inner_allocator() is equal to *this and that would trigger an infinite loop + , this->inner_allocator() + ); + } +}; + +} //namespace dtl { + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//Scoped allocator +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +#if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST) + +//! This class is a C++03-compatible implementation of std::scoped_allocator_adaptor. +//! The class template scoped_allocator_adaptor is an allocator template that specifies +//! the memory resource (the outer allocator) to be used by a container (as any other +//! allocator does) and also specifies an inner allocator resource to be passed to +//! the constructor of every element within the container. +//! +//! This adaptor is +//! instantiated with one outer and zero or more inner allocator types. If +//! instantiated with only one allocator type, the inner allocator becomes the +//! scoped_allocator_adaptor itself, thus using the same allocator resource for the +//! container and every element within the container and, if the elements themselves +//! are containers, each of their elements recursively. If instantiated with more than +//! one allocator, the first allocator is the outer allocator for use by the container, +//! the second allocator is passed to the constructors of the container's elements, +//! and, if the elements themselves are containers, the third allocator is passed to +//! the elements' elements, and so on. If containers are nested to a depth greater +//! than the number of allocators, the last allocator is used repeatedly, as in the +//! single-allocator case, for any remaining recursions. +//! +//! [Note: The +//! scoped_allocator_adaptor is derived from the outer allocator type so it can be +//! substituted for the outer allocator type in most expressions. -end note] +//! +//! In the construct member functions, OUTERMOST(x) is x if x does not have +//! an outer_allocator() member function and +//! OUTERMOST(x.outer_allocator()) otherwise; OUTERMOST_ALLOC_TRAITS(x) is +//! allocator_traits. +//! +//! [Note: OUTERMOST(x) and +//! OUTERMOST_ALLOC_TRAITS(x) are recursive operations. It is incumbent upon +//! the definition of outer_allocator() to ensure that the recursion terminates. +//! It will terminate for all instantiations of scoped_allocator_adaptor. -end note] +template +class scoped_allocator_adaptor + +#else // #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST) + +template +class scoped_allocator_adaptor + +#endif // #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST) + +#else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +template +class scoped_allocator_adaptor +#endif + + : public dtl::scoped_allocator_adaptor_base + +{ + BOOST_COPYABLE_AND_MOVABLE(scoped_allocator_adaptor) + + public: + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + typedef dtl::scoped_allocator_adaptor_base + base_type; + typedef typename base_type::internal_type_t internal_type_t; + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + typedef OuterAlloc outer_allocator_type; + //! Type: For exposition only + //! + typedef allocator_traits outer_traits_type; + //! Type: scoped_allocator_adaptor if sizeof...(InnerAllocs) is zero; otherwise, + //! scoped_allocator_adaptor. + typedef typename base_type::inner_allocator_type inner_allocator_type; + typedef allocator_traits inner_traits_type; + typedef typename outer_traits_type::value_type value_type; + typedef typename outer_traits_type::size_type size_type; + typedef typename outer_traits_type::difference_type difference_type; + typedef typename outer_traits_type::pointer pointer; + typedef typename outer_traits_type::const_pointer const_pointer; + typedef typename outer_traits_type::void_pointer void_pointer; + typedef typename outer_traits_type::const_void_pointer const_void_pointer; + //! Type: A type with a constant boolean value == true if + //!`allocator_traits:: propagate_on_container_copy_assignment::value` is + //! true for any Allocator in the set of OuterAlloc and InnerAllocs..., false otherwise. + typedef typename base_type:: + propagate_on_container_copy_assignment propagate_on_container_copy_assignment; + //! Type: A type with a constant boolean value == true if + //!`allocator_traits:: propagate_on_container_move_assignment::value` is + //! true for any Allocator in the set of OuterAlloc and InnerAllocs..., false otherwise. + typedef typename base_type:: + propagate_on_container_move_assignment propagate_on_container_move_assignment; + + //! Type: A type with a constant boolean value == true if + //! `allocator_traits:: propagate_on_container_swap::value` is + //! true for any Allocator in the set of OuterAlloc and InnerAllocs..., false otherwise. + typedef typename base_type:: + propagate_on_container_swap propagate_on_container_swap; + + //! Type: A type with a constant boolean value == true if + //!`allocator_traits:: is_always_equal::value` is + //! true for all Allocator in the set of OuterAlloc and InnerAllocs..., false otherwise. + typedef typename base_type:: + is_always_equal is_always_equal; + + //! Type: Rebinds scoped allocator to + //! typedef scoped_allocator_adaptor + //! < typename outer_traits_type::template portable_rebind_alloc::type + //! , InnerAllocs... > + template + struct rebind + { + typedef scoped_allocator_adaptor + < typename outer_traits_type::template portable_rebind_alloc::type + , BOOST_CONTAINER_SCOPEDALLOC_ALLINNER> other; + }; + + //! Effects: value-initializes the OuterAlloc base class + //! and the inner allocator object. + scoped_allocator_adaptor() + {} + + ~scoped_allocator_adaptor() + {} + + //! Effects: initializes each allocator within the adaptor with + //! the corresponding allocator from other. + scoped_allocator_adaptor(const scoped_allocator_adaptor& other) + : base_type(other.base()) + {} + + //! Effects: move constructs each allocator within the adaptor with + //! the corresponding allocator from other. + scoped_allocator_adaptor(BOOST_RV_REF(scoped_allocator_adaptor) other) + : base_type(::boost::move(other.base())) + {} + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Requires: OuterAlloc shall be constructible from OuterA2. + //! + //! Effects: initializes the OuterAlloc base class with boost::forward(outerAlloc) and inner + //! with innerAllocs...(hence recursively initializing each allocator within the adaptor with the + //! corresponding allocator from the argument list). + template + scoped_allocator_adaptor(BOOST_FWD_REF(OuterA2) outerAlloc, const InnerAllocs & ...innerAllocs) + : base_type(::boost::forward(outerAlloc), innerAllocs...) + {} + #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + #define BOOST_CONTAINER_SCOPED_ALLOCATOR_ADAPTOR_RELATED_ALLOCATOR_CONSTRUCTOR_CODE(N)\ + template \ + scoped_allocator_adaptor(BOOST_FWD_REF(OuterA2) outerAlloc BOOST_MOVE_I##N BOOST_MOVE_CREF##N)\ + : base_type(::boost::forward(outerAlloc) BOOST_MOVE_I##N BOOST_MOVE_ARG##N)\ + {}\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_ADAPTOR_RELATED_ALLOCATOR_CONSTRUCTOR_CODE) + #undef BOOST_CONTAINER_SCOPED_ALLOCATOR_ADAPTOR_RELATED_ALLOCATOR_CONSTRUCTOR_CODE + + #endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Requires: OuterAlloc shall be constructible from OuterA2. + //! + //! Effects: initializes each allocator within the adaptor with the corresponding allocator from other. + template + scoped_allocator_adaptor(const scoped_allocator_adaptor &other) + : base_type(other.base()) + {} + + //! Requires: OuterAlloc shall be constructible from OuterA2. + //! + //! Effects: initializes each allocator within the adaptor with the corresponding allocator + //! rvalue from other. + template + scoped_allocator_adaptor(BOOST_RV_REF_BEG scoped_allocator_adaptor + BOOST_RV_REF_END other) + : base_type(::boost::move(other.base())) + {} + + scoped_allocator_adaptor &operator=(BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor) other) + { return static_cast(base_type::operator=(static_cast(other))); } + + scoped_allocator_adaptor &operator=(BOOST_RV_REF(scoped_allocator_adaptor) other) + { return static_cast(base_type::operator=(boost::move(other.base()))); } + + #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + //! Effects: swaps *this with r. + //! + void swap(scoped_allocator_adaptor &r); + + //! Effects: swaps *this with r. + //! + friend void swap(scoped_allocator_adaptor &l, scoped_allocator_adaptor &r); + + //! Returns: + //! static_cast(*this). + outer_allocator_type & outer_allocator() BOOST_NOEXCEPT_OR_NOTHROW; + + //! Returns: + //! static_cast(*this). + const outer_allocator_type &outer_allocator() const BOOST_NOEXCEPT_OR_NOTHROW; + + //! Returns: + //! *this if sizeof...(InnerAllocs) is zero; otherwise, inner. + inner_allocator_type& inner_allocator() BOOST_NOEXCEPT_OR_NOTHROW; + + //! Returns: + //! *this if sizeof...(InnerAllocs) is zero; otherwise, inner. + inner_allocator_type const& inner_allocator() const BOOST_NOEXCEPT_OR_NOTHROW; + + #endif //BOOST_CONTAINER_DOXYGEN_INVOKED + + //! Returns: + //! allocator_traits:: max_size(outer_allocator()). + size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW + { return outer_traits_type::max_size(this->outer_allocator()); } + + //! Effects: + //! calls OUTERMOST_ALLOC_TRAITS(*this):: destroy(OUTERMOST(*this), p). + template + void destroy(T* p) BOOST_NOEXCEPT_OR_NOTHROW + { + allocator_traits::type> + ::destroy(get_outermost_allocator(this->outer_allocator()), p); + } + + //! Returns: + //! allocator_traits::allocate(outer_allocator(), n). + pointer allocate(size_type n) + { return outer_traits_type::allocate(this->outer_allocator(), n); } + + //! Returns: + //! allocator_traits::allocate(outer_allocator(), n, hint). + pointer allocate(size_type n, const_void_pointer hint) + { return outer_traits_type::allocate(this->outer_allocator(), n, hint); } + + //! Effects: + //! allocator_traits::deallocate(outer_allocator(), p, n). + void deallocate(pointer p, size_type n) + { outer_traits_type::deallocate(this->outer_allocator(), p, n); } + + #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED + //! Returns: A new scoped_allocator_adaptor object where each allocator + //! Allocator in the adaptor is initialized from the result of calling + //! allocator_traits::select_on_container_copy_construction() on + //! the corresponding allocator in *this. + scoped_allocator_adaptor select_on_container_copy_construction() const; + #endif //BOOST_CONTAINER_DOXYGEN_INVOKED + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + base_type &base() { return *this; } + + const base_type &base() const { return *this; } + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Effects: + //! 1) If uses_allocator::value is false calls + //! OUTERMOST_ALLOC_TRAITS(*this):: + //! construct(OUTERMOST(*this), p, std::forward(args)...). + //! + //! 2) Otherwise, if uses_allocator::value is true and + //! is_constructible:: value is true, calls + //! OUTERMOST_ALLOC_TRAITS(*this):: construct(OUTERMOST(*this), p, allocator_arg, + //! inner_allocator(), std::forward(args)...). + //! + //! [Note: In compilers without advanced decltype SFINAE support, is_constructible can't + //! be implemented so that condition will be replaced by + //! constructible_with_allocator_prefix::value. -end note] + //! + //! 3) Otherwise, if uses_allocator::value is true and + //! is_constructible:: value is true, calls + //! OUTERMOST_ALLOC_TRAITS(*this):: construct(OUTERMOST(*this), p, + //! std::forward(args)..., inner_allocator()). + //! + //! [Note: In compilers without advanced decltype SFINAE support, is_constructible can't be + //! implemented so that condition will be replaced by + //! constructible_with_allocator_suffix:: value. -end note] + //! + //! 4) Otherwise, the program is ill-formed. + //! + //! [Note: An error will result if uses_allocator evaluates + //! to true but the specific constructor does not take an allocator. This definition prevents a silent + //! failure to pass an inner allocator to a contained element. -end note] + template < typename T, class ...Args> + void construct(T* p, BOOST_FWD_REF(Args)...args) + { + dtl::dispatch_uses_allocator + ( (get_outermost_allocator)(this->outer_allocator()) + , this->inner_allocator(), p, ::boost::forward(args)...); + } + + #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //Disable this overload if the first argument is pair as some compilers have + //overload selection problems when the first parameter is a pair. + #define BOOST_CONTAINER_SCOPED_ALLOCATOR_CONSTRUCT_CODE(N) \ + template < typename T BOOST_MOVE_I##N BOOST_MOVE_CLASSQ##N >\ + void construct(T* p BOOST_MOVE_I##N BOOST_MOVE_UREFQ##N)\ + {\ + dtl::dispatch_uses_allocator\ + ( (get_outermost_allocator)(this->outer_allocator())\ + , this->inner_allocator(), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\ + }\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_CONSTRUCT_CODE) + #undef BOOST_CONTAINER_SCOPED_ALLOCATOR_CONSTRUCT_CODE + + #endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + public: + //Internal function + template + scoped_allocator_adaptor(internal_type_t, BOOST_FWD_REF(OuterA2) outer, const inner_allocator_type& inner) + : base_type(internal_type_t(), ::boost::forward(outer), inner) + {} + + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED +}; + +/// @cond + +template +struct scoped_allocator_operator_equal +{ + //Optimize equal outer allocator types with + //allocator_traits::equal which uses is_always_equal + template + static bool equal_outer(const IA &l, const IA &r) + { return allocator_traits::equal(l, r); } + + //Otherwise compare it normally + template + static bool equal_outer(const IA1 &l, const IA2 &r) + { return l == r; } + + //Otherwise compare it normally + template + static bool equal_inner(const IA &l, const IA &r) + { return allocator_traits::equal(l, r); } +}; + +template<> +struct scoped_allocator_operator_equal + : scoped_allocator_operator_equal +{ + //when inner allocator count is zero, + //inner_allocator_type is the same as outer_allocator_type + //so both types can be different in operator== + template + static bool equal_inner(const IA1 &, const IA2 &) + { return true; } +}; + +/// @endcond + +template +inline bool operator==(const scoped_allocator_adaptor& a + ,const scoped_allocator_adaptor& b) +{ + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + const bool has_zero_inner = sizeof...(InnerAllocs) == 0u; + #else + const bool has_zero_inner = boost::container::dtl::is_same::value; + #endif + typedef scoped_allocator_operator_equal equal_t; + return equal_t::equal_outer(a.outer_allocator(), b.outer_allocator()) && + equal_t::equal_inner(a.inner_allocator(), b.inner_allocator()); +} + +template +inline bool operator!=(const scoped_allocator_adaptor& a + ,const scoped_allocator_adaptor& b) +{ return !(a == b); } + +}} // namespace boost { namespace container { + +#include + +#endif // BOOST_CONTAINER_ALLOCATOR_SCOPED_ALLOCATOR_HPP diff --git a/boost/container/scoped_allocator_fwd.hpp b/boost/container/scoped_allocator_fwd.hpp new file mode 100644 index 0000000..cddf7fa --- /dev/null +++ b/boost/container/scoped_allocator_fwd.hpp @@ -0,0 +1,71 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. 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/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_ALLOCATOR_SCOPED_ALLOCATOR_FWD_HPP +#define BOOST_CONTAINER_ALLOCATOR_SCOPED_ALLOCATOR_FWD_HPP + +//! \file +//! This header file forward declares boost::container::scoped_allocator_adaptor + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include + +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif + +namespace boost { namespace container { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST) + + template + class scoped_allocator_adaptor; + + #else // #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST) + + template + class scoped_allocator_adaptor; + + template + class scoped_allocator_adaptor; + + #endif // #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST) + +#else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + class scoped_allocator_adaptor; + +#endif + + +#else //BOOST_CONTAINER_DOXYGEN_INVOKED + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +}} // namespace boost { namespace container { + +#include + +#endif // BOOST_CONTAINER_ALLOCATOR_SCOPED_ALLOCATOR_FWD_HPP diff --git a/boost/container/set.hpp b/boost/container/set.hpp index ca6334f..b216c01 100644 --- a/boost/container/set.hpp +++ b/boost/container/set.hpp @@ -718,7 +718,7 @@ class set BOOST_NOEXCEPT_IF( allocator_traits_type::is_always_equal::value && boost::container::dtl::is_nothrow_swappable::value ); - //! Effects: erase(a.begin(),a.end()). + //! Effects: erase(begin(),end()). //! //! Postcondition: size() == 0. //! @@ -806,13 +806,13 @@ class set bool contains(const K& x) const; //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator lower_bound(const key_type& x); //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator lower_bound(const key_type& x) const; @@ -821,7 +821,7 @@ class set //! key_compare::is_transparent exists. //! //! Returns: An iterator pointing to the first element with key not less - //! than k, or a.end() if such an element is not found. + //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template @@ -831,20 +831,20 @@ class set //! key_compare::is_transparent exists. //! //! Returns: A const iterator pointing to the first element with key not - //! less than k, or a.end() if such an element is not found. + //! less than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template const_iterator lower_bound(const K& x) const; - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic iterator upper_bound(const key_type& x); - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic const_iterator upper_bound(const key_type& x) const; @@ -852,7 +852,7 @@ class set //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: An iterator pointing to the first element with key not less + //! Returns: An iterator pointing to the first element with key greater //! than x, or end() if such an element is not found. //! //! Complexity: Logarithmic @@ -862,8 +862,8 @@ class set //! Requires: This overload is available only if //! key_compare::is_transparent exists. //! - //! Returns: A const iterator pointing to the first element with key not - //! less than x, or end() if such an element is not found. + //! Returns: A const iterator pointing to the first element with key + //! greater than x, or end() if such an element is not found. //! //! Complexity: Logarithmic template diff --git a/boost/container/static_vector.hpp b/boost/container/static_vector.hpp index 2c08be8..6408c22 100644 --- a/boost/container/static_vector.hpp +++ b/boost/container/static_vector.hpp @@ -1116,27 +1116,33 @@ public: //! Constant O(1). const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW; - //! @brief Returns container's capacity. - //! - //! @return container's capacity. - //! - //! @par Throws - //! Nothing. - //! - //! @par Complexity - //! Constant O(1). - static size_type capacity() BOOST_NOEXCEPT_OR_NOTHROW; + #endif //#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED - //! @brief Returns container's capacity. - //! - //! @return container's capacity. - //! - //! @par Throws - //! Nothing. - //! - //! @par Complexity - //! Constant O(1). - static size_type max_size() BOOST_NOEXCEPT_OR_NOTHROW; + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + BOOST_CONTAINER_FORCEINLINE static size_type capacity() BOOST_NOEXCEPT_OR_NOTHROW + { return static_capacity; } + + //! @brief Returns container's capacity. + //! + //! @return container's capacity. + //! + //! @par Throws + //! Nothing. + //! + //! @par Complexity + //! Constant O(1). + BOOST_CONTAINER_FORCEINLINE static size_type max_size() BOOST_NOEXCEPT_OR_NOTHROW + { return static_capacity; } + + #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED //! @brief Returns the number of stored elements. //! diff --git a/boost/container/uses_allocator.hpp b/boost/container/uses_allocator.hpp new file mode 100644 index 0000000..e0e3518 --- /dev/null +++ b/boost/container/uses_allocator.hpp @@ -0,0 +1,169 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2013. 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/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_USES_ALLOCATOR_HPP +#define BOOST_CONTAINER_USES_ALLOCATOR_HPP + +#include +#include + +namespace boost { +namespace container { + +//! Remark: if a specialization constructible_with_allocator_suffix::value is true, indicates that T may be constructed +//! with an allocator as its last constructor argument. Ideally, all constructors of T (including the +//! copy and move constructors) should have a variant that accepts a final argument of +//! allocator_type. +//! +//! Requires: if a specialization constructible_with_allocator_suffix::value is true, T must have a nested type, +//! allocator_type and at least one constructor for which allocator_type is the last +//! parameter. If not all constructors of T can be called with a final allocator_type argument, +//! and if T is used in a context where a container must call such a constructor, then the program is +//! ill-formed. +//! +//! +//! template > +//! class Z { +//! public: +//! typedef Allocator allocator_type; +//! +//! // Default constructor with optional allocator suffix +//! Z(const allocator_type& a = allocator_type()); +//! +//! // Copy constructor and allocator-extended copy constructor +//! Z(const Z& zz); +//! Z(const Z& zz, const allocator_type& a); +//! }; +//! +//! // Specialize trait for class template Z +//! template > +//! struct constructible_with_allocator_suffix > +//! { static const bool value = true; }; +//! +//! +//! Note: This trait is a workaround inspired by "N2554: The Scoped A Model (Rev 2)" +//! (Pablo Halpern, 2008-02-29) to backport the scoped allocator model to C++03, as +//! in C++03 there is no mechanism to detect if a type can be constructed from arbitrary arguments. +//! Applications aiming portability with several compilers should always define this trait. +//! +//! In conforming C++11 compilers or compilers supporting SFINAE expressions +//! (when BOOST_NO_SFINAE_EXPR is NOT defined), this trait is ignored and C++11 rules will be used +//! to detect if a type should be constructed with suffix or prefix allocator arguments. +template +struct constructible_with_allocator_suffix +{ static const bool value = false; }; + +//! Remark: if a specialization constructible_with_allocator_prefix::value is true, indicates that T may be constructed +//! with allocator_arg and T::allocator_type as its first two constructor arguments. +//! Ideally, all constructors of T (including the copy and move constructors) should have a variant +//! that accepts these two initial arguments. +//! +//! Requires: specialization constructible_with_allocator_prefix::value is true, T must have a nested type, +//! allocator_type and at least one constructor for which allocator_arg_t is the first +//! parameter and allocator_type is the second parameter. If not all constructors of T can be +//! called with these initial arguments, and if T is used in a context where a container must call such +//! a constructor, then the program is ill-formed. +//! +//! +//! template > +//! class Y { +//! public: +//! typedef Allocator allocator_type; +//! +//! // Default constructor with and allocator-extended default constructor +//! Y(); +//! Y(allocator_arg_t, const allocator_type& a); +//! +//! // Copy constructor and allocator-extended copy constructor +//! Y(const Y& yy); +//! Y(allocator_arg_t, const allocator_type& a, const Y& yy); +//! +//! // Variadic constructor and allocator-extended variadic constructor +//! template Y(Args&& args...); +//! template +//! Y(allocator_arg_t, const allocator_type& a, BOOST_FWD_REF(Args)... args); +//! }; +//! +//! // Specialize trait for class template Y +//! template > +//! struct constructible_with_allocator_prefix > +//! { static const bool value = true; }; +//! +//! +//! +//! Note: This trait is a workaround inspired by "N2554: The Scoped Allocator Model (Rev 2)" +//! (Pablo Halpern, 2008-02-29) to backport the scoped allocator model to C++03, as +//! in C++03 there is no mechanism to detect if a type can be constructed from arbitrary arguments. +//! Applications aiming portability with several compilers should always define this trait. +//! +//! In conforming C++11 compilers or compilers supporting SFINAE expressions +//! (when BOOST_NO_SFINAE_EXPR is NOT defined), this trait is ignored and C++11 rules will be used +//! to detect if a type should be constructed with suffix or prefix allocator arguments. +template +struct constructible_with_allocator_prefix +{ static const bool value = false; }; + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +namespace dtl { + +template +struct uses_allocator_imp +{ + // Use SFINAE (Substitution Failure Is Not An Error) to detect the + // presence of an 'allocator_type' nested type convertilble from Allocator. + private: + typedef char yes_type; + struct no_type{ char dummy[2]; }; + + // Match this function if T::allocator_type exists and is + // implicitly convertible from Allocator + template + static yes_type test(typename U::allocator_type); + + // Match this function if T::allocator_type exists and it's type is `erased_type`. + template + static typename dtl::enable_if + < dtl::is_same + , yes_type + >::type test(const V&); + + // Match this function if TypeT::allocator_type does not exist or is + // not convertible from Allocator. + template + static no_type test(...); + static Allocator alloc; // Declared but not defined + + public: + static const bool value = sizeof(test(alloc)) == sizeof(yes_type); +}; + +} //namespace dtl { + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! Remark: Automatically detects whether T has a nested allocator_type that is convertible from +//! Allocator. Meets the BinaryTypeTrait requirements ([meta.rqmts] 20.4.1). A program may +//! specialize this type to define uses_allocator::value as true for a T of user-defined type if T does not +//! have a nested allocator_type but is nonetheless constructible using the specified Allocator where either: +//! the first argument of a constructor has type allocator_arg_t and the second argument has type Alloc or +//! the last argument of a constructor has type Alloc. +//! +//! Result: uses_allocator::value== true if a type T::allocator_type +//! exists and either is_convertible::value != false or T::allocator_type +//! is an alias `erased_type`. False otherwise. +template +struct uses_allocator + : dtl::uses_allocator_imp +{}; + +}} //namespace boost::container + +#endif //BOOST_CONTAINER_USES_ALLOCATOR_HPP diff --git a/boost/container/uses_allocator_fwd.hpp b/boost/container/uses_allocator_fwd.hpp new file mode 100644 index 0000000..42a5b90 --- /dev/null +++ b/boost/container/uses_allocator_fwd.hpp @@ -0,0 +1,73 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. 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/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_USES_ALLOCATOR_FWD_HPP +#define BOOST_CONTAINER_USES_ALLOCATOR_FWD_HPP + +#include +#include + +//! \file +//! This header forward declares boost::container::constructible_with_allocator_prefix, +//! boost::container::constructible_with_allocator_suffix and +//! boost::container::uses_allocator. Also defines the following types: + +namespace boost { +namespace container { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + template + struct std_allocator_arg_holder + { + static ::std::allocator_arg_t *dummy; + }; + + template //Silence null-reference compiler warnings + ::std::allocator_arg_t *std_allocator_arg_holder::dummy = reinterpret_cast< ::std::allocator_arg_t * >(0x1234); + +typedef const std::allocator_arg_t & allocator_arg_t; + +#else + +//! The allocator_arg_t struct is an empty structure type used as a unique type to +//! disambiguate constructor and function overloading. Specifically, several types +//! have constructors with allocator_arg_t as the first argument, immediately followed +//! by an argument of a type that satisfies Allocator requirements +typedef unspecified allocator_arg_t; + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! The `erased_type` struct is an empty struct that serves as a placeholder for a type +//! T in situations where the actual type T is determined at runtime. For example, +//! the nested type, `allocator_type`, is an alias for `erased_type` in classes that +//! use type-erased allocators. +struct erased_type {}; + +//! A instance of type +//! allocator_arg_t +static allocator_arg_t allocator_arg = BOOST_CONTAINER_DOC1ST(unspecified, *std_allocator_arg_holder<>::dummy); + +// @cond + +template +struct constructible_with_allocator_suffix; + +template +struct constructible_with_allocator_prefix; + +template +struct uses_allocator; + +// @endcond + +}} // namespace boost { namespace container { + +#endif //BOOST_CONTAINER_USES_ALLOCATOR_HPP diff --git a/boost/context/continuation.hpp b/boost/context/continuation.hpp new file mode 100644 index 0000000..8db62a9 --- /dev/null +++ b/boost/context/continuation.hpp @@ -0,0 +1,13 @@ + +// Copyright Oliver Kowalke 2017. +// 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) + +#if defined(BOOST_USE_UCONTEXT) +#include +#elif defined(BOOST_USE_WINFIB) +#include +#else +#include +#endif diff --git a/boost/context/continuation_fcontext.hpp b/boost/context/continuation_fcontext.hpp new file mode 100644 index 0000000..a16ea63 --- /dev/null +++ b/boost/context/continuation_fcontext.hpp @@ -0,0 +1,373 @@ + +// Copyright Oliver Kowalke 2017. +// 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_CONTEXT_CONTINUATION_H +#define BOOST_CONTEXT_CONTINUATION_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) +#include +#endif +#if defined(BOOST_NO_CXX17_STD_INVOKE) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable: 4702) +#endif + +namespace boost { +namespace context { +namespace detail { + +inline +transfer_t context_unwind( transfer_t t) { + throw forced_unwind( t.fctx); + return { nullptr, nullptr }; +} + +template< typename Rec > +transfer_t context_exit( transfer_t t) noexcept { + Rec * rec = static_cast< Rec * >( t.data); + // destroy context stack + rec->deallocate(); + return { nullptr, nullptr }; +} + +template< typename Rec > +void context_entry( transfer_t t) noexcept { + // transfer control structure to the context-stack + Rec * rec = static_cast< Rec * >( t.data); + BOOST_ASSERT( nullptr != t.fctx); + BOOST_ASSERT( nullptr != rec); + try { + // jump back to `create_context()` + t = jump_fcontext( t.fctx, nullptr); + // start executing + t.fctx = rec->run( t.fctx); + } catch ( forced_unwind const& ex) { + t = { ex.fctx, nullptr }; +#ifndef BOOST_ASSERT_IS_VOID + const_cast< forced_unwind & >( ex).caught = true; +#endif + } + BOOST_ASSERT( nullptr != t.fctx); + // destroy context-stack of `this`context on next context + ontop_fcontext( t.fctx, rec, context_exit< Rec >); + BOOST_ASSERT_MSG( false, "context already terminated"); +} + +template< typename Ctx, typename Fn > +transfer_t context_ontop( transfer_t t) { + auto p = static_cast< std::tuple< Fn > * >( t.data); + BOOST_ASSERT( nullptr != p); + typename std::decay< Fn >::type fn = std::get< 0 >( * p); + t.data = nullptr; + Ctx c{ t.fctx }; + // execute function, pass continuation via reference + c = fn( std::move( c) ); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return { exchange( c.fctx_, nullptr), nullptr }; +#else + return { std::exchange( c.fctx_, nullptr), nullptr }; +#endif +} + +template< typename Ctx, typename StackAlloc, typename Fn > +class record { +private: + stack_context sctx_; + typename std::decay< StackAlloc >::type salloc_; + typename std::decay< Fn >::type fn_; + + static void destroy( record * p) noexcept { + typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); + stack_context sctx = p->sctx_; + // deallocate record + p->~record(); + // destroy stack with stack allocator + salloc.deallocate( sctx); + } + +public: + record( stack_context sctx, StackAlloc && salloc, + Fn && fn) noexcept : + sctx_( sctx), + salloc_( std::forward< StackAlloc >( salloc)), + fn_( std::forward< Fn >( fn) ) { + } + + record( record const&) = delete; + record & operator=( record const&) = delete; + + void deallocate() noexcept { + destroy( this); + } + + fcontext_t run( fcontext_t fctx) { + Ctx c{ fctx }; + // invoke context-function +#if defined(BOOST_NO_CXX17_STD_INVOKE) + c = boost::context::detail::invoke( fn_, std::move( c) ); +#else + c = std::invoke( fn_, std::move( c) ); +#endif +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( c.fctx_, nullptr); +#else + return std::exchange( c.fctx_, nullptr); +#endif + } +}; + +template< typename Record, typename StackAlloc, typename Fn > +fcontext_t create_context1( StackAlloc && salloc, Fn && fn) { + auto sctx = salloc.allocate(); + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( Record) ) ) + & ~static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + Record * record = new ( storage) Record{ + sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + // 64byte gab between control structure and stack top + // should be 16byte aligned + void * stack_top = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) ); + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); + // create fast-context + const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom); + const fcontext_t fctx = make_fcontext( stack_top, size, & context_entry< Record >); + BOOST_ASSERT( nullptr != fctx); + // transfer control structure to context-stack + return jump_fcontext( fctx, record).fctx; +} + +template< typename Record, typename StackAlloc, typename Fn > +fcontext_t create_context2( preallocated palloc, StackAlloc && salloc, Fn && fn) { + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( Record) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context-stack + Record * record = new ( storage) Record{ + palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + // 64byte gab between control structure and stack top + void * stack_top = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) ); + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) ); + // create fast-context + const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom); + const fcontext_t fctx = make_fcontext( stack_top, size, & context_entry< Record >); + BOOST_ASSERT( nullptr != fctx); + // transfer control structure to context-stack + return jump_fcontext( fctx, record).fctx; +} + +} + +class continuation { +private: + template< typename Ctx, typename StackAlloc, typename Fn > + friend class detail::record; + + template< typename Ctx, typename Fn > + friend detail::transfer_t + detail::context_ontop( detail::transfer_t); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, StackAlloc &&, Fn &&); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&); + + detail::fcontext_t fctx_{ nullptr }; + + continuation( detail::fcontext_t fctx) noexcept : + fctx_{ fctx } { + } + +public: + continuation() noexcept = default; + + ~continuation() { + if ( BOOST_UNLIKELY( nullptr != fctx_) ) { + detail::ontop_fcontext( +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::exchange( fctx_, nullptr), +#else + std::exchange( fctx_, nullptr), +#endif + nullptr, + detail::context_unwind); + } + } + + continuation( continuation && other) noexcept { + swap( other); + } + + continuation & operator=( continuation && other) noexcept { + if ( BOOST_LIKELY( this != & other) ) { + continuation tmp = std::move( other); + swap( tmp); + } + return * this; + } + + continuation( continuation const& other) noexcept = delete; + continuation & operator=( continuation const& other) noexcept = delete; + + continuation resume() & { + return std::move( * this).resume(); + } + + continuation resume() && { + BOOST_ASSERT( nullptr != fctx_); + return { detail::jump_fcontext( +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::exchange( fctx_, nullptr), +#else + std::exchange( fctx_, nullptr), +#endif + nullptr).fctx }; + } + + template< typename Fn > + continuation resume_with( Fn && fn) & { + return std::move( * this).resume_with( std::forward< Fn >( fn) ); + } + + template< typename Fn > + continuation resume_with( Fn && fn) && { + BOOST_ASSERT( nullptr != fctx_); + auto p = std::make_tuple( std::forward< Fn >( fn) ); + return { detail::ontop_fcontext( +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::exchange( fctx_, nullptr), +#else + std::exchange( fctx_, nullptr), +#endif + & p, + detail::context_ontop< continuation, Fn >).fctx }; + } + + explicit operator bool() const noexcept { + return nullptr != fctx_; + } + + bool operator!() const noexcept { + return nullptr == fctx_; + } + + bool operator<( continuation const& other) const noexcept { + return fctx_ < other.fctx_; + } + + template< typename charT, class traitsT > + friend std::basic_ostream< charT, traitsT > & + operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other) { + if ( nullptr != other.fctx_) { + return os << other.fctx_; + } else { + return os << "{not-a-context}"; + } + } + + void swap( continuation & other) noexcept { + std::swap( fctx_, other.fctx_); + } +}; + +template< + typename Fn, + typename = detail::disable_overload< continuation, Fn > +> +continuation +callcc( Fn && fn) { + return callcc( + std::allocator_arg, fixedsize_stack(), + std::forward< Fn >( fn) ); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) { + using Record = detail::record< continuation, StackAlloc, Fn >; + return continuation{ + detail::create_context1< Record >( + std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume(); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) { + using Record = detail::record< continuation, StackAlloc, Fn >; + return continuation{ + detail::create_context2< Record >( + palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume(); +} + +#if defined(BOOST_USE_SEGMENTED_STACKS) +template< typename Fn > +continuation +callcc( std::allocator_arg_t, segmented_stack, Fn &&); + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, preallocated, segmented_stack, Fn &&); +#endif + +inline +void swap( continuation & l, continuation & r) noexcept { + l.swap( r); +} + +}} + +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_CONTINUATION_H diff --git a/boost/context/continuation_ucontext.hpp b/boost/context/continuation_ucontext.hpp new file mode 100644 index 0000000..1390a72 --- /dev/null +++ b/boost/context/continuation_ucontext.hpp @@ -0,0 +1,526 @@ + +// Copyright Oliver Kowalke 2017. +// 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_CONTEXT_CONTINUATION_H +#define BOOST_CONTEXT_CONTINUATION_H + +#include +#if BOOST_OS_MACOS +#define _XOPEN_SOURCE 600 +#endif + +extern "C" { +#include +} + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) +#include +#endif +#include +#if defined(BOOST_NO_CXX17_STD_INVOKE) +#include +#endif +#include +#include +#include +#if defined(BOOST_USE_SEGMENTED_STACKS) +#include +#endif +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +// tampoline function +// entered if the execution context +// is resumed for the first time +template< typename Record > +static void entry_func( void * data) noexcept { + Record * record = static_cast< Record * >( data); + BOOST_ASSERT( nullptr != record); + // start execution of toplevel context-function + record->run(); +} + +struct BOOST_CONTEXT_DECL activation_record { + ucontext_t uctx{}; + stack_context sctx{}; + bool main_ctx{ true }; + activation_record * from{ nullptr }; + std::function< activation_record*(activation_record*&) > ontop{}; + bool terminated{ false }; + bool force_unwind{ false }; +#if defined(BOOST_USE_ASAN) + void * fake_stack{ nullptr }; + void * stack_bottom{ nullptr }; + std::size_t stack_size{ 0 }; +#endif + + static activation_record *& current() noexcept; + + // used for toplevel-context + // (e.g. main context, thread-entry context) + activation_record() { + if ( BOOST_UNLIKELY( 0 != ::getcontext( & uctx) ) ) { + throw std::system_error( + std::error_code( errno, std::system_category() ), + "getcontext() failed"); + } + } + + activation_record( stack_context sctx_) noexcept : + sctx( sctx_ ), + main_ctx( false ) { + } + + virtual ~activation_record() { + } + + activation_record( activation_record const&) = delete; + activation_record & operator=( activation_record const&) = delete; + + bool is_main_context() const noexcept { + return main_ctx; + } + + activation_record * resume() { + from = current(); + // store `this` in static, thread local pointer + // `this` will become the active (running) context + current() = this; +#if defined(BOOST_USE_SEGMENTED_STACKS) + // adjust segmented stack properties + __splitstack_getcontext( from->sctx.segments_ctx); + __splitstack_setcontext( sctx.segments_ctx); +#endif +#if defined(BOOST_USE_ASAN) + if ( terminated) { + __sanitizer_start_switch_fiber( nullptr, stack_bottom, stack_size); + } else { + __sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size); + } +#endif + // context switch from parent context to `this`-context + ::swapcontext( & from->uctx, & uctx); +#if defined(BOOST_USE_ASAN) + __sanitizer_finish_switch_fiber( current()->fake_stack, + (const void **) & current()->from->stack_bottom, + & current()->from->stack_size); +#endif +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( current()->from, nullptr); +#else + return std::exchange( current()->from, nullptr); +#endif + } + + template< typename Ctx, typename Fn > + activation_record * resume_with( Fn && fn) { + from = current(); + // store `this` in static, thread local pointer + // `this` will become the active (running) context + // returned by continuation::current() + current() = this; +#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + current()->ontop = std::bind( + [](typename std::decay< Fn >::type & fn, activation_record *& ptr){ + Ctx c{ ptr }; + c = fn( std::move( c) ); + if ( ! c) { + ptr = nullptr; + } +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( c.ptr_, nullptr); +#else + return std::exchange( c.ptr_, nullptr); +#endif + }, + std::forward< Fn >( fn), + std::placeholders::_1); +#else + current()->ontop = [fn=std::forward(fn)](activation_record *& ptr){ + Ctx c{ ptr }; + c = fn( std::move( c) ); + if ( ! c) { + ptr = nullptr; + } +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( c.ptr_, nullptr); +#else + return std::exchange( c.ptr_, nullptr); +#endif + }; +#endif +#if defined(BOOST_USE_SEGMENTED_STACKS) + // adjust segmented stack properties + __splitstack_getcontext( from->sctx.segments_ctx); + __splitstack_setcontext( sctx.segments_ctx); +#endif +#if defined(BOOST_USE_ASAN) + __sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size); +#endif + // context switch from parent context to `this`-context + ::swapcontext( & from->uctx, & uctx); +#if defined(BOOST_USE_ASAN) + __sanitizer_finish_switch_fiber( current()->fake_stack, + (const void **) & current()->from->stack_bottom, + & current()->from->stack_size); +#endif +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( current()->from, nullptr); +#else + return std::exchange( current()->from, nullptr); +#endif + } + + virtual void deallocate() noexcept { + } +}; + +struct BOOST_CONTEXT_DECL activation_record_initializer { + activation_record_initializer() noexcept; + ~activation_record_initializer(); +}; + +struct forced_unwind { + activation_record * from{ nullptr }; +#ifndef BOOST_ASSERT_IS_VOID + bool caught{ false }; +#endif + + forced_unwind( activation_record * from_) noexcept : + from{ from_ } { + } + +#ifndef BOOST_ASSERT_IS_VOID + ~forced_unwind() { + BOOST_ASSERT( caught); + } +#endif +}; + +template< typename Ctx, typename StackAlloc, typename Fn > +class capture_record : public activation_record { +private: + typename std::decay< StackAlloc >::type salloc_; + typename std::decay< Fn >::type fn_; + + static void destroy( capture_record * p) noexcept { + typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); + stack_context sctx = p->sctx; + // deallocate activation record + p->~capture_record(); + // destroy stack with stack allocator + salloc.deallocate( sctx); + } + +public: + capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept : + activation_record{ sctx }, + salloc_{ std::forward< StackAlloc >( salloc) }, + fn_( std::forward< Fn >( fn) ) { + } + + void deallocate() noexcept override final { + BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) ); + destroy( this); + } + + void run() { +#if defined(BOOST_USE_ASAN) + __sanitizer_finish_switch_fiber( fake_stack, + (const void **) & from->stack_bottom, + & from->stack_size); +#endif + Ctx c{ from }; + try { + // invoke context-function +#if defined(BOOST_NO_CXX17_STD_INVOKE) + c = boost::context::detail::invoke( fn_, std::move( c) ); +#else + c = std::invoke( fn_, std::move( c) ); +#endif + } catch ( forced_unwind const& ex) { + c = Ctx{ ex.from }; +#ifndef BOOST_ASSERT_IS_VOID + const_cast< forced_unwind & >( ex).caught = true; +#endif + } + // this context has finished its task + from = nullptr; + ontop = nullptr; + terminated = true; + force_unwind = false; + c.resume(); + BOOST_ASSERT_MSG( false, "continuation already terminated"); + } +}; + +template< typename Ctx, typename StackAlloc, typename Fn > +static activation_record * create_context1( StackAlloc && salloc, Fn && fn) { + typedef capture_record< Ctx, StackAlloc, Fn > capture_t; + + auto sctx = salloc.allocate(); + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + capture_t * record = new ( storage) capture_t{ + sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + // stack bottom + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); + // create user-context + if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) { + record->~capture_t(); + salloc.deallocate( sctx); + throw std::system_error( + std::error_code( errno, std::system_category() ), + "getcontext() failed"); + } + record->uctx.uc_stack.ss_sp = stack_bottom; + // 64byte gap between control structure and stack top + record->uctx.uc_stack.ss_size = reinterpret_cast< uintptr_t >( storage) - + reinterpret_cast< uintptr_t >( stack_bottom) - static_cast< uintptr_t >( 64); + record->uctx.uc_link = nullptr; + ::makecontext( & record->uctx, ( void (*)() ) & entry_func< capture_t >, 1, record); +#if defined(BOOST_USE_ASAN) + record->stack_bottom = record->uctx.uc_stack.ss_sp; + record->stack_size = record->uctx.uc_stack.ss_size; +#endif + return record; +} + +template< typename Ctx, typename StackAlloc, typename Fn > +static activation_record * create_context2( preallocated palloc, StackAlloc && salloc, Fn && fn) { + typedef capture_record< Ctx, StackAlloc, Fn > capture_t; + + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + capture_t * record = new ( storage) capture_t{ + palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + // stack bottom + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) ); + // create user-context + if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) { + record->~capture_t(); + salloc.deallocate( palloc.sctx); + throw std::system_error( + std::error_code( errno, std::system_category() ), + "getcontext() failed"); + } + record->uctx.uc_stack.ss_sp = stack_bottom; + // 64byte gap between control structure and stack top + record->uctx.uc_stack.ss_size = reinterpret_cast< uintptr_t >( storage) - + reinterpret_cast< uintptr_t >( stack_bottom) - static_cast< uintptr_t >( 64); + record->uctx.uc_link = nullptr; + ::makecontext( & record->uctx, ( void (*)() ) & entry_func< capture_t >, 1, record); +#if defined(BOOST_USE_ASAN) + record->stack_bottom = record->uctx.uc_stack.ss_sp; + record->stack_size = record->uctx.uc_stack.ss_size; +#endif + return record; +} + +} + +class BOOST_CONTEXT_DECL continuation { +private: + friend struct detail::activation_record; + + template< typename Ctx, typename StackAlloc, typename Fn > + friend class detail::capture_record; + + template< typename Ctx, typename StackAlloc, typename Fn > + friend detail::activation_record * detail::create_context1( StackAlloc &&, Fn &&); + + template< typename Ctx, typename StackAlloc, typename Fn > + friend detail::activation_record * detail::create_context2( preallocated, StackAlloc &&, Fn &&); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, StackAlloc &&, Fn &&); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&); + + detail::activation_record * ptr_{ nullptr }; + + continuation( detail::activation_record * ptr) noexcept : + ptr_{ ptr } { + } + +public: + continuation() = default; + + ~continuation() { + if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) { + if ( BOOST_LIKELY( ! ptr_->terminated) ) { + ptr_->force_unwind = true; + ptr_->resume(); + BOOST_ASSERT( ptr_->terminated); + } + ptr_->deallocate(); + } + } + + continuation( continuation const&) = delete; + continuation & operator=( continuation const&) = delete; + + continuation( continuation && other) noexcept { + swap( other); + } + + continuation & operator=( continuation && other) noexcept { + if ( BOOST_LIKELY( this != & other) ) { + continuation tmp = std::move( other); + swap( tmp); + } + return * this; + } + + continuation resume() & { + return std::move( * this).resume(); + } + + continuation resume() && { +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::activation_record * ptr = detail::exchange( ptr_, nullptr)->resume(); +#else + detail::activation_record * ptr = std::exchange( ptr_, nullptr)->resume(); +#endif + if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) { + throw detail::forced_unwind{ ptr}; + } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) { + ptr = detail::activation_record::current()->ontop( ptr); + detail::activation_record::current()->ontop = nullptr; + } + return { ptr }; + } + + template< typename Fn > + continuation resume_with( Fn && fn) & { + return std::move( * this).resume_with( std::forward< Fn >( fn) ); + } + + template< typename Fn > + continuation resume_with( Fn && fn) && { +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::activation_record * ptr = + detail::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) ); +#else + detail::activation_record * ptr = + std::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) ); +#endif + if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) { + throw detail::forced_unwind{ ptr}; + } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) { + ptr = detail::activation_record::current()->ontop( ptr); + detail::activation_record::current()->ontop = nullptr; + } + return { ptr }; + } + + explicit operator bool() const noexcept { + return nullptr != ptr_ && ! ptr_->terminated; + } + + bool operator!() const noexcept { + return nullptr == ptr_ || ptr_->terminated; + } + + bool operator<( continuation const& other) const noexcept { + return ptr_ < other.ptr_; + } + + template< typename charT, class traitsT > + friend std::basic_ostream< charT, traitsT > & + operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other) { + if ( nullptr != other.ptr_) { + return os << other.ptr_; + } else { + return os << "{not-a-context}"; + } + } + + void swap( continuation & other) noexcept { + std::swap( ptr_, other.ptr_); + } +}; + +template< + typename Fn, + typename = detail::disable_overload< continuation, Fn > +> +continuation +callcc( Fn && fn) { + return callcc( + std::allocator_arg, +#if defined(BOOST_USE_SEGMENTED_STACKS) + segmented_stack(), +#else + fixedsize_stack(), +#endif + std::forward< Fn >( fn) ); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) { + return continuation{ + detail::create_context1< continuation >( + std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume(); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) { + return continuation{ + detail::create_context2< continuation >( + palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume(); +} + +inline +void swap( continuation & l, continuation & r) noexcept { + l.swap( r); +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_CONTINUATION_H diff --git a/boost/context/continuation_winfib.hpp b/boost/context/continuation_winfib.hpp new file mode 100644 index 0000000..b75cbec --- /dev/null +++ b/boost/context/continuation_winfib.hpp @@ -0,0 +1,461 @@ + +// Copyright Oliver Kowalke 2017. +// 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_CONTEXT_CONTINUATION_H +#define BOOST_CONTEXT_CONTINUATION_H + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) +#include +#endif +#if defined(BOOST_NO_CXX17_STD_INVOKE) +#include +#endif +#include +#include +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable: 4702) +#endif + +namespace boost { +namespace context { +namespace detail { + +// tampoline function +// entered if the execution context +// is resumed for the first time +template< typename Record > +static VOID WINAPI entry_func( LPVOID data) noexcept { + Record * record = static_cast< Record * >( data); + BOOST_ASSERT( nullptr != record); + // start execution of toplevel context-function + record->run(); +} + +struct BOOST_CONTEXT_DECL activation_record { + LPVOID fiber{ nullptr }; + stack_context sctx{}; + bool main_ctx{ true }; + activation_record * from{ nullptr }; + std::function< activation_record*(activation_record*&) > ontop{}; + bool terminated{ false }; + bool force_unwind{ false }; + + static activation_record *& current() noexcept; + + // used for toplevel-context + // (e.g. main context, thread-entry context) + activation_record() noexcept { +#if ( _WIN32_WINNT > 0x0600) + if ( ::IsThreadAFiber() ) { + fiber = ::GetCurrentFiber(); + } else { + fiber = ::ConvertThreadToFiber( nullptr); + } +#else + fiber = ::ConvertThreadToFiber( nullptr); + if ( BOOST_UNLIKELY( nullptr == fiber) ) { + DWORD err = ::GetLastError(); + BOOST_ASSERT( ERROR_ALREADY_FIBER == err); + fiber = ::GetCurrentFiber(); + BOOST_ASSERT( nullptr != fiber); + BOOST_ASSERT( reinterpret_cast< LPVOID >( 0x1E00) != fiber); + } +#endif + } + + activation_record( stack_context sctx_) noexcept : + sctx{ sctx_ }, + main_ctx{ false } { + } + + virtual ~activation_record() { + if ( BOOST_UNLIKELY( main_ctx) ) { + ::ConvertFiberToThread(); + } else { + ::DeleteFiber( fiber); + } + } + + activation_record( activation_record const&) = delete; + activation_record & operator=( activation_record const&) = delete; + + bool is_main_context() const noexcept { + return main_ctx; + } + + activation_record * resume() { + from = current(); + // store `this` in static, thread local pointer + // `this` will become the active (running) context + current() = this; + // context switch from parent context to `this`-context + // context switch + ::SwitchToFiber( fiber); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return detail::exchange( current()->from, nullptr); +#else + return std::exchange( current()->from, nullptr); +#endif + } + + template< typename Ctx, typename Fn > + activation_record * resume_with( Fn && fn) { + from = current(); + // store `this` in static, thread local pointer + // `this` will become the active (running) context + // returned by continuation::current() + current() = this; +#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + current()->ontop = std::bind( + [](typename std::decay< Fn >::type & fn, activation_record *& ptr){ + Ctx c{ ptr }; + c = fn( std::move( c) ); + if ( ! c) { + ptr = nullptr; + } +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( c.ptr_, nullptr); +#else + return std::exchange( c.ptr_, nullptr); +#endif + }, + std::forward< Fn >( fn), + std::placeholders::_1); +#else + current()->ontop = [fn=std::forward(fn)](activation_record *& ptr){ + Ctx c{ ptr }; + c = fn( std::move( c) ); + if ( ! c) { + ptr = nullptr; + } +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( c.ptr_, nullptr); +#else + return std::exchange( c.ptr_, nullptr); +#endif + }; +#endif + // context switch + ::SwitchToFiber( fiber); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return detail::exchange( current()->from, nullptr); +#else + return std::exchange( current()->from, nullptr); +#endif + } + + virtual void deallocate() noexcept { + } +}; + +struct BOOST_CONTEXT_DECL activation_record_initializer { + activation_record_initializer() noexcept; + ~activation_record_initializer(); +}; + +struct forced_unwind { + activation_record * from{ nullptr }; +#ifndef BOOST_ASSERT_IS_VOID + bool caught{ false }; +#endif + + explicit forced_unwind( activation_record * from_) : + from{ from_ } { + } + +#ifndef BOOST_ASSERT_IS_VOID + ~forced_unwind() { + BOOST_ASSERT( caught); + } +#endif +}; + +template< typename Ctx, typename StackAlloc, typename Fn > +class capture_record : public activation_record { +private: + typename std::decay< StackAlloc >::type salloc_; + typename std::decay< Fn >::type fn_; + + static void destroy( capture_record * p) noexcept { + typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); + stack_context sctx = p->sctx; + // deallocate activation record + p->~capture_record(); + // destroy stack with stack allocator + salloc.deallocate( sctx); + } + +public: + capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept : + activation_record( sctx), + salloc_( std::forward< StackAlloc >( salloc)), + fn_( std::forward< Fn >( fn) ) { + } + + void deallocate() noexcept override final { + BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) ); + destroy( this); + } + + void run() { + Ctx c{ from }; + try { + // invoke context-function +#if defined(BOOST_NO_CXX17_STD_INVOKE) + c = boost::context::detail::invoke( fn_, std::move( c) ); +#else + c = std::invoke( fn_, std::move( c) ); +#endif + } catch ( forced_unwind const& ex) { + c = Ctx{ ex.from }; +#ifndef BOOST_ASSERT_IS_VOID + const_cast< forced_unwind & >( ex).caught = true; +#endif + } + // this context has finished its task + from = nullptr; + ontop = nullptr; + terminated = true; + force_unwind = false; + c.resume(); + BOOST_ASSERT_MSG( false, "continuation already terminated"); + } +}; + +template< typename Ctx, typename StackAlloc, typename Fn > +static activation_record * create_context1( StackAlloc && salloc, Fn && fn) { + typedef capture_record< Ctx, StackAlloc, Fn > capture_t; + + auto sctx = salloc.allocate(); + BOOST_ASSERT( ( sizeof( capture_t) ) < sctx.size); + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + capture_t * record = new ( storage) capture_t{ + sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + // create user-context + record->fiber = ::CreateFiber( sctx.size, & detail::entry_func< capture_t >, record); + return record; +} + +template< typename Ctx, typename StackAlloc, typename Fn > +static activation_record * create_context2( preallocated palloc, StackAlloc && salloc, Fn && fn) { + typedef capture_record< Ctx, StackAlloc, Fn > capture_t; + + BOOST_ASSERT( ( sizeof( capture_t) ) < palloc.size); + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + capture_t * record = new ( storage) capture_t{ + palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + // create user-context + record->fiber = ::CreateFiber( palloc.sctx.size, & detail::entry_func< capture_t >, record); + return record; +} + +} + +class BOOST_CONTEXT_DECL continuation { +private: + friend struct detail::activation_record; + + template< typename Ctx, typename StackAlloc, typename Fn > + friend class detail::capture_record; + + template< typename Ctx, typename StackAlloc, typename Fn > + friend detail::activation_record * detail::create_context1( StackAlloc &&, Fn &&); + + template< typename Ctx, typename StackAlloc, typename Fn > + friend detail::activation_record * detail::create_context2( preallocated, StackAlloc &&, Fn &&); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, StackAlloc &&, Fn &&); + + template< typename StackAlloc, typename Fn > + friend continuation + callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&); + + detail::activation_record * ptr_{ nullptr }; + + continuation( detail::activation_record * ptr) noexcept : + ptr_{ ptr } { + } + +public: + continuation() = default; + + ~continuation() { + if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) { + if ( BOOST_LIKELY( ! ptr_->terminated) ) { + ptr_->force_unwind = true; + ptr_->resume(); + BOOST_ASSERT( ptr_->terminated); + } + ptr_->deallocate(); + } + } + + continuation( continuation const&) = delete; + continuation & operator=( continuation const&) = delete; + + continuation( continuation && other) noexcept { + swap( other); + } + + continuation & operator=( continuation && other) noexcept { + if ( BOOST_LIKELY( this != & other) ) { + continuation tmp = std::move( other); + swap( tmp); + } + return * this; + } + + continuation resume() & { + return std::move( * this).resume(); + } + + continuation resume() && { +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::activation_record * ptr = detail::exchange( ptr_, nullptr)->resume(); +#else + detail::activation_record * ptr = std::exchange( ptr_, nullptr)->resume(); +#endif + if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) { + throw detail::forced_unwind{ ptr}; + } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) { + ptr = detail::activation_record::current()->ontop( ptr); + detail::activation_record::current()->ontop = nullptr; + } + return { ptr }; + } + + template< typename Fn > + continuation resume_with( Fn && fn) & { + return std::move( * this).resume_with( std::forward< Fn >( fn) ); + } + + template< typename Fn > + continuation resume_with( Fn && fn) && { +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::activation_record * ptr = + detail::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) ); +#else + detail::activation_record * ptr = + std::exchange( ptr_, nullptr)->resume_with< continuation >( std::forward< Fn >( fn) ); +#endif + if ( BOOST_UNLIKELY( detail::activation_record::current()->force_unwind) ) { + throw detail::forced_unwind{ ptr}; + } else if ( BOOST_UNLIKELY( nullptr != detail::activation_record::current()->ontop) ) { + ptr = detail::activation_record::current()->ontop( ptr); + detail::activation_record::current()->ontop = nullptr; + } + return { ptr }; + } + + explicit operator bool() const noexcept { + return nullptr != ptr_ && ! ptr_->terminated; + } + + bool operator!() const noexcept { + return nullptr == ptr_ || ptr_->terminated; + } + + bool operator<( continuation const& other) const noexcept { + return ptr_ < other.ptr_; + } + + template< typename charT, class traitsT > + friend std::basic_ostream< charT, traitsT > & + operator<<( std::basic_ostream< charT, traitsT > & os, continuation const& other) { + if ( nullptr != other.ptr_) { + return os << other.ptr_; + } else { + return os << "{not-a-context}"; + } + } + + void swap( continuation & other) noexcept { + std::swap( ptr_, other.ptr_); + } +}; + +template< + typename Fn, + typename = detail::disable_overload< continuation, Fn > +> +continuation +callcc( Fn && fn) { + return callcc( + std::allocator_arg, + fixedsize_stack(), + std::forward< Fn >( fn) ); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) { + return continuation{ + detail::create_context1< continuation >( + std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume(); +} + +template< typename StackAlloc, typename Fn > +continuation +callcc( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) { + return continuation{ + detail::create_context2< continuation >( + palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) }.resume(); +} + +inline +void swap( continuation & l, continuation & r) noexcept { + l.swap( r); +} + +}} + +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_CONTINUATION_H diff --git a/boost/context/detail/apply.hpp b/boost/context/detail/apply.hpp new file mode 100644 index 0000000..fbf0ca6 --- /dev/null +++ b/boost/context/detail/apply.hpp @@ -0,0 +1,74 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_DETAIL_APPLY_H +#define BOOST_CONTEXT_DETAIL_APPLY_H + +#include +#include +#include +#include + +#include + +#include +#if defined(BOOST_NO_CXX17_STD_INVOKE) +#include +#endif +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable: 4100) +#endif + +namespace boost { +namespace context { +namespace detail { + +template< typename Fn, typename Tpl, std::size_t ... I > +auto +apply_impl( Fn && fn, Tpl && tpl, index_sequence< I ... >) +#if defined(BOOST_NO_CXX17_STD_INVOKE) + -> decltype( boost::context::detail::invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... ) ) +#else + -> decltype( std::invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... ) ) +#endif +{ +#if defined(BOOST_NO_CXX17_STD_INVOKE) + return boost::context::detail::invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... ); +#else + return std::invoke( std::forward< Fn >( fn), std::get< I >( std::forward< Tpl >( tpl) ) ... ); +#endif +} + +template< typename Fn, typename Tpl > +auto +apply( Fn && fn, Tpl && tpl) + -> decltype( apply_impl( std::forward< Fn >( fn), + std::forward< Tpl >( tpl), + make_index_sequence< std::tuple_size< typename std::decay< Tpl >::type >::value >{}) ) +{ + return apply_impl( std::forward< Fn >( fn), + std::forward< Tpl >( tpl), + make_index_sequence< std::tuple_size< typename std::decay< Tpl >::type >::value >{}); +} + +}}} + +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_APPLY_H diff --git a/boost/context/detail/config.hpp b/boost/context/detail/config.hpp new file mode 100644 index 0000000..dbce9a0 --- /dev/null +++ b/boost/context/detail/config.hpp @@ -0,0 +1,132 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_DETAIL_CONFIG_H +#define BOOST_CONTEXT_DETAIL_CONFIG_H + +// required for SD-6 compile-time integer sequences +#include + +#include +#include + +#ifdef BOOST_CONTEXT_DECL +# undef BOOST_CONTEXT_DECL +#endif + +#if (defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTEXT_DYN_LINK) ) && ! defined(BOOST_CONTEXT_STATIC_LINK) +# if defined(BOOST_CONTEXT_SOURCE) +# define BOOST_CONTEXT_DECL BOOST_SYMBOL_EXPORT +# define BOOST_CONTEXT_BUILD_DLL +# else +# define BOOST_CONTEXT_DECL BOOST_SYMBOL_IMPORT +# endif +#endif + +#if ! defined(BOOST_CONTEXT_DECL) +# define BOOST_CONTEXT_DECL +#endif + +#if ! defined(BOOST_CONTEXT_SOURCE) && ! defined(BOOST_ALL_NO_LIB) && ! defined(BOOST_CONTEXT_NO_LIB) +# define BOOST_LIB_NAME boost_context +# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTEXT_DYN_LINK) +# define BOOST_DYN_LINK +# endif +# include +#endif + +#undef BOOST_CONTEXT_CALLDECL +#if (defined(i386) || defined(__i386__) || defined(__i386) \ + || defined(__i486__) || defined(__i586__) || defined(__i686__) \ + || defined(__X86__) || defined(_X86_) || defined(__THW_INTEL__) \ + || defined(__I86__) || defined(__INTEL__) || defined(__IA32__) \ + || defined(_M_IX86) || defined(_I86_)) && defined(BOOST_WINDOWS) +# define BOOST_CONTEXT_CALLDECL __cdecl +#else +# define BOOST_CONTEXT_CALLDECL +#endif + +#if defined(BOOST_USE_SEGMENTED_STACKS) +# if ! ( (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) ) ) || \ + (defined(__clang__) && (__clang_major__ > 2 || ( __clang_major__ == 2 && __clang_minor__ > 3) ) ) ) +# error "compiler does not support segmented_stack stacks" +# endif +# define BOOST_CONTEXT_SEGMENTS 10 +#endif + + +#define BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE +// use rd6 macros for std::integer_sequence +#if defined(__cpp_lib_integer_sequence) && __cpp_lib_integer_sequence >= 201304 +# undef BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE +#endif +// workaroud: MSVC 14 does not provide macros to test for compile-time integer sequence +#if _MSC_VER > 1800 // _MSC_VER == 1800 -> MS Visual Studio 2013 +# undef BOOST_CONTEXT_NO_INDEX_SEQUENCE +#endif +// workaround: Xcode clang feature detection +#if ! defined(__cpp_lib_integer_sequence) && __cpp_lib_integer_sequence >= 201304 +# if _LIBCPP_STD_VER > 11 +# undef BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE +# endif +#endif + +// workaroud: MSVC 14 does support constexpr +#if _MSC_VER > 1800 // _MSC_VER == 1800 -> MS Visual Studio 2013 +# undef BOOST_NO_CXX11_CONSTEXPR +#endif + +#undef BOOST_CONTEXT_NO_CXX11 +#if defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) || \ + defined(BOOST_NO_CXX11_CONSTEXPR) || \ + defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || \ + defined(BOOST_NO_CXX11_FINAL) || \ + defined(BOOST_NO_CXX11_HDR_TUPLE) || \ + defined(BOOST_NO_CXX11_NOEXCEPT) || \ + defined(BOOST_NO_CXX11_NULLPTR) || \ + defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || \ + defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) || \ + defined(BOOST_NO_CXX11_UNIFIED_INITIALISATION_SYNTAX) || \ + defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || \ + defined(BOOST_NO_HDR_ATOMIC) || \ + defined(BOOST_NO_HDR_TUPLE) +# define BOOST_CONTEXT_NO_CXX11 +#endif + +#if ! defined(BOOST_EXECUTION_CONTEXT) +# if defined(BOOST_USE_SEGMENTED_STACKS) +# define BOOST_EXECUTION_CONTEXT 1 +# else +# define BOOST_EXECUTION_CONTEXT 2 +# endif +#endif + +#if ! defined(BOOST_NO_CXX11_CONSTEXPR) +// modern architectures have cachelines with 64byte length +// ARM Cortex-A15 32/64byte, Cortex-A9 16/32/64bytes +// MIPS 74K: 32byte, 4KEc: 16byte +// ist should be safe to use 64byte for all +static constexpr std::size_t cache_alignment{ 64 }; +static constexpr std::size_t cacheline_length{ 64 }; +// lookahead size for prefetching +static constexpr std::size_t prefetch_stride{ 4 * cacheline_length }; +#endif + +#if defined(__GLIBCPP__) || defined(__GLIBCXX__) +// GNU libstdc++ 3 +# define BOOST_CONTEXT_HAS_CXXABI_H +#endif + +#if defined( BOOST_CONTEXT_HAS_CXXABI_H ) +# include +#endif + +#if defined(__OpenBSD__) +// stacks need mmap(2) with MAP_STACK +# define BOOST_CONTEXT_USE_MAP_STACK +#endif + +#endif // BOOST_CONTEXT_DETAIL_CONFIG_H diff --git a/boost/context/detail/disable_overload.hpp b/boost/context/detail/disable_overload.hpp new file mode 100644 index 0000000..c88f916 --- /dev/null +++ b/boost/context/detail/disable_overload.hpp @@ -0,0 +1,40 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_DETAIL_DISABLE_OVERLOAD_H +#define BOOST_CONTEXT_DETAIL_DISABLE_OVERLOAD_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +// http://ericniebler.com/2013/08/07/universal-references-and-the-copy-constructo/ +template< typename X, typename Y > +using disable_overload = + typename std::enable_if< + ! std::is_base_of< + X, + typename std::decay< Y >::type + >::value + >::type; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_DISABLE_OVERLOAD_H diff --git a/boost/context/detail/exception.hpp b/boost/context/detail/exception.hpp new file mode 100644 index 0000000..87abaf1 --- /dev/null +++ b/boost/context/detail/exception.hpp @@ -0,0 +1,48 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_DETAIL_EXCEPTION_H +#define BOOST_CONTEXT_DETAIL_EXCEPTION_H + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +struct forced_unwind { + fcontext_t fctx{ nullptr }; +#ifndef BOOST_ASSERT_IS_VOID + bool caught{ false }; +#endif + + forced_unwind() = default; + + forced_unwind( fcontext_t fctx_) : + fctx( fctx_) { + } + +#ifndef BOOST_ASSERT_IS_VOID + ~forced_unwind() { + BOOST_ASSERT( caught); + } +#endif +}; + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_EXCEPTION_H diff --git a/boost/context/detail/exchange.hpp b/boost/context/detail/exchange.hpp new file mode 100644 index 0000000..c5ee912 --- /dev/null +++ b/boost/context/detail/exchange.hpp @@ -0,0 +1,36 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_DETAIL_EXCHANGE_H +#define BOOST_CONTEXT_DETAIL_EXCHANGE_H + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +template< typename T, typename U = T > +T exchange( T & t, U && nv) { + T ov = std::move( t); + t = std::forward< U >( nv); + return ov; +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_EXCHANGE_H diff --git a/boost/context/detail/externc.hpp b/boost/context/detail/externc.hpp new file mode 100644 index 0000000..850bc1a --- /dev/null +++ b/boost/context/detail/externc.hpp @@ -0,0 +1,23 @@ + +// Copyright Oliver Kowalke 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +#if defined(BOOST_USE_ASAN) +extern "C" { +void __sanitizer_start_switch_fiber( void **, const void *, size_t); +void __sanitizer_finish_switch_fiber( void *, const void **, size_t *); +} +#endif + +#if defined(BOOST_USE_SEGMENTED_STACKS) +extern "C" { +void __splitstack_getcontext( void * [BOOST_CONTEXT_SEGMENTS]); +void __splitstack_setcontext( void * [BOOST_CONTEXT_SEGMENTS]); +} +#endif diff --git a/boost/context/detail/fcontext.hpp b/boost/context/detail/fcontext.hpp new file mode 100644 index 0000000..00cb24d --- /dev/null +++ b/boost/context/detail/fcontext.hpp @@ -0,0 +1,46 @@ + +// Copyright Oliver Kowalke 2009. +// 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_CONTEXT_DETAIL_FCONTEXT_H +#define BOOST_CONTEXT_DETAIL_FCONTEXT_H + +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +typedef void* fcontext_t; + +struct transfer_t { + fcontext_t fctx; + void * data; +}; + +extern "C" BOOST_CONTEXT_DECL +transfer_t BOOST_CONTEXT_CALLDECL jump_fcontext( fcontext_t const to, void * vp); +extern "C" BOOST_CONTEXT_DECL +fcontext_t BOOST_CONTEXT_CALLDECL make_fcontext( void * sp, std::size_t size, void (* fn)( transfer_t) ); + +// based on an idea of Giovanni Derreta +extern "C" BOOST_CONTEXT_DECL +transfer_t BOOST_CONTEXT_CALLDECL ontop_fcontext( fcontext_t const to, void * vp, transfer_t (* fn)( transfer_t) ); + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_FCONTEXT_H + diff --git a/boost/context/detail/index_sequence.hpp b/boost/context/detail/index_sequence.hpp new file mode 100644 index 0000000..2d484ba --- /dev/null +++ b/boost/context/detail/index_sequence.hpp @@ -0,0 +1,72 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_DETAIL_INDEX_SEQUENCE_H +#define BOOST_CONTEXT_DETAIL_INDEX_SEQUENCE_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +#if ! defined(BOOST_CONTEXT_NO_CXX14_INTEGER_SEQUENCE) +template< std::size_t ... I > +using index_sequence = std::index_sequence< I ... >; +template< std::size_t I > +using make_index_sequence = std::make_index_sequence< I >; +template< typename ... T > +using index_sequence_for = std::index_sequence_for< T ... >; +#else +//http://stackoverflow.com/questions/17424477/implementation-c14-make-integer-sequence + +template< std::size_t ... I > +struct index_sequence { + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() { + return sizeof ... (I); + } +}; + +template< typename Seq1, typename Seq2 > +struct concat_sequence; + +template< std::size_t ... I1, std::size_t ... I2 > +struct concat_sequence< index_sequence< I1 ... >, index_sequence< I2 ... > > : public index_sequence< I1 ..., (sizeof ... (I1)+I2) ... > { +}; + +template< std::size_t I > +struct make_index_sequence : public concat_sequence< typename make_index_sequence< I/2 >::type, + typename make_index_sequence< I-I/2 >::type > { +}; + +template<> +struct make_index_sequence< 0 > : public index_sequence<> { +}; +template<> +struct make_index_sequence< 1 > : public index_sequence< 0 > { +}; + +template< typename ... T > +using index_sequence_for = make_index_sequence< sizeof ... (T) >; +#endif + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_INDEX_SEQUENCE_H diff --git a/boost/context/detail/invoke.hpp b/boost/context/detail/invoke.hpp new file mode 100644 index 0000000..9173cbc --- /dev/null +++ b/boost/context/detail/invoke.hpp @@ -0,0 +1,50 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_DETAIL_INVOKE_H +#define BOOST_CONTEXT_DETAIL_INVOKE_H + +#include +#include +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +template< typename Fn, typename ... Args > +typename std::enable_if< + std::is_member_pointer< typename std::decay< Fn >::type >::value, + typename std::result_of< Fn &&( Args && ... ) >::type +>::type +invoke( Fn && fn, Args && ... args) { + return std::mem_fn( fn)( std::forward< Args >( args) ... ); +} + +template< typename Fn, typename ... Args > +typename std::enable_if< + ! std::is_member_pointer< typename std::decay< Fn >::type >::value, + typename std::result_of< Fn &&( Args && ... ) >::type +>::type +invoke( Fn && fn, Args && ... args) { + return std::forward< Fn >( fn)( std::forward< Args >( args) ... ); +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_INVOKE_H diff --git a/boost/context/detail/prefetch.hpp b/boost/context/detail/prefetch.hpp new file mode 100644 index 0000000..27f2fdb --- /dev/null +++ b/boost/context/detail/prefetch.hpp @@ -0,0 +1,78 @@ +// Copyright Oliver Kowalke 2017. +// 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_CONTEXT_DETAIL_PREFETCH_H +#define BOOST_CONTEXT_DETAIL_PREFETCH_H + +#include +#include + +#include +#include + +#include + +#if BOOST_COMP_INTEL || BOOST_COMP_INTEL_EMULATED +#include +#endif + +#if BOOST_COMP_MSVC && !defined(_M_ARM) && !defined(_M_ARM64) +#include +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +#if BOOST_COMP_GNUC || BOOST_COMP_CLANG +#define BOOST_HAS_PREFETCH 1 +BOOST_FORCEINLINE +void prefetch( void * addr) { + // L1 cache : hint == 1 + __builtin_prefetch( addr, 1, 1); +} +#elif BOOST_COMP_INTEL || BOOST_COMP_INTEL_EMULATED +#define BOOST_HAS_PREFETCH 1 +BOOST_FORCEINLINE +void prefetch( void * addr) { + // L1 cache : hint == _MM_HINT_T0 + _mm_prefetch( (const char *)addr, _MM_HINT_T0); +} +#elif BOOST_COMP_MSVC && !defined(_M_ARM) && !defined(_M_ARM64) +#define BOOST_HAS_PREFETCH 1 +BOOST_FORCEINLINE +void prefetch( void * addr) { + // L1 cache : hint == _MM_HINT_T0 + _mm_prefetch( (const char *)addr, _MM_HINT_T0); +} +#endif + +inline +void prefetch_range( void * addr, std::size_t len) { +#if defined(BOOST_HAS_PREFETCH) + void * vp = addr; + void * end = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( addr) + static_cast< uintptr_t >( len) ); + while ( vp < end) { + prefetch( vp); + vp = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( vp) + static_cast< uintptr_t >( prefetch_stride) ); + } +#endif +} + +#undef BOOST_HAS_PREFETCH + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_PREFETCH_H diff --git a/boost/context/detail/tuple.hpp b/boost/context/detail/tuple.hpp new file mode 100644 index 0000000..e1b2f86 --- /dev/null +++ b/boost/context/detail/tuple.hpp @@ -0,0 +1,129 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_DETAIL_TUPLE_H +#define BOOST_CONTEXT_DETAIL_TUPLE_H + +#include +#include + +#include + +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +template< typename ... S, typename ... T, std::size_t ... I > +void +head_impl( std::tuple< S ... > & s, + std::tuple< T ... > & t, index_sequence< I ... >) { + t = std::tuple< T ... >{ std::get< I >( s) ... }; +} + +template< typename ... S, typename ... T, std::size_t ... I > +void +head_impl( std::tuple< S ... > && s, + std::tuple< T ... > & t, index_sequence< I ... >) { + t = std::tuple< T ... >{ std::get< I >( std::move( s) ) ... }; +} + +template< typename ... S, std::size_t ... I1, typename ... T, std::size_t ... I2 > +void +tail_impl( std::tuple< S ... > & s, index_sequence< I1 ... >, + std::tuple< T ... > & t, index_sequence< I2 ... >) { + constexpr std::size_t Idx = (sizeof...(I1)) - (sizeof...(I2)); + t = std::tuple< T ... >{ std::get< (Idx + I2) >( s) ... }; +} + +template< typename ... S, std::size_t ... I1, typename ... T, std::size_t ... I2 > +void +tail_impl( std::tuple< S ... > && s, index_sequence< I1 ... >, + std::tuple< T ... > & t, index_sequence< I2 ... >) { + constexpr std::size_t Idx = (sizeof...(I1)) - (sizeof...(I2)); + t = std::tuple< T ... >{ std::get< (Idx + I2) >( std::move( s) ) ... }; +} + +template< typename ... T > +class tuple_head; + +template< typename ... T > +class tuple_head< std::tuple< T ... > > { +private: + std::tuple< T ... > & t_; + +public: + tuple_head( std::tuple< T ... > & t) noexcept : + t_( t) { + } + + template< typename ... S > + void operator=( std::tuple< S ... > & s) { + static_assert((sizeof...(T)) <= (sizeof...(S)), "invalid tuple size"); + head_impl( s, + t_, index_sequence_for< T ... >{} ); + } + template< typename ... S > + void operator=( std::tuple< S ... > && s) { + static_assert((sizeof...(T)) <= (sizeof...(S)), "invalid tuple size"); + head_impl( std::move( s), + t_, index_sequence_for< T ... >{} ); + } +}; + +template< typename ... T > +class tuple_tail; + +template< typename ... T > +class tuple_tail< std::tuple< T ... > > { +private: + std::tuple< T ... > & t_; + +public: + tuple_tail( std::tuple< T ... > & t) noexcept : + t_( t) { + } + + template< typename ... S > + void operator=( std::tuple< S ... > & s) { + static_assert((sizeof...(T)) <= (sizeof...(S)), "invalid tuple size"); + tail_impl( s, index_sequence_for< S ... >{}, + t_, index_sequence_for< T ... >{} ); + } + + template< typename ... S > + void operator=( std::tuple< S ... > && s) { + static_assert((sizeof...(T)) <= (sizeof...(S)), "invalid tuple size"); + tail_impl( std::move( s), index_sequence_for< S ... >{}, + t_, index_sequence_for< T ... >{} ); + } +}; + +template< typename ... T > +detail::tuple_head< std::tuple< T ... > > +head( std::tuple< T ... > & tpl) { + return tuple_head< std::tuple< T ... > >{ tpl }; +} + +template< typename ... T > +detail::tuple_tail< std::tuple< T ... > > +tail( std::tuple< T ... > & tpl) { + return tuple_tail< std::tuple< T ... > >{ tpl }; +} + +}}} + +#ifdef BOOST_HAS_ABI_HEADERS +#include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_DETAIL_TUPLE_H diff --git a/boost/context/fiber.hpp b/boost/context/fiber.hpp new file mode 100644 index 0000000..ff1b79e --- /dev/null +++ b/boost/context/fiber.hpp @@ -0,0 +1,13 @@ + +// Copyright Oliver Kowalke 2017. +// 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) + +#if defined(BOOST_USE_UCONTEXT) +#include +#elif defined(BOOST_USE_WINFIB) +#include +#else +#include +#endif diff --git a/boost/context/fiber_fcontext.hpp b/boost/context/fiber_fcontext.hpp new file mode 100644 index 0000000..2503b82 --- /dev/null +++ b/boost/context/fiber_fcontext.hpp @@ -0,0 +1,349 @@ + +// Copyright Oliver Kowalke 2017. +// 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_CONTEXT_FIBER_H +#define BOOST_CONTEXT_FIBER_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) +#include +#endif +#if defined(BOOST_NO_CXX17_STD_INVOKE) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable: 4702) +#endif + +namespace boost { +namespace context { +namespace detail { + +inline +transfer_t fiber_unwind( transfer_t t) { + throw forced_unwind( t.fctx); + return { nullptr, nullptr }; +} + +template< typename Rec > +transfer_t fiber_exit( transfer_t t) noexcept { + Rec * rec = static_cast< Rec * >( t.data); + // destroy context stack + rec->deallocate(); + return { nullptr, nullptr }; +} + +template< typename Rec > +void fiber_entry( transfer_t t) noexcept { + // transfer control structure to the context-stack + Rec * rec = static_cast< Rec * >( t.data); + BOOST_ASSERT( nullptr != t.fctx); + BOOST_ASSERT( nullptr != rec); + try { + // jump back to `create_context()` + t = jump_fcontext( t.fctx, nullptr); + // start executing + t.fctx = rec->run( t.fctx); + } catch ( forced_unwind const& ex) { + t = { ex.fctx, nullptr }; +#ifndef BOOST_ASSERT_IS_VOID + const_cast< forced_unwind & >( ex).caught = true; +#endif + } + BOOST_ASSERT( nullptr != t.fctx); + // destroy context-stack of `this`context on next context + ontop_fcontext( t.fctx, rec, fiber_exit< Rec >); + BOOST_ASSERT_MSG( false, "context already terminated"); +} + +template< typename Ctx, typename Fn > +transfer_t fiber_ontop( transfer_t t) { + BOOST_ASSERT( nullptr != t.data); + auto p = *static_cast< Fn * >( t.data); + t.data = nullptr; + // execute function, pass fiber via reference + Ctx c = p( Ctx{ t.fctx } ); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return { exchange( c.fctx_, nullptr), nullptr }; +#else + return { std::exchange( c.fctx_, nullptr), nullptr }; +#endif +} + +template< typename Ctx, typename StackAlloc, typename Fn > +class fiber_record { +private: + stack_context sctx_; + typename std::decay< StackAlloc >::type salloc_; + typename std::decay< Fn >::type fn_; + + static void destroy( fiber_record * p) noexcept { + typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); + stack_context sctx = p->sctx_; + // deallocate fiber_record + p->~fiber_record(); + // destroy stack with stack allocator + salloc.deallocate( sctx); + } + +public: + fiber_record( stack_context sctx, StackAlloc && salloc, + Fn && fn) noexcept : + sctx_( sctx), + salloc_( std::forward< StackAlloc >( salloc)), + fn_( std::forward< Fn >( fn) ) { + } + + fiber_record( fiber_record const&) = delete; + fiber_record & operator=( fiber_record const&) = delete; + + void deallocate() noexcept { + destroy( this); + } + + fcontext_t run( fcontext_t fctx) { + // invoke context-function +#if defined(BOOST_NO_CXX17_STD_INVOKE) + Ctx c = boost::context::detail::invoke( fn_, Ctx{ fctx } ); +#else + Ctx c = std::invoke( fn_, Ctx{ fctx } ); +#endif +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( c.fctx_, nullptr); +#else + return std::exchange( c.fctx_, nullptr); +#endif + } +}; + +template< typename Record, typename StackAlloc, typename Fn > +fcontext_t create_fiber1( StackAlloc && salloc, Fn && fn) { + auto sctx = salloc.allocate(); + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( Record) ) ) + & ~static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + Record * record = new ( storage) Record{ + sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + // 64byte gab between control structure and stack top + // should be 16byte aligned + void * stack_top = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) ); + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); + // create fast-context + const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom); + const fcontext_t fctx = make_fcontext( stack_top, size, & fiber_entry< Record >); + BOOST_ASSERT( nullptr != fctx); + // transfer control structure to context-stack + return jump_fcontext( fctx, record).fctx; +} + +template< typename Record, typename StackAlloc, typename Fn > +fcontext_t create_fiber2( preallocated palloc, StackAlloc && salloc, Fn && fn) { + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( Record) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context-stack + Record * record = new ( storage) Record{ + palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + // 64byte gab between control structure and stack top + void * stack_top = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( storage) - static_cast< uintptr_t >( 64) ); + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) ); + // create fast-context + const std::size_t size = reinterpret_cast< uintptr_t >( stack_top) - reinterpret_cast< uintptr_t >( stack_bottom); + const fcontext_t fctx = make_fcontext( stack_top, size, & fiber_entry< Record >); + BOOST_ASSERT( nullptr != fctx); + // transfer control structure to context-stack + return jump_fcontext( fctx, record).fctx; +} + +} + +class fiber { +private: + template< typename Ctx, typename StackAlloc, typename Fn > + friend class detail::fiber_record; + + template< typename Ctx, typename Fn > + friend detail::transfer_t + detail::fiber_ontop( detail::transfer_t); + + template< typename StackAlloc, typename Fn > + friend fiber + callcc( std::allocator_arg_t, StackAlloc &&, Fn &&); + + template< typename StackAlloc, typename Fn > + friend fiber + callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&); + + detail::fcontext_t fctx_{ nullptr }; + + fiber( detail::fcontext_t fctx) noexcept : + fctx_{ fctx } { + } + +public: + fiber() noexcept = default; + + template< typename Fn, typename = detail::disable_overload< fiber, Fn > > + fiber( Fn && fn) : + fiber{ std::allocator_arg, fixedsize_stack(), std::forward< Fn >( fn) } { + } + + template< typename StackAlloc, typename Fn > + fiber( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) : + fctx_{ detail::create_fiber1< detail::fiber_record< fiber, StackAlloc, Fn > >( + std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } { + } + + template< typename StackAlloc, typename Fn > + fiber( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) : + fctx_{ detail::create_fiber2< detail::fiber_record< fiber, StackAlloc, Fn > >( + palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } { + } + +#if defined(BOOST_USE_SEGMENTED_STACKS) + template< typename Fn > + fiber( std::allocator_arg_t, segmented_stack, Fn &&); + + template< typename StackAlloc, typename Fn > + fiber( std::allocator_arg_t, preallocated, segmented_stack, Fn &&); +#endif + + ~fiber() { + if ( BOOST_UNLIKELY( nullptr != fctx_) ) { + detail::ontop_fcontext( +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::exchange( fctx_, nullptr), +#else + std::exchange( fctx_, nullptr), +#endif + nullptr, + detail::fiber_unwind); + } + } + + fiber( fiber && other) noexcept { + swap( other); + } + + fiber & operator=( fiber && other) noexcept { + if ( BOOST_LIKELY( this != & other) ) { + fiber tmp = std::move( other); + swap( tmp); + } + return * this; + } + + fiber( fiber const& other) noexcept = delete; + fiber & operator=( fiber const& other) noexcept = delete; + + fiber resume() && { + BOOST_ASSERT( nullptr != fctx_); + return { detail::jump_fcontext( +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::exchange( fctx_, nullptr), +#else + std::exchange( fctx_, nullptr), +#endif + nullptr).fctx }; + } + + template< typename Fn > + fiber resume_with( Fn && fn) && { + BOOST_ASSERT( nullptr != fctx_); + auto p = std::forward< Fn >( fn); + return { detail::ontop_fcontext( +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::exchange( fctx_, nullptr), +#else + std::exchange( fctx_, nullptr), +#endif + & p, + detail::fiber_ontop< fiber, decltype(p) >).fctx }; + } + + explicit operator bool() const noexcept { + return nullptr != fctx_; + } + + bool operator!() const noexcept { + return nullptr == fctx_; + } + + bool operator<( fiber const& other) const noexcept { + return fctx_ < other.fctx_; + } + + template< typename charT, class traitsT > + friend std::basic_ostream< charT, traitsT > & + operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) { + if ( nullptr != other.fctx_) { + return os << other.fctx_; + } else { + return os << "{not-a-context}"; + } + } + + void swap( fiber & other) noexcept { + std::swap( fctx_, other.fctx_); + } +}; + +inline +void swap( fiber & l, fiber & r) noexcept { + l.swap( r); +} + +typedef fiber fiber_context; + +}} + +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_FIBER_H diff --git a/boost/context/fiber_ucontext.hpp b/boost/context/fiber_ucontext.hpp new file mode 100644 index 0000000..e61b4de --- /dev/null +++ b/boost/context/fiber_ucontext.hpp @@ -0,0 +1,513 @@ + +// Copyright Oliver Kowalke 2017. +// 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_CONTEXT_FIBER_H +#define BOOST_CONTEXT_FIBER_H + +#include +#if BOOST_OS_MACOS +#define _XOPEN_SOURCE 600 +#endif + +extern "C" { +#include +} + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) +#include +#endif +#include +#if defined(BOOST_NO_CXX17_STD_INVOKE) +#include +#endif +#include +#include +#include +#if defined(BOOST_USE_SEGMENTED_STACKS) +#include +#endif +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +// tampoline function +// entered if the execution context +// is resumed for the first time +template< typename Record > +static void fiber_entry_func( void * data) noexcept { + Record * record = static_cast< Record * >( data); + BOOST_ASSERT( nullptr != record); + // start execution of toplevel context-function + record->run(); +} + +struct BOOST_CONTEXT_DECL fiber_activation_record { + ucontext_t uctx{}; + stack_context sctx{}; + bool main_ctx{ true }; + fiber_activation_record * from{ nullptr }; + std::function< fiber_activation_record*(fiber_activation_record*&) > ontop{}; + bool terminated{ false }; + bool force_unwind{ false }; +#if defined(BOOST_USE_ASAN) + void * fake_stack{ nullptr }; + void * stack_bottom{ nullptr }; + std::size_t stack_size{ 0 }; +#endif + + static fiber_activation_record *& current() noexcept; + + // used for toplevel-context + // (e.g. main context, thread-entry context) + fiber_activation_record() { + if ( BOOST_UNLIKELY( 0 != ::getcontext( & uctx) ) ) { + throw std::system_error( + std::error_code( errno, std::system_category() ), + "getcontext() failed"); + } + } + + fiber_activation_record( stack_context sctx_) noexcept : + sctx( sctx_ ), + main_ctx( false ) { + } + + virtual ~fiber_activation_record() { + } + + fiber_activation_record( fiber_activation_record const&) = delete; + fiber_activation_record & operator=( fiber_activation_record const&) = delete; + + bool is_main_context() const noexcept { + return main_ctx; + } + + fiber_activation_record * resume() { + from = current(); + // store `this` in static, thread local pointer + // `this` will become the active (running) context + current() = this; +#if defined(BOOST_USE_SEGMENTED_STACKS) + // adjust segmented stack properties + __splitstack_getcontext( from->sctx.segments_ctx); + __splitstack_setcontext( sctx.segments_ctx); +#endif +#if defined(BOOST_USE_ASAN) + if ( terminated) { + __sanitizer_start_switch_fiber( nullptr, stack_bottom, stack_size); + } else { + __sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size); + } +#endif + // context switch from parent context to `this`-context + ::swapcontext( & from->uctx, & uctx); +#if defined(BOOST_USE_ASAN) + __sanitizer_finish_switch_fiber( current()->fake_stack, + (const void **) & current()->from->stack_bottom, + & current()->from->stack_size); +#endif +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( current()->from, nullptr); +#else + return std::exchange( current()->from, nullptr); +#endif + } + + template< typename Ctx, typename Fn > + fiber_activation_record * resume_with( Fn && fn) { + from = current(); + // store `this` in static, thread local pointer + // `this` will become the active (running) context + // returned by fiber::current() + current() = this; +#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + current()->ontop = std::bind( + [](typename std::decay< Fn >::type & fn, fiber_activation_record *& ptr){ + Ctx c{ ptr }; + c = fn( std::move( c) ); + if ( ! c) { + ptr = nullptr; + } +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( c.ptr_, nullptr); +#else + return std::exchange( c.ptr_, nullptr); +#endif + }, + std::forward< Fn >( fn), + std::placeholders::_1); +#else + current()->ontop = [fn=std::forward(fn)](fiber_activation_record *& ptr){ + Ctx c{ ptr }; + c = fn( std::move( c) ); + if ( ! c) { + ptr = nullptr; + } +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( c.ptr_, nullptr); +#else + return std::exchange( c.ptr_, nullptr); +#endif + }; +#endif +#if defined(BOOST_USE_SEGMENTED_STACKS) + // adjust segmented stack properties + __splitstack_getcontext( from->sctx.segments_ctx); + __splitstack_setcontext( sctx.segments_ctx); +#endif +#if defined(BOOST_USE_ASAN) + __sanitizer_start_switch_fiber( & from->fake_stack, stack_bottom, stack_size); +#endif + // context switch from parent context to `this`-context + ::swapcontext( & from->uctx, & uctx); +#if defined(BOOST_USE_ASAN) + __sanitizer_finish_switch_fiber( current()->fake_stack, + (const void **) & current()->from->stack_bottom, + & current()->from->stack_size); +#endif +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( current()->from, nullptr); +#else + return std::exchange( current()->from, nullptr); +#endif + } + + virtual void deallocate() noexcept { + } +}; + +struct BOOST_CONTEXT_DECL fiber_activation_record_initializer { + fiber_activation_record_initializer() noexcept; + ~fiber_activation_record_initializer(); +}; + +struct forced_unwind { + fiber_activation_record * from{ nullptr }; +#ifndef BOOST_ASSERT_IS_VOID + bool caught{ false }; +#endif + + forced_unwind( fiber_activation_record * from_) noexcept : + from{ from_ } { + } + +#ifndef BOOST_ASSERT_IS_VOID + ~forced_unwind() { + BOOST_ASSERT( caught); + } +#endif +}; + +template< typename Ctx, typename StackAlloc, typename Fn > +class fiber_capture_record : public fiber_activation_record { +private: + typename std::decay< StackAlloc >::type salloc_; + typename std::decay< Fn >::type fn_; + + static void destroy( fiber_capture_record * p) noexcept { + typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); + stack_context sctx = p->sctx; + // deallocate activation record + p->~fiber_capture_record(); + // destroy stack with stack allocator + salloc.deallocate( sctx); + } + +public: + fiber_capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept : + fiber_activation_record{ sctx }, + salloc_{ std::forward< StackAlloc >( salloc) }, + fn_( std::forward< Fn >( fn) ) { + } + + void deallocate() noexcept override final { + BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) ); + destroy( this); + } + + void run() { +#if defined(BOOST_USE_ASAN) + __sanitizer_finish_switch_fiber( fake_stack, + (const void **) & from->stack_bottom, + & from->stack_size); +#endif + Ctx c{ from }; + try { + // invoke context-function +#if defined(BOOST_NO_CXX17_STD_INVOKE) + c = boost::context::detail::invoke( fn_, std::move( c) ); +#else + c = std::invoke( fn_, std::move( c) ); +#endif + } catch ( forced_unwind const& ex) { + c = Ctx{ ex.from }; +#ifndef BOOST_ASSERT_IS_VOID + const_cast< forced_unwind & >( ex).caught = true; +#endif + } + // this context has finished its task + from = nullptr; + ontop = nullptr; + terminated = true; + force_unwind = false; + std::move( c).resume(); + BOOST_ASSERT_MSG( false, "fiber already terminated"); + } +}; + +template< typename Ctx, typename StackAlloc, typename Fn > +static fiber_activation_record * create_fiber1( StackAlloc && salloc, Fn && fn) { + typedef fiber_capture_record< Ctx, StackAlloc, Fn > capture_t; + + auto sctx = salloc.allocate(); + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + capture_t * record = new ( storage) capture_t{ + sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + // stack bottom + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sctx.size) ); + // create user-context + if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) { + record->~capture_t(); + salloc.deallocate( sctx); + throw std::system_error( + std::error_code( errno, std::system_category() ), + "getcontext() failed"); + } + record->uctx.uc_stack.ss_sp = stack_bottom; + // 64byte gap between control structure and stack top + record->uctx.uc_stack.ss_size = reinterpret_cast< uintptr_t >( storage) - + reinterpret_cast< uintptr_t >( stack_bottom) - static_cast< uintptr_t >( 64); + record->uctx.uc_link = nullptr; + ::makecontext( & record->uctx, ( void (*)() ) & fiber_entry_func< capture_t >, 1, record); +#if defined(BOOST_USE_ASAN) + record->stack_bottom = record->uctx.uc_stack.ss_sp; + record->stack_size = record->uctx.uc_stack.ss_size; +#endif + return record; +} + +template< typename Ctx, typename StackAlloc, typename Fn > +static fiber_activation_record * create_fiber2( preallocated palloc, StackAlloc && salloc, Fn && fn) { + typedef fiber_capture_record< Ctx, StackAlloc, Fn > capture_t; + + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + capture_t * record = new ( storage) capture_t{ + palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + // stack bottom + void * stack_bottom = reinterpret_cast< void * >( + reinterpret_cast< uintptr_t >( palloc.sctx.sp) - static_cast< uintptr_t >( palloc.sctx.size) ); + // create user-context + if ( BOOST_UNLIKELY( 0 != ::getcontext( & record->uctx) ) ) { + record->~capture_t(); + salloc.deallocate( palloc.sctx); + throw std::system_error( + std::error_code( errno, std::system_category() ), + "getcontext() failed"); + } + record->uctx.uc_stack.ss_sp = stack_bottom; + // 64byte gap between control structure and stack top + record->uctx.uc_stack.ss_size = reinterpret_cast< uintptr_t >( storage) - + reinterpret_cast< uintptr_t >( stack_bottom) - static_cast< uintptr_t >( 64); + record->uctx.uc_link = nullptr; + ::makecontext( & record->uctx, ( void (*)() ) & fiber_entry_func< capture_t >, 1, record); +#if defined(BOOST_USE_ASAN) + record->stack_bottom = record->uctx.uc_stack.ss_sp; + record->stack_size = record->uctx.uc_stack.ss_size; +#endif + return record; +} + +} + +class BOOST_CONTEXT_DECL fiber { +private: + friend struct detail::fiber_activation_record; + + template< typename Ctx, typename StackAlloc, typename Fn > + friend class detail::fiber_capture_record; + + template< typename Ctx, typename StackAlloc, typename Fn > + friend detail::fiber_activation_record * detail::create_fiber1( StackAlloc &&, Fn &&); + + template< typename Ctx, typename StackAlloc, typename Fn > + friend detail::fiber_activation_record * detail::create_fiber2( preallocated, StackAlloc &&, Fn &&); + + template< typename StackAlloc, typename Fn > + friend fiber + callcc( std::allocator_arg_t, StackAlloc &&, Fn &&); + + template< typename StackAlloc, typename Fn > + friend fiber + callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&); + + detail::fiber_activation_record * ptr_{ nullptr }; + + fiber( detail::fiber_activation_record * ptr) noexcept : + ptr_{ ptr } { + } + +public: + fiber() = default; + + template< typename Fn, typename = detail::disable_overload< fiber, Fn > > + fiber( Fn && fn) : + fiber{ + std::allocator_arg, +#if defined(BOOST_USE_SEGMENTED_STACKS) + segmented_stack(), +#else + fixedsize_stack(), +#endif + std::forward< Fn >( fn) } { + } + + template< typename StackAlloc, typename Fn > + fiber( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) : + ptr_{ detail::create_fiber1< fiber >( + std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } { + } + + template< typename StackAlloc, typename Fn > + fiber( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) : + ptr_{ detail::create_fiber2< fiber >( + palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } { + } + + ~fiber() { + if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) { + if ( BOOST_LIKELY( ! ptr_->terminated) ) { + ptr_->force_unwind = true; + ptr_->resume(); + BOOST_ASSERT( ptr_->terminated); + } + ptr_->deallocate(); + } + } + + fiber( fiber const&) = delete; + fiber & operator=( fiber const&) = delete; + + fiber( fiber && other) noexcept { + swap( other); + } + + fiber & operator=( fiber && other) noexcept { + if ( BOOST_LIKELY( this != & other) ) { + fiber tmp = std::move( other); + swap( tmp); + } + return * this; + } + + fiber resume() && { + BOOST_ASSERT( nullptr != ptr_); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::fiber_activation_record * ptr = detail::exchange( ptr_, nullptr)->resume(); +#else + detail::fiber_activation_record * ptr = std::exchange( ptr_, nullptr)->resume(); +#endif + if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) { + throw detail::forced_unwind{ ptr}; + } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) { + ptr = detail::fiber_activation_record::current()->ontop( ptr); + detail::fiber_activation_record::current()->ontop = nullptr; + } + return { ptr }; + } + + template< typename Fn > + fiber resume_with( Fn && fn) && { + BOOST_ASSERT( nullptr != ptr_); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::fiber_activation_record * ptr = + detail::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) ); +#else + detail::fiber_activation_record * ptr = + std::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) ); +#endif + if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) { + throw detail::forced_unwind{ ptr}; + } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) { + ptr = detail::fiber_activation_record::current()->ontop( ptr); + detail::fiber_activation_record::current()->ontop = nullptr; + } + return { ptr }; + } + + explicit operator bool() const noexcept { + return nullptr != ptr_ && ! ptr_->terminated; + } + + bool operator!() const noexcept { + return nullptr == ptr_ || ptr_->terminated; + } + + bool operator<( fiber const& other) const noexcept { + return ptr_ < other.ptr_; + } + + template< typename charT, class traitsT > + friend std::basic_ostream< charT, traitsT > & + operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) { + if ( nullptr != other.ptr_) { + return os << other.ptr_; + } else { + return os << "{not-a-context}"; + } + } + + void swap( fiber & other) noexcept { + std::swap( ptr_, other.ptr_); + } +}; + +inline +void swap( fiber & l, fiber & r) noexcept { + l.swap( r); +} + +typedef fiber fiber_context; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_FIBER_H diff --git a/boost/context/fiber_winfib.hpp b/boost/context/fiber_winfib.hpp new file mode 100644 index 0000000..f2612fd --- /dev/null +++ b/boost/context/fiber_winfib.hpp @@ -0,0 +1,446 @@ + +// Copyright Oliver Kowalke 2017. +// 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_CONTEXT_FIBER_H +#define BOOST_CONTEXT_FIBER_H + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) +#include +#endif +#if defined(BOOST_NO_CXX17_STD_INVOKE) +#include +#endif +#include +#include +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if defined(BOOST_MSVC) +# pragma warning(push) +# pragma warning(disable: 4702) +#endif + +namespace boost { +namespace context { +namespace detail { + +// tampoline function +// entered if the execution context +// is resumed for the first time +template< typename Record > +static VOID WINAPI fiber_entry_func( LPVOID data) noexcept { + Record * record = static_cast< Record * >( data); + BOOST_ASSERT( nullptr != record); + // start execution of toplevel context-function + record->run(); +} + +struct BOOST_CONTEXT_DECL fiber_activation_record { + LPVOID fiber{ nullptr }; + stack_context sctx{}; + bool main_ctx{ true }; + fiber_activation_record * from{ nullptr }; + std::function< fiber_activation_record*(fiber_activation_record*&) > ontop{}; + bool terminated{ false }; + bool force_unwind{ false }; + + static fiber_activation_record *& current() noexcept; + + // used for toplevel-context + // (e.g. main context, thread-entry context) + fiber_activation_record() noexcept { +#if ( _WIN32_WINNT > 0x0600) + if ( ::IsThreadAFiber() ) { + fiber = ::GetCurrentFiber(); + } else { + fiber = ::ConvertThreadToFiber( nullptr); + } +#else + fiber = ::ConvertThreadToFiber( nullptr); + if ( BOOST_UNLIKELY( nullptr == fiber) ) { + BOOST_ASSERT( ERROR_ALREADY_FIBER == ::GetLastError()); + fiber = ::GetCurrentFiber(); + BOOST_ASSERT( nullptr != fiber); + BOOST_ASSERT( reinterpret_cast< LPVOID >( 0x1E00) != fiber); + } +#endif + } + + fiber_activation_record( stack_context sctx_) noexcept : + sctx{ sctx_ }, + main_ctx{ false } { + } + + virtual ~fiber_activation_record() { + if ( BOOST_UNLIKELY( main_ctx) ) { + ::ConvertFiberToThread(); + } else { + ::DeleteFiber( fiber); + } + } + + fiber_activation_record( fiber_activation_record const&) = delete; + fiber_activation_record & operator=( fiber_activation_record const&) = delete; + + bool is_main_context() const noexcept { + return main_ctx; + } + + fiber_activation_record * resume() { + from = current(); + // store `this` in static, thread local pointer + // `this` will become the active (running) context + current() = this; + // context switch from parent context to `this`-context + // context switch + ::SwitchToFiber( fiber); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return detail::exchange( current()->from, nullptr); +#else + return std::exchange( current()->from, nullptr); +#endif + } + + template< typename Ctx, typename Fn > + fiber_activation_record * resume_with( Fn && fn) { + from = current(); + // store `this` in static, thread local pointer + // `this` will become the active (running) context + // returned by fiber::current() + current() = this; +#if defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) + current()->ontop = std::bind( + [](typename std::decay< Fn >::type & fn, fiber_activation_record *& ptr){ + Ctx c{ ptr }; + c = fn( std::move( c) ); + if ( ! c) { + ptr = nullptr; + } +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( c.ptr_, nullptr); +#else + return std::exchange( c.ptr_, nullptr); +#endif + }, + std::forward< Fn >( fn), + std::placeholders::_1); +#else + current()->ontop = [fn=std::forward(fn)](fiber_activation_record *& ptr){ + Ctx c{ ptr }; + c = fn( std::move( c) ); + if ( ! c) { + ptr = nullptr; + } +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return exchange( c.ptr_, nullptr); +#else + return std::exchange( c.ptr_, nullptr); +#endif + }; +#endif + // context switch + ::SwitchToFiber( fiber); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + return detail::exchange( current()->from, nullptr); +#else + return std::exchange( current()->from, nullptr); +#endif + } + + virtual void deallocate() noexcept { + } +}; + +struct BOOST_CONTEXT_DECL fiber_activation_record_initializer { + fiber_activation_record_initializer() noexcept; + ~fiber_activation_record_initializer(); +}; + +struct forced_unwind { + fiber_activation_record * from{ nullptr }; +#ifndef BOOST_ASSERT_IS_VOID + bool caught{ false }; +#endif + + explicit forced_unwind( fiber_activation_record * from_) : + from{ from_ } { + } + +#ifndef BOOST_ASSERT_IS_VOID + ~forced_unwind() { + BOOST_ASSERT( caught); + } +#endif +}; + +template< typename Ctx, typename StackAlloc, typename Fn > +class fiber_capture_record : public fiber_activation_record { +private: + typename std::decay< StackAlloc >::type salloc_; + typename std::decay< Fn >::type fn_; + + static void destroy( fiber_capture_record * p) noexcept { + typename std::decay< StackAlloc >::type salloc = std::move( p->salloc_); + stack_context sctx = p->sctx; + // deallocate activation record + p->~fiber_capture_record(); + // destroy stack with stack allocator + salloc.deallocate( sctx); + } + +public: + fiber_capture_record( stack_context sctx, StackAlloc && salloc, Fn && fn) noexcept : + fiber_activation_record( sctx), + salloc_( std::forward< StackAlloc >( salloc)), + fn_( std::forward< Fn >( fn) ) { + } + + void deallocate() noexcept override final { + BOOST_ASSERT( main_ctx || ( ! main_ctx && terminated) ); + destroy( this); + } + + void run() { + Ctx c{ from }; + try { + // invoke context-function +#if defined(BOOST_NO_CXX17_STD_INVOKE) + c = boost::context::detail::invoke( fn_, std::move( c) ); +#else + c = std::invoke( fn_, std::move( c) ); +#endif + } catch ( forced_unwind const& ex) { + c = Ctx{ ex.from }; +#ifndef BOOST_ASSERT_IS_VOID + const_cast< forced_unwind & >( ex).caught = true; +#endif + } + // this context has finished its task + from = nullptr; + ontop = nullptr; + terminated = true; + force_unwind = false; + std::move( c).resume(); + BOOST_ASSERT_MSG( false, "fiber already terminated"); + } +}; + +template< typename Ctx, typename StackAlloc, typename Fn > +static fiber_activation_record * create_fiber1( StackAlloc && salloc, Fn && fn) { + typedef fiber_capture_record< Ctx, StackAlloc, Fn > capture_t; + + auto sctx = salloc.allocate(); + BOOST_ASSERT( ( sizeof( capture_t) ) < sctx.size); + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( sctx.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + capture_t * record = new ( storage) capture_t{ + sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + // create user-context + record->fiber = ::CreateFiber( sctx.size, & detail::fiber_entry_func< capture_t >, record); + return record; +} + +template< typename Ctx, typename StackAlloc, typename Fn > +static fiber_activation_record * create_fiber2( preallocated palloc, StackAlloc && salloc, Fn && fn) { + typedef fiber_capture_record< Ctx, StackAlloc, Fn > capture_t; + + BOOST_ASSERT( ( sizeof( capture_t) ) < palloc.size); + // reserve space for control structure + void * storage = reinterpret_cast< void * >( + ( reinterpret_cast< uintptr_t >( palloc.sp) - static_cast< uintptr_t >( sizeof( capture_t) ) ) + & ~ static_cast< uintptr_t >( 0xff) ); + // placment new for control structure on context stack + capture_t * record = new ( storage) capture_t{ + palloc.sctx, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) }; + // create user-context + record->fiber = ::CreateFiber( palloc.sctx.size, & detail::fiber_entry_func< capture_t >, record); + return record; +} + +} + +class BOOST_CONTEXT_DECL fiber { +private: + friend struct detail::fiber_activation_record; + + template< typename Ctx, typename StackAlloc, typename Fn > + friend class detail::fiber_capture_record; + + template< typename Ctx, typename StackAlloc, typename Fn > + friend detail::fiber_activation_record * detail::create_fiber1( StackAlloc &&, Fn &&); + + template< typename Ctx, typename StackAlloc, typename Fn > + friend detail::fiber_activation_record * detail::create_fiber2( preallocated, StackAlloc &&, Fn &&); + + template< typename StackAlloc, typename Fn > + friend fiber + callcc( std::allocator_arg_t, StackAlloc &&, Fn &&); + + template< typename StackAlloc, typename Fn > + friend fiber + callcc( std::allocator_arg_t, preallocated, StackAlloc &&, Fn &&); + + detail::fiber_activation_record * ptr_{ nullptr }; + + fiber( detail::fiber_activation_record * ptr) noexcept : + ptr_{ ptr } { + } + +public: + fiber() = default; + + template< typename Fn, typename = detail::disable_overload< fiber, Fn > > + fiber( Fn && fn) : + fiber{ std::allocator_arg, + fixedsize_stack(), + std::forward< Fn >( fn) } { + } + + template< typename StackAlloc, typename Fn > + fiber( std::allocator_arg_t, StackAlloc && salloc, Fn && fn) : + ptr_{ detail::create_fiber1< fiber >( + std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } {; + } + + template< typename StackAlloc, typename Fn > + fiber( std::allocator_arg_t, preallocated palloc, StackAlloc && salloc, Fn && fn) : + ptr_{ detail::create_fiber2< fiber >( + palloc, std::forward< StackAlloc >( salloc), std::forward< Fn >( fn) ) } { + } + + ~fiber() { + if ( BOOST_UNLIKELY( nullptr != ptr_) && ! ptr_->main_ctx) { + if ( BOOST_LIKELY( ! ptr_->terminated) ) { + ptr_->force_unwind = true; + ptr_->resume(); + BOOST_ASSERT( ptr_->terminated); + } + ptr_->deallocate(); + } + } + + fiber( fiber const&) = delete; + fiber & operator=( fiber const&) = delete; + + fiber( fiber && other) noexcept { + swap( other); + } + + fiber & operator=( fiber && other) noexcept { + if ( BOOST_LIKELY( this != & other) ) { + fiber tmp = std::move( other); + swap( tmp); + } + return * this; + } + + fiber resume() && { + BOOST_ASSERT( nullptr != ptr_); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::fiber_activation_record * ptr = detail::exchange( ptr_, nullptr)->resume(); +#else + detail::fiber_activation_record * ptr = std::exchange( ptr_, nullptr)->resume(); +#endif + if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) { + throw detail::forced_unwind{ ptr}; + } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) { + ptr = detail::fiber_activation_record::current()->ontop( ptr); + detail::fiber_activation_record::current()->ontop = nullptr; + } + return { ptr }; + } + + template< typename Fn > + fiber resume_with( Fn && fn) && { + BOOST_ASSERT( nullptr != ptr_); +#if defined(BOOST_NO_CXX14_STD_EXCHANGE) + detail::fiber_activation_record * ptr = + detail::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) ); +#else + detail::fiber_activation_record * ptr = + std::exchange( ptr_, nullptr)->resume_with< fiber >( std::forward< Fn >( fn) ); +#endif + if ( BOOST_UNLIKELY( detail::fiber_activation_record::current()->force_unwind) ) { + throw detail::forced_unwind{ ptr}; + } else if ( BOOST_UNLIKELY( nullptr != detail::fiber_activation_record::current()->ontop) ) { + ptr = detail::fiber_activation_record::current()->ontop( ptr); + detail::fiber_activation_record::current()->ontop = nullptr; + } + return { ptr }; + } + + explicit operator bool() const noexcept { + return nullptr != ptr_ && ! ptr_->terminated; + } + + bool operator!() const noexcept { + return nullptr == ptr_ || ptr_->terminated; + } + + bool operator<( fiber const& other) const noexcept { + return ptr_ < other.ptr_; + } + + template< typename charT, class traitsT > + friend std::basic_ostream< charT, traitsT > & + operator<<( std::basic_ostream< charT, traitsT > & os, fiber const& other) { + if ( nullptr != other.ptr_) { + return os << other.ptr_; + } else { + return os << "{not-a-context}"; + } + } + + void swap( fiber & other) noexcept { + std::swap( ptr_, other.ptr_); + } +}; + +inline +void swap( fiber & l, fiber & r) noexcept { + l.swap( r); +} + +typedef fiber fiber_context; + +}} + +#if defined(BOOST_MSVC) +# pragma warning(pop) +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_FIBER_H diff --git a/boost/context/fixedsize_stack.hpp b/boost/context/fixedsize_stack.hpp new file mode 100644 index 0000000..c309347 --- /dev/null +++ b/boost/context/fixedsize_stack.hpp @@ -0,0 +1,97 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_FIXEDSIZE_H +#define BOOST_CONTEXT_FIXEDSIZE_H + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#if defined(BOOST_CONTEXT_USE_MAP_STACK) +extern "C" { +#include +} +#endif + +#if defined(BOOST_USE_VALGRIND) +#include +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { + +template< typename traitsT > +class basic_fixedsize_stack { +private: + std::size_t size_; + +public: + typedef traitsT traits_type; + + basic_fixedsize_stack( std::size_t size = traits_type::default_size() ) BOOST_NOEXCEPT_OR_NOTHROW : + size_( size) { + } + + stack_context allocate() { +#if defined(BOOST_CONTEXT_USE_MAP_STACK) + void * vp = ::mmap( 0, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0); + if ( vp == MAP_FAILED) { + throw std::bad_alloc(); + } +#else + void * vp = std::malloc( size_); + if ( ! vp) { + throw std::bad_alloc(); + } +#endif + stack_context sctx; + sctx.size = size_; + sctx.sp = static_cast< char * >( vp) + sctx.size; +#if defined(BOOST_USE_VALGRIND) + sctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( sctx.sp, vp); +#endif + return sctx; + } + + void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT( sctx.sp); + +#if defined(BOOST_USE_VALGRIND) + VALGRIND_STACK_DEREGISTER( sctx.valgrind_stack_id); +#endif + void * vp = static_cast< char * >( sctx.sp) - sctx.size; +#if defined(BOOST_CONTEXT_USE_MAP_STACK) + ::munmap( vp, sctx.size); +#else + std::free( vp); +#endif + } +}; + +typedef basic_fixedsize_stack< stack_traits > fixedsize_stack; +# if ! defined(BOOST_USE_SEGMENTED_STACKS) +typedef fixedsize_stack default_stack; +# endif + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_FIXEDSIZE_H diff --git a/boost/context/flags.hpp b/boost/context/flags.hpp new file mode 100644 index 0000000..c7ff117 --- /dev/null +++ b/boost/context/flags.hpp @@ -0,0 +1,28 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_FLAGS_H +#define BOOST_CONTEXT_FLAGS_H + +# include + +# ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +# endif + +namespace boost { +namespace context { + +struct exec_ontop_arg_t {}; +const exec_ontop_arg_t exec_ontop_arg{}; + +}} + +# ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +# endif + +#endif // BOOST_CONTEXT_FLAGS_H diff --git a/boost/context/pooled_fixedsize_stack.hpp b/boost/context/pooled_fixedsize_stack.hpp new file mode 100644 index 0000000..c115c86 --- /dev/null +++ b/boost/context/pooled_fixedsize_stack.hpp @@ -0,0 +1,152 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_POOLED_pooled_fixedsize_H +#define BOOST_CONTEXT_POOLED_pooled_fixedsize_H + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#if defined(BOOST_CONTEXT_USE_MAP_STACK) +extern "C" { +#include +#include +} +#endif + +#if defined(BOOST_USE_VALGRIND) +#include +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { + +#if defined(BOOST_CONTEXT_USE_MAP_STACK) +namespace detail { +template< typename traitsT > +struct map_stack_allocator { + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + static char * malloc( const size_type bytes) { + void * block; + if ( ::posix_memalign( &block, traitsT::page_size(), bytes) != 0) { + return 0; + } + if ( mmap( block, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_STACK, -1, 0) == MAP_FAILED) { + std::free( block); + return 0; + } + return reinterpret_cast< char * >( block); + } + static void free( char * const block) { + std::free( block); + } +}; +} +#endif + +template< typename traitsT > +class basic_pooled_fixedsize_stack { +private: + class storage { + private: + std::atomic< std::size_t > use_count_; + std::size_t stack_size_; +#if defined(BOOST_CONTEXT_USE_MAP_STACK) + boost::pool< detail::map_stack_allocator< traitsT > > storage_; +#else + boost::pool< boost::default_user_allocator_malloc_free > storage_; +#endif + + public: + storage( std::size_t stack_size, std::size_t next_size, std::size_t max_size) : + use_count_( 0), + stack_size_( stack_size), + storage_( stack_size, next_size, max_size) { + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= stack_size_) ); + } + + stack_context allocate() { + void * vp = storage_.malloc(); + if ( ! vp) { + throw std::bad_alloc(); + } + stack_context sctx; + sctx.size = stack_size_; + sctx.sp = static_cast< char * >( vp) + sctx.size; +#if defined(BOOST_USE_VALGRIND) + sctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( sctx.sp, vp); +#endif + return sctx; + } + + void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT( sctx.sp); + BOOST_ASSERT( traits_type::is_unbounded() || ( traits_type::maximum_size() >= sctx.size) ); + +#if defined(BOOST_USE_VALGRIND) + VALGRIND_STACK_DEREGISTER( sctx.valgrind_stack_id); +#endif + void * vp = static_cast< char * >( sctx.sp) - sctx.size; + storage_.free( vp); + } + + friend void intrusive_ptr_add_ref( storage * s) noexcept { + ++s->use_count_; + } + + friend void intrusive_ptr_release( storage * s) noexcept { + if ( 0 == --s->use_count_) { + delete s; + } + } + }; + + intrusive_ptr< storage > storage_; + +public: + typedef traitsT traits_type; + + basic_pooled_fixedsize_stack( std::size_t stack_size = traits_type::default_size(), + std::size_t next_size = 32, + std::size_t max_size = 0) BOOST_NOEXCEPT_OR_NOTHROW : + storage_( new storage( stack_size, next_size, max_size) ) { + } + + stack_context allocate() { + return storage_->allocate(); + } + + void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { + storage_->deallocate( sctx); + } +}; + +typedef basic_pooled_fixedsize_stack< stack_traits > pooled_fixedsize_stack; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_POOLED_pooled_fixedsize_H diff --git a/boost/context/posix/protected_fixedsize_stack.hpp b/boost/context/posix/protected_fixedsize_stack.hpp new file mode 100644 index 0000000..79e462f --- /dev/null +++ b/boost/context/posix/protected_fixedsize_stack.hpp @@ -0,0 +1,107 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_PROTECTED_FIXEDSIZE_H +#define BOOST_CONTEXT_PROTECTED_FIXEDSIZE_H + +extern "C" { +#include +#include +#include +#include +} + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#if defined(BOOST_USE_VALGRIND) +#include +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { + +template< typename traitsT > +class basic_protected_fixedsize_stack { +private: + std::size_t size_; + +public: + typedef traitsT traits_type; + + basic_protected_fixedsize_stack( std::size_t size = traits_type::default_size() ) BOOST_NOEXCEPT_OR_NOTHROW : + size_( size) { + } + + stack_context allocate() { + // calculate how many pages are required + const std::size_t pages( + static_cast< std::size_t >( + std::ceil( + static_cast< float >( size_) / traits_type::page_size() ) ) ); + // add one page at bottom that will be used as guard-page + const std::size_t size__ = ( pages + 1) * traits_type::page_size(); + +#if defined(BOOST_CONTEXT_USE_MAP_STACK) + void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0); +#elif defined(MAP_ANON) + void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); +#else + void * vp = ::mmap( 0, size__, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#endif + if ( MAP_FAILED == vp) throw std::bad_alloc(); + + // conforming to POSIX.1-2001 +#if defined(BOOST_DISABLE_ASSERTS) + ::mprotect( vp, traits_type::page_size(), PROT_NONE); +#else + const int result( ::mprotect( vp, traits_type::page_size(), PROT_NONE) ); + BOOST_ASSERT( 0 == result); +#endif + + stack_context sctx; + sctx.size = size__; + sctx.sp = static_cast< char * >( vp) + sctx.size; +#if defined(BOOST_USE_VALGRIND) + sctx.valgrind_stack_id = VALGRIND_STACK_REGISTER( sctx.sp, vp); +#endif + return sctx; + } + + void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT( sctx.sp); + +#if defined(BOOST_USE_VALGRIND) + VALGRIND_STACK_DEREGISTER( sctx.valgrind_stack_id); +#endif + + void * vp = static_cast< char * >( sctx.sp) - sctx.size; + // conform to POSIX.4 (POSIX.1b-1993, _POSIX_C_SOURCE=199309L) + ::munmap( vp, sctx.size); + } +}; + +typedef basic_protected_fixedsize_stack< stack_traits > protected_fixedsize_stack; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_PROTECTED_FIXEDSIZE_H diff --git a/boost/context/posix/segmented_stack.hpp b/boost/context/posix/segmented_stack.hpp new file mode 100644 index 0000000..e3d2efc --- /dev/null +++ b/boost/context/posix/segmented_stack.hpp @@ -0,0 +1,82 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_SEGMENTED_H +#define BOOST_CONTEXT_SEGMENTED_H + +#include +#include + +#include + +#include +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +// forward declaration for splitstack-functions defined in libgcc +extern "C" { +void *__splitstack_makecontext( std::size_t, + void * [BOOST_CONTEXT_SEGMENTS], + std::size_t *); + +void __splitstack_releasecontext( void * [BOOST_CONTEXT_SEGMENTS]); + +void __splitstack_resetcontext( void * [BOOST_CONTEXT_SEGMENTS]); + +void __splitstack_block_signals_context( void * [BOOST_CONTEXT_SEGMENTS], + int * new_value, int * old_value); +} + +namespace boost { +namespace context { + +template< typename traitsT > +class basic_segmented_stack { +private: + std::size_t size_; + +public: + typedef traitsT traits_type; + + basic_segmented_stack( std::size_t size = traits_type::default_size() ) BOOST_NOEXCEPT_OR_NOTHROW : + size_( size) { + } + + stack_context allocate() { + stack_context sctx; + void * vp = __splitstack_makecontext( size_, sctx.segments_ctx, & sctx.size); + if ( ! vp) throw std::bad_alloc(); + + // sctx.size is already filled by __splitstack_makecontext + sctx.sp = static_cast< char * >( vp) + sctx.size; + + int off = 0; + __splitstack_block_signals_context( sctx.segments_ctx, & off, 0); + + return sctx; + } + + void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { + __splitstack_releasecontext( sctx.segments_ctx); + } +}; + +typedef basic_segmented_stack< stack_traits > segmented_stack; +# if defined(BOOST_USE_SEGMENTED_STACKS) +typedef segmented_stack default_stack; +# endif + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_SEGMENTED_H diff --git a/boost/context/preallocated.hpp b/boost/context/preallocated.hpp new file mode 100644 index 0000000..862a6a5 --- /dev/null +++ b/boost/context/preallocated.hpp @@ -0,0 +1,39 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_PREALLOCATED_H +#define BOOST_CONTEXT_PREALLOCATED_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { + +struct preallocated { + void * sp; + std::size_t size; + stack_context sctx; + + preallocated( void * sp_, std::size_t size_, stack_context sctx_) noexcept : + sp( sp_), size( size_), sctx( sctx_) { + } +}; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_PREALLOCATED_H diff --git a/boost/context/protected_fixedsize_stack.hpp b/boost/context/protected_fixedsize_stack.hpp new file mode 100644 index 0000000..a05aa73 --- /dev/null +++ b/boost/context/protected_fixedsize_stack.hpp @@ -0,0 +1,13 @@ + +// Copyright Oliver Kowalke 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#if defined(BOOST_WINDOWS) +# include +#else +# include +#endif diff --git a/boost/context/segmented_stack.hpp b/boost/context/segmented_stack.hpp new file mode 100644 index 0000000..88e3e6a --- /dev/null +++ b/boost/context/segmented_stack.hpp @@ -0,0 +1,13 @@ + +// Copyright Oliver Kowalke 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#if defined(BOOST_USE_SEGMENTED_STACKS) +# if ! defined(BOOST_WINDOWS) +# include +# endif +#endif diff --git a/boost/context/stack_context.hpp b/boost/context/stack_context.hpp new file mode 100644 index 0000000..740d981 --- /dev/null +++ b/boost/context/stack_context.hpp @@ -0,0 +1,72 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_STACK_CONTEXT_H +#define BOOST_CONTEXT_STACK_CONTEXT_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { + +#if ! defined(BOOST_CONTEXT_NO_CXX11) +struct BOOST_CONTEXT_DECL stack_context { +# if defined(BOOST_USE_SEGMENTED_STACKS) + typedef void * segments_context[BOOST_CONTEXT_SEGMENTS]; +# endif + + std::size_t size{ 0 }; + void * sp{ nullptr }; +# if defined(BOOST_USE_SEGMENTED_STACKS) + segments_context segments_ctx{}; +# endif +# if defined(BOOST_USE_VALGRIND) + unsigned valgrind_stack_id{ 0 }; +# endif +}; +#else +struct BOOST_CONTEXT_DECL stack_context { +# if defined(BOOST_USE_SEGMENTED_STACKS) + typedef void * segments_context[BOOST_CONTEXT_SEGMENTS]; +# endif + + std::size_t size; + void * sp; +# if defined(BOOST_USE_SEGMENTED_STACKS) + segments_context segments_ctx; +# endif +# if defined(BOOST_USE_VALGRIND) + unsigned valgrind_stack_id; +# endif + + stack_context() : + size( 0), + sp( 0) +# if defined(BOOST_USE_SEGMENTED_STACKS) + , segments_ctx() +# endif +# if defined(BOOST_USE_VALGRIND) + , valgrind_stack_id( 0) +# endif + {} +}; +#endif + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_STACK_CONTEXT_H diff --git a/boost/context/stack_traits.hpp b/boost/context/stack_traits.hpp new file mode 100644 index 0000000..d5320f5 --- /dev/null +++ b/boost/context/stack_traits.hpp @@ -0,0 +1,42 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_STACK_TRAITS_H +#define BOOST_CONTEXT_STACK_TRAITS_H + +#include + +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { + +struct BOOST_CONTEXT_DECL stack_traits +{ + static bool is_unbounded() BOOST_NOEXCEPT_OR_NOTHROW; + + static std::size_t page_size() BOOST_NOEXCEPT_OR_NOTHROW; + + static std::size_t default_size() BOOST_NOEXCEPT_OR_NOTHROW; + + static std::size_t minimum_size() BOOST_NOEXCEPT_OR_NOTHROW; + + static std::size_t maximum_size() BOOST_NOEXCEPT_OR_NOTHROW; +}; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_STACK_TRAITS_H diff --git a/boost/context/windows/protected_fixedsize_stack.hpp b/boost/context/windows/protected_fixedsize_stack.hpp new file mode 100644 index 0000000..26d2086 --- /dev/null +++ b/boost/context/windows/protected_fixedsize_stack.hpp @@ -0,0 +1,87 @@ + +// Copyright Oliver Kowalke 2014. +// 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_CONTEXT_PROTECTED_FIXEDSIZE_H +#define BOOST_CONTEXT_PROTECTED_FIXEDSIZE_H + +extern "C" { +#include +} + +#include +#include +#include + +#include + +#include +#include +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { + +template< typename traitsT > +class basic_protected_fixedsize_stack { +private: + std::size_t size_; + +public: + typedef traitsT traits_type; + + basic_protected_fixedsize_stack( std::size_t size = traits_type::default_size() ) BOOST_NOEXCEPT_OR_NOTHROW : + size_( size) { + } + + stack_context allocate() { + // calculate how many pages are required + const std::size_t pages( + static_cast< std::size_t >( + std::ceil( + static_cast< float >( size_) / traits_type::page_size() ) ) ); + // add one page at bottom that will be used as guard-page + const std::size_t size__ = ( pages + 1) * traits_type::page_size(); + + void * vp = ::VirtualAlloc( 0, size__, MEM_COMMIT, PAGE_READWRITE); + if ( ! vp) throw std::bad_alloc(); + + DWORD old_options; +#if defined(BOOST_DISABLE_ASSERTS) + ::VirtualProtect( + vp, traits_type::page_size(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); +#else + const BOOL result = ::VirtualProtect( + vp, traits_type::page_size(), PAGE_READWRITE | PAGE_GUARD /*PAGE_NOACCESS*/, & old_options); + BOOST_ASSERT( FALSE != result); +#endif + + stack_context sctx; + sctx.size = size__; + sctx.sp = static_cast< char * >( vp) + sctx.size; + return sctx; + } + + void deallocate( stack_context & sctx) BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT( sctx.sp); + + void * vp = static_cast< char * >( sctx.sp) - sctx.size; + ::VirtualFree( vp, 0, MEM_RELEASE); + } +}; + +typedef basic_protected_fixedsize_stack< stack_traits > protected_fixedsize_stack; + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_CONTEXT_PROTECTED_FIXEDSIZE_H diff --git a/boost/core/alloc_construct.hpp b/boost/core/alloc_construct.hpp new file mode 100644 index 0000000..7b87525 --- /dev/null +++ b/boost/core/alloc_construct.hpp @@ -0,0 +1,245 @@ +/* +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_CORE_ALLOC_CONSTRUCT_HPP +#define BOOST_CORE_ALLOC_CONSTRUCT_HPP + +#include + +namespace boost { + +#if !defined(BOOST_NO_CXX11_ALLOCATOR) +template +inline void +alloc_destroy(A& a, T* p) +{ + std::allocator_traits::destroy(a, p); +} + +template +inline void +alloc_destroy_n(A& a, T* p, std::size_t n) +{ + while (n > 0) { + std::allocator_traits::destroy(a, p + --n); + } +} +#else +template +inline void +alloc_destroy(A&, T* p) +{ + p->~T(); +} + +template +inline void +alloc_destroy_n(A&, T* p, std::size_t n) +{ + while (n > 0) { + p[--n].~T(); + } +} +#endif + +namespace detail { + +template +class alloc_destroyer { +public: + alloc_destroyer(A& a, T* p) BOOST_NOEXCEPT + : a_(a), + p_(p), + n_(0) { } + + ~alloc_destroyer() { + boost::alloc_destroy_n(a_, p_, n_); + } + + std::size_t& size() BOOST_NOEXCEPT { + return n_; + } + +private: + alloc_destroyer(const alloc_destroyer&); + alloc_destroyer& operator=(const alloc_destroyer&); + + A& a_; + T* p_; + std::size_t n_; +}; + +} /* detail */ + +#if !defined(BOOST_NO_CXX11_ALLOCATOR) +template +inline void +alloc_construct(A& a, T* p) +{ + std::allocator_traits::construct(a, p); +} + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +template +inline void +alloc_construct(A& a, T* p, U&& u, V&&... v) +{ + std::allocator_traits::construct(a, p, std::forward(u), + std::forward(v)...); +} +#else +template +inline void +alloc_construct(A& a, T* p, U&& u) +{ + std::allocator_traits::construct(a, p, std::forward(u)); +} +#endif +#else +template +inline void +alloc_construct(A& a, T* p, const U& u) +{ + std::allocator_traits::construct(a, p, u); +} + +template +inline void +alloc_construct(A& a, T* p, U& u) +{ + std::allocator_traits::construct(a, p, u); +} +#endif + +template +inline void +alloc_construct_n(A& a, T* p, std::size_t n) +{ + detail::alloc_destroyer hold(a, p); + for (std::size_t& i = hold.size(); i < n; ++i) { + std::allocator_traits::construct(a, p + i); + } + hold.size() = 0; +} + +template +inline void +alloc_construct_n(A& a, T* p, std::size_t n, const T* l, std::size_t m) +{ + detail::alloc_destroyer hold(a, p); + for (std::size_t& i = hold.size(); i < n; ++i) { + std::allocator_traits::construct(a, p + i, l[i % m]); + } + hold.size() = 0; +} + +template +inline void +alloc_construct_n(A& a, T* p, std::size_t n, I b) +{ + detail::alloc_destroyer hold(a, p); + for (std::size_t& i = hold.size(); i < n; void(++i), void(++b)) { + std::allocator_traits::construct(a, p + i, *b); + } + hold.size() = 0; +} +#else +template +inline void +alloc_construct(A&, T* p) +{ + ::new(static_cast(p)) T(); +} + +template +inline void +alloc_construct(noinit_adaptor&, T* p) +{ + ::new(static_cast(p)) T; +} + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +template +inline void +alloc_construct(A&, T* p, U&& u, V&&... v) +{ + ::new(static_cast(p)) T(std::forward(u), std::forward(v)...); +} +#else +template +inline void +alloc_construct(A& a, T* p, U&& u) +{ + ::new(static_cast(p)) T(std::forward(u)); +} +#endif +#else +template +inline void +alloc_construct(A&, T* p, const U& u) +{ + ::new(static_cast(p)) T(u); +} + +template +inline void +alloc_construct(A&, T* p, U& u) +{ + ::new(static_cast(p)) T(u); +} +#endif + +template +inline void +alloc_construct_n(A& a, T* p, std::size_t n) +{ + detail::alloc_destroyer hold(a, p); + for (std::size_t& i = hold.size(); i < n; ++i) { + ::new(static_cast(p + i)) T(); + } + hold.size() = 0; +} + +template +inline void +alloc_construct_n(noinit_adaptor& a, T* p, std::size_t n) +{ + detail::alloc_destroyer, T> hold(a, p); + for (std::size_t& i = hold.size(); i < n; ++i) { + ::new(static_cast(p + i)) T; + } + hold.size() = 0; +} + +template +inline void +alloc_construct_n(A& a, T* p, std::size_t n, const T* l, std::size_t m) +{ + detail::alloc_destroyer hold(a, p); + for (std::size_t& i = hold.size(); i < n; ++i) { + ::new(static_cast(p + i)) T(l[i % m]); + } + hold.size() = 0; +} + +template +inline void +alloc_construct_n(A& a, T* p, std::size_t n, I b) +{ + detail::alloc_destroyer hold(a, p); + for (std::size_t& i = hold.size(); i < n; void(++i), void(++b)) { + ::new(static_cast(p + i)) T(*b); + } + hold.size() = 0; +} +#endif + +} /* boost */ + +#endif diff --git a/boost/core/default_allocator.hpp b/boost/core/default_allocator.hpp new file mode 100644 index 0000000..9fc3ea2 --- /dev/null +++ b/boost/core/default_allocator.hpp @@ -0,0 +1,158 @@ +/* +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_CORE_DEFAULT_ALLOCATOR_HPP +#define BOOST_CORE_DEFAULT_ALLOCATOR_HPP + +#include +#include +#include + +#if defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 60000 +#define BOOST_CORE_NO_CXX11_ALLOCATOR +#endif + +namespace boost { + +#if defined(BOOST_NO_EXCEPTIONS) +BOOST_NORETURN void throw_exception(const std::exception&); +#endif + +namespace default_ { + +struct true_type { + typedef bool value_type; + typedef true_type type; + + BOOST_STATIC_CONSTANT(bool, value = true); + + BOOST_CONSTEXPR operator bool() const BOOST_NOEXCEPT { + return true; + } + + BOOST_CONSTEXPR bool operator()() const BOOST_NOEXCEPT { + return true; + } +}; + +template +struct add_reference { + typedef T& type; +}; + +template<> +struct add_reference { + typedef void type; +}; + +template<> +struct add_reference { + typedef const void type; +}; + +template +struct default_allocator { + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef typename add_reference::type reference; + typedef typename add_reference::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef true_type propagate_on_container_move_assignment; + typedef true_type is_always_equal; + + template + struct rebind { + typedef default_allocator other; + }; + +#if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) + default_allocator() = default; +#else + BOOST_CONSTEXPR default_allocator() BOOST_NOEXCEPT { } +#endif + + template + BOOST_CONSTEXPR default_allocator(const default_allocator&) + BOOST_NOEXCEPT { } + +#if defined(PTRDIFF_MAX) && defined(SIZE_MAX) + BOOST_CONSTEXPR std::size_t max_size() const BOOST_NOEXCEPT { + return PTRDIFF_MAX < SIZE_MAX / sizeof(T) + ? PTRDIFF_MAX : SIZE_MAX / sizeof(T); + } +#else + BOOST_CONSTEXPR std::size_t max_size() const BOOST_NOEXCEPT { + return ~static_cast(0) / sizeof(T); + } +#endif + +#if !defined(BOOST_NO_EXCEPTIONS) + T* allocate(std::size_t n) { + if (n > max_size()) { + throw std::bad_alloc(); + } + return static_cast(::operator new(sizeof(T) * n)); + } + + void deallocate(T* p, std::size_t) { + ::operator delete(p); + } +#else + T* allocate(std::size_t n) { + if (n > max_size()) { + boost::throw_exception(std::bad_alloc()); + } + void* p = ::operator new(sizeof(T) * n, std::nothrow); + if (!p) { + boost::throw_exception(std::bad_alloc()); + } + return static_cast(p); + } + + void deallocate(T* p, std::size_t) { + ::operator delete(p, std::nothrow); + } +#endif + +#if defined(BOOST_NO_CXX11_ALLOCATOR) || defined(BOOST_CORE_NO_CXX11_ALLOCATOR) + template + void construct(U* p, const V& v) { + ::new(p) U(v); + } + + template + void destroy(U* p) { + p->~U(); + } +#endif +}; + +template +BOOST_CONSTEXPR inline bool +operator==(const default_allocator&, + const default_allocator&) BOOST_NOEXCEPT +{ + return true; +} + +template +BOOST_CONSTEXPR inline bool +operator!=(const default_allocator&, + const default_allocator&) BOOST_NOEXCEPT +{ + return false; +} + +} /* default_ */ + +using default_::default_allocator; + +} /* boost */ + +#endif diff --git a/boost/core/first_scalar.hpp b/boost/core/first_scalar.hpp new file mode 100644 index 0000000..5373542 --- /dev/null +++ b/boost/core/first_scalar.hpp @@ -0,0 +1,45 @@ +/* +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_CORE_FIRST_SCALAR_HPP +#define BOOST_CORE_FIRST_SCALAR_HPP + +#include +#include + +namespace boost { +namespace detail { + +template +struct make_scalar { + typedef T type; +}; + +template +struct make_scalar { + typedef typename make_scalar::type type; +}; + +} /* detail */ + +template +BOOST_CONSTEXPR inline T* +first_scalar(T* p) BOOST_NOEXCEPT +{ + return p; +} + +template +BOOST_CONSTEXPR inline typename detail::make_scalar::type* +first_scalar(T (*p)[N]) BOOST_NOEXCEPT +{ + return boost::first_scalar(&(*p)[0]); +} + +} /* boost */ + +#endif diff --git a/boost/core/ignore_unused.hpp b/boost/core/ignore_unused.hpp new file mode 100644 index 0000000..994e5f6 --- /dev/null +++ b/boost/core/ignore_unused.hpp @@ -0,0 +1,70 @@ +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. +// +// Use, modification and distribution is subject to 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_CORE_IGNORE_UNUSED_HPP +#define BOOST_CORE_IGNORE_UNUSED_HPP + +#include + +namespace boost { + +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + +template +BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR void ignore_unused(Ts const& ...) +{} + +template +BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR void ignore_unused() +{} + +#else + +template +BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR void ignore_unused(T1 const&) +{} + +template +BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR void ignore_unused(T1 const&, T2 const&) +{} + +template +BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR void ignore_unused(T1 const&, T2 const&, T3 const&) +{} + +template +BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR void ignore_unused(T1 const&, T2 const&, T3 const&, T4 const&) +{} + +template +BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR void ignore_unused(T1 const&, T2 const&, T3 const&, T4 const&, T5 const&) +{} + +template +BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR void ignore_unused() +{} + +template +BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR void ignore_unused() +{} + +template +BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR void ignore_unused() +{} + +template +BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR void ignore_unused() +{} + +template +BOOST_FORCEINLINE BOOST_CXX14_CONSTEXPR void ignore_unused() +{} + +#endif + +} // namespace boost + +#endif // BOOST_CORE_IGNORE_UNUSED_HPP diff --git a/boost/core/noinit_adaptor.hpp b/boost/core/noinit_adaptor.hpp new file mode 100644 index 0000000..22c9aab --- /dev/null +++ b/boost/core/noinit_adaptor.hpp @@ -0,0 +1,112 @@ +/* +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_CORE_NOINIT_ADAPTOR_HPP +#define BOOST_CORE_NOINIT_ADAPTOR_HPP + +#include +#if !defined(BOOST_NO_CXX11_ALLOCATOR) +#include +#endif +#include +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#include +#endif + +namespace boost { + +template +struct noinit_adaptor + : A { + template + struct rebind { +#if !defined(BOOST_NO_CXX11_ALLOCATOR) + typedef noinit_adaptor::template + rebind_alloc > other; +#else + typedef noinit_adaptor::other> other; +#endif + }; + + noinit_adaptor() + : A() { } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + noinit_adaptor(U&& u) BOOST_NOEXCEPT + : A(std::forward(u)) { } +#else + template + noinit_adaptor(const U& u) BOOST_NOEXCEPT + : A(u) { } +#endif + + template + noinit_adaptor(const noinit_adaptor& u) BOOST_NOEXCEPT + : A(static_cast(u)) { } + + template + void construct(U* p) { + ::new((void*)p) U; + } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + void construct(U* p, V&& v, Args&&... args) { + ::new((void*)p) U(std::forward(v), std::forward(args)...); + } +#else + template + void construct(U* p, V&& v) { + ::new((void*)p) U(std::forward(v)); + } +#endif +#else + template + void construct(U* p, const V& v) { + ::new((void*)p) U(v); + } + + template + void construct(U* p, V& v) { + ::new((void*)p) U(v); + } +#endif + + template + void destroy(U* p) { + p->~U(); + } +}; + +template +inline bool +operator==(const noinit_adaptor& lhs, + const noinit_adaptor& rhs) BOOST_NOEXCEPT +{ + return static_cast(lhs) == static_cast(rhs); +} + +template +inline bool +operator!=(const noinit_adaptor& lhs, + const noinit_adaptor& rhs) BOOST_NOEXCEPT +{ + return !(lhs == rhs); +} + +template +inline noinit_adaptor +noinit_adapt(const A& a) BOOST_NOEXCEPT +{ + return noinit_adaptor(a); +} + +} /* boost */ + +#endif diff --git a/boost/core/scoped_enum.hpp b/boost/core/scoped_enum.hpp new file mode 100644 index 0000000..56dd0ed --- /dev/null +++ b/boost/core/scoped_enum.hpp @@ -0,0 +1,194 @@ +// scoped_enum.hpp ---------------------------------------------------------// + +// Copyright Beman Dawes, 2009 +// Copyright (C) 2011-2012 Vicente J. Botet Escriba +// Copyright (C) 2012 Anthony Williams + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CORE_SCOPED_ENUM_HPP +#define BOOST_CORE_SCOPED_ENUM_HPP + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost +{ + +#ifdef BOOST_NO_CXX11_SCOPED_ENUMS + + /** + * Meta-function to get the native enum type associated to an enum class or its emulation. + */ + template + struct native_type + { + /** + * The member typedef type names the native enum type associated to the scoped enum, + * which is it self if the compiler supports scoped enums or EnumType::enum_type if it is an emulated scoped enum. + */ + typedef typename EnumType::enum_type type; + }; + + /** + * Casts a scoped enum to its underlying type. + * + * This function is useful when working with scoped enum classes, which doens't implicitly convert to the underlying type. + * @param v A scoped enum. + * @returns The underlying type. + * @throws No-throws. + */ + template + inline + BOOST_CONSTEXPR UnderlyingType underlying_cast(EnumType v) BOOST_NOEXCEPT + { + return v.get_underlying_value_(); + } + + /** + * Casts a scoped enum to its native enum type. + * + * This function is useful to make programs portable when the scoped enum emulation can not be use where native enums can. + * + * EnumType the scoped enum type + * + * @param v A scoped enum. + * @returns The native enum value. + * @throws No-throws. + */ + template + inline + BOOST_CONSTEXPR typename EnumType::enum_type native_value(EnumType e) BOOST_NOEXCEPT + { + return e.get_native_value_(); + } + +#else // BOOST_NO_CXX11_SCOPED_ENUMS + + template + struct native_type + { + typedef EnumType type; + }; + + template + inline + BOOST_CONSTEXPR UnderlyingType underlying_cast(EnumType v) BOOST_NOEXCEPT + { + return static_cast(v); + } + + template + inline + BOOST_CONSTEXPR EnumType native_value(EnumType e) BOOST_NOEXCEPT + { + return e; + } + +#endif // BOOST_NO_CXX11_SCOPED_ENUMS +} + + +#ifdef BOOST_NO_CXX11_SCOPED_ENUMS + +#ifndef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS + +#define BOOST_SCOPED_ENUM_UT_DECLARE_CONVERSION_OPERATOR \ + explicit BOOST_CONSTEXPR operator underlying_type() const BOOST_NOEXCEPT { return get_underlying_value_(); } + +#else + +#define BOOST_SCOPED_ENUM_UT_DECLARE_CONVERSION_OPERATOR + +#endif + +/** + * Start a declaration of a scoped enum. + * + * @param EnumType The new scoped enum. + * @param UnderlyingType The underlying type. + */ +#define BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(EnumType, UnderlyingType) \ + struct EnumType { \ + typedef void is_boost_scoped_enum_tag; \ + typedef UnderlyingType underlying_type; \ + EnumType() BOOST_NOEXCEPT {} \ + explicit BOOST_CONSTEXPR EnumType(underlying_type v) BOOST_NOEXCEPT : v_(v) {} \ + BOOST_CONSTEXPR underlying_type get_underlying_value_() const BOOST_NOEXCEPT { return v_; } \ + BOOST_SCOPED_ENUM_UT_DECLARE_CONVERSION_OPERATOR \ + private: \ + underlying_type v_; \ + typedef EnumType self_type; \ + public: \ + enum enum_type + +#define BOOST_SCOPED_ENUM_DECLARE_END2() \ + BOOST_CONSTEXPR enum_type get_native_value_() const BOOST_NOEXCEPT { return enum_type(v_); } \ + friend BOOST_CONSTEXPR bool operator ==(self_type lhs, self_type rhs) BOOST_NOEXCEPT { return enum_type(lhs.v_)==enum_type(rhs.v_); } \ + friend BOOST_CONSTEXPR bool operator ==(self_type lhs, enum_type rhs) BOOST_NOEXCEPT { return enum_type(lhs.v_)==rhs; } \ + friend BOOST_CONSTEXPR bool operator ==(enum_type lhs, self_type rhs) BOOST_NOEXCEPT { return lhs==enum_type(rhs.v_); } \ + friend BOOST_CONSTEXPR bool operator !=(self_type lhs, self_type rhs) BOOST_NOEXCEPT { return enum_type(lhs.v_)!=enum_type(rhs.v_); } \ + friend BOOST_CONSTEXPR bool operator !=(self_type lhs, enum_type rhs) BOOST_NOEXCEPT { return enum_type(lhs.v_)!=rhs; } \ + friend BOOST_CONSTEXPR bool operator !=(enum_type lhs, self_type rhs) BOOST_NOEXCEPT { return lhs!=enum_type(rhs.v_); } \ + friend BOOST_CONSTEXPR bool operator <(self_type lhs, self_type rhs) BOOST_NOEXCEPT { return enum_type(lhs.v_)(self_type lhs, self_type rhs) BOOST_NOEXCEPT { return enum_type(lhs.v_)>enum_type(rhs.v_); } \ + friend BOOST_CONSTEXPR bool operator >(self_type lhs, enum_type rhs) BOOST_NOEXCEPT { return enum_type(lhs.v_)>rhs; } \ + friend BOOST_CONSTEXPR bool operator >(enum_type lhs, self_type rhs) BOOST_NOEXCEPT { return lhs>enum_type(rhs.v_); } \ + friend BOOST_CONSTEXPR bool operator >=(self_type lhs, self_type rhs) BOOST_NOEXCEPT { return enum_type(lhs.v_)>=enum_type(rhs.v_); } \ + friend BOOST_CONSTEXPR bool operator >=(self_type lhs, enum_type rhs) BOOST_NOEXCEPT { return enum_type(lhs.v_)>=rhs; } \ + friend BOOST_CONSTEXPR bool operator >=(enum_type lhs, self_type rhs) BOOST_NOEXCEPT { return lhs>=enum_type(rhs.v_); } \ + }; + +#define BOOST_SCOPED_ENUM_DECLARE_END(EnumType) \ + ; \ + BOOST_CONSTEXPR EnumType(enum_type v) BOOST_NOEXCEPT : v_(v) {} \ + BOOST_SCOPED_ENUM_DECLARE_END2() + +/** + * Starts a declaration of a scoped enum with the default int underlying type. + * + * @param EnumType The new scoped enum. + */ +#define BOOST_SCOPED_ENUM_DECLARE_BEGIN(EnumType) \ + BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(EnumType,int) + +/** + * Name of the native enum type. + * + * @param EnumType The new scoped enum. + */ +#define BOOST_SCOPED_ENUM_NATIVE(EnumType) EnumType::enum_type +/** + * Forward declares an scoped enum. + * + * @param EnumType The scoped enum. + */ +#define BOOST_SCOPED_ENUM_FORWARD_DECLARE(EnumType) struct EnumType + +#else // BOOST_NO_CXX11_SCOPED_ENUMS + +#define BOOST_SCOPED_ENUM_UT_DECLARE_BEGIN(EnumType,UnderlyingType) enum class EnumType : UnderlyingType +#define BOOST_SCOPED_ENUM_DECLARE_BEGIN(EnumType) enum class EnumType +#define BOOST_SCOPED_ENUM_DECLARE_END2() +#define BOOST_SCOPED_ENUM_DECLARE_END(EnumType) ; + +#define BOOST_SCOPED_ENUM_NATIVE(EnumType) EnumType +#define BOOST_SCOPED_ENUM_FORWARD_DECLARE(EnumType) enum class EnumType + +#endif // BOOST_NO_CXX11_SCOPED_ENUMS + +// Deprecated macros +#define BOOST_SCOPED_ENUM_START(name) BOOST_SCOPED_ENUM_DECLARE_BEGIN(name) +#define BOOST_SCOPED_ENUM_END BOOST_SCOPED_ENUM_DECLARE_END2() +#define BOOST_SCOPED_ENUM(name) BOOST_SCOPED_ENUM_NATIVE(name) + +#endif // BOOST_CORE_SCOPED_ENUM_HPP diff --git a/boost/cstdint.hpp b/boost/cstdint.hpp index c8474c4..9c88d13 100644 --- a/boost/cstdint.hpp +++ b/boost/cstdint.hpp @@ -52,9 +52,9 @@ // so we disable use of stdint.h when GLIBC does not define __GLIBC_HAVE_LONG_LONG. // See https://svn.boost.org/trac/boost/ticket/3548 and http://sources.redhat.com/bugzilla/show_bug.cgi?id=10990 // -#if defined(BOOST_HAS_STDINT_H) \ - && (!defined(__GLIBC__) \ - || defined(__GLIBC_HAVE_LONG_LONG) \ +#if defined(BOOST_HAS_STDINT_H) \ + && (!defined(__GLIBC__) \ + || defined(__GLIBC_HAVE_LONG_LONG) \ || (defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 17))))) // The following #include is an implementation artifact; not part of interface. diff --git a/boost/date_time/constrained_value.hpp b/boost/date_time/constrained_value.hpp index b1122d7..cba6461 100644 --- a/boost/date_time/constrained_value.hpp +++ b/boost/date_time/constrained_value.hpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include namespace boost { @@ -95,8 +95,8 @@ namespace CV { } }; - typedef typename mpl::if_< - is_base_of< std::exception, exception_type >, + typedef typename conditional< + is_base_of< std::exception, exception_type >::value, exception_type, exception_wrapper >::type actual_exception_type; diff --git a/boost/date_time/time.hpp b/boost/date_time/time.hpp index 632f10d..1eafe88 100644 --- a/boost/date_time/time.hpp +++ b/boost/date_time/time.hpp @@ -164,7 +164,7 @@ namespace date_time { } time_type operator+=(const time_duration_type& td) { - time_ = (time_system::get_time_rep(date(), time_of_day() + td)); + time_ = time_system::add_time_duration(time_,td); return time_type(time_); } //! subtract time durations @@ -174,7 +174,7 @@ namespace date_time { } time_type operator-=(const time_duration_type& td) { - time_ = (time_system::get_time_rep(date(), time_of_day() - td)); + time_ = time_system::subtract_time_duration(time_, td); return time_type(time_); } diff --git a/boost/date_time/time_duration.hpp b/boost/date_time/time_duration.hpp index c52779b..161ee68 100644 --- a/boost/date_time/time_duration.hpp +++ b/boost/date_time/time_duration.hpp @@ -144,10 +144,26 @@ namespace date_time { { return duration_type(ticks_ * (-1)); } + duration_type abs() const + { + if ( is_negative() ) + { + return invert_sign(); + } + return duration_type(ticks_); + } bool is_negative() const { return ticks_ < 0; } + bool is_zero() const + { + return ticks_ == 0; + } + bool is_positive() const + { + return ticks_ > 0; + } bool operator<(const time_duration& rhs) const { return ticks_ < rhs.ticks_; diff --git a/boost/detail/interlocked.hpp b/boost/detail/interlocked.hpp new file mode 100644 index 0000000..8084857 --- /dev/null +++ b/boost/detail/interlocked.hpp @@ -0,0 +1,273 @@ +#ifndef BOOST_DETAIL_INTERLOCKED_HPP_INCLUDED +#define BOOST_DETAIL_INTERLOCKED_HPP_INCLUDED + +// +// boost/detail/interlocked.hpp +// +// Copyright 2005 Peter Dimov +// Copyright 2018, 2019 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// BOOST_INTERLOCKED_HAS_INTRIN_H + +// VC9 has intrin.h, but it collides with +#if defined( BOOST_MSVC ) && BOOST_MSVC >= 1600 + +# define BOOST_INTERLOCKED_HAS_INTRIN_H + +// Unlike __MINGW64__, __MINGW64_VERSION_MAJOR is defined by MinGW-w64 for both 32 and 64-bit targets. +#elif defined( __MINGW64_VERSION_MAJOR ) + +// MinGW-w64 provides intrin.h for both 32 and 64-bit targets. +# define BOOST_INTERLOCKED_HAS_INTRIN_H + +#elif defined( __CYGWIN__ ) + +// Cygwin and Cygwin64 provide intrin.h. On Cygwin64 we have to use intrin.h because it's an LP64 target, +// where long is 64-bit and therefore _Interlocked* functions have different signatures. +# define BOOST_INTERLOCKED_HAS_INTRIN_H + +// Intel C++ on Windows on VC10+ stdlib +#elif defined( BOOST_INTEL_WIN ) && defined( _CPPLIB_VER ) && _CPPLIB_VER >= 520 + +# define BOOST_INTERLOCKED_HAS_INTRIN_H + +// clang-cl on Windows on VC10+ stdlib +#elif defined( __clang__ ) && defined( _MSC_VER ) && defined( _CPPLIB_VER ) && _CPPLIB_VER >= 520 + +# define BOOST_INTERLOCKED_HAS_INTRIN_H + +#endif + +#if !defined(__LP64__) +#define BOOST_INTERLOCKED_LONG32 long +#else +#define BOOST_INTERLOCKED_LONG32 int +#endif + +#if defined( BOOST_USE_WINDOWS_H ) + +# include + +# define BOOST_INTERLOCKED_INCREMENT(dest) \ + InterlockedIncrement((BOOST_INTERLOCKED_LONG32*)(dest)) +# define BOOST_INTERLOCKED_DECREMENT(dest) \ + InterlockedDecrement((BOOST_INTERLOCKED_LONG32*)(dest)) +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) \ + InterlockedCompareExchange((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange), (BOOST_INTERLOCKED_LONG32)(compare)) +# define BOOST_INTERLOCKED_EXCHANGE(dest, exchange) \ + InterlockedExchange((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange)) +# define BOOST_INTERLOCKED_EXCHANGE_ADD(dest, add) \ + InterlockedExchangeAdd((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(add)) +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) \ + InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +# define BOOST_INTERLOCKED_EXCHANGE_POINTER(dest, exchange) \ + InterlockedExchangePointer((void**)(dest), (void*)(exchange)) + +#elif defined( BOOST_USE_INTRIN_H ) || defined( BOOST_INTERLOCKED_HAS_INTRIN_H ) + +#include + +# define BOOST_INTERLOCKED_INCREMENT(dest) \ + _InterlockedIncrement((BOOST_INTERLOCKED_LONG32*)(dest)) +# define BOOST_INTERLOCKED_DECREMENT(dest) \ + _InterlockedDecrement((BOOST_INTERLOCKED_LONG32*)(dest)) +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) \ + _InterlockedCompareExchange((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange), (BOOST_INTERLOCKED_LONG32)(compare)) +# define BOOST_INTERLOCKED_EXCHANGE(dest, exchange) \ + _InterlockedExchange((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange)) +# define BOOST_INTERLOCKED_EXCHANGE_ADD(dest, add) \ + _InterlockedExchangeAdd((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(add)) + +// Note: Though MSVC-12 defines _InterlockedCompareExchangePointer and _InterlockedExchangePointer in intrin.h, the latter +// is actually broken as it conflicts with winnt.h from Windows SDK 8.1. +# if (defined(_MSC_VER) && _MSC_VER >= 1900) || \ + (defined(_M_IA64) || defined(_M_AMD64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_ARM64)) + +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) \ + _InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +# define BOOST_INTERLOCKED_EXCHANGE_POINTER(dest, exchange) \ + _InterlockedExchangePointer((void**)(dest), (void*)(exchange)) + +# else + +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) \ + ((void*)BOOST_INTERLOCKED_COMPARE_EXCHANGE((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange), (BOOST_INTERLOCKED_LONG32)(compare))) +# define BOOST_INTERLOCKED_EXCHANGE_POINTER(dest, exchange) \ + ((void*)BOOST_INTERLOCKED_EXCHANGE((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange))) + +# endif + +#elif defined(_WIN32_WCE) + +#if _WIN32_WCE >= 0x600 + +extern "C" BOOST_INTERLOCKED_LONG32 __cdecl _InterlockedIncrement( BOOST_INTERLOCKED_LONG32 volatile * ); +extern "C" BOOST_INTERLOCKED_LONG32 __cdecl _InterlockedDecrement( BOOST_INTERLOCKED_LONG32 volatile * ); +extern "C" BOOST_INTERLOCKED_LONG32 __cdecl _InterlockedCompareExchange( BOOST_INTERLOCKED_LONG32 volatile *, BOOST_INTERLOCKED_LONG32, BOOST_INTERLOCKED_LONG32 ); +extern "C" BOOST_INTERLOCKED_LONG32 __cdecl _InterlockedExchange( BOOST_INTERLOCKED_LONG32 volatile *, BOOST_INTERLOCKED_LONG32 ); +extern "C" BOOST_INTERLOCKED_LONG32 __cdecl _InterlockedExchangeAdd( BOOST_INTERLOCKED_LONG32 volatile *, BOOST_INTERLOCKED_LONG32 ); + +# define BOOST_INTERLOCKED_INCREMENT(dest) \ + _InterlockedIncrement((BOOST_INTERLOCKED_LONG32*)(dest)) +# define BOOST_INTERLOCKED_DECREMENT(dest) \ + _InterlockedDecrement((BOOST_INTERLOCKED_LONG32*)(dest)) +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) \ + _InterlockedCompareExchange((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange), (BOOST_INTERLOCKED_LONG32)(compare)) +# define BOOST_INTERLOCKED_EXCHANGE(dest, exchange) \ + _InterlockedExchange((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange)) +# define BOOST_INTERLOCKED_EXCHANGE_ADD(dest, add) \ + _InterlockedExchangeAdd((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(add)) + +#else // _WIN32_WCE >= 0x600 + +// under Windows CE we still have old-style Interlocked* functions + +extern "C" BOOST_INTERLOCKED_LONG32 __cdecl InterlockedIncrement( BOOST_INTERLOCKED_LONG32 * ); +extern "C" BOOST_INTERLOCKED_LONG32 __cdecl InterlockedDecrement( BOOST_INTERLOCKED_LONG32 * ); +extern "C" BOOST_INTERLOCKED_LONG32 __cdecl InterlockedCompareExchange( BOOST_INTERLOCKED_LONG32 *, BOOST_INTERLOCKED_LONG32, BOOST_INTERLOCKED_LONG32 ); +extern "C" BOOST_INTERLOCKED_LONG32 __cdecl InterlockedExchange( BOOST_INTERLOCKED_LONG32 *, BOOST_INTERLOCKED_LONG32 ); +extern "C" BOOST_INTERLOCKED_LONG32 __cdecl InterlockedExchangeAdd( BOOST_INTERLOCKED_LONG32 *, BOOST_INTERLOCKED_LONG32 ); + +# define BOOST_INTERLOCKED_INCREMENT(dest) \ + InterlockedIncrement((BOOST_INTERLOCKED_LONG32*)(dest)) +# define BOOST_INTERLOCKED_DECREMENT(dest) \ + InterlockedDecrement((BOOST_INTERLOCKED_LONG32*)(dest)) +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) \ + InterlockedCompareExchange((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange), (BOOST_INTERLOCKED_LONG32)(compare)) +# define BOOST_INTERLOCKED_EXCHANGE(dest, exchange) \ + InterlockedExchange((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange)) +# define BOOST_INTERLOCKED_EXCHANGE_ADD(dest, add) \ + InterlockedExchangeAdd((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(add)) + +#endif // _WIN32_WCE >= 0x600 + +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) \ + ((void*)BOOST_INTERLOCKED_COMPARE_EXCHANGE((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange), (BOOST_INTERLOCKED_LONG32)(compare))) +# define BOOST_INTERLOCKED_EXCHANGE_POINTER(dest, exchange) \ + ((void*)BOOST_INTERLOCKED_EXCHANGE((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange))) + +#elif defined( BOOST_MSVC ) || defined( BOOST_INTEL_WIN ) + +# if defined( __CLRCALL_PURE_OR_CDECL ) +# define BOOST_INTERLOCKED_CLRCALL_PURE_OR_CDECL __CLRCALL_PURE_OR_CDECL +# else +# define BOOST_INTERLOCKED_CLRCALL_PURE_OR_CDECL __cdecl +# endif + +extern "C" BOOST_INTERLOCKED_LONG32 BOOST_INTERLOCKED_CLRCALL_PURE_OR_CDECL _InterlockedIncrement( BOOST_INTERLOCKED_LONG32 volatile * ); +extern "C" BOOST_INTERLOCKED_LONG32 BOOST_INTERLOCKED_CLRCALL_PURE_OR_CDECL _InterlockedDecrement( BOOST_INTERLOCKED_LONG32 volatile * ); +extern "C" BOOST_INTERLOCKED_LONG32 BOOST_INTERLOCKED_CLRCALL_PURE_OR_CDECL _InterlockedCompareExchange( BOOST_INTERLOCKED_LONG32 volatile *, BOOST_INTERLOCKED_LONG32, BOOST_INTERLOCKED_LONG32 ); +extern "C" BOOST_INTERLOCKED_LONG32 BOOST_INTERLOCKED_CLRCALL_PURE_OR_CDECL _InterlockedExchange( BOOST_INTERLOCKED_LONG32 volatile *, BOOST_INTERLOCKED_LONG32 ); +extern "C" BOOST_INTERLOCKED_LONG32 BOOST_INTERLOCKED_CLRCALL_PURE_OR_CDECL _InterlockedExchangeAdd( BOOST_INTERLOCKED_LONG32 volatile *, BOOST_INTERLOCKED_LONG32 ); + +# if defined( BOOST_MSVC ) && BOOST_MSVC >= 1310 +# pragma intrinsic( _InterlockedIncrement ) +# pragma intrinsic( _InterlockedDecrement ) +# pragma intrinsic( _InterlockedCompareExchange ) +# pragma intrinsic( _InterlockedExchange ) +# pragma intrinsic( _InterlockedExchangeAdd ) +# endif + +# if defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM64) + +extern "C" void* BOOST_INTERLOCKED_CLRCALL_PURE_OR_CDECL _InterlockedCompareExchangePointer( void* volatile *, void*, void* ); +extern "C" void* BOOST_INTERLOCKED_CLRCALL_PURE_OR_CDECL _InterlockedExchangePointer( void* volatile *, void* ); + +# if defined( BOOST_MSVC ) && BOOST_MSVC >= 1310 +# pragma intrinsic( _InterlockedCompareExchangePointer ) +# pragma intrinsic( _InterlockedExchangePointer ) +# endif + +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) \ + _InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +# define BOOST_INTERLOCKED_EXCHANGE_POINTER(dest, exchange) \ + _InterlockedExchangePointer((void**)(dest), (void*)(exchange)) + +# else + +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) \ + ((void*)BOOST_INTERLOCKED_COMPARE_EXCHANGE((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange), (BOOST_INTERLOCKED_LONG32)(compare))) +# define BOOST_INTERLOCKED_EXCHANGE_POINTER(dest, exchange) \ + ((void*)BOOST_INTERLOCKED_EXCHANGE((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange))) + +# endif + +# undef BOOST_INTERLOCKED_CLRCALL_PURE_OR_CDECL + +# define BOOST_INTERLOCKED_INCREMENT(dest) \ + _InterlockedIncrement((BOOST_INTERLOCKED_LONG32*)(dest)) +# define BOOST_INTERLOCKED_DECREMENT(dest) \ + _InterlockedDecrement((BOOST_INTERLOCKED_LONG32*)(dest)) +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) \ + _InterlockedCompareExchange((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange), (BOOST_INTERLOCKED_LONG32)(compare)) +# define BOOST_INTERLOCKED_EXCHANGE(dest, exchange) \ + _InterlockedExchange((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange)) +# define BOOST_INTERLOCKED_EXCHANGE_ADD(dest, add) \ + _InterlockedExchangeAdd((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(add)) + +#elif defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ ) + +#define BOOST_INTERLOCKED_IMPORT __declspec(dllimport) + +namespace boost +{ + +namespace detail +{ + +extern "C" BOOST_INTERLOCKED_IMPORT BOOST_INTERLOCKED_LONG32 __stdcall InterlockedIncrement( BOOST_INTERLOCKED_LONG32 volatile * ); +extern "C" BOOST_INTERLOCKED_IMPORT BOOST_INTERLOCKED_LONG32 __stdcall InterlockedDecrement( BOOST_INTERLOCKED_LONG32 volatile * ); +extern "C" BOOST_INTERLOCKED_IMPORT BOOST_INTERLOCKED_LONG32 __stdcall InterlockedCompareExchange( BOOST_INTERLOCKED_LONG32 volatile *, BOOST_INTERLOCKED_LONG32, BOOST_INTERLOCKED_LONG32 ); +extern "C" BOOST_INTERLOCKED_IMPORT BOOST_INTERLOCKED_LONG32 __stdcall InterlockedExchange( BOOST_INTERLOCKED_LONG32 volatile *, BOOST_INTERLOCKED_LONG32 ); +extern "C" BOOST_INTERLOCKED_IMPORT BOOST_INTERLOCKED_LONG32 __stdcall InterlockedExchangeAdd( BOOST_INTERLOCKED_LONG32 volatile *, BOOST_INTERLOCKED_LONG32 ); + +# if defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM64) +extern "C" BOOST_INTERLOCKED_IMPORT void* __stdcall InterlockedCompareExchangePointer( void* volatile *, void*, void* ); +extern "C" BOOST_INTERLOCKED_IMPORT void* __stdcall InterlockedExchangePointer( void* volatile *, void* ); +# endif + +} // namespace detail + +} // namespace boost + +# define BOOST_INTERLOCKED_INCREMENT(dest) \ + ::boost::detail::InterlockedIncrement((BOOST_INTERLOCKED_LONG32*)(dest)) +# define BOOST_INTERLOCKED_DECREMENT(dest) \ + ::boost::detail::InterlockedDecrement((BOOST_INTERLOCKED_LONG32*)(dest)) +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) \ + ::boost::detail::InterlockedCompareExchange((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange), (BOOST_INTERLOCKED_LONG32)(compare)) +# define BOOST_INTERLOCKED_EXCHANGE(dest, exchange) \ + ::boost::detail::InterlockedExchange((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(exchange)) +# define BOOST_INTERLOCKED_EXCHANGE_ADD(dest, add) \ + ::boost::detail::InterlockedExchangeAdd((BOOST_INTERLOCKED_LONG32*)(dest), (BOOST_INTERLOCKED_LONG32)(add)) + +# if defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM64) +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) \ + ::boost::detail::InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +# define BOOST_INTERLOCKED_EXCHANGE_POINTER(dest, exchange) \ + ::boost::detail::InterlockedExchangePointer((void**)(dest), (void*)(exchange)) +# else +# define BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) \ + ((void*)BOOST_INTERLOCKED_COMPARE_EXCHANGE((BOOST_INTERLOCKED_LONG32 volatile*)(dest),(BOOST_INTERLOCKED_LONG32)(exchange),(BOOST_INTERLOCKED_LONG32)(compare))) +# define BOOST_INTERLOCKED_EXCHANGE_POINTER(dest, exchange) \ + ((void*)BOOST_INTERLOCKED_EXCHANGE((BOOST_INTERLOCKED_LONG32*)(dest),(BOOST_INTERLOCKED_LONG32)(exchange))) +# endif + +#else + +# error "Interlocked intrinsics not available" + +#endif + +#endif // #ifndef BOOST_DETAIL_INTERLOCKED_HPP_INCLUDED diff --git a/boost/detail/scoped_enum_emulation.hpp b/boost/detail/scoped_enum_emulation.hpp new file mode 100644 index 0000000..1c7bc23 --- /dev/null +++ b/boost/detail/scoped_enum_emulation.hpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2014 Andrey Semashev + * + * 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_DETAIL_SCOPED_ENUM_EMULATION_HPP +#define BOOST_DETAIL_SCOPED_ENUM_EMULATION_HPP + +// The header file at this path is deprecated; +// use boost/core/scoped_enum.hpp instead. + +#include + +#endif diff --git a/boost/detail/winapi/time.hpp b/boost/detail/winapi/time.hpp new file mode 100644 index 0000000..a6d728a --- /dev/null +++ b/boost/detail/winapi/time.hpp @@ -0,0 +1,20 @@ +/* + * Copyright 2017 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + * + * This header is deprecated, use boost/winapi/time.hpp instead. + */ + +#ifndef BOOST_DETAIL_WINAPI_TIME_HPP_ +#define BOOST_DETAIL_WINAPI_TIME_HPP_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif // BOOST_DETAIL_WINAPI_TIME_HPP_ diff --git a/boost/detail/winapi/timers.hpp b/boost/detail/winapi/timers.hpp new file mode 100644 index 0000000..4b874e2 --- /dev/null +++ b/boost/detail/winapi/timers.hpp @@ -0,0 +1,20 @@ +/* + * Copyright 2017 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + * + * This header is deprecated, use boost/winapi/timers.hpp instead. + */ + +#ifndef BOOST_DETAIL_WINAPI_TIMERS_HPP +#define BOOST_DETAIL_WINAPI_TIMERS_HPP + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif // BOOST_DETAIL_WINAPI_TIMERS_HPP diff --git a/boost/enable_shared_from_this.hpp b/boost/enable_shared_from_this.hpp new file mode 100644 index 0000000..18b938d --- /dev/null +++ b/boost/enable_shared_from_this.hpp @@ -0,0 +1,18 @@ +#ifndef BOOST_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED +#define BOOST_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED + +// +// enable_shared_from_this.hpp +// +// Copyright (c) 2002 Peter Dimov +// +// 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/libs/smart_ptr/ for documentation. +// + +#include + +#endif // #ifndef BOOST_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED diff --git a/boost/exception/current_exception_cast.hpp b/boost/exception/current_exception_cast.hpp new file mode 100644 index 0000000..5d81f00 --- /dev/null +++ b/boost/exception/current_exception_cast.hpp @@ -0,0 +1,43 @@ +//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_7E83C166200811DE885E826156D89593 +#define UUID_7E83C166200811DE885E826156D89593 +#if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma GCC system_header +#endif +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(push,1) +#endif + +namespace +boost + { + template + inline + E * + current_exception_cast() + { + try + { + throw; + } + catch( + E & e ) + { + return &e; + } + catch( + ...) + { + return 0; + } + } + } + +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(pop) +#endif +#endif diff --git a/boost/exception/detail/clone_current_exception.hpp b/boost/exception/detail/clone_current_exception.hpp new file mode 100644 index 0000000..6fc1374 --- /dev/null +++ b/boost/exception/detail/clone_current_exception.hpp @@ -0,0 +1,56 @@ +//Copyright (c) 2006-2013 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_81522C0EB56511DFAB613DB0DFD72085 +#define UUID_81522C0EB56511DFAB613DB0DFD72085 +#if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma GCC system_header +#endif +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(push,1) +#endif + +#ifdef BOOST_NO_EXCEPTIONS +# error This header requires exception handling to be enabled. +#endif + +namespace +boost + { + namespace + exception_detail + { + class clone_base; + +#ifdef BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR + int clone_current_exception_non_intrusive( clone_base const * & cloned ); +#endif + + namespace + clone_current_exception_result + { + int const success=0; + int const bad_alloc=1; + int const bad_exception=2; + int const not_supported=3; + } + + inline + int + clone_current_exception( clone_base const * & cloned ) + { +#ifdef BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR + return clone_current_exception_non_intrusive(cloned); +#else + return clone_current_exception_result::not_supported; +#endif + } + } + } + +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(pop) +#endif +#endif diff --git a/boost/exception/detail/error_info_impl.hpp b/boost/exception/detail/error_info_impl.hpp new file mode 100644 index 0000000..bef7fd8 --- /dev/null +++ b/boost/exception/detail/error_info_impl.hpp @@ -0,0 +1,102 @@ +//Copyright (c) 2006-2010 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_CE6983AC753411DDA764247956D89593 +#define UUID_CE6983AC753411DDA764247956D89593 + +#include +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#include +#endif +#include +#include + +#if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma GCC system_header +#endif +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(push,1) +#endif + +namespace +boost + { + namespace + exception_detail + { + class + error_info_base + { + public: + + virtual std::string name_value_string() const = 0; + virtual error_info_base * clone() const = 0; + + virtual + ~error_info_base() BOOST_NOEXCEPT_OR_NOTHROW + { + } + }; + } + + template + class + error_info: + public exception_detail::error_info_base + { + exception_detail::error_info_base * + clone() const + { + return new error_info(*this); + } + public: + typedef T value_type; + error_info( value_type const & v ): + v_(v) + { + } +#if (__GNUC__*100+__GNUC_MINOR__!=406) //workaround for g++ bug +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + error_info( error_info const & x ): + v_(x.v_) + { + } + error_info( T && v ) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible::value): + v_(std::move(v)) + { + } + error_info( error_info && x ) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible::value): + v_(std::move(x.v_)) + { + } +#endif +#endif + ~error_info() BOOST_NOEXCEPT_OR_NOTHROW + { + } + value_type const & + value() const + { + return v_; + } + value_type & + value() + { + return v_; + } + private: + error_info & operator=( error_info const & ); +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + error_info & operator=( error_info && x ); +#endif + std::string name_value_string() const; + value_type v_; + }; + } + +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(pop) +#endif +#endif diff --git a/boost/exception/detail/exception_ptr.hpp b/boost/exception/detail/exception_ptr.hpp new file mode 100644 index 0000000..a7f0a25 --- /dev/null +++ b/boost/exception/detail/exception_ptr.hpp @@ -0,0 +1,514 @@ +//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_618474C2DE1511DEB74A388C56D89593 +#define UUID_618474C2DE1511DEB74A388C56D89593 + +#include +#ifdef BOOST_NO_EXCEPTIONS +#error This header requires exception handling to be enabled. +#endif +#include +#include +#include +#include +#include +#ifndef BOOST_NO_RTTI +#include +#endif +#include +#include +#include +#include +#include + +#if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma GCC system_header +#endif +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(push,1) +#endif + +namespace +boost + { + class exception_ptr; + BOOST_NORETURN void rethrow_exception( exception_ptr const & ); + exception_ptr current_exception(); + + class + exception_ptr + { + typedef boost::shared_ptr impl; + impl ptr_; + friend void rethrow_exception( exception_ptr const & ); + typedef exception_detail::clone_base const * (impl::*unspecified_bool_type)() const; + public: + exception_ptr() + { + } + explicit + exception_ptr( impl const & ptr ): + ptr_(ptr) + { + } + bool + operator==( exception_ptr const & other ) const + { + return ptr_==other.ptr_; + } + bool + operator!=( exception_ptr const & other ) const + { + return ptr_!=other.ptr_; + } + operator unspecified_bool_type() const + { + return ptr_?&impl::get:0; + } + }; + + template + inline + exception_ptr + copy_exception( T const & e ) + { + try + { + throw enable_current_exception(e); + } + catch( + ... ) + { + return current_exception(); + } + } + +#ifndef BOOST_NO_RTTI + typedef error_info original_exception_type; + + inline + std::string + to_string( original_exception_type const & x ) + { + return core::demangle(x.value()->name()); + } +#endif + + namespace + exception_detail + { + struct + bad_alloc_: + boost::exception, + std::bad_alloc + { + ~bad_alloc_() BOOST_NOEXCEPT_OR_NOTHROW { } + }; + + struct + bad_exception_: + boost::exception, + std::bad_exception + { + ~bad_exception_() BOOST_NOEXCEPT_OR_NOTHROW { } + }; + + template + exception_ptr + get_static_exception_object() + { + Exception ba; + exception_detail::clone_impl c(ba); +#ifndef BOOST_EXCEPTION_DISABLE + c << + throw_function(BOOST_CURRENT_FUNCTION) << + throw_file(__FILE__) << + throw_line(__LINE__); +#endif + static exception_ptr ep(shared_ptr(new exception_detail::clone_impl(c))); + return ep; + } + + template + struct + exception_ptr_static_exception_object + { + static exception_ptr const e; + }; + + template + exception_ptr const + exception_ptr_static_exception_object:: + e = get_static_exception_object(); + } + +#if defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility push (default) +# endif +#endif + class + unknown_exception: + public boost::exception, + public std::exception + { + public: + + unknown_exception() + { + } + + explicit + unknown_exception( std::exception const & e ) + { + add_original_type(e); + } + + explicit + unknown_exception( boost::exception const & e ): + boost::exception(e) + { + add_original_type(e); + } + + ~unknown_exception() BOOST_NOEXCEPT_OR_NOTHROW + { + } + + private: + + template + void + add_original_type( E const & e ) + { +#ifndef BOOST_NO_RTTI + (*this) << original_exception_type(&typeid(e)); +#endif + } + }; +#if defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility pop +# endif +#endif + + namespace + exception_detail + { + template + class + current_exception_std_exception_wrapper: + public T, + public boost::exception + { + public: + + explicit + current_exception_std_exception_wrapper( T const & e1 ): + T(e1) + { + add_original_type(e1); + } + + current_exception_std_exception_wrapper( T const & e1, boost::exception const & e2 ): + T(e1), + boost::exception(e2) + { + add_original_type(e1); + } + + ~current_exception_std_exception_wrapper() BOOST_NOEXCEPT_OR_NOTHROW + { + } + + private: + + template + void + add_original_type( E const & e ) + { +#ifndef BOOST_NO_RTTI + (*this) << original_exception_type(&typeid(e)); +#endif + } + }; + +#ifdef BOOST_NO_RTTI + template + boost::exception const * + get_boost_exception( T const * ) + { + try + { + throw; + } + catch( + boost::exception & x ) + { + return &x; + } + catch(...) + { + return 0; + } + } +#else + template + boost::exception const * + get_boost_exception( T const * x ) + { + return dynamic_cast(x); + } +#endif + + template + inline + exception_ptr + current_exception_std_exception( T const & e1 ) + { + if( boost::exception const * e2 = get_boost_exception(&e1) ) + return boost::copy_exception(current_exception_std_exception_wrapper(e1,*e2)); + else + return boost::copy_exception(current_exception_std_exception_wrapper(e1)); + } + + inline + exception_ptr + current_exception_unknown_exception() + { + return boost::copy_exception(unknown_exception()); + } + + inline + exception_ptr + current_exception_unknown_boost_exception( boost::exception const & e ) + { + return boost::copy_exception(unknown_exception(e)); + } + + inline + exception_ptr + current_exception_unknown_std_exception( std::exception const & e ) + { + if( boost::exception const * be = get_boost_exception(&e) ) + return current_exception_unknown_boost_exception(*be); + else + return boost::copy_exception(unknown_exception(e)); + } + + inline + exception_ptr + current_exception_impl() + { + exception_detail::clone_base const * e=0; + switch( + exception_detail::clone_current_exception(e) ) + { + case exception_detail::clone_current_exception_result:: + success: + { + BOOST_ASSERT(e!=0); + return exception_ptr(shared_ptr(e)); + } + case exception_detail::clone_current_exception_result:: + bad_alloc: + { + BOOST_ASSERT(!e); + return exception_detail::exception_ptr_static_exception_object::e; + } + case exception_detail::clone_current_exception_result:: + bad_exception: + { + BOOST_ASSERT(!e); + return exception_detail::exception_ptr_static_exception_object::e; + } + default: + BOOST_ASSERT(0); + case exception_detail::clone_current_exception_result:: + not_supported: + { + BOOST_ASSERT(!e); + try + { + throw; + } + catch( + exception_detail::clone_base & e ) + { + return exception_ptr(shared_ptr(e.clone())); + } + catch( + std::domain_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::invalid_argument & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::length_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::out_of_range & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::logic_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::range_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::overflow_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::underflow_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::ios_base::failure & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::runtime_error & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::bad_alloc & e ) + { + return exception_detail::current_exception_std_exception(e); + } + #ifndef BOOST_NO_TYPEID + catch( + std::bad_cast & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::bad_typeid & e ) + { + return exception_detail::current_exception_std_exception(e); + } + #endif + catch( + std::bad_exception & e ) + { + return exception_detail::current_exception_std_exception(e); + } + catch( + std::exception & e ) + { + return exception_detail::current_exception_unknown_std_exception(e); + } + catch( + boost::exception & e ) + { + return exception_detail::current_exception_unknown_boost_exception(e); + } + catch( + ... ) + { + return exception_detail::current_exception_unknown_exception(); + } + } + } + } + } + + inline + exception_ptr + current_exception() + { + exception_ptr ret; + try + { + ret=exception_detail::current_exception_impl(); + } + catch( + std::bad_alloc & ) + { + ret=exception_detail::exception_ptr_static_exception_object::e; + } + catch( + ... ) + { + ret=exception_detail::exception_ptr_static_exception_object::e; + } + BOOST_ASSERT(ret); + return ret; + } + + BOOST_NORETURN + inline + void + rethrow_exception( exception_ptr const & p ) + { + BOOST_ASSERT(p); + p.ptr_->rethrow(); + BOOST_ASSERT(0); + #if defined(UNDER_CE) + // some CE platforms don't define ::abort() + exit(-1); + #else + abort(); + #endif + } + + inline + std::string + diagnostic_information( exception_ptr const & p, bool verbose=true ) + { + if( p ) + try + { + rethrow_exception(p); + } + catch( + ... ) + { + return current_exception_diagnostic_information(verbose); + } + return ""; + } + + inline + std::string + to_string( exception_ptr const & p ) + { + std::string s='\n'+diagnostic_information(p); + std::string padding(" "); + std::string r; + bool f=false; + for( std::string::const_iterator i=s.begin(),e=s.end(); i!=e; ++i ) + { + if( f ) + r+=padding; + char c=*i; + r+=c; + f=(c=='\n'); + } + return r; + } + } + +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(pop) +#endif +#endif diff --git a/boost/exception/detail/is_output_streamable.hpp b/boost/exception/detail/is_output_streamable.hpp new file mode 100644 index 0000000..10e5c51 --- /dev/null +++ b/boost/exception/detail/is_output_streamable.hpp @@ -0,0 +1,61 @@ +//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_898984B4076411DD973EDFA055D89593 +#define UUID_898984B4076411DD973EDFA055D89593 + +#include + +#if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma GCC system_header +#endif +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(push,1) +#endif + +namespace +boost + { + namespace + to_string_detail + { + struct + partial_ordering_helper1 + { + template + partial_ordering_helper1( std::basic_ostream & ); + }; + + struct + partial_ordering_helper2 + { + template + partial_ordering_helper2( T const & ); + }; + + char operator<<( partial_ordering_helper1, partial_ordering_helper2 ); + + template + struct + is_output_streamable_impl + { + static std::basic_ostream & f(); + static T const & g(); + enum e { value=1!=(sizeof(f()< > + struct + is_output_streamable + { + enum e { value=to_string_detail::is_output_streamable_impl::value }; + }; + } + +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(pop) +#endif +#endif diff --git a/boost/exception/detail/object_hex_dump.hpp b/boost/exception/detail/object_hex_dump.hpp new file mode 100644 index 0000000..267bf0b --- /dev/null +++ b/boost/exception/detail/object_hex_dump.hpp @@ -0,0 +1,51 @@ +//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_6F463AC838DF11DDA3E6909F56D89593 +#define UUID_6F463AC838DF11DDA3E6909F56D89593 + +#include +#include +#include +#include +#include +#include + +#if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma GCC system_header +#endif +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(push,1) +#endif + +namespace +boost + { + namespace + exception_detail + { + template + inline + std::string + object_hex_dump( T const & x, std::size_t max_size=16 ) + { + std::ostringstream s; + s << "type: " << type_name() << ", size: " << sizeof(T) << ", dump: "; + std::size_t n=sizeof(T)>max_size?max_size:sizeof(T); + s.fill('0'); + s.width(2); + unsigned char const * b=reinterpret_cast(&x); + s << std::setw(2) << std::hex << (unsigned int)*b; + for( unsigned char const * e=b+n; ++b!=e; ) + s << " " << std::setw(2) << std::hex << (unsigned int)*b; + return s.str(); + } + } + } + +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(pop) +#endif +#endif diff --git a/boost/exception/detail/shared_ptr.hpp b/boost/exception/detail/shared_ptr.hpp new file mode 100644 index 0000000..51febe8 --- /dev/null +++ b/boost/exception/detail/shared_ptr.hpp @@ -0,0 +1,17 @@ +//Copyright (c) 2006-2008 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_837060E885AF11E68DA91D15E31AC075 +#define UUID_837060E885AF11E68DA91D15E31AC075 + +#ifdef BOOST_EXCEPTION_MINI_BOOST +#include +namespace boost { namespace exception_detail { using std::shared_ptr; } } +#else +#include +namespace boost { namespace exception_detail { using boost::shared_ptr; } } +#endif + +#endif diff --git a/boost/exception/detail/type_info.hpp b/boost/exception/detail/type_info.hpp new file mode 100644 index 0000000..739ac57 --- /dev/null +++ b/boost/exception/detail/type_info.hpp @@ -0,0 +1,82 @@ +//Copyright (c) 2006-2010 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_C3E1741C754311DDB2834CCA55D89593 +#define UUID_C3E1741C754311DDB2834CCA55D89593 + +#include +#include +#include +#include +#include + +#if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma GCC system_header +#endif +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(push,1) +#endif + +namespace +boost + { + template + inline + std::string + tag_type_name() + { +#ifdef BOOST_NO_TYPEID + return BOOST_CURRENT_FUNCTION; +#else + return core::demangle(typeid(T*).name()); +#endif + } + + template + inline + std::string + type_name() + { +#ifdef BOOST_NO_TYPEID + return BOOST_CURRENT_FUNCTION; +#else + return core::demangle(typeid(T).name()); +#endif + } + + namespace + exception_detail + { + struct + type_info_ + { + core::typeinfo const * type_; + + explicit + type_info_( core::typeinfo const & type ): + type_(&type) + { + } + + friend + bool + operator<( type_info_ const & a, type_info_ const & b ) + { + return 0!=(a.type_->before(*b.type_)); + } + }; + } + } + +#define BOOST_EXCEPTION_STATIC_TYPEID(T) ::boost::exception_detail::type_info_(BOOST_CORE_TYPEID(T)) + +#ifndef BOOST_NO_RTTI +#define BOOST_EXCEPTION_DYNAMIC_TYPEID(x) ::boost::exception_detail::type_info_(typeid(x)) +#endif + +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(pop) +#endif +#endif diff --git a/boost/exception/diagnostic_information.hpp b/boost/exception/diagnostic_information.hpp new file mode 100644 index 0000000..ad22735 --- /dev/null +++ b/boost/exception/diagnostic_information.hpp @@ -0,0 +1,208 @@ +//Copyright (c) 2006-2010 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_0552D49838DD11DD90146B8956D89593 +#define UUID_0552D49838DD11DD90146B8956D89593 + +#include +#include +#include +#include +#ifndef BOOST_NO_RTTI +#include +#endif +#include +#include +#include +#ifndef BOOST_NO_EXCEPTIONS +#include +#endif + +#if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma GCC system_header +#endif +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(push,1) +#endif + +#ifndef BOOST_NO_EXCEPTIONS +namespace +boost + { + namespace + exception_detail + { + std::string diagnostic_information_impl( boost::exception const *, std::exception const *, bool, bool ); + } + + inline + std::string + current_exception_diagnostic_information( bool verbose=true) + { + boost::exception const * be=current_exception_cast(); + std::exception const * se=current_exception_cast(); + if( be || se ) + return exception_detail::diagnostic_information_impl(be,se,true,verbose); +#if defined(__GLIBCXX__) && __cplusplus >= 201103L && !defined(BOOST_NO_RTTI) + else if (auto* p=std::current_exception().__cxa_exception_type()) + return "Dynamic exception type: "+boost::core::demangle(p->name()); +#endif + else + return "No diagnostic information available."; + } + } +#endif + +namespace +boost + { + namespace + exception_detail + { + inline + exception const * + get_boost_exception( exception const * e ) + { + return e; + } + + inline + exception const * + get_boost_exception( ... ) + { + return 0; + } + + inline + std::exception const * + get_std_exception( std::exception const * e ) + { + return e; + } + + inline + std::exception const * + get_std_exception( ... ) + { + return 0; + } + + inline + char const * + get_diagnostic_information( exception const & x, char const * header ) + { +#ifndef BOOST_NO_EXCEPTIONS + try + { +#endif + error_info_container * c=x.data_.get(); + if( !c ) + x.data_.adopt(c=new exception_detail::error_info_container_impl); + char const * di=c->diagnostic_information(header); + BOOST_ASSERT(di!=0); + return di; +#ifndef BOOST_NO_EXCEPTIONS + } + catch(...) + { + return 0; + } +#endif + } + + inline + std::string + diagnostic_information_impl( boost::exception const * be, std::exception const * se, bool with_what, bool verbose ) + { + if( !be && !se ) + return "Unknown exception."; +#ifndef BOOST_NO_RTTI + if( !be ) + be=dynamic_cast(se); + if( !se ) + se=dynamic_cast(be); +#endif + char const * wh=0; + if( with_what && se ) + { + wh=se->what(); + if( be && exception_detail::get_diagnostic_information(*be,0)==wh ) + return wh; + } + std::ostringstream tmp; + if( be && verbose ) + { + char const * const * f=get_error_info(*be); + int const * l=get_error_info(*be); + char const * const * fn=get_error_info(*be); + if( !f && !l && !fn ) + tmp << "Throw location unknown (consider using BOOST_THROW_EXCEPTION)\n"; + else + { + if( f ) + { + tmp << *f; + if( int const * l=get_error_info(*be) ) + tmp << '(' << *l << "): "; + } + tmp << "Throw in function "; + if( char const * const * fn=get_error_info(*be) ) + tmp << *fn; + else + tmp << "(unknown)"; + tmp << '\n'; + } + } +#ifndef BOOST_NO_RTTI + if ( verbose ) + tmp << std::string("Dynamic exception type: ") << + core::demangle((be?(BOOST_EXCEPTION_DYNAMIC_TYPEID(*be)):(BOOST_EXCEPTION_DYNAMIC_TYPEID(*se))).type_->name()) << '\n'; +#endif + if( with_what && se && verbose ) + tmp << "std::exception::what: " << (wh ? wh : "(null)") << '\n'; + if( be ) + if( char const * s=exception_detail::get_diagnostic_information(*be,tmp.str().c_str()) ) + if( *s ) + return std::string(s); + return tmp.str(); + } + } + + template + std::string + diagnostic_information( T const & e, bool verbose=true ) + { + return exception_detail::diagnostic_information_impl(exception_detail::get_boost_exception(&e),exception_detail::get_std_exception(&e),true,verbose); + } + + inline + char const * + diagnostic_information_what( exception const & e, bool verbose=true ) BOOST_NOEXCEPT_OR_NOTHROW + { + char const * w=0; +#ifndef BOOST_NO_EXCEPTIONS + try + { +#endif + (void) exception_detail::diagnostic_information_impl(&e,0,false,verbose); + if( char const * di=exception_detail::get_diagnostic_information(e,0) ) + return di; + else + return "Failed to produce boost::diagnostic_information_what()"; +#ifndef BOOST_NO_EXCEPTIONS + } + catch( + ... ) + { + } +#endif + return w; + } + } + +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(pop) +#endif +#endif diff --git a/boost/exception/exception.hpp b/boost/exception/exception.hpp index ab78767..5fe3009 100644 --- a/boost/exception/exception.hpp +++ b/boost/exception/exception.hpp @@ -21,6 +21,7 @@ namespace boost { namespace exception_detail { using boost::shared_ptr; } } #endif #if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) #pragma warning(push,1) +#pragma warning(disable: 4265) #endif namespace diff --git a/boost/exception/get_error_info.hpp b/boost/exception/get_error_info.hpp new file mode 100644 index 0000000..831717d --- /dev/null +++ b/boost/exception/get_error_info.hpp @@ -0,0 +1,133 @@ +//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_1A590226753311DD9E4CCF6156D89593 +#define UUID_1A590226753311DD9E4CCF6156D89593 + +#include +#include +#include +#include +#include +#include + +#if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma GCC system_header +#endif +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(push,1) +#endif + +namespace +boost + { + namespace + exception_detail + { + template + struct + get_info + { + static + typename ErrorInfo::value_type * + get( exception const & x ) + { + if( exception_detail::error_info_container * c=x.data_.get() ) + if( shared_ptr eib = c->get(BOOST_EXCEPTION_STATIC_TYPEID(ErrorInfo)) ) + { +#ifndef BOOST_NO_RTTI + BOOST_ASSERT( 0!=dynamic_cast(eib.get()) ); +#endif + ErrorInfo * w = static_cast(eib.get()); + return &w->value(); + } + return 0; + } + }; + + template <> + struct + get_info + { + static + char const * * + get( exception const & x ) + { + return x.throw_function_ ? &x.throw_function_ : 0; + } + }; + + template <> + struct + get_info + { + static + char const * * + get( exception const & x ) + { + return x.throw_file_ ? &x.throw_file_ : 0; + } + }; + + template <> + struct + get_info + { + static + int * + get( exception const & x ) + { + return x.throw_line_!=-1 ? &x.throw_line_ : 0; + } + }; + + template + struct + get_error_info_return_type + { + typedef R * type; + }; + + template + struct + get_error_info_return_type + { + typedef R const * type; + }; + } + +#ifdef BOOST_NO_RTTI + template + inline + typename ErrorInfo::value_type const * + get_error_info( boost::exception const & x ) + { + return exception_detail::get_info::get(x); + } + template + inline + typename ErrorInfo::value_type * + get_error_info( boost::exception & x ) + { + return exception_detail::get_info::get(x); + } +#else + template + inline + typename exception_detail::get_error_info_return_type::type + get_error_info( E & some_exception ) + { + if( exception const * x = dynamic_cast(&some_exception) ) + return exception_detail::get_info::get(*x); + else + return 0; + } +#endif + } + +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(pop) +#endif +#endif diff --git a/boost/exception/info.hpp b/boost/exception/info.hpp new file mode 100644 index 0000000..5e3ad52 --- /dev/null +++ b/boost/exception/info.hpp @@ -0,0 +1,277 @@ +//Copyright (c) 2006-2010 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_8D22C4CA9CC811DCAA9133D256D89593 +#define UUID_8D22C4CA9CC811DCAA9133D256D89593 + +#include +#include +#include +#include +#include +#include + +#if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma GCC system_header +#endif +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(push,1) +#endif + +namespace +boost + { + template + inline + std::string + error_info_name( error_info const & x ) + { + return tag_type_name(); + } + + template + inline + std::string + to_string( error_info const & x ) + { + return '[' + error_info_name(x) + "] = " + to_string_stub(x.value()) + '\n'; + } + + template + inline + std::string + error_info:: + name_value_string() const + { + return to_string_stub(*this); + } + + namespace + exception_detail + { + class + error_info_container_impl: + public error_info_container + { + public: + + error_info_container_impl(): + count_(0) + { + } + + ~error_info_container_impl() BOOST_NOEXCEPT_OR_NOTHROW + { + } + + void + set( shared_ptr const & x, type_info_ const & typeid_ ) + { + BOOST_ASSERT(x); + info_[typeid_] = x; + diagnostic_info_str_.clear(); + } + + shared_ptr + get( type_info_ const & ti ) const + { + error_info_map::const_iterator i=info_.find(ti); + if( info_.end()!=i ) + { + shared_ptr const & p = i->second; +#ifndef BOOST_NO_RTTI + BOOST_ASSERT( *BOOST_EXCEPTION_DYNAMIC_TYPEID(*p).type_==*ti.type_ ); +#endif + return p; + } + return shared_ptr(); + } + + char const * + diagnostic_information( char const * header ) const + { + if( header ) + { + std::ostringstream tmp; + tmp << header; + for( error_info_map::const_iterator i=info_.begin(),end=info_.end(); i!=end; ++i ) + { + error_info_base const & x = *i->second; + tmp << x.name_value_string(); + } + tmp.str().swap(diagnostic_info_str_); + } + return diagnostic_info_str_.c_str(); + } + + private: + + friend class boost::exception; + + typedef std::map< type_info_, shared_ptr > error_info_map; + error_info_map info_; + mutable std::string diagnostic_info_str_; + mutable int count_; + + error_info_container_impl( error_info_container_impl const & ); + error_info_container_impl & operator=( error_info_container const & ); + + void + add_ref() const + { + ++count_; + } + + bool + release() const + { + if( --count_ ) + return false; + else + { + delete this; + return true; + } + } + + refcount_ptr + clone() const + { + refcount_ptr p; + error_info_container_impl * c=new error_info_container_impl; + p.adopt(c); + for( error_info_map::const_iterator i=info_.begin(),e=info_.end(); i!=e; ++i ) + { + shared_ptr cp(i->second->clone()); + c->info_.insert(std::make_pair(i->first,cp)); + } + return p; + } + }; + + template + inline + E const & + set_info( E const & x, error_info const & v ) + { + typedef error_info error_info_tag_t; + shared_ptr p( new error_info_tag_t(v) ); + exception_detail::error_info_container * c=x.data_.get(); + if( !c ) + x.data_.adopt(c=new exception_detail::error_info_container_impl); + c->set(p,BOOST_EXCEPTION_STATIC_TYPEID(error_info_tag_t)); + return x; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template + E const & set_info( E const &, error_info && ); + template + struct set_info_rv; + template + struct + set_info_rv > + { + template + friend E const & set_info( E const &, error_info && ); + template + static + E const & + set( E const & x, error_info && v ) + { + typedef error_info error_info_tag_t; + shared_ptr p( new error_info_tag_t(std::move(v)) ); + exception_detail::error_info_container * c=x.data_.get(); + if( !c ) + x.data_.adopt(c=new exception_detail::error_info_container_impl); + c->set(p,BOOST_EXCEPTION_STATIC_TYPEID(error_info_tag_t)); + return x; + } + }; + template <> + struct + set_info_rv + { + template + friend E const & set_info( E const &, error_info && ); + template + static + E const & + set( E const & x, throw_function && y ) + { + x.throw_function_=y.v_; + return x; + } + }; + template <> + struct + set_info_rv + { + template + friend E const & set_info( E const &, error_info && ); + template + static + E const & + set( E const & x, throw_file && y ) + { + x.throw_file_=y.v_; + return x; + } + }; + template <> + struct + set_info_rv + { + template + friend E const & set_info( E const &, error_info && ); + template + static + E const & + set( E const & x, throw_line && y ) + { + x.throw_line_=y.v_; + return x; + } + }; + template + inline + E const & + set_info( E const & x, error_info && v ) + { + return set_info_rv >::template set(x,std::move(v)); + } +#endif + + template + struct + derives_boost_exception + { + enum e { value = (sizeof(dispatch_boost_exception((T*)0))==sizeof(large_size)) }; + }; + } + + template + inline + typename enable_if,E const &>::type + operator<<( E const & x, error_info const & v ) + { + return exception_detail::set_info(x,v); + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template + inline + typename enable_if,E const &>::type + operator<<( E const & x, error_info && v ) + { + return exception_detail::set_info(x,std::move(v)); + } +#endif + } + +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(pop) +#endif +#endif diff --git a/boost/exception/to_string.hpp b/boost/exception/to_string.hpp new file mode 100644 index 0000000..51425b1 --- /dev/null +++ b/boost/exception/to_string.hpp @@ -0,0 +1,89 @@ +//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_7E48761AD92811DC9011477D56D89593 +#define UUID_7E48761AD92811DC9011477D56D89593 + +#include +#include +#include + +#if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma GCC system_header +#endif +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(push,1) +#endif + +namespace +boost + { + template + std::string to_string( std::pair const & ); + std::string to_string( std::exception const & ); + + namespace + to_string_detail + { + template + typename disable_if,char>::type to_string( T const & ); + using boost::to_string; + + template + struct has_to_string_impl; + + template + struct + has_to_string_impl + { + enum e { value=1 }; + }; + + template + struct + has_to_string_impl + { + static T const & f(); + enum e { value=1!=sizeof(to_string(f())) }; + }; + } + + template + inline + typename enable_if,std::string>::type + to_string( T const & x ) + { + std::ostringstream out; + out << x; + return out.str(); + } + + template + struct + has_to_string + { + enum e { value=to_string_detail::has_to_string_impl::value>::value }; + }; + + template + inline + std::string + to_string( std::pair const & x ) + { + return std::string("(") + to_string(x.first) + ',' + to_string(x.second) + ')'; + } + + inline + std::string + to_string( std::exception const & x ) + { + return x.what(); + } + } + +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(pop) +#endif +#endif diff --git a/boost/exception/to_string_stub.hpp b/boost/exception/to_string_stub.hpp new file mode 100644 index 0000000..8ff5e47 --- /dev/null +++ b/boost/exception/to_string_stub.hpp @@ -0,0 +1,118 @@ +//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_E788439ED9F011DCB181F25B55D89593 +#define UUID_E788439ED9F011DCB181F25B55D89593 + +#include +#include +#include + +#if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma GCC system_header +#endif +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(push,1) +#endif + +namespace +boost + { + namespace + exception_detail + { + template + struct + to_string_dispatcher + { + template + static + std::string + convert( T const & x, Stub ) + { + return to_string(x); + } + }; + + template <> + struct + to_string_dispatcher + { + template + static + std::string + convert( T const & x, Stub s ) + { + return s(x); + } + + template + static + std::string + convert( T const & x, std::string s ) + { + return s; + } + + template + static + std::string + convert( T const & x, char const * s ) + { + BOOST_ASSERT(s!=0); + return s; + } + }; + + namespace + to_string_dispatch + { + template + inline + std::string + dispatch( T const & x, Stub s ) + { + return to_string_dispatcher::value>::convert(x,s); + } + } + + template + inline + std::string + string_stub_dump( T const & x ) + { + return "[ " + exception_detail::object_hex_dump(x) + " ]"; + } + } + + template + inline + std::string + to_string_stub( T const & x ) + { + return exception_detail::to_string_dispatch::dispatch(x,&exception_detail::string_stub_dump); + } + + template + inline + std::string + to_string_stub( T const & x, Stub s ) + { + return exception_detail::to_string_dispatch::dispatch(x,s); + } + + template + inline + std::string + to_string_stub( std::pair const & x, Stub s ) + { + return std::string("(") + to_string_stub(x.first,s) + ',' + to_string_stub(x.second,s) + ')'; + } + } + +#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS) +#pragma warning(pop) +#endif +#endif diff --git a/boost/exception_ptr.hpp b/boost/exception_ptr.hpp new file mode 100644 index 0000000..d48cce9 --- /dev/null +++ b/boost/exception_ptr.hpp @@ -0,0 +1,11 @@ +//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef UUID_FA5836A2CADA11DC8CD47C8555D89593 +#define UUID_FA5836A2CADA11DC8CD47C8555D89593 + +#include + +#endif diff --git a/boost/intrusive_ptr.hpp b/boost/intrusive_ptr.hpp new file mode 100644 index 0000000..c43adbd --- /dev/null +++ b/boost/intrusive_ptr.hpp @@ -0,0 +1,18 @@ +#ifndef BOOST_INTRUSIVE_PTR_HPP_INCLUDED +#define BOOST_INTRUSIVE_PTR_HPP_INCLUDED + +// +// intrusive_ptr.hpp +// +// Copyright (c) 2001, 2002 Peter Dimov +// +// 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/libs/smart_ptr/ for documentation. +// + +#include + +#endif // #ifndef BOOST_INTRUSIVE_PTR_HPP_INCLUDED diff --git a/boost/logic/tribool.hpp b/boost/logic/tribool.hpp deleted file mode 100644 index 041c59c..0000000 --- a/boost/logic/tribool.hpp +++ /dev/null @@ -1,469 +0,0 @@ -// Three-state boolean logic library - -// Copyright Douglas Gregor 2002-2004. Use, modification and -// distribution is subject to 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) - - -// For more information, see http://www.boost.org -#ifndef BOOST_LOGIC_TRIBOOL_HPP -#define BOOST_LOGIC_TRIBOOL_HPP - -#include -#include -#include - -#ifdef BOOST_HAS_PRAGMA_ONCE -# pragma once -#endif - -namespace boost { namespace logic { - -/// INTERNAL ONLY -namespace detail { -/** - * INTERNAL ONLY - * - * \brief A type used only to uniquely identify the 'indeterminate' - * function/keyword. - */ -struct indeterminate_t -{ -#if BOOST_WORKAROUND(__BORLANDC__, < 0x0600) - char dummy_; // BCB would use 8 bytes by default -#endif -}; - -} // end namespace detail - -/** - * INTERNAL ONLY - * The type of the 'indeterminate' keyword. This has the same type as the - * function 'indeterminate' so that we can recognize when the keyword is - * used. - */ -typedef bool (*indeterminate_keyword_t)(tribool, detail::indeterminate_t); - -/** - * \brief Keyword and test function for the indeterminate tribool value - * - * The \c indeterminate function has a dual role. It's first role is - * as a unary function that tells whether the tribool value is in the - * "indeterminate" state. It's second role is as a keyword - * representing the indeterminate (just like "true" and "false" - * represent the true and false states). If you do not like the name - * "indeterminate", and would prefer to use a different name, see the - * macro \c BOOST_TRIBOOL_THIRD_STATE. - * - * \returns x.value == tribool::indeterminate_value - * \throws nothrow - */ -BOOST_CONSTEXPR inline bool -indeterminate(tribool x, - detail::indeterminate_t dummy = detail::indeterminate_t()) BOOST_NOEXCEPT; - -/** - * \brief A 3-state boolean type. - * - * 3-state boolean values are either true, false, or - * indeterminate. - */ -class tribool -{ -#if defined( BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS ) -private: - /// INTERNAL ONLY - struct dummy { - void nonnull() {}; - }; - - typedef void (dummy::*safe_bool)(); -#endif - -public: - /** - * Construct a new 3-state boolean value with the value 'false'. - * - * \throws nothrow - */ - BOOST_CONSTEXPR tribool() BOOST_NOEXCEPT : value(false_value) {} - - /** - * Construct a new 3-state boolean value with the given boolean - * value, which may be \c true or \c false. - * - * \throws nothrow - */ - BOOST_CONSTEXPR tribool(bool initial_value) BOOST_NOEXCEPT : value(initial_value? true_value : false_value) {} - - /** - * Construct a new 3-state boolean value with an indeterminate value. - * - * \throws nothrow - */ - BOOST_CONSTEXPR tribool(indeterminate_keyword_t) BOOST_NOEXCEPT : value(indeterminate_value) {} - - /** - * Use a 3-state boolean in a boolean context. Will evaluate true in a - * boolean context only when the 3-state boolean is definitely true. - * - * \returns true if the 3-state boolean is true, false otherwise - * \throws nothrow - */ -#if !defined( BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS ) - - BOOST_CONSTEXPR explicit operator bool () const BOOST_NOEXCEPT - { - return value == true_value; - } - -#else - - BOOST_CONSTEXPR operator safe_bool() const BOOST_NOEXCEPT - { - return value == true_value? &dummy::nonnull : 0; - } - -#endif - - /** - * The actual stored value in this 3-state boolean, which may be false, true, - * or indeterminate. - */ - enum value_t { false_value, true_value, indeterminate_value } value; -}; - -// Check if the given tribool has an indeterminate value. Also doubles as a -// keyword for the 'indeterminate' value -BOOST_CONSTEXPR inline bool indeterminate(tribool x, detail::indeterminate_t) BOOST_NOEXCEPT -{ - return x.value == tribool::indeterminate_value; -} - -/** @defgroup logical Logical operations - */ -//@{ -/** - * \brief Computes the logical negation of a tribool - * - * \returns the logical negation of the tribool, according to the - * table: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
!
- *
false
true
true
false
indeterminate
indeterminate
- * \throws nothrow - */ -BOOST_CONSTEXPR inline tribool operator!(tribool x) BOOST_NOEXCEPT -{ - return x.value == tribool::false_value? tribool(true) - :x.value == tribool::true_value? tribool(false) - :tribool(indeterminate); -} - -/** - * \brief Computes the logical conjunction of two tribools - * - * \returns the result of logically ANDing the two tribool values, - * according to the following table: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
&&
false
true
indeterminate
false
false
false
false
true
false
true
indeterminate
indeterminate
false
indeterminate
indeterminate
- * \throws nothrow - */ -BOOST_CONSTEXPR inline tribool operator&&(tribool x, tribool y) BOOST_NOEXCEPT -{ - return (static_cast(!x) || static_cast(!y)) - ? tribool(false) - : ((static_cast(x) && static_cast(y)) ? tribool(true) : indeterminate) - ; -} - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator&&(tribool x, bool y) BOOST_NOEXCEPT -{ return y? x : tribool(false); } - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator&&(bool x, tribool y) BOOST_NOEXCEPT -{ return x? y : tribool(false); } - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator&&(indeterminate_keyword_t, tribool x) BOOST_NOEXCEPT -{ return !x? tribool(false) : tribool(indeterminate); } - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator&&(tribool x, indeterminate_keyword_t) BOOST_NOEXCEPT -{ return !x? tribool(false) : tribool(indeterminate); } - -/** - * \brief Computes the logical disjunction of two tribools - * - * \returns the result of logically ORing the two tribool values, - * according to the following table: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
||
false
true
indeterminate
false
false
true
indeterminate
true
true
true
true
indeterminate
indeterminate
true
indeterminate
- * \throws nothrow - */ -BOOST_CONSTEXPR inline tribool operator||(tribool x, tribool y) BOOST_NOEXCEPT -{ - return (static_cast(!x) && static_cast(!y)) - ? tribool(false) - : ((static_cast(x) || static_cast(y)) ? tribool(true) : tribool(indeterminate)) - ; -} - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator||(tribool x, bool y) BOOST_NOEXCEPT -{ return y? tribool(true) : x; } - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator||(bool x, tribool y) BOOST_NOEXCEPT -{ return x? tribool(true) : y; } - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator||(indeterminate_keyword_t, tribool x) BOOST_NOEXCEPT -{ return x? tribool(true) : tribool(indeterminate); } - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator||(tribool x, indeterminate_keyword_t) BOOST_NOEXCEPT -{ return x? tribool(true) : tribool(indeterminate); } -//@} - -/** - * \brief Compare tribools for equality - * - * \returns the result of comparing two tribool values, according to - * the following table: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
==
false
true
indeterminate
false
true
false
indeterminate
true
false
true
indeterminate
indeterminate
indeterminate
indeterminate
indeterminate
- * \throws nothrow - */ -BOOST_CONSTEXPR inline tribool operator==(tribool x, tribool y) BOOST_NOEXCEPT -{ - return (indeterminate(x) || indeterminate(y)) - ? indeterminate - : ((x && y) || (!x && !y)) - ; -} - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator==(tribool x, bool y) BOOST_NOEXCEPT { return x == tribool(y); } - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator==(bool x, tribool y) BOOST_NOEXCEPT { return tribool(x) == y; } - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator==(indeterminate_keyword_t, tribool x) BOOST_NOEXCEPT -{ return tribool(indeterminate) == x; } - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator==(tribool x, indeterminate_keyword_t) BOOST_NOEXCEPT -{ return tribool(indeterminate) == x; } - -/** - * \brief Compare tribools for inequality - * - * \returns the result of comparing two tribool values for inequality, - * according to the following table: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
!=
false
true
indeterminate
false
false
true
indeterminate
true
true
false
indeterminate
indeterminate
indeterminate
indeterminate
indeterminate
- * \throws nothrow - */ -BOOST_CONSTEXPR inline tribool operator!=(tribool x, tribool y) BOOST_NOEXCEPT -{ - return (indeterminate(x) || indeterminate(y)) - ? indeterminate - : !((x && y) || (!x && !y)) - ; -} - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator!=(tribool x, bool y) BOOST_NOEXCEPT { return x != tribool(y); } - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator!=(bool x, tribool y) BOOST_NOEXCEPT { return tribool(x) != y; } - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator!=(indeterminate_keyword_t, tribool x) BOOST_NOEXCEPT -{ return tribool(indeterminate) != x; } - -/** - * \overload - */ -BOOST_CONSTEXPR inline tribool operator!=(tribool x, indeterminate_keyword_t) BOOST_NOEXCEPT -{ return x != tribool(indeterminate); } - -} } // end namespace boost::logic - -// Pull tribool and indeterminate into namespace "boost" -namespace boost { - using logic::tribool; - using logic::indeterminate; -} - -/** - * \brief Declare a new name for the third state of a tribool - * - * Use this macro to declare a new name for the third state of a - * tribool. This state can have any number of new names (in addition - * to \c indeterminate), all of which will be equivalent. The new name will be - * placed in the namespace in which the macro is expanded. - * - * Example: - * BOOST_TRIBOOL_THIRD_STATE(true_or_false) - * - * tribool x(true_or_false); - * // potentially set x - * if (true_or_false(x)) { - * // don't know what x is - * } - */ -#define BOOST_TRIBOOL_THIRD_STATE(Name) \ -inline bool \ -Name(boost::logic::tribool x, \ - boost::logic::detail::indeterminate_t = \ - boost::logic::detail::indeterminate_t()) \ -{ return x.value == boost::logic::tribool::indeterminate_value; } - -#endif // BOOST_LOGIC_TRIBOOL_HPP - diff --git a/boost/logic/tribool_fwd.hpp b/boost/logic/tribool_fwd.hpp deleted file mode 100644 index 2cdd91b..0000000 --- a/boost/logic/tribool_fwd.hpp +++ /dev/null @@ -1,15 +0,0 @@ -// Three-state boolean logic library - -// Copyright Douglas Gregor 2002-2004. Use, modification and -// distribution is subject to 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) - - -// For more information, see http://www.boost.org -#ifndef BOOST_LOGIC_TRIBOOL_FWD_HPP -#define BOOST_LOGIC_TRIBOOL_FWD_HPP - -namespace boost { namespace logic { class tribool; } } - -#endif // BOOST_LOGIC_TRIBOOL_FWD_HPP diff --git a/boost/logic/tribool_io.hpp b/boost/logic/tribool_io.hpp deleted file mode 100644 index 2696dca..0000000 --- a/boost/logic/tribool_io.hpp +++ /dev/null @@ -1,343 +0,0 @@ -// Three-state boolean logic library - -// Copyright Douglas Gregor 2002-2004. Use, modification and -// distribution is subject to 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_LOGIC_TRIBOOL_IO_HPP -#define BOOST_LOGIC_TRIBOOL_IO_HPP - -#include -#include -#include - -#if defined(_MSC_VER) -# pragma once -#endif - -#ifndef BOOST_NO_STD_LOCALE -# include -#endif - -#include -#include - -namespace boost { namespace logic { - -#ifdef BOOST_NO_STD_LOCALE - -/** - * \brief Returns a string containing the default name for the \c - * false value of a tribool with the given character type T. - * - * This function only exists when the C++ standard library - * implementation does not support locales. - */ -template std::basic_string default_false_name(); - -/** - * \brief Returns the character string "false". - * - * This function only exists when the C++ standard library - * implementation does not support locales. - */ -template<> -inline std::basic_string default_false_name() -{ return "false"; } - -# if !defined(BOOST_NO_CWCHAR) -/** - * \brief Returns the wide character string L"false". - * - * This function only exists when the C++ standard library - * implementation does not support locales. - */ -template<> -inline std::basic_string default_false_name() -{ return L"false"; } -# endif - -/** - * \brief Returns a string containing the default name for the \c true - * value of a tribool with the given character type T. - * - * This function only exists when the C++ standard library - * implementation does not support locales. - */ -template std::basic_string default_true_name(); - -/** - * \brief Returns the character string "true". - * - * This function only exists when the C++ standard library - * implementation does not support locales. - */ -template<> -inline std::basic_string default_true_name() -{ return "true"; } - -# if !defined(BOOST_NO_CWCHAR) -/** - * \brief Returns the wide character string L"true". - * - * This function only exists * when the C++ standard library - * implementation does not support * locales. - */ -template<> -inline std::basic_string default_true_name() -{ return L"true"; } -# endif -#endif - -/** - * \brief Returns a string containing the default name for the indeterminate - * value of a tribool with the given character type T. - * - * This routine is used by the input and output streaming operators - * for tribool when there is no locale support or the stream's locale - * does not contain the indeterminate_name facet. - */ -template std::basic_string get_default_indeterminate_name(); - -/// Returns the character string "indeterminate". -template<> -inline std::basic_string get_default_indeterminate_name() -{ return "indeterminate"; } - -#if !defined(BOOST_NO_CWCHAR) -/// Returns the wide character string L"indeterminate". -template<> -inline std::basic_string get_default_indeterminate_name() -{ return L"indeterminate"; } -#endif - -// http://www.cantrip.org/locale.html - -#ifndef BOOST_NO_STD_LOCALE -/** - * \brief A locale facet specifying the name of the indeterminate - * value of a tribool. - * - * The facet is used to perform I/O on tribool values when \c - * std::boolalpha has been specified. This class template is only - * available if the C++ standard library implementation supports - * locales. - */ -template -class indeterminate_name : public std::locale::facet, private boost::noncopyable -{ -public: - typedef CharT char_type; - typedef std::basic_string string_type; - - /// Construct the facet with the default name - indeterminate_name() : name_(get_default_indeterminate_name()) {} - - /// Construct the facet with the given name for the indeterminate value - explicit indeterminate_name(const string_type& initial_name) - : name_(initial_name) {} - - /// Returns the name for the indeterminate value - string_type name() const { return name_; } - - /// Uniquily identifies this facet with the locale. - static std::locale::id id; - -private: - string_type name_; -}; - -template std::locale::id indeterminate_name::id; -#endif - -/** - * \brief Writes the value of a tribool to a stream. - * - * When the value of @p x is either \c true or \c false, this routine - * is semantically equivalent to: - * \code out << static_cast(x); \endcode - * - * When @p x has an indeterminate value, it outputs either the integer - * value 2 (if (out.flags() & std::ios_base::boolalpha) == 0) - * or the name of the indeterminate value. The name of the - * indeterminate value comes from the indeterminate_name facet (if it - * is defined in the output stream's locale), or from the - * get_default_indeterminate_name function (if it is not defined in the - * locale or if the C++ standard library implementation does not - * support locales). - * - * \returns @p out - */ -template -inline std::basic_ostream& -operator<<(std::basic_ostream& out, tribool x) -{ - if (!indeterminate(x)) { - out << static_cast(x); - } else { - typename std::basic_ostream::sentry cerberus(out); - if (cerberus) { - if (out.flags() & std::ios_base::boolalpha) { -#ifndef BOOST_NO_STD_LOCALE - if (BOOST_HAS_FACET(indeterminate_name, out.getloc())) { - const indeterminate_name& facet = - BOOST_USE_FACET(indeterminate_name, out.getloc()); - out << facet.name(); - } else { - out << get_default_indeterminate_name(); - } -#else - out << get_default_indeterminate_name(); -#endif - } - else - out << 2; - } - } - return out; -} - -/** - * \brief Writes the indeterminate tribool value to a stream. - * - * This routine outputs either the integer - * value 2 (if (out.flags() & std::ios_base::boolalpha) == 0) - * or the name of the indeterminate value. The name of the - * indeterminate value comes from the indeterminate_name facet (if it - * is defined in the output stream's locale), or from the - * get_default_indeterminate_name function (if it is not defined in the - * locale or if the C++ standard library implementation does not - * support locales). - * - * \returns @p out - */ -template -inline std::basic_ostream& -operator<<(std::basic_ostream& out, - bool (*)(tribool, detail::indeterminate_t)) -{ return out << tribool(indeterminate); } - -/** - * \brief Reads a tribool value from a stream. - * - * When (out.flags() & std::ios_base::boolalpha) == 0, this - * function reads a \c long value from the input stream @p in and - * converts that value to a tribool. If that value is 0, @p x becomes - * \c false; if it is 1, @p x becomes \c true; if it is 2, @p becomes - * \c indetermine; otherwise, the operation fails (and the fail bit is - * set on the input stream @p in). - * - * When (out.flags() & std::ios_base::boolalpha) != 0, this - * function first determines the names of the false, true, and - * indeterminate values. The false and true names are extracted from - * the \c std::numpunct facet of the input stream's locale (if the C++ - * standard library implementation supports locales), or from the \c - * default_false_name and \c default_true_name functions (if there is - * no locale support). The indeterminate name is extracted from the - * appropriate \c indeterminate_name facet (if it is available in the - * input stream's locale), or from the \c get_default_indeterminate_name - * function (if the C++ standard library implementation does not - * support locales, or the \c indeterminate_name facet is not - * specified for this locale object). The input is then matched to - * each of these names, and the tribool @p x is assigned the value - * corresponding to the longest name that matched. If no name is - * matched or all names are empty, the operation fails (and the fail - * bit is set on the input stream @p in). - * - * \returns @p in - */ -template -inline std::basic_istream& -operator>>(std::basic_istream& in, tribool& x) -{ - if (in.flags() & std::ios_base::boolalpha) { - typename std::basic_istream::sentry cerberus(in); - if (cerberus) { - typedef std::basic_string string_type; - -#ifndef BOOST_NO_STD_LOCALE - const std::numpunct& numpunct_facet = - BOOST_USE_FACET(std::numpunct, in.getloc()); - - string_type falsename = numpunct_facet.falsename(); - string_type truename = numpunct_facet.truename(); - - string_type othername; - if (BOOST_HAS_FACET(indeterminate_name, in.getloc())) { - othername = - BOOST_USE_FACET(indeterminate_name, in.getloc()).name(); - } else { - othername = get_default_indeterminate_name(); - } -#else - string_type falsename = default_false_name(); - string_type truename = default_true_name(); - string_type othername = get_default_indeterminate_name(); -#endif - - typename string_type::size_type pos = 0; - bool falsename_ok = true, truename_ok = true, othername_ok = true; - - // Modeled after the code from Library DR 17 - while ((falsename_ok && pos < falsename.size()) - || (truename_ok && pos < truename.size()) - || (othername_ok && pos < othername.size())) { - typename Traits::int_type c = in.get(); - if (c == Traits::eof()) - return in; - - bool matched = false; - if (falsename_ok && pos < falsename.size()) { - if (Traits::eq(Traits::to_char_type(c), falsename[pos])) - matched = true; - else - falsename_ok = false; - } - - if (truename_ok && pos < truename.size()) { - if (Traits::eq(Traits::to_char_type(c), truename[pos])) - matched = true; - else - truename_ok = false; - } - - if (othername_ok && pos < othername.size()) { - if (Traits::eq(Traits::to_char_type(c), othername[pos])) - matched = true; - else - othername_ok = false; - } - - if (matched) { ++pos; } - if (pos > falsename.size()) falsename_ok = false; - if (pos > truename.size()) truename_ok = false; - if (pos > othername.size()) othername_ok = false; - } - - if (pos == 0) - in.setstate(std::ios_base::failbit); - else { - if (falsename_ok) x = false; - else if (truename_ok) x = true; - else if (othername_ok) x = indeterminate; - else in.setstate(std::ios_base::failbit); - } - } - } else { - long value; - if (in >> value) { - switch (value) { - case 0: x = false; break; - case 1: x = true; break; - case 2: x = indeterminate; break; - default: in.setstate(std::ios_base::failbit); break; - } - } - } - - return in; -} - -} } // end namespace boost::logic - -#endif // BOOST_LOGIC_TRIBOOL_IO_HPP diff --git a/boost/math/special_functions/math_fwd.hpp b/boost/math/special_functions/math_fwd.hpp index 795620b..bf5ad6b 100644 --- a/boost/math/special_functions/math_fwd.hpp +++ b/boost/math/special_functions/math_fwd.hpp @@ -1103,7 +1103,18 @@ namespace boost template typename boost::math::tools::promote_args::type lambert_wm1_prime(T z); + // Hypergeometrics: + template typename tools::promote_args::type hypergeometric_1F0(T1 a, T2 z); + template typename tools::promote_args::type hypergeometric_1F0(T1 a, T2 z, const Policy&); + template typename tools::promote_args::type hypergeometric_0F1(T1 b, T2 z); + template typename tools::promote_args::type hypergeometric_0F1(T1 b, T2 z, const Policy&); + + template typename tools::promote_args::type hypergeometric_2F0(T1 a1, T2 a2, T3 z); + template typename tools::promote_args::type hypergeometric_2F0(T1 a1, T2 a2, T3 z, const Policy&); + + template typename tools::promote_args::type hypergeometric_1F1(T1 a, T2 b, T3 z); + template typename tools::promote_args::type hypergeometric_1F1(T1 a, T2 b, T3 z, const Policy&); } // namespace math @@ -1125,9 +1136,20 @@ namespace boost #define BOOST_MATH_DETAIL_LL_FUNC(Policy) #endif +#if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) && !defined(BOOST_NO_CXX11_HDR_ARRAY) +# define BOOST_MATH_DETAIL_11_FUNC(Policy)\ + template \ + inline typename boost::math::tools::promote_args::type hypergeometric_1F1(const T& a, const U& b, const V& z)\ + { return boost::math::hypergeometric_1F1(a, b, z, Policy()); }\ + +#else +# define BOOST_MATH_DETAIL_11_FUNC(Policy) +#endif + #define BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(Policy)\ \ BOOST_MATH_DETAIL_LL_FUNC(Policy)\ + BOOST_MATH_DETAIL_11_FUNC(Policy)\ \ template \ inline typename boost::math::tools::promote_args::type \ @@ -1669,6 +1691,18 @@ template \ template inline typename boost::math::tools::promote_args::type lambert_w0_prime(T z) { return boost::math::lambert_w0(z, Policy()); }\ template inline typename boost::math::tools::promote_args::type lambert_wm1_prime(T z) { return boost::math::lambert_w0(z, Policy()); }\ \ + template \ + inline typename boost::math::tools::promote_args::type hypergeometric_1F0(const T& a, const U& z)\ + { return boost::math::hypergeometric_1F0(a, z, Policy()); }\ + \ + template \ + inline typename boost::math::tools::promote_args::type hypergeometric_0F1(const T& a, const U& z)\ + { return boost::math::hypergeometric_0F1(a, z, Policy()); }\ + \ + template \ + inline typename boost::math::tools::promote_args::type hypergeometric_2F0(const T& a1, const U& a2, const V& z)\ + { return boost::math::hypergeometric_2F0(a1, a2, z, Policy()); }\ + \ diff --git a/boost/memory_order.hpp b/boost/memory_order.hpp new file mode 100644 index 0000000..1f7d202 --- /dev/null +++ b/boost/memory_order.hpp @@ -0,0 +1,88 @@ +// boost/memory_order.hpp +// +// Defines enum boost::memory_order per the C++0x working draft +// +// Copyright (c) 2008, 2009 Peter Dimov +// Copyright (c) 2018 Andrey Semashev +// +// 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_MEMORY_ORDER_HPP_INCLUDED +#define BOOST_MEMORY_ORDER_HPP_INCLUDED + +#include + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +namespace boost +{ + +// +// Enum values are chosen so that code that needs to insert +// a trailing fence for acquire semantics can use a single +// test such as: +// +// if( mo & memory_order_acquire ) { ...fence... } +// +// For leading fences one can use: +// +// if( mo & memory_order_release ) { ...fence... } +// +// Architectures such as Alpha that need a fence on consume +// can use: +// +// if( mo & ( memory_order_acquire | memory_order_consume ) ) { ...fence... } +// +// The values are also in the order of increasing "strength" +// of the fences so that success/failure orders can be checked +// efficiently in compare_exchange methods. +// + +#if !defined(BOOST_NO_CXX11_SCOPED_ENUMS) + +enum class memory_order : unsigned int +{ + relaxed = 0, + consume = 1, + acquire = 2, + release = 4, + acq_rel = 6, // acquire | release + seq_cst = 14 // acq_rel | 8 +}; + +#if !defined(BOOST_NO_CXX17_INLINE_VARIABLES) +#define BOOST_MEMORY_ORDER_INLINE_VARIABLE inline +#else +#define BOOST_MEMORY_ORDER_INLINE_VARIABLE +#endif + +BOOST_MEMORY_ORDER_INLINE_VARIABLE BOOST_CONSTEXPR_OR_CONST memory_order memory_order_relaxed = memory_order::relaxed; +BOOST_MEMORY_ORDER_INLINE_VARIABLE BOOST_CONSTEXPR_OR_CONST memory_order memory_order_consume = memory_order::consume; +BOOST_MEMORY_ORDER_INLINE_VARIABLE BOOST_CONSTEXPR_OR_CONST memory_order memory_order_acquire = memory_order::acquire; +BOOST_MEMORY_ORDER_INLINE_VARIABLE BOOST_CONSTEXPR_OR_CONST memory_order memory_order_release = memory_order::release; +BOOST_MEMORY_ORDER_INLINE_VARIABLE BOOST_CONSTEXPR_OR_CONST memory_order memory_order_acq_rel = memory_order::acq_rel; +BOOST_MEMORY_ORDER_INLINE_VARIABLE BOOST_CONSTEXPR_OR_CONST memory_order memory_order_seq_cst = memory_order::seq_cst; + +#undef BOOST_MEMORY_ORDER_INLINE_VARIABLE + +#else // !defined(BOOST_NO_CXX11_SCOPED_ENUMS) + +enum memory_order +{ + memory_order_relaxed = 0, + memory_order_consume = 1, + memory_order_acquire = 2, + memory_order_release = 4, + memory_order_acq_rel = 6, // acquire | release + memory_order_seq_cst = 14 // acq_rel | 8 +}; + +#endif // !defined(BOOST_NO_CXX11_SCOPED_ENUMS) + +} // namespace boost + +#endif // #ifndef BOOST_MEMORY_ORDER_HPP_INCLUDED diff --git a/boost/mp11.hpp b/boost/mp11.hpp deleted file mode 100644 index 5e45939..0000000 --- a/boost/mp11.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef BOOST_MP11_HPP_INCLUDED -#define BOOST_MP11_HPP_INCLUDED - -// Copyright 2015 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif // #ifndef BOOST_MP11_HPP_INCLUDED diff --git a/boost/mp11/algorithm.hpp b/boost/mp11/algorithm.hpp deleted file mode 100644 index 6ffc572..0000000 --- a/boost/mp11/algorithm.hpp +++ /dev/null @@ -1,1111 +0,0 @@ -#ifndef BOOST_MP11_ALGORITHM_HPP_INCLUDED -#define BOOST_MP11_ALGORITHM_HPP_INCLUDED - -// Copyright 2015-2019 Peter Dimov -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_transform -namespace detail -{ - -template class F, class... L> struct mp_transform_impl -{ -}; - -template class F, template class L, class... T> struct mp_transform_impl> -{ -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) - - template struct f { using type = F; }; - - using type = L::type...>; - -#else - - using type = L...>; - -#endif -}; - -template class F, template class L1, class... T1, template class L2, class... T2> struct mp_transform_impl, L2> -{ -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) - - template struct f { using type = F; }; - - using type = L1::type...>; - -#else - - using type = L1...>; - -#endif -}; - -template class F, template class L1, class... T1, template class L2, class... T2, template class L3, class... T3> struct mp_transform_impl, L2, L3> -{ -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) - - template struct f { using type = F; }; - - using type = L1::type...>; - -#else - - using type = L1...>; - -#endif -}; - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, == 1900 ) || BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, < 40800 ) - -template using mp_same_size_1 = mp_same...>; -template struct mp_same_size_2: mp_defer {}; - -#endif - -struct list_size_mismatch -{ -}; - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 ) - -template class F, class... L> struct mp_transform_cuda_workaround -{ - using type = mp_if...>, detail::mp_transform_impl, detail::list_size_mismatch>; -}; - -#endif - -} // namespace detail - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, == 1900 ) || BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, < 40800 ) - -template class F, class... L> using mp_transform = typename mp_if::type, detail::mp_transform_impl, detail::list_size_mismatch>::type; - -#else - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 ) - -template class F, class... L> using mp_transform = typename detail::mp_transform_cuda_workaround< F, L...>::type::type; - -#else - -template class F, class... L> using mp_transform = typename mp_if...>, detail::mp_transform_impl, detail::list_size_mismatch>::type; - -#endif - -#endif - -template using mp_transform_q = mp_transform; - -namespace detail -{ - -template class F, template class L1, class... T1, template class L2, class... T2, template class L3, class... T3, template class L4, class... T4, class... L> struct mp_transform_impl, L2, L3, L4, L...> -{ - using A1 = L1...>; - - template using _f = mp_transform; - - using A2 = mp_fold, A1, _f>; - - template using _g = mp_apply; - - using type = mp_transform<_g, A2>; -}; - -} // namespace detail - -// mp_transform_if -namespace detail -{ - -template class P, template class F, class... L> struct mp_transform_if_impl -{ - // the stupid quote-unquote dance avoids "pack expansion used as argument for non-pack parameter of alias template" - - using Qp = mp_quote

; - using Qf = mp_quote; - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) - - template struct _f_ { using type = mp_eval_if_q>, mp_first>, Qf, U...>; }; - template using _f = typename _f_::type; - -#else - - template using _f = mp_eval_if_q>, mp_first>, Qf, U...>; - -#endif - - using type = mp_transform<_f, L...>; -}; - -} // namespace detail - -template class P, template class F, class... L> using mp_transform_if = typename detail::mp_transform_if_impl::type; -template using mp_transform_if_q = typename detail::mp_transform_if_impl::type; - -// mp_filter -namespace detail -{ - -template class P, class L1, class... L> struct mp_filter_impl -{ - using Qp = mp_quote

; - - template using _f = mp_if< mp_invoke_q, mp_list, mp_list<> >; - - using _t1 = mp_transform<_f, L1, L...>; - using _t2 = mp_apply; - - using type = mp_assign; -}; - -} // namespace detail - -template class P, class... L> using mp_filter = typename detail::mp_filter_impl::type; -template using mp_filter_q = typename detail::mp_filter_impl::type; - -// mp_fill -namespace detail -{ - -template struct mp_fill_impl; - -template class L, class... T, class V> struct mp_fill_impl, V> -{ -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, <= 1900 ) - - template struct _f { using type = V; }; - using type = L::type...>; - -#else - - template using _f = V; - using type = L<_f...>; - -#endif -}; - -} // namespace detail - -template using mp_fill = typename detail::mp_fill_impl::type; - -// mp_contains -template using mp_contains = mp_to_bool>; - -// mp_repeat(_c) -namespace detail -{ - -template struct mp_repeat_c_impl -{ - using _l1 = typename mp_repeat_c_impl::type; - using _l2 = typename mp_repeat_c_impl::type; - - using type = mp_append<_l1, _l1, _l2>; -}; - -template struct mp_repeat_c_impl -{ - using type = mp_clear; -}; - -template struct mp_repeat_c_impl -{ - using type = L; -}; - -} // namespace detail - -template using mp_repeat_c = typename detail::mp_repeat_c_impl::type; -template using mp_repeat = typename detail::mp_repeat_c_impl::type; - -// mp_product -namespace detail -{ - -template class F, class P, class... L> struct mp_product_impl_2; - -template class F, class P> struct mp_product_impl_2 -{ - using type = mp_list>; -}; - -template class F, class P, template class L1, class... T1, class... L> struct mp_product_impl_2, L...> -{ - using type = mp_append, L...>::type...>; -}; - -template class F, class... L> struct mp_product_impl; - -template class F, class L1, class... L> struct mp_product_impl -{ - using type = mp_assign, L1, L...>::type>; -}; - -} // namespace detail - -template class F, class... L> using mp_product = typename detail::mp_product_impl::type; -template using mp_product_q = typename detail::mp_product_impl::type; - -// mp_drop(_c) -namespace detail -{ - -template struct mp_drop_impl; - -template class L, class... T, template class L2, class... U> struct mp_drop_impl, L2> -{ - template static mp_identity> f( U*..., mp_identity*... ); - - using R = decltype( f( (mp_identity*)0 ... ) ); - - using type = typename R::type; -}; - -} // namespace detail - -template using mp_drop_c = typename detail::mp_drop_impl, N>>::type; - -template using mp_drop = typename detail::mp_drop_impl, N>>::type; - -// mp_from_sequence -namespace detail -{ - -template struct mp_from_sequence_impl; - -template class S, class U, U... J> struct mp_from_sequence_impl> -{ - using type = mp_list...>; -}; - -} // namespace detail - -template using mp_from_sequence = typename detail::mp_from_sequence_impl::type; - -// mp_iota(_c) -template using mp_iota_c = mp_from_sequence>; -template using mp_iota = mp_from_sequence::type, N::value>>; - -// mp_at(_c) -namespace detail -{ - -template struct mp_at_c_impl; - -#if defined(BOOST_MP11_HAS_TYPE_PACK_ELEMENT) - -template class L, class... T, std::size_t I> struct mp_at_c_impl, I> -{ - using type = __type_pack_element; -}; - -#else - -template struct mp_at_c_impl -{ - using _map = mp_transform >, L>; - using type = mp_second > >; -}; - -#endif - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 ) - -template struct mp_at_c_cuda_workaround -{ - using type = mp_if_c<(I < mp_size::value), detail::mp_at_c_impl, void>; -}; - -#endif - -} // namespace detail - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 ) - -template using mp_at_c = typename detail::mp_at_c_cuda_workaround< L, I >::type::type; - -#else - -template using mp_at_c = typename mp_if_c<(I < mp_size::value), detail::mp_at_c_impl, void>::type; - -#endif - -template using mp_at = mp_at_c; - -// mp_take(_c) -namespace detail -{ - -template struct mp_take_c_impl -{ -}; - -template class L, class... T> -struct mp_take_c_impl<0, L> -{ - using type = L<>; -}; - -template class L, class T1, class... T> -struct mp_take_c_impl<1, L> -{ - using type = L; -}; - -template class L, class T1, class T2, class... T> -struct mp_take_c_impl<2, L> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class... T> -struct mp_take_c_impl<3, L> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4, class... T> -struct mp_take_c_impl<4, L> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4, class T5, class... T> -struct mp_take_c_impl<5, L> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4, class T5, class T6, class... T> -struct mp_take_c_impl<6, L> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class... T> -struct mp_take_c_impl<7, L> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class... T> -struct mp_take_c_impl<8, L> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class... T> -struct mp_take_c_impl<9, L> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class... T, std::size_t N> -struct mp_take_c_impl, typename std::enable_if= 10>::type> -{ - using type = mp_append, typename mp_take_c_impl>::type>; -}; - -} // namespace detail - -template using mp_take_c = typename detail::mp_take_c_impl::type; -template using mp_take = typename detail::mp_take_c_impl::type; - -// mp_back -template using mp_back = mp_at_c::value - 1>; - -// mp_pop_back -template using mp_pop_back = mp_take_c::value - 1>; - -// mp_replace -namespace detail -{ - -template struct mp_replace_impl; - -template class L, class... T, class V, class W> struct mp_replace_impl, V, W> -{ -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, <= 1800 ) - template struct _f { using type = mp_if, W, A>; }; - using type = L::type...>; -#else - template using _f = mp_if, W, A>; - using type = L<_f...>; -#endif -}; - -} // namespace detail - -template using mp_replace = typename detail::mp_replace_impl::type; - -// mp_replace_if -namespace detail -{ - -template class P, class W> struct mp_replace_if_impl; - -template class L, class... T, template class P, class W> struct mp_replace_if_impl, P, W> -{ -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) - template struct _f { using type = mp_if, W, U>; }; - using type = L::type...>; -#else - template using _f = mp_if, W, U>; - using type = L<_f...>; -#endif -}; - -} // namespace detail - -template class P, class W> using mp_replace_if = typename detail::mp_replace_if_impl::type; -template using mp_replace_if_q = mp_replace_if; - -// mp_copy_if -// in detail/mp_copy_if.hpp - -// mp_remove -namespace detail -{ - -template struct mp_remove_impl; - -template class L, class... T, class V> struct mp_remove_impl, V> -{ -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) - template struct _f { using type = mp_if, mp_list<>, mp_list>; }; - using type = mp_append, typename _f::type...>; -#else - template using _f = mp_if, mp_list<>, mp_list>; - using type = mp_append, _f...>; -#endif -}; - -} // namespace detail - -template using mp_remove = typename detail::mp_remove_impl::type; - -// mp_remove_if -// in detail/mp_remove_if.hpp - -// mp_flatten> -namespace detail -{ - -template struct mp_flatten_impl -{ - template using fn = mp_if, T, mp_list>; -}; - -} // namespace detail - -template> using mp_flatten = mp_apply, L>, mp_clear>>; - -// mp_partition -namespace detail -{ - -template class P> struct mp_partition_impl; - -template class L, class... T, template class P> struct mp_partition_impl, P> -{ - using type = L, P>, mp_remove_if, P>>; -}; - -} // namespace detail - -template class P> using mp_partition = typename detail::mp_partition_impl::type; -template using mp_partition_q = mp_partition; - -// mp_sort -namespace detail -{ - -template class P> struct mp_sort_impl; - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, <= 1800 ) - -template class L, class... T, template class P> struct mp_sort_impl, P> -{ - static_assert( sizeof...(T) == 0, "T... must be empty" ); - using type = L<>; -}; - -#else - -template class L, template class P> struct mp_sort_impl, P> -{ - using type = L<>; -}; - -#endif - -template class L, class T1, template class P> struct mp_sort_impl, P> -{ - using type = L; -}; - -template class L, class T1, class... T, template class P> struct mp_sort_impl, P> -{ - template using F = P; - - using part = mp_partition, F>; - - using S1 = typename mp_sort_impl, P>::type; - using S2 = typename mp_sort_impl, P>::type; - - using type = mp_append, S2>; -}; - -} // namespace detail - -template class P> using mp_sort = typename detail::mp_sort_impl::type; -template using mp_sort_q = mp_sort; - -// mp_nth_element(_c) -namespace detail -{ - -template class P> struct mp_nth_element_impl; - -template class L, class T1, std::size_t I, template class P> struct mp_nth_element_impl, I, P> -{ - static_assert( I == 0, "mp_nth_element index out of range" ); - using type = T1; -}; - -template class L, class T1, class... T, std::size_t I, template class P> struct mp_nth_element_impl, I, P> -{ - static_assert( I < 1 + sizeof...(T), "mp_nth_element index out of range" ); - - template using F = P; - - using part = mp_partition, F>; - - using L1 = mp_first; - static std::size_t const N1 = mp_size::value; - - using L2 = mp_second; - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 ) - - struct detail - { - struct mp_nth_element_impl_cuda_workaround - { - using type = mp_cond< - - mp_bool<(I < N1)>, mp_nth_element_impl, - mp_bool<(I == N1)>, mp_identity, - mp_true, mp_nth_element_impl - - >; - }; - }; - - using type = typename detail::mp_nth_element_impl_cuda_workaround::type::type; - -#else - - using type = typename mp_cond< - - mp_bool<(I < N1)>, mp_nth_element_impl, - mp_bool<(I == N1)>, mp_identity, - mp_true, mp_nth_element_impl - - >::type; - -#endif -}; - -} // namespace detail - -template class P> using mp_nth_element_c = typename detail::mp_nth_element_impl::type; -template class P> using mp_nth_element = typename detail::mp_nth_element_impl::type; -template using mp_nth_element_q = mp_nth_element; - -// mp_find -namespace detail -{ - -template struct mp_find_impl; - -#if BOOST_MP11_CLANG && defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) - -struct mp_index_holder -{ - std::size_t i_; - bool f_; -}; - -constexpr inline mp_index_holder operator+( mp_index_holder const & v, bool f ) -{ - if( v.f_ ) - { - return v; - } - else if( f ) - { - return { v.i_, true }; - } - else - { - return { v.i_ + 1, false }; - } -} - -template class L, class... T, class V> struct mp_find_impl, V> -{ - static constexpr mp_index_holder _v{ 0, false }; - using type = mp_size_t< (_v + ... + std::is_same::value).i_ >; -}; - -#elif !defined( BOOST_MP11_NO_CONSTEXPR ) - -template class L, class V> struct mp_find_impl, V> -{ - using type = mp_size_t<0>; -}; - -#if defined( BOOST_MP11_HAS_CXX14_CONSTEXPR ) - -constexpr std::size_t cx_find_index( bool const * first, bool const * last ) -{ - std::size_t m = 0; - - while( first != last && !*first ) - { - ++m; - ++first; - } - - return m; -} - -#else - -constexpr std::size_t cx_find_index( bool const * first, bool const * last ) -{ - return first == last || *first? 0: 1 + cx_find_index( first + 1, last ); -} - -#endif - -template class L, class... T, class V> struct mp_find_impl, V> -{ - static constexpr bool _v[] = { std::is_same::value... }; - using type = mp_size_t< cx_find_index( _v, _v + sizeof...(T) ) >; -}; - -#else - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, <= 1800 ) - -template class L, class... T, class V> struct mp_find_impl, V> -{ - static_assert( sizeof...(T) == 0, "T... must be empty" ); - using type = mp_size_t<0>; -}; - -#else - -template class L, class V> struct mp_find_impl, V> -{ - using type = mp_size_t<0>; -}; - -#endif - -template class L, class... T, class V> struct mp_find_impl, V> -{ - using type = mp_size_t<0>; -}; - -template class L, class T1, class... T, class V> struct mp_find_impl, V> -{ - using _r = typename mp_find_impl, V>::type; - using type = mp_size_t<1 + _r::value>; -}; - -#endif - -} // namespace detail - -template using mp_find = typename detail::mp_find_impl::type; - -// mp_find_if -namespace detail -{ - -template class P> struct mp_find_if_impl; - -#if BOOST_MP11_CLANG && defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) - -template class L, class... T, template class P> struct mp_find_if_impl, P> -{ - static constexpr mp_index_holder _v{ 0, false }; - using type = mp_size_t< (_v + ... + P::value).i_ >; -}; - -#elif !defined( BOOST_MP11_NO_CONSTEXPR ) - -template class L, template class P> struct mp_find_if_impl, P> -{ - using type = mp_size_t<0>; -}; - -template class L, class... T, template class P> struct mp_find_if_impl, P> -{ - static constexpr bool _v[] = { P::value... }; - using type = mp_size_t< cx_find_index( _v, _v + sizeof...(T) ) >; -}; - -#else - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, <= 1800 ) - -template class L, class... T, template class P> struct mp_find_if_impl, P> -{ - static_assert( sizeof...(T) == 0, "T... must be empty" ); - using type = mp_size_t<0>; -}; - -#else - -template class L, template class P> struct mp_find_if_impl, P> -{ - using type = mp_size_t<0>; -}; - -#endif - -template class P> struct mp_find_if_impl_2 -{ - using _r = typename mp_find_if_impl::type; - using type = mp_size_t<1 + _r::value>; -}; - -template class L, class T1, class... T, template class P> struct mp_find_if_impl, P> -{ - using type = typename mp_if, mp_identity>, mp_find_if_impl_2, P>>::type; -}; - -#endif - -} // namespace detail - -template class P> using mp_find_if = typename detail::mp_find_if_impl::type; -template using mp_find_if_q = mp_find_if; - -// mp_reverse -namespace detail -{ - -template struct mp_reverse_impl; - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, <= 1800 ) - -template class L, class... T> struct mp_reverse_impl> -{ - static_assert( sizeof...(T) == 0, "T... must be empty" ); - using type = L<>; -}; - -#else - -template class L> struct mp_reverse_impl> -{ - using type = L<>; -}; - -#endif - -template class L, class T1> struct mp_reverse_impl> -{ - using type = L; -}; - -template class L, class T1, class T2> struct mp_reverse_impl> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3> struct mp_reverse_impl> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4> struct mp_reverse_impl> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4, class T5> struct mp_reverse_impl> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4, class T5, class T6> struct mp_reverse_impl> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7> struct mp_reverse_impl> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8> struct mp_reverse_impl> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9> struct mp_reverse_impl> -{ - using type = L; -}; - -template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class... T> struct mp_reverse_impl> -{ - using type = mp_push_back>::type, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1>; -}; - -} // namespace detail - -template using mp_reverse = typename detail::mp_reverse_impl::type; - -// mp_fold -// in detail/mp_fold.hpp - -// mp_reverse_fold -namespace detail -{ - -template class F> struct mp_reverse_fold_impl; - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, <= 1800 ) - -template class L, class... T, class V, template class F> struct mp_reverse_fold_impl, V, F> -{ - static_assert( sizeof...(T) == 0, "T... must be empty" ); - using type = V; -}; - -#else - -template class L, class V, template class F> struct mp_reverse_fold_impl, V, F> -{ - using type = V; -}; - -#endif - -template class L, class T1, class... T, class V, template class F> struct mp_reverse_fold_impl, V, F> -{ - using rest = typename mp_reverse_fold_impl, V, F>::type; - using type = F; -}; - -template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class... T, class V, template class F> struct mp_reverse_fold_impl, V, F> -{ - using rest = typename mp_reverse_fold_impl, V, F>::type; - using type = F > > > > > > > > >; -}; - -} // namespace detail - -template class F> using mp_reverse_fold = typename detail::mp_reverse_fold_impl::type; -template using mp_reverse_fold_q = mp_reverse_fold; - -// mp_unique -namespace detail -{ - -template struct mp_unique_impl; - -template class L, class... T> struct mp_unique_impl> -{ - using type = mp_set_push_back, T...>; -}; - -} // namespace detail - -template using mp_unique = typename detail::mp_unique_impl::type; - -// mp_unique_if -namespace detail -{ - -template class P> struct mp_unique_if_push_back -{ - template struct impl - { - }; - - template class L, class... Ts, class T> - struct impl, T> - { - using type = mp_if...>, L, L>; - }; - - template using fn = typename impl::type; -}; - -} // namespace detail - -template class P> -using mp_unique_if = mp_fold_q, detail::mp_unique_if_push_back

>; - -template using mp_unique_if_q = mp_unique_if; - -// mp_all_of -template class P> using mp_all_of = mp_bool< mp_count_if::value == mp_size::value >; -template using mp_all_of_q = mp_all_of; - -// mp_none_of -template class P> using mp_none_of = mp_bool< mp_count_if::value == 0 >; -template using mp_none_of_q = mp_none_of; - -// mp_any_of -template class P> using mp_any_of = mp_bool< mp_count_if::value != 0 >; -template using mp_any_of_q = mp_any_of; - -// mp_replace_at_c -namespace detail -{ - -template struct mp_replace_at_impl -{ - static_assert( I::value >= 0, "mp_replace_at: I must not be negative" ); - - template using _p = std::is_same>; - template using _f = W; - - using type = mp_transform_if<_p, _f, L, mp_iota > >; -}; - -} // namespace detail - -template using mp_replace_at = typename detail::mp_replace_at_impl::type; -template using mp_replace_at_c = typename detail::mp_replace_at_impl, W>::type; - -//mp_for_each(f) -namespace detail -{ - -template BOOST_MP11_CONSTEXPR F mp_for_each_impl( mp_list, F && f ) -{ - using A = int[sizeof...(T)]; - return (void)A{ ((void)f(T()), 0)... }, std::forward(f); -} - -template BOOST_MP11_CONSTEXPR F mp_for_each_impl( mp_list<>, F && f ) -{ - return std::forward(f); -} - -} // namespace detail - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, >= 1900 ) - -// msvc has a limit of 1024 - -template BOOST_MP11_CONSTEXPR mp_if_c::value <= 1024, F> mp_for_each( F && f ) -{ - return detail::mp_for_each_impl( mp_rename(), std::forward(f) ); -} - -template BOOST_MP11_CONSTEXPR mp_if_c::value >= 1025, F> mp_for_each( F && f ) -{ - using L2 = mp_rename; - - using L3 = mp_take_c; - using L4 = mp_drop_c; - - return mp_for_each( mp_for_each( std::forward(f) ) ); -} - -#else - -template BOOST_MP11_CONSTEXPR F mp_for_each( F && f ) -{ - return detail::mp_for_each_impl( mp_rename(), std::forward(f) ); -} - -#endif - -// mp_insert -template using mp_insert = mp_append, mp_push_front, T...>>; - -// mp_insert_c -template using mp_insert_c = mp_append, mp_push_front, T...>>; - -// mp_erase -template using mp_erase = mp_append, mp_drop>; - -// mp_erase_c -template using mp_erase_c = mp_append, mp_drop_c>; - -// mp_starts_with -// contributed by Glen Joseph Fernandes (glenjofe@gmail.com) -namespace detail { - -template -struct mp_starts_with_impl { }; - -template class L1, class... T1, template class L2, - class... T2> -struct mp_starts_with_impl, L2 > { - template - static mp_false check(L); - - template - static mp_true check(mp_list); - - using type = decltype(check(mp_list())); -}; - -} // namespace detail - -template -using mp_starts_with = typename detail::mp_starts_with_impl::type; - -// mp_min_element -// mp_max_element -// in detail/mp_min_element.hpp - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_ALGORITHM_HPP_INCLUDED diff --git a/boost/mp11/bind.hpp b/boost/mp11/bind.hpp deleted file mode 100644 index bbdecd2..0000000 --- a/boost/mp11/bind.hpp +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef BOOST_MP11_BIND_HPP_INCLUDED -#define BOOST_MP11_BIND_HPP_INCLUDED - -// Copyright 2017, 2018 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_bind_front -template class F, class... T> struct mp_bind_front -{ - // the indirection through mp_defer works around the language inability - // to expand U... into a fixed parameter list of an alias template - - template using fn = typename mp_defer::type; -}; - -template using mp_bind_front_q = mp_bind_front; - -// mp_bind_back -template class F, class... T> struct mp_bind_back -{ - template using fn = typename mp_defer::type; -}; - -template using mp_bind_back_q = mp_bind_back; - -// mp_arg -template struct mp_arg -{ - template using fn = mp_at_c, I>; -}; - -using _1 = mp_arg<0>; -using _2 = mp_arg<1>; -using _3 = mp_arg<2>; -using _4 = mp_arg<3>; -using _5 = mp_arg<4>; -using _6 = mp_arg<5>; -using _7 = mp_arg<6>; -using _8 = mp_arg<7>; -using _9 = mp_arg<8>; - -// mp_bind -template class F, class... T> struct mp_bind; - -namespace detail -{ - -template struct eval_bound_arg -{ - using type = V; -}; - -template struct eval_bound_arg, T...> -{ - using type = typename mp_arg::template fn; -}; - -template class F, class... U, class... T> struct eval_bound_arg, T...> -{ - using type = typename mp_bind::template fn; -}; - -template class F, class... U, class... T> struct eval_bound_arg, T...> -{ - using type = typename mp_bind_front::template fn; -}; - -template class F, class... U, class... T> struct eval_bound_arg, T...> -{ - using type = typename mp_bind_back::template fn; -}; - -} // namespace detail - -template class F, class... T> struct mp_bind -{ -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, == 1915 ) -private: - - template struct _f { using type = F::type...>; }; - -public: - - template using fn = typename _f::type; - -#else - - template using fn = F::type...>; - -#endif -}; - -template using mp_bind_q = mp_bind; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_BIND_HPP_INCLUDED diff --git a/boost/mp11/detail/config.hpp b/boost/mp11/detail/config.hpp deleted file mode 100644 index 248dce0..0000000 --- a/boost/mp11/detail/config.hpp +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_CONFIG_HPP_INCLUDED -#define BOOST_MP11_DETAIL_CONFIG_HPP_INCLUDED - -// Copyright 2016, 2018, 2019 Peter Dimov. -// -// 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 - -// BOOST_MP11_WORKAROUND - -#if defined( BOOST_STRICT_CONFIG ) || defined( BOOST_MP11_NO_WORKAROUNDS ) - -# define BOOST_MP11_WORKAROUND( symbol, test ) 0 - -#else - -# define BOOST_MP11_WORKAROUND( symbol, test ) ((symbol) != 0 && ((symbol) test)) - -#endif - -// - -#define BOOST_MP11_CUDA 0 -#define BOOST_MP11_CLANG 0 -#define BOOST_MP11_INTEL 0 -#define BOOST_MP11_GCC 0 -#define BOOST_MP11_MSVC 0 - -#define BOOST_MP11_CONSTEXPR constexpr - -#if defined( __CUDACC__ ) - -// nvcc - -# undef BOOST_MP11_CUDA -# define BOOST_MP11_CUDA (__CUDACC_VER_MAJOR__ * 1000000 + __CUDACC_VER_MINOR__ * 10000 + __CUDACC_VER_BUILD__) - -// CUDA (8.0) has no constexpr support in msvc mode: -# if defined(_MSC_VER) && (BOOST_MP11_CUDA < 9000000) - -# define BOOST_MP11_NO_CONSTEXPR - -# undef BOOST_MP11_CONSTEXPR -# define BOOST_MP11_CONSTEXPR - -# endif - -#elif defined(__clang__) - -// Clang - -# undef BOOST_MP11_CLANG -# define BOOST_MP11_CLANG (__clang_major__ * 100 + __clang_minor__) - -# if defined(__has_cpp_attribute) -# if __has_cpp_attribute(fallthrough) && __cplusplus >= 201406L // Clang 3.9+ in c++1z mode -# define BOOST_MP11_HAS_FOLD_EXPRESSIONS -# endif -# endif - -#if BOOST_MP11_CLANG < 400 && __cplusplus >= 201402L \ - && defined( __GLIBCXX__ ) && !__has_include() - -// Clang pre-4 in C++14 mode, libstdc++ pre-4.9, ::gets is not defined, -// but Clang tries to import it into std - - extern "C" char *gets (char *__s); -#endif - -#elif defined(__INTEL_COMPILER) - -// Intel C++ - -# undef BOOST_MP11_INTEL -# define BOOST_MP11_INTEL __INTEL_COMPILER - -#elif defined(__GNUC__) - -// g++ - -# undef BOOST_MP11_GCC -# define BOOST_MP11_GCC (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) - -#elif defined(_MSC_VER) - -// MS Visual C++ - -# undef BOOST_MP11_MSVC -# define BOOST_MP11_MSVC _MSC_VER - -# if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) -# define BOOST_MP11_NO_CONSTEXPR -# endif - -#if _MSC_FULL_VER < 190024210 // 2015u3 -# undef BOOST_MP11_CONSTEXPR -# define BOOST_MP11_CONSTEXPR -#endif - -#endif - -// BOOST_MP11_HAS_CXX14_CONSTEXPR - -#if !defined(BOOST_MP11_NO_CONSTEXPR) && defined(__cpp_constexpr) && __cpp_constexpr >= 201304 -# define BOOST_MP11_HAS_CXX14_CONSTEXPR -#endif - -// BOOST_MP11_HAS_FOLD_EXPRESSIONS - -#if !defined(BOOST_MP11_HAS_FOLD_EXPRESSIONS) && defined(__cpp_fold_expressions) && __cpp_fold_expressions >= 201603 -# define BOOST_MP11_HAS_FOLD_EXPRESSIONS -#endif - -// BOOST_MP11_HAS_TYPE_PACK_ELEMENT - -#if defined(__has_builtin) -# if __has_builtin(__type_pack_element) -# define BOOST_MP11_HAS_TYPE_PACK_ELEMENT -# endif -#endif - -// BOOST_MP11_DEPRECATED(msg) - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 ) -# define BOOST_MP11_DEPRECATED(msg) -#elif BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, < 50000 ) -# define BOOST_MP11_DEPRECATED(msg) __attribute__((deprecated(msg))) -#elif BOOST_MP11_WORKAROUND( BOOST_MP11_CLANG, < 304 ) -# define BOOST_MP11_DEPRECATED(msg) -#elif BOOST_MP11_CLANG -// -pedantic warns about [[deprecated]] when in C++11 mode -# define BOOST_MP11_DEPRECATED(msg) __attribute__((deprecated(msg))) -#else -# define BOOST_MP11_DEPRECATED(msg) [[deprecated(msg)]] -#endif - -#endif // #ifndef BOOST_MP11_DETAIL_CONFIG_HPP_INCLUDED diff --git a/boost/mp11/detail/mp_append.hpp b/boost/mp11/detail/mp_append.hpp deleted file mode 100644 index 937d15e..0000000 --- a/boost/mp11/detail/mp_append.hpp +++ /dev/null @@ -1,185 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_MP_APPEND_HPP_INCLUDED -#define BOOST_MP11_DETAIL_MP_APPEND_HPP_INCLUDED - -// Copyright 2015-2017 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_append - -namespace detail -{ - -template struct mp_append_impl; - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, <= 1800 ) - -template struct mp_append_impl -{ -}; - -template<> struct mp_append_impl<> -{ - using type = mp_list<>; -}; - -template class L, class... T> struct mp_append_impl> -{ - using type = L; -}; - -template class L1, class... T1, template class L2, class... T2> struct mp_append_impl, L2> -{ - using type = L1; -}; - -template class L1, class... T1, template class L2, class... T2, template class L3, class... T3> struct mp_append_impl, L2, L3> -{ - using type = L1; -}; - -template class L1, class... T1, template class L2, class... T2, template class L3, class... T3, template class L4, class... T4> struct mp_append_impl, L2, L3, L4> -{ - using type = L1; -}; - -template class L1, class... T1, template class L2, class... T2, template class L3, class... T3, template class L4, class... T4, template class L5, class... T5, class... Lr> struct mp_append_impl, L2, L3, L4, L5, Lr...> -{ - using type = typename mp_append_impl, Lr...>::type; -}; - -#else - -template, class L2 = mp_list<>, class L3 = mp_list<>, class L4 = mp_list<>, class L5 = mp_list<>, class L6 = mp_list<>, class L7 = mp_list<>, class L8 = mp_list<>, class L9 = mp_list<>, class L10 = mp_list<>, class L11 = mp_list<>> struct append_11_impl -{ -}; - -template< - template class L1, class... T1, - template class L2, class... T2, - template class L3, class... T3, - template class L4, class... T4, - template class L5, class... T5, - template class L6, class... T6, - template class L7, class... T7, - template class L8, class... T8, - template class L9, class... T9, - template class L10, class... T10, - template class L11, class... T11> - -struct append_11_impl, L2, L3, L4, L5, L6, L7, L8, L9, L10, L11> -{ - using type = L1; -}; - -template< - - class L00 = mp_list<>, class L01 = mp_list<>, class L02 = mp_list<>, class L03 = mp_list<>, class L04 = mp_list<>, class L05 = mp_list<>, class L06 = mp_list<>, class L07 = mp_list<>, class L08 = mp_list<>, class L09 = mp_list<>, class L0A = mp_list<>, - class L10 = mp_list<>, class L11 = mp_list<>, class L12 = mp_list<>, class L13 = mp_list<>, class L14 = mp_list<>, class L15 = mp_list<>, class L16 = mp_list<>, class L17 = mp_list<>, class L18 = mp_list<>, class L19 = mp_list<>, - class L20 = mp_list<>, class L21 = mp_list<>, class L22 = mp_list<>, class L23 = mp_list<>, class L24 = mp_list<>, class L25 = mp_list<>, class L26 = mp_list<>, class L27 = mp_list<>, class L28 = mp_list<>, class L29 = mp_list<>, - class L30 = mp_list<>, class L31 = mp_list<>, class L32 = mp_list<>, class L33 = mp_list<>, class L34 = mp_list<>, class L35 = mp_list<>, class L36 = mp_list<>, class L37 = mp_list<>, class L38 = mp_list<>, class L39 = mp_list<>, - class L40 = mp_list<>, class L41 = mp_list<>, class L42 = mp_list<>, class L43 = mp_list<>, class L44 = mp_list<>, class L45 = mp_list<>, class L46 = mp_list<>, class L47 = mp_list<>, class L48 = mp_list<>, class L49 = mp_list<>, - class L50 = mp_list<>, class L51 = mp_list<>, class L52 = mp_list<>, class L53 = mp_list<>, class L54 = mp_list<>, class L55 = mp_list<>, class L56 = mp_list<>, class L57 = mp_list<>, class L58 = mp_list<>, class L59 = mp_list<>, - class L60 = mp_list<>, class L61 = mp_list<>, class L62 = mp_list<>, class L63 = mp_list<>, class L64 = mp_list<>, class L65 = mp_list<>, class L66 = mp_list<>, class L67 = mp_list<>, class L68 = mp_list<>, class L69 = mp_list<>, - class L70 = mp_list<>, class L71 = mp_list<>, class L72 = mp_list<>, class L73 = mp_list<>, class L74 = mp_list<>, class L75 = mp_list<>, class L76 = mp_list<>, class L77 = mp_list<>, class L78 = mp_list<>, class L79 = mp_list<>, - class L80 = mp_list<>, class L81 = mp_list<>, class L82 = mp_list<>, class L83 = mp_list<>, class L84 = mp_list<>, class L85 = mp_list<>, class L86 = mp_list<>, class L87 = mp_list<>, class L88 = mp_list<>, class L89 = mp_list<>, - class L90 = mp_list<>, class L91 = mp_list<>, class L92 = mp_list<>, class L93 = mp_list<>, class L94 = mp_list<>, class L95 = mp_list<>, class L96 = mp_list<>, class L97 = mp_list<>, class L98 = mp_list<>, class L99 = mp_list<>, - class LA0 = mp_list<>, class LA1 = mp_list<>, class LA2 = mp_list<>, class LA3 = mp_list<>, class LA4 = mp_list<>, class LA5 = mp_list<>, class LA6 = mp_list<>, class LA7 = mp_list<>, class LA8 = mp_list<>, class LA9 = mp_list<> - -> struct append_111_impl -{ - using type = typename append_11_impl< - - typename append_11_impl::type, - typename append_11_impl, L10, L11, L12, L13, L14, L15, L16, L17, L18, L19>::type, - typename append_11_impl, L20, L21, L22, L23, L24, L25, L26, L27, L28, L29>::type, - typename append_11_impl, L30, L31, L32, L33, L34, L35, L36, L37, L38, L39>::type, - typename append_11_impl, L40, L41, L42, L43, L44, L45, L46, L47, L48, L49>::type, - typename append_11_impl, L50, L51, L52, L53, L54, L55, L56, L57, L58, L59>::type, - typename append_11_impl, L60, L61, L62, L63, L64, L65, L66, L67, L68, L69>::type, - typename append_11_impl, L70, L71, L72, L73, L74, L75, L76, L77, L78, L79>::type, - typename append_11_impl, L80, L81, L82, L83, L84, L85, L86, L87, L88, L89>::type, - typename append_11_impl, L90, L91, L92, L93, L94, L95, L96, L97, L98, L99>::type, - typename append_11_impl, LA0, LA1, LA2, LA3, LA4, LA5, LA6, LA7, LA8, LA9>::type - - >::type; -}; - -template< - - class L00, class L01, class L02, class L03, class L04, class L05, class L06, class L07, class L08, class L09, class L0A, - class L10, class L11, class L12, class L13, class L14, class L15, class L16, class L17, class L18, class L19, - class L20, class L21, class L22, class L23, class L24, class L25, class L26, class L27, class L28, class L29, - class L30, class L31, class L32, class L33, class L34, class L35, class L36, class L37, class L38, class L39, - class L40, class L41, class L42, class L43, class L44, class L45, class L46, class L47, class L48, class L49, - class L50, class L51, class L52, class L53, class L54, class L55, class L56, class L57, class L58, class L59, - class L60, class L61, class L62, class L63, class L64, class L65, class L66, class L67, class L68, class L69, - class L70, class L71, class L72, class L73, class L74, class L75, class L76, class L77, class L78, class L79, - class L80, class L81, class L82, class L83, class L84, class L85, class L86, class L87, class L88, class L89, - class L90, class L91, class L92, class L93, class L94, class L95, class L96, class L97, class L98, class L99, - class LA0, class LA1, class LA2, class LA3, class LA4, class LA5, class LA6, class LA7, class LA8, class LA9, - class... Lr - -> struct append_inf_impl -{ - using prefix = typename append_111_impl< - - L00, L01, L02, L03, L04, L05, L06, L07, L08, L09, L0A, - L10, L11, L12, L13, L14, L15, L16, L17, L18, L19, - L20, L21, L22, L23, L24, L25, L26, L27, L28, L29, - L30, L31, L32, L33, L34, L35, L36, L37, L38, L39, - L40, L41, L42, L43, L44, L45, L46, L47, L48, L49, - L50, L51, L52, L53, L54, L55, L56, L57, L58, L59, - L60, L61, L62, L63, L64, L65, L66, L67, L68, L69, - L70, L71, L72, L73, L74, L75, L76, L77, L78, L79, - L80, L81, L82, L83, L84, L85, L86, L87, L88, L89, - L90, L91, L92, L93, L94, L95, L96, L97, L98, L99, - LA0, LA1, LA2, LA3, LA4, LA5, LA6, LA7, LA8, LA9 - - >::type; - - using type = typename mp_append_impl::type; -}; - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 ) - -template -struct mp_append_impl_cuda_workaround -{ - using type = mp_if_c<(sizeof...(L) > 111), mp_quote, mp_if_c<(sizeof...(L) > 11), mp_quote, mp_quote > >; -}; - -template struct mp_append_impl: mp_append_impl_cuda_workaround::type::template fn -{ -}; - -#else - -template struct mp_append_impl: mp_if_c<(sizeof...(L) > 111), mp_quote, mp_if_c<(sizeof...(L) > 11), mp_quote, mp_quote > >::template fn -{ -}; - -#endif - -#endif - -} // namespace detail - -template using mp_append = typename detail::mp_append_impl::type; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_DETAIL_MP_APPEND_HPP_INCLUDED diff --git a/boost/mp11/detail/mp_copy_if.hpp b/boost/mp11/detail/mp_copy_if.hpp deleted file mode 100644 index 4edcde0..0000000 --- a/boost/mp11/detail/mp_copy_if.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_MP_COPY_IF_HPP_INCLUDED -#define BOOST_MP11_DETAIL_MP_COPY_IF_HPP_INCLUDED - -// Copyright 2015-2019 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_copy_if -namespace detail -{ - -template class P> struct mp_copy_if_impl -{ -}; - -template class L, class... T, template class P> struct mp_copy_if_impl, P> -{ -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) - template struct _f { using type = mp_if, mp_list, mp_list<>>; }; - using type = mp_append, typename _f::type...>; -#else - template using _f = mp_if, mp_list, mp_list<>>; - using type = mp_append, _f...>; -#endif -}; - -} // namespace detail - -template class P> using mp_copy_if = typename detail::mp_copy_if_impl::type; -template using mp_copy_if_q = mp_copy_if; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_DETAIL_MP_COPY_IF_HPP_INCLUDED diff --git a/boost/mp11/detail/mp_count.hpp b/boost/mp11/detail/mp_count.hpp deleted file mode 100644 index 1e221ca..0000000 --- a/boost/mp11/detail/mp_count.hpp +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_MP_COUNT_HPP_INCLUDED -#define BOOST_MP11_DETAIL_MP_COUNT_HPP_INCLUDED - -// Copyright 2015, 2016 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_count -namespace detail -{ - -template struct mp_count_impl; - -#if defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) - -template class L, class... T, class V> struct mp_count_impl, V> -{ - using type = mp_size_t<(std::is_same::value + ... + 0)>; -}; - -#elif !defined( BOOST_MP11_NO_CONSTEXPR ) - -constexpr std::size_t cx_plus() -{ - return 0; -} - -template constexpr std::size_t cx_plus(T1 t1, T... t) -{ - return static_cast(t1) + cx_plus(t...); -} - -template -constexpr std::size_t cx_plus(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10, T... t) -{ - return static_cast(t1 + t2 + t3 + t4 + t5 + t6 + t7 + t8 + t9 + t10) + cx_plus(t...); -} - -template class L, class... T, class V> struct mp_count_impl, V> -{ - using type = mp_size_t::value...)>; -}; - -#else - -template class L, class... T, class V> struct mp_count_impl, V> -{ - using type = mp_size_t...>::value>; -}; - -#endif - -} // namespace detail - -template using mp_count = typename detail::mp_count_impl::type; - -// mp_count_if -namespace detail -{ - -template class P> struct mp_count_if_impl; - -#if defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) && !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) - -template class L, class... T, template class P> struct mp_count_if_impl, P> -{ - using type = mp_size_t<(mp_to_bool>::value + ... + 0)>; -}; - -#elif !defined( BOOST_MP11_NO_CONSTEXPR ) - -template class L, class... T, template class P> struct mp_count_if_impl, P> -{ - using type = mp_size_t>::value...)>; -}; - -#else - -template class L, class... T, template class P> struct mp_count_if_impl, P> -{ -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) - - template struct _f { using type = mp_to_bool>; }; - using type = mp_size_t::type...>::value>; - -#else - - using type = mp_size_t>...>::value>; - -#endif -}; - -#endif - -} // namespace detail - -template class P> using mp_count_if = typename detail::mp_count_if_impl::type; -template using mp_count_if_q = mp_count_if; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_DETAIL_MP_COUNT_HPP_INCLUDED diff --git a/boost/mp11/detail/mp_fold.hpp b/boost/mp11/detail/mp_fold.hpp deleted file mode 100644 index 0745e87..0000000 --- a/boost/mp11/detail/mp_fold.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_MP_FOLD_HPP_INCLUDED -#define BOOST_MP11_DETAIL_MP_FOLD_HPP_INCLUDED - -// Copyright 2015-2017 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_fold -namespace detail -{ - -template class F> struct mp_fold_impl -{ -// An error "no type named 'type'" here means that the first argument to mp_fold is not a list -}; - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, <= 1800 ) - -template class L, class... T, class V, template class F> struct mp_fold_impl, V, F> -{ - static_assert( sizeof...(T) == 0, "T... must be empty" ); - using type = V; -}; - -#else - -template class L, class V, template class F> struct mp_fold_impl, V, F> -{ - using type = V; -}; - -#endif - -template class L, class T1, class... T, class V, template class F> struct mp_fold_impl, V, F> -{ - using type = typename mp_fold_impl, F, F>::type; -}; - -template class L, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10, class... T, class V, template class F> struct mp_fold_impl, V, F> -{ - using type = typename mp_fold_impl, F, T2>, T3>, T4>, T5>, T6>, T7>, T8>, T9>, T10>, F>::type; -}; - -} // namespace detail - -template class F> using mp_fold = typename detail::mp_fold_impl::type; -template using mp_fold_q = mp_fold; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_DETAIL_MP_FOLD_HPP_INCLUDED diff --git a/boost/mp11/detail/mp_is_list.hpp b/boost/mp11/detail/mp_is_list.hpp deleted file mode 100644 index 25b378b..0000000 --- a/boost/mp11/detail/mp_is_list.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_MP_IS_LIST_HPP_INCLUDED -#define BOOST_MP11_DETAIL_MP_IS_LIST_HPP_INCLUDED - -// Copyright 2015-2019 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_is_list -namespace detail -{ - -template struct mp_is_list_impl -{ - using type = mp_false; -}; - -template class L, class... T> struct mp_is_list_impl> -{ - using type = mp_true; -}; - -} // namespace detail - -template using mp_is_list = typename detail::mp_is_list_impl::type; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_DETAIL_MP_IS_LIST_HPP_INCLUDED diff --git a/boost/mp11/detail/mp_list.hpp b/boost/mp11/detail/mp_list.hpp deleted file mode 100644 index 8e8d3e5..0000000 --- a/boost/mp11/detail/mp_list.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_MP_LIST_HPP_INCLUDED -#define BOOST_MP11_DETAIL_MP_LIST_HPP_INCLUDED - -// Copyright 2015, 2016 Peter Dimov. -// -// 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 - -namespace boost -{ -namespace mp11 -{ - -// mp_list -template struct mp_list -{ -}; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_DETAIL_MP_LIST_HPP_INCLUDED diff --git a/boost/mp11/detail/mp_map_find.hpp b/boost/mp11/detail/mp_map_find.hpp deleted file mode 100644 index ec0fabd..0000000 --- a/boost/mp11/detail/mp_map_find.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_MP_MAP_FIND_HPP_INCLUDED -#define BOOST_MP11_DETAIL_MP_MAP_FIND_HPP_INCLUDED - -// Copyright 2015 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_map_find -namespace detail -{ - -template struct mp_map_find_impl; - -template class M, class... T, class K> struct mp_map_find_impl, K> -{ - using U = mp_inherit...>; - - template class L, class... U> static mp_identity> f( mp_identity>* ); - static mp_identity f( ... ); - - using V = decltype( f((U*)0) ); - - using type = typename V::type; -}; - -} // namespace detail - -template using mp_map_find = typename detail::mp_map_find_impl::type; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_DETAIL_MP_MAP_FIND_HPP_INCLUDED diff --git a/boost/mp11/detail/mp_min_element.hpp b/boost/mp11/detail/mp_min_element.hpp deleted file mode 100644 index 55c21ac..0000000 --- a/boost/mp11/detail/mp_min_element.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_MP_MIN_ELEMENT_HPP_INCLUDED -#define BOOST_MP11_DETAIL_MP_MIN_ELEMENT_HPP_INCLUDED - -// Copyright 2015-2017 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_min_element -namespace detail -{ - -template class P> struct select_min -{ - template using fn = mp_if, T1, T2>; -}; - -} // namespace detail - -template class P> using mp_min_element = mp_fold_q, mp_first, detail::select_min

>; -template using mp_min_element_q = mp_min_element; - -// mp_max_element -namespace detail -{ - -template class P> struct select_max -{ - template using fn = mp_if, T1, T2>; -}; - -} // namespace detail - -template class P> using mp_max_element = mp_fold_q, mp_first, detail::select_max

>; -template using mp_max_element_q = mp_max_element; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_DETAIL_MP_MIN_ELEMENT_HPP_INCLUDED diff --git a/boost/mp11/detail/mp_plus.hpp b/boost/mp11/detail/mp_plus.hpp deleted file mode 100644 index 90ed4c9..0000000 --- a/boost/mp11/detail/mp_plus.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_MP_PLUS_HPP_INCLUDED -#define BOOST_MP11_DETAIL_MP_PLUS_HPP_INCLUDED - -// Copyright 2015 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_plus -namespace detail -{ - -#if defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) && !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) - -template struct mp_plus_impl -{ - static const auto _v = (T::value + ... + 0); - using type = std::integral_constant::type, _v>; -}; - -#else - -template struct mp_plus_impl; - -template<> struct mp_plus_impl<> -{ - using type = std::integral_constant; -}; - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, < 40800 ) - -template struct mp_plus_impl -{ - static const decltype(T1::value + mp_plus_impl::type::value) _v = T1::value + mp_plus_impl::type::value; - using type = std::integral_constant::type, _v>; -}; - -template struct mp_plus_impl -{ - static const - decltype(T1::value + T2::value + T3::value + T4::value + T5::value + T6::value + T7::value + T8::value + T9::value + T10::value + mp_plus_impl::type::value) - _v = T1::value + T2::value + T3::value + T4::value + T5::value + T6::value + T7::value + T8::value + T9::value + T10::value + mp_plus_impl::type::value; - using type = std::integral_constant::type, _v>; -}; - -#else - -template struct mp_plus_impl -{ - static const auto _v = T1::value + mp_plus_impl::type::value; - using type = std::integral_constant::type, _v>; -}; - -template struct mp_plus_impl -{ - static const auto _v = T1::value + T2::value + T3::value + T4::value + T5::value + T6::value + T7::value + T8::value + T9::value + T10::value + mp_plus_impl::type::value; - using type = std::integral_constant::type, _v>; -}; - -#endif - -#endif - -} // namespace detail - -template using mp_plus = typename detail::mp_plus_impl::type; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_DETAIL_MP_PLUS_HPP_INCLUDED diff --git a/boost/mp11/detail/mp_remove_if.hpp b/boost/mp11/detail/mp_remove_if.hpp deleted file mode 100644 index 9687b4a..0000000 --- a/boost/mp11/detail/mp_remove_if.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_MP_REMOVE_IF_HPP_INCLUDED -#define BOOST_MP11_DETAIL_MP_REMOVE_IF_HPP_INCLUDED - -// Copyright 2015-2019 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_remove_if -namespace detail -{ - -template class P> struct mp_remove_if_impl -{ -}; - -template class L, class... T, template class P> struct mp_remove_if_impl, P> -{ -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) - template struct _f { using type = mp_if, mp_list<>, mp_list>; }; - using type = mp_append, typename _f::type...>; -#else - template using _f = mp_if, mp_list<>, mp_list>; - using type = mp_append, _f...>; -#endif -}; - -} // namespace detail - -template class P> using mp_remove_if = typename detail::mp_remove_if_impl::type; -template using mp_remove_if_q = mp_remove_if; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_DETAIL_MP_REMOVE_IF_HPP_INCLUDED diff --git a/boost/mp11/detail/mp_void.hpp b/boost/mp11/detail/mp_void.hpp deleted file mode 100644 index a7ac7b7..0000000 --- a/boost/mp11/detail/mp_void.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_MP_VOID_HPP_INCLUDED -#define BOOST_MP11_DETAIL_MP_VOID_HPP_INCLUDED - -// Copyright 2015-2017 Peter Dimov. -// -// 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 - -namespace boost -{ -namespace mp11 -{ - -// mp_void -namespace detail -{ - -template struct mp_void_impl -{ - using type = void; -}; - -} // namespace detail - -template using mp_void = typename detail::mp_void_impl::type; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_DETAIL_MP_VOID_HPP_INCLUDED diff --git a/boost/mp11/detail/mp_with_index.hpp b/boost/mp11/detail/mp_with_index.hpp deleted file mode 100644 index 1062877..0000000 --- a/boost/mp11/detail/mp_with_index.hpp +++ /dev/null @@ -1,396 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_MP_WITH_INDEX_HPP_INCLUDED -#define BOOST_MP11_DETAIL_MP_WITH_INDEX_HPP_INCLUDED - -// Copyright 2017 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include -#include -#include - -#if defined( BOOST_MP11_HAS_CXX14_CONSTEXPR ) -# define BOOST_MP11_CONSTEXPR14 constexpr -#else -# define BOOST_MP11_CONSTEXPR14 -#endif - -#if defined( _MSC_VER ) && !defined( __clang__ ) -# define BOOST_MP11_UNREACHABLE() __assume(false) -#else -# define BOOST_MP11_UNREACHABLE() __builtin_unreachable() -#endif - -namespace boost -{ -namespace mp11 -{ - -namespace detail -{ - -template struct mp_with_index_impl_ -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - case 4: return std::forward(f)( mp_size_t() ); - case 5: return std::forward(f)( mp_size_t() ); - case 6: return std::forward(f)( mp_size_t() ); - case 7: return std::forward(f)( mp_size_t() ); - case 8: return std::forward(f)( mp_size_t() ); - case 9: return std::forward(f)( mp_size_t() ); - case 10: return std::forward(f)( mp_size_t() ); - case 11: return std::forward(f)( mp_size_t() ); - case 12: return std::forward(f)( mp_size_t() ); - case 13: return std::forward(f)( mp_size_t() ); - case 14: return std::forward(f)( mp_size_t() ); - case 15: return std::forward(f)( mp_size_t() ); - } - - return mp_with_index_impl_::template call( i-16, std::forward(f) ); - } -}; - -template<> struct mp_with_index_impl_<0> -{ -}; - -template<> struct mp_with_index_impl_<1> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t /*i*/, F && f ) - { - return std::forward(f)( mp_size_t() ); - } -}; - -template<> struct mp_with_index_impl_<2> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<3> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<4> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<5> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - case 4: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<6> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - case 4: return std::forward(f)( mp_size_t() ); - case 5: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<7> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - case 4: return std::forward(f)( mp_size_t() ); - case 5: return std::forward(f)( mp_size_t() ); - case 6: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<8> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - case 4: return std::forward(f)( mp_size_t() ); - case 5: return std::forward(f)( mp_size_t() ); - case 6: return std::forward(f)( mp_size_t() ); - case 7: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<9> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - case 4: return std::forward(f)( mp_size_t() ); - case 5: return std::forward(f)( mp_size_t() ); - case 6: return std::forward(f)( mp_size_t() ); - case 7: return std::forward(f)( mp_size_t() ); - case 8: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<10> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - case 4: return std::forward(f)( mp_size_t() ); - case 5: return std::forward(f)( mp_size_t() ); - case 6: return std::forward(f)( mp_size_t() ); - case 7: return std::forward(f)( mp_size_t() ); - case 8: return std::forward(f)( mp_size_t() ); - case 9: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<11> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - case 4: return std::forward(f)( mp_size_t() ); - case 5: return std::forward(f)( mp_size_t() ); - case 6: return std::forward(f)( mp_size_t() ); - case 7: return std::forward(f)( mp_size_t() ); - case 8: return std::forward(f)( mp_size_t() ); - case 9: return std::forward(f)( mp_size_t() ); - case 10: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<12> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - case 4: return std::forward(f)( mp_size_t() ); - case 5: return std::forward(f)( mp_size_t() ); - case 6: return std::forward(f)( mp_size_t() ); - case 7: return std::forward(f)( mp_size_t() ); - case 8: return std::forward(f)( mp_size_t() ); - case 9: return std::forward(f)( mp_size_t() ); - case 10: return std::forward(f)( mp_size_t() ); - case 11: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<13> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - case 4: return std::forward(f)( mp_size_t() ); - case 5: return std::forward(f)( mp_size_t() ); - case 6: return std::forward(f)( mp_size_t() ); - case 7: return std::forward(f)( mp_size_t() ); - case 8: return std::forward(f)( mp_size_t() ); - case 9: return std::forward(f)( mp_size_t() ); - case 10: return std::forward(f)( mp_size_t() ); - case 11: return std::forward(f)( mp_size_t() ); - case 12: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<14> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - case 4: return std::forward(f)( mp_size_t() ); - case 5: return std::forward(f)( mp_size_t() ); - case 6: return std::forward(f)( mp_size_t() ); - case 7: return std::forward(f)( mp_size_t() ); - case 8: return std::forward(f)( mp_size_t() ); - case 9: return std::forward(f)( mp_size_t() ); - case 10: return std::forward(f)( mp_size_t() ); - case 11: return std::forward(f)( mp_size_t() ); - case 12: return std::forward(f)( mp_size_t() ); - case 13: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<15> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - case 4: return std::forward(f)( mp_size_t() ); - case 5: return std::forward(f)( mp_size_t() ); - case 6: return std::forward(f)( mp_size_t() ); - case 7: return std::forward(f)( mp_size_t() ); - case 8: return std::forward(f)( mp_size_t() ); - case 9: return std::forward(f)( mp_size_t() ); - case 10: return std::forward(f)( mp_size_t() ); - case 11: return std::forward(f)( mp_size_t() ); - case 12: return std::forward(f)( mp_size_t() ); - case 13: return std::forward(f)( mp_size_t() ); - case 14: return std::forward(f)( mp_size_t() ); - } - } -}; - -template<> struct mp_with_index_impl_<16> -{ - template static BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) call( std::size_t i, F && f ) - { - switch( i ) - { - default: BOOST_MP11_UNREACHABLE(); - case 0: return std::forward(f)( mp_size_t() ); - case 1: return std::forward(f)( mp_size_t() ); - case 2: return std::forward(f)( mp_size_t() ); - case 3: return std::forward(f)( mp_size_t() ); - case 4: return std::forward(f)( mp_size_t() ); - case 5: return std::forward(f)( mp_size_t() ); - case 6: return std::forward(f)( mp_size_t() ); - case 7: return std::forward(f)( mp_size_t() ); - case 8: return std::forward(f)( mp_size_t() ); - case 9: return std::forward(f)( mp_size_t() ); - case 10: return std::forward(f)( mp_size_t() ); - case 11: return std::forward(f)( mp_size_t() ); - case 12: return std::forward(f)( mp_size_t() ); - case 13: return std::forward(f)( mp_size_t() ); - case 14: return std::forward(f)( mp_size_t() ); - case 15: return std::forward(f)( mp_size_t() ); - } - } -}; - -} // namespace detail - -template inline BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) mp_with_index( std::size_t i, F && f ) -{ - assert( i < N ); - return detail::mp_with_index_impl_::template call<0>( i, std::forward(f) ); -} - -template inline BOOST_MP11_CONSTEXPR14 decltype(std::declval()(std::declval>())) mp_with_index( std::size_t i, F && f ) -{ - return mp_with_index( i, std::forward(f) ); -} - -#undef BOOST_MP11_CONSTEXPR14 -#undef BOOST_MP11_UNREACHABLE - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_DETAIL_MP_WITH_INDEX_HPP_INCLUDED diff --git a/boost/mp11/detail/mpl_common.hpp b/boost/mp11/detail/mpl_common.hpp deleted file mode 100644 index 208885c..0000000 --- a/boost/mp11/detail/mpl_common.hpp +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef BOOST_MP11_DETAIL_MPL_COMMON_HPP_INCLUDED -#define BOOST_MP11_DETAIL_MPL_COMMON_HPP_INCLUDED - -// Copyright 2017, 2019 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include - -namespace boost -{ -namespace mpl -{ - -struct forward_iterator_tag; - -namespace aux -{ - -struct mp11_tag {}; - -template struct mp11_iterator -{ - using category = forward_iterator_tag; - - using type = mp11::mp_first; - using next = mp11_iterator>; -}; - -} // namespace aux - -// at - -template< typename Tag > struct at_impl; - -template<> struct at_impl -{ - template struct apply - { - using type = mp11::mp_at; - }; -}; - -// back - -template< typename Tag > struct back_impl; - -template<> struct back_impl -{ - template struct apply - { - using N = mp11::mp_size; - using type = mp11::mp_at_c; - }; -}; - -// begin - -template< typename Tag > struct begin_impl; - -template<> struct begin_impl -{ - template struct apply - { - using type = aux::mp11_iterator; - }; -}; - -// clear - -template< typename Tag > struct clear_impl; - -template<> struct clear_impl -{ - template struct apply - { - using type = mp11::mp_clear; - }; -}; - -// end - -template< typename Tag > struct end_impl; - -template<> struct end_impl -{ - template struct apply - { - using type = aux::mp11_iterator>; - }; -}; - -// front - -template< typename Tag > struct front_impl; - -template<> struct front_impl -{ - template struct apply - { - using type = mp11::mp_front; - }; -}; - -// pop_front - -template< typename Tag > struct pop_front_impl; - -template<> struct pop_front_impl -{ - template struct apply - { - using type = mp11::mp_pop_front; - }; -}; - -// push_back - -template< typename Tag > struct push_back_impl; - -template<> struct push_back_impl -{ - template struct apply - { - using type = mp11::mp_push_back; - }; -}; - -// push_front - -template< typename Tag > struct push_front_impl; - -template<> struct push_front_impl -{ - template struct apply - { - using type = mp11::mp_push_front; - }; -}; - -// size - -template< typename Tag > struct size_impl; - -template<> struct size_impl -{ - template struct apply - { - using type = mp11::mp_size; - }; -}; - -} // namespace mpl -} // namespace boost - -#endif // #ifndef BOOST_MP11_DETAIL_MPL_COMMON_HPP_INCLUDED diff --git a/boost/mp11/function.hpp b/boost/mp11/function.hpp deleted file mode 100644 index 1aeccac..0000000 --- a/boost/mp11/function.hpp +++ /dev/null @@ -1,226 +0,0 @@ -#ifndef BOOST_MP11_FUNCTION_HPP_INCLUDED -#define BOOST_MP11_FUNCTION_HPP_INCLUDED - -// Copyright 2015-2019 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_void -// in detail/mp_void.hpp - -// mp_and -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1910 ) - -namespace detail -{ - -template struct mp_and_impl; - -} // namespace detail - -template using mp_and = mp_to_bool< typename detail::mp_and_impl::type >; - -namespace detail -{ - -template<> struct mp_and_impl<> -{ - using type = mp_true; -}; - -template struct mp_and_impl -{ - using type = T; -}; - -template struct mp_and_impl -{ - using type = mp_eval_if< mp_not, T1, mp_and, T... >; -}; - -} // namespace detail - -#else - -namespace detail -{ - -template struct mp_and_impl -{ - using type = mp_false; -}; - -template struct mp_and_impl< mp_list, mp_void...> > -{ - using type = mp_true; -}; - -} // namespace detail - -template using mp_and = typename detail::mp_and_impl>::type; - -#endif - -// mp_all -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86355 -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) || BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, != 0 ) - -template using mp_all = mp_bool< mp_count_if< mp_list, mp_not >::value == 0 >; - -#elif defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) - -template using mp_all = mp_bool<(static_cast(T::value) && ...)>; - -#else - -template using mp_all = mp_and...>; - -#endif - -// mp_or -namespace detail -{ - -template struct mp_or_impl; - -} // namespace detail - -template using mp_or = mp_to_bool< typename detail::mp_or_impl::type >; - -namespace detail -{ - -template<> struct mp_or_impl<> -{ - using type = mp_false; -}; - -template struct mp_or_impl -{ - using type = T; -}; - -template struct mp_or_impl -{ - using type = mp_eval_if< T1, T1, mp_or, T... >; -}; - -} // namespace detail - -// mp_any -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86356 -#if defined( BOOST_MP11_HAS_FOLD_EXPRESSIONS ) && !BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, != 0 ) && !BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1920 ) - -template using mp_any = mp_bool<(static_cast(T::value) || ...)>; - -#else - -template using mp_any = mp_bool< mp_count_if< mp_list, mp_to_bool >::value != 0 >; - -#endif - -// mp_same -namespace detail -{ - -template struct mp_same_impl; - -template<> struct mp_same_impl<> -{ - using type = mp_true; -}; - -template struct mp_same_impl -{ - using type = mp_all...>; -}; - -} // namespace detail - -template using mp_same = typename detail::mp_same_impl::type; - -// mp_similar -namespace detail -{ - -template struct mp_similar_impl; - -template<> struct mp_similar_impl<> -{ - using type = mp_true; -}; - -template struct mp_similar_impl -{ - using type = mp_true; -}; - -template struct mp_similar_impl -{ - using type = mp_true; -}; - -template struct mp_similar_impl -{ - using type = mp_false; -}; - -template class L, class... T1, class... T2> struct mp_similar_impl, L> -{ - using type = mp_true; -}; - -template class L, class... T> struct mp_similar_impl, L> -{ - using type = mp_true; -}; - -template struct mp_similar_impl -{ - using type = mp_all< typename mp_similar_impl::type, typename mp_similar_impl::type, typename mp_similar_impl::type... >; -}; - -} // namespace detail - -template using mp_similar = typename detail::mp_similar_impl::type; - -#if BOOST_MP11_GCC -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wsign-compare" -#endif - -// mp_less -template using mp_less = mp_bool<(T1::value < 0 && T2::value >= 0) || ((T1::value < T2::value) && !(T1::value >= 0 && T2::value < 0))>; - -#if BOOST_MP11_GCC -# pragma GCC diagnostic pop -#endif - -// mp_min -template using mp_min = mp_min_element, mp_less>; - -// mp_max -template using mp_max = mp_max_element, mp_less>; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_FUNCTION_HPP_INCLUDED diff --git a/boost/mp11/integer_sequence.hpp b/boost/mp11/integer_sequence.hpp deleted file mode 100644 index 83e2450..0000000 --- a/boost/mp11/integer_sequence.hpp +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef BOOST_MP11_INTEGER_SEQUENCE_HPP_INCLUDED -#define BOOST_MP11_INTEGER_SEQUENCE_HPP_INCLUDED - -// Copyright 2015, 2017, 2019 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include - -#if defined(__has_builtin) -# if __has_builtin(__make_integer_seq) -# define BOOST_MP11_HAS_MAKE_INTEGER_SEQ -# endif -#endif - -namespace boost -{ -namespace mp11 -{ - -// integer_sequence -template struct integer_sequence -{ -}; - -#if defined(BOOST_MP11_HAS_MAKE_INTEGER_SEQ) - -template using make_integer_sequence = __make_integer_seq; - -#else - -// detail::make_integer_sequence_impl -namespace detail -{ - -// iseq_if_c -template struct iseq_if_c_impl; - -template struct iseq_if_c_impl -{ - using type = T; -}; - -template struct iseq_if_c_impl -{ - using type = E; -}; - -template using iseq_if_c = typename iseq_if_c_impl::type; - -// iseq_identity -template struct iseq_identity -{ - using type = T; -}; - -template struct append_integer_sequence; - -template struct append_integer_sequence, integer_sequence> -{ - using type = integer_sequence< T, I..., ( J + sizeof...(I) )... >; -}; - -template struct make_integer_sequence_impl; - -template struct make_integer_sequence_impl_ -{ -private: - - static_assert( N >= 0, "make_integer_sequence: N must not be negative" ); - - static T const M = N / 2; - static T const R = N % 2; - - using S1 = typename make_integer_sequence_impl::type; - using S2 = typename append_integer_sequence::type; - using S3 = typename make_integer_sequence_impl::type; - using S4 = typename append_integer_sequence::type; - -public: - - using type = S4; -}; - -template struct make_integer_sequence_impl: iseq_if_c>, iseq_if_c>, make_integer_sequence_impl_ > > -{ -}; - -} // namespace detail - -// make_integer_sequence -template using make_integer_sequence = typename detail::make_integer_sequence_impl::type; - -#endif // defined(BOOST_MP11_HAS_MAKE_INTEGER_SEQ) - -// index_sequence -template using index_sequence = integer_sequence; - -// make_index_sequence -template using make_index_sequence = make_integer_sequence; - -// index_sequence_for -template using index_sequence_for = make_integer_sequence; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_INTEGER_SEQUENCE_HPP_INCLUDED diff --git a/boost/mp11/integral.hpp b/boost/mp11/integral.hpp deleted file mode 100644 index 0671673..0000000 --- a/boost/mp11/integral.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef BOOST_MP11_INTEGRAL_HPP_INCLUDED -#define BOOST_MP11_INTEGRAL_HPP_INCLUDED - -// Copyright 2015 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_bool -template using mp_bool = std::integral_constant; - -using mp_true = mp_bool; -using mp_false = mp_bool; - -// mp_to_bool -template using mp_to_bool = mp_bool( T::value )>; - -// mp_not -template using mp_not = mp_bool< !T::value >; - -// mp_int -template using mp_int = std::integral_constant; - -// mp_size_t -template using mp_size_t = std::integral_constant; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_INTEGRAL_HPP_INCLUDED diff --git a/boost/mp11/list.hpp b/boost/mp11/list.hpp deleted file mode 100644 index e0d3e29..0000000 --- a/boost/mp11/list.hpp +++ /dev/null @@ -1,335 +0,0 @@ -#ifndef BOOST_MP11_LIST_HPP_INCLUDED -#define BOOST_MP11_LIST_HPP_INCLUDED - -// Copyright 2015-2017 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include -#include -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_list_c -template using mp_list_c = mp_list...>; - -// mp_is_list -// in detail/mp_is_list.hpp - -// mp_size -namespace detail -{ - -template struct mp_size_impl -{ -// An error "no type named 'type'" here means that the argument to mp_size is not a list -}; - -template class L, class... T> struct mp_size_impl> -{ - using type = mp_size_t; -}; - -} // namespace detail - -template using mp_size = typename detail::mp_size_impl::type; - -// mp_empty -template using mp_empty = mp_bool< mp_size::value == 0 >; - -// mp_assign -namespace detail -{ - -template struct mp_assign_impl; - -template class L1, class... T, template class L2, class... U> struct mp_assign_impl, L2> -{ - using type = L1; -}; - -} // namespace detail - -template using mp_assign = typename detail::mp_assign_impl::type; - -// mp_clear -template using mp_clear = mp_assign>; - -// mp_front -namespace detail -{ - -template struct mp_front_impl -{ -// An error "no type named 'type'" here means that the argument to mp_front -// is either not a list, or is an empty list -}; - -template class L, class T1, class... T> struct mp_front_impl> -{ - using type = T1; -}; - -} // namespace detail - -template using mp_front = typename detail::mp_front_impl::type; - -// mp_pop_front -namespace detail -{ - -template struct mp_pop_front_impl -{ -// An error "no type named 'type'" here means that the argument to mp_pop_front -// is either not a list, or is an empty list -}; - -template class L, class T1, class... T> struct mp_pop_front_impl> -{ - using type = L; -}; - -} // namespace detail - -template using mp_pop_front = typename detail::mp_pop_front_impl::type; - -// mp_first -template using mp_first = mp_front; - -// mp_rest -template using mp_rest = mp_pop_front; - -// mp_second -namespace detail -{ - -template struct mp_second_impl -{ -// An error "no type named 'type'" here means that the argument to mp_second -// is either not a list, or has fewer than two elements -}; - -template class L, class T1, class T2, class... T> struct mp_second_impl> -{ - using type = T2; -}; - -} // namespace detail - -template using mp_second = typename detail::mp_second_impl::type; - -// mp_third -namespace detail -{ - -template struct mp_third_impl -{ -// An error "no type named 'type'" here means that the argument to mp_third -// is either not a list, or has fewer than three elements -}; - -template class L, class T1, class T2, class T3, class... T> struct mp_third_impl> -{ - using type = T3; -}; - -} // namespace detail - -template using mp_third = typename detail::mp_third_impl::type; - -// mp_push_front -namespace detail -{ - -template struct mp_push_front_impl -{ -// An error "no type named 'type'" here means that the first argument to mp_push_front is not a list -}; - -template class L, class... U, class... T> struct mp_push_front_impl, T...> -{ - using type = L; -}; - -} // namespace detail - -template using mp_push_front = typename detail::mp_push_front_impl::type; - -// mp_push_back -namespace detail -{ - -template struct mp_push_back_impl -{ -// An error "no type named 'type'" here means that the first argument to mp_push_back is not a list -}; - -template class L, class... U, class... T> struct mp_push_back_impl, T...> -{ - using type = L; -}; - -} // namespace detail - -template using mp_push_back = typename detail::mp_push_back_impl::type; - -// mp_rename -namespace detail -{ - -template class B> struct mp_rename_impl -{ -// An error "no type named 'type'" here means that the first argument to mp_rename is not a list -}; - -template class A, class... T, template class B> struct mp_rename_impl, B> -{ - using type = B; -}; - -} // namespace detail - -template class B> using mp_rename = typename detail::mp_rename_impl::type; - -template class F, class L> using mp_apply = typename detail::mp_rename_impl::type; - -template using mp_apply_q = typename detail::mp_rename_impl::type; - -// mp_replace_front -namespace detail -{ - -template struct mp_replace_front_impl -{ -// An error "no type named 'type'" here means that the first argument to mp_replace_front -// is either not a list, or is an empty list -}; - -template class L, class U1, class... U, class T> struct mp_replace_front_impl, T> -{ - using type = L; -}; - -} // namespace detail - -template using mp_replace_front = typename detail::mp_replace_front_impl::type; - -// mp_replace_first -template using mp_replace_first = typename detail::mp_replace_front_impl::type; - -// mp_replace_second -namespace detail -{ - -template struct mp_replace_second_impl -{ -// An error "no type named 'type'" here means that the first argument to mp_replace_second -// is either not a list, or has fewer than two elements -}; - -template class L, class U1, class U2, class... U, class T> struct mp_replace_second_impl, T> -{ - using type = L; -}; - -} // namespace detail - -template using mp_replace_second = typename detail::mp_replace_second_impl::type; - -// mp_replace_third -namespace detail -{ - -template struct mp_replace_third_impl -{ -// An error "no type named 'type'" here means that the first argument to mp_replace_third -// is either not a list, or has fewer than three elements -}; - -template class L, class U1, class U2, class U3, class... U, class T> struct mp_replace_third_impl, T> -{ - using type = L; -}; - -} // namespace detail - -template using mp_replace_third = typename detail::mp_replace_third_impl::type; - -// mp_transform_front -namespace detail -{ - -template class F> struct mp_transform_front_impl -{ -// An error "no type named 'type'" here means that the first argument to mp_transform_front -// is either not a list, or is an empty list -}; - -template class L, class U1, class... U, template class F> struct mp_transform_front_impl, F> -{ - using type = L, U...>; -}; - -} // namespace detail - -template class F> using mp_transform_front = typename detail::mp_transform_front_impl::type; -template using mp_transform_front_q = mp_transform_front; - -// mp_transform_first -template class F> using mp_transform_first = typename detail::mp_transform_front_impl::type; -template using mp_transform_first_q = mp_transform_first; - -// mp_transform_second -namespace detail -{ - -template class F> struct mp_transform_second_impl -{ -// An error "no type named 'type'" here means that the first argument to mp_transform_second -// is either not a list, or has fewer than two elements -}; - -template class L, class U1, class U2, class... U, template class F> struct mp_transform_second_impl, F> -{ - using type = L, U...>; -}; - -} // namespace detail - -template class F> using mp_transform_second = typename detail::mp_transform_second_impl::type; -template using mp_transform_second_q = mp_transform_second; - -// mp_transform_third -namespace detail -{ - -template class F> struct mp_transform_third_impl -{ -// An error "no type named 'type'" here means that the first argument to mp_transform_third -// is either not a list, or has fewer than three elements -}; - -template class L, class U1, class U2, class U3, class... U, template class F> struct mp_transform_third_impl, F> -{ - using type = L, U...>; -}; - -} // namespace detail - -template class F> using mp_transform_third = typename detail::mp_transform_third_impl::type; -template using mp_transform_third_q = mp_transform_third; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_LIST_HPP_INCLUDED diff --git a/boost/mp11/map.hpp b/boost/mp11/map.hpp deleted file mode 100644 index b9581ac..0000000 --- a/boost/mp11/map.hpp +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef BOOST_MP11_MAP_HPP_INCLUDED -#define BOOST_MP11_MAP_HPP_INCLUDED - -// Copyright 2015-2017 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_map_contains -template using mp_map_contains = mp_not, void>>; - -// mp_map_insert -template using mp_map_insert = mp_if< mp_map_contains>, M, mp_push_back >; - -// mp_map_replace -namespace detail -{ - -template struct mp_map_replace_impl; - -template class M, class... U, class T> struct mp_map_replace_impl, T> -{ - using K = mp_first; - - // mp_replace_if is inlined here using a struct _f because of msvc-14.0 - - template struct _f { using type = mp_if< std::is_same, K>, T, V >; }; - - using type = mp_if< mp_map_contains, K>, M::type...>, M >; -}; - -} // namespace detail - -template using mp_map_replace = typename detail::mp_map_replace_impl::type; - -// mp_map_update -namespace detail -{ - -template class F> struct mp_map_update_impl -{ - template using _f = std::is_same, mp_first>; - - // _f3> -> L> - template using _f3 = mp_assign, mp_rename > >; - - using type = mp_if< mp_map_contains>, mp_transform_if<_f, _f3, M>, mp_push_back >; -}; - -} // namespace detail - -template class F> using mp_map_update = typename detail::mp_map_update_impl::type; -template using mp_map_update_q = mp_map_update; - -// mp_map_erase -namespace detail -{ - -template struct mp_map_erase_impl -{ - template using _f = std::is_same, K>; - using type = mp_remove_if; -}; - -} // namespace detail - -template using mp_map_erase = typename detail::mp_map_erase_impl::type; - -// mp_map_keys -template using mp_map_keys = mp_transform; - -// mp_is_map -namespace detail -{ - -template struct mp_is_map_element: mp_false -{ -}; - -template class L, class T1, class... T> struct mp_is_map_element>: mp_true -{ -}; - -template using mp_keys_are_set = mp_is_set>; - -template struct mp_is_map_impl -{ - using type = mp_false; -}; - -template class M, class... T> struct mp_is_map_impl> -{ - using type = mp_eval_if...>>, mp_false, mp_keys_are_set, M>; -}; - -} // namespace detail - -template using mp_is_map = typename detail::mp_is_map_impl::type; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_MAP_HPP_INCLUDED diff --git a/boost/mp11/mpl.hpp b/boost/mp11/mpl.hpp deleted file mode 100644 index 994705f..0000000 --- a/boost/mp11/mpl.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef BOOST_MP11_MPL_HPP_INCLUDED -#define BOOST_MP11_MPL_HPP_INCLUDED - -// Copyright 2017, 2019 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include - -#endif // #ifndef BOOST_MP11_MPL_HPP_INCLUDED diff --git a/boost/mp11/mpl_list.hpp b/boost/mp11/mpl_list.hpp deleted file mode 100644 index 643da43..0000000 --- a/boost/mp11/mpl_list.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef BOOST_MP11_MPL_LIST_HPP_INCLUDED -#define BOOST_MP11_MPL_LIST_HPP_INCLUDED - -// Copyright 2017, 2019 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include - -namespace boost -{ -namespace mpl -{ - -template< typename Sequence > struct sequence_tag; - -template struct sequence_tag> -{ - using type = aux::mp11_tag; -}; - -} // namespace mpl -} // namespace boost - -#endif // #ifndef BOOST_MP11_MPL_LIST_HPP_INCLUDED diff --git a/boost/mp11/mpl_tuple.hpp b/boost/mp11/mpl_tuple.hpp deleted file mode 100644 index b6900b1..0000000 --- a/boost/mp11/mpl_tuple.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef BOOST_MP11_MPL_TUPLE_HPP_INCLUDED -#define BOOST_MP11_MPL_TUPLE_HPP_INCLUDED - -// Copyright 2017, 2019 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include - -namespace boost -{ -namespace mpl -{ - -template< typename Sequence > struct sequence_tag; - -template struct sequence_tag> -{ - using type = aux::mp11_tag; -}; - -} // namespace mpl -} // namespace boost - -#endif // #ifndef BOOST_MP11_MPL_TUPLE_HPP_INCLUDED diff --git a/boost/mp11/set.hpp b/boost/mp11/set.hpp deleted file mode 100644 index 808636b..0000000 --- a/boost/mp11/set.hpp +++ /dev/null @@ -1,188 +0,0 @@ -#ifndef BOOST_MP11_SET_HPP_INCLUDED -#define BOOST_MP11_SET_HPP_INCLUDED - -// Copyright 2015, 2019 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_set_contains -namespace detail -{ - -template struct mp_set_contains_impl -{ -}; - -template class L, class... T, class V> struct mp_set_contains_impl, V> -{ - using type = mp_to_bool, mp_inherit...> > >; -}; - -} // namespace detail - -template using mp_set_contains = typename detail::mp_set_contains_impl::type; - -// mp_set_push_back -namespace detail -{ - -template struct mp_set_push_back_impl -{ -}; - -template class L, class... U> struct mp_set_push_back_impl> -{ - using type = L; -}; - -template class L, class... U, class T1, class... T> struct mp_set_push_back_impl, T1, T...> -{ - using S = mp_if, T1>, L, L>; - using type = typename mp_set_push_back_impl::type; -}; - -} // namespace detail - -template using mp_set_push_back = typename detail::mp_set_push_back_impl::type; - -// mp_set_push_front -namespace detail -{ - -template struct mp_set_push_front_impl -{ -}; - -template class L, class... U> struct mp_set_push_front_impl> -{ - using type = L; -}; - -template class L, class... U, class T1> struct mp_set_push_front_impl, T1> -{ - using type = mp_if, T1>, L, L>; -}; - -template class L, class... U, class T1, class... T> struct mp_set_push_front_impl, T1, T...> -{ - using S = typename mp_set_push_front_impl, T...>::type; - using type = typename mp_set_push_front_impl::type; -}; - -} // namespace detail - -template using mp_set_push_front = typename detail::mp_set_push_front_impl::type; - -// mp_is_set -namespace detail -{ - -template struct mp_is_set_impl -{ - using type = mp_false; -}; - -template class L, class... T> struct mp_is_set_impl> -{ - using type = mp_to_bool, mp_set_push_back, T...> > >; -}; - -} // namespace detail - -template using mp_is_set = typename detail::mp_is_set_impl::type; - -// mp_set_union -namespace detail -{ - -template struct mp_set_union_impl -{ -}; - -template<> struct mp_set_union_impl<> -{ - using type = mp_list<>; -}; - -template class L, class... T> struct mp_set_union_impl> -{ - using type = L; -}; - -template class L1, class... T1, template class L2, class... T2> struct mp_set_union_impl, L2> -{ - using type = mp_set_push_back, T2...>; -}; - -template using mp_set_union_ = typename mp_set_union_impl, L...>>::type; - -template struct mp_set_union_impl: mp_defer -{ -}; - -} // namespace detail - -template using mp_set_union = typename detail::mp_set_union_impl::type; - -// mp_set_intersection -namespace detail -{ - -template struct in_all_sets -{ - template using fn = mp_all< mp_set_contains... >; -}; - -template using mp_set_intersection_ = mp_if< mp_all...>, mp_copy_if_q> >; - -template struct mp_set_intersection_impl -{ -}; - -template<> struct mp_set_intersection_impl<> -{ - using type = mp_list<>; -}; - -template struct mp_set_intersection_impl: mp_defer -{ -}; - -} // namespace detail - -template using mp_set_intersection = typename detail::mp_set_intersection_impl::type; - -// mp_set_difference -namespace detail -{ - -template struct in_any_set -{ - template using fn = mp_any< mp_set_contains... >; -}; - -} // namespace detail - -template using mp_set_difference = mp_if< mp_all...>, mp_remove_if_q> >; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_SET_HPP_INCLUDED diff --git a/boost/mp11/tuple.hpp b/boost/mp11/tuple.hpp deleted file mode 100644 index c65be1b..0000000 --- a/boost/mp11/tuple.hpp +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef BOOST_MP11_TUPLE_HPP_INCLUDED -#define BOOST_MP11_TUPLE_HPP_INCLUDED - -// Copyright 2015, 2017 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include -#include -#include -#include - -#if BOOST_MP11_MSVC -# pragma warning( push ) -# pragma warning( disable: 4100 ) // unreferenced formal parameter 'tp' -#endif - -namespace boost -{ -namespace mp11 -{ - -// tuple_apply -namespace detail -{ - -template BOOST_MP11_CONSTEXPR auto tuple_apply_impl( F && f, Tp && tp, integer_sequence ) - -> decltype( std::forward(f)( std::get(std::forward(tp))... ) ) -{ - return std::forward(f)( std::get(std::forward(tp))... ); -} - -} // namespace detail - -template::type>::value>> -BOOST_MP11_CONSTEXPR auto tuple_apply( F && f, Tp && tp ) - -> decltype( detail::tuple_apply_impl( std::forward(f), std::forward(tp), Seq() ) ) -{ - return detail::tuple_apply_impl( std::forward(f), std::forward(tp), Seq() ); -} - -// construct_from_tuple -namespace detail -{ - -template BOOST_MP11_CONSTEXPR T construct_from_tuple_impl( Tp && tp, integer_sequence ) -{ - return T( std::get(std::forward(tp))... ); -} - -} // namespace detail - -template::type>::value>> -BOOST_MP11_CONSTEXPR T construct_from_tuple( Tp && tp ) -{ - return detail::construct_from_tuple_impl( std::forward(tp), Seq() ); -} - -// tuple_for_each -namespace detail -{ - -template BOOST_MP11_CONSTEXPR F tuple_for_each_impl( Tp && tp, integer_sequence, F && f ) -{ - using A = int[sizeof...(J)]; - return (void)A{ ((void)f(std::get(std::forward(tp))), 0)... }, std::forward(f); -} - -template BOOST_MP11_CONSTEXPR F tuple_for_each_impl( Tp && /*tp*/, integer_sequence, F && f ) -{ - return std::forward(f); -} - -} // namespace detail - -template BOOST_MP11_CONSTEXPR F tuple_for_each( Tp && tp, F && f ) -{ - using seq = make_index_sequence::type>::value>; - return detail::tuple_for_each_impl( std::forward(tp), seq(), std::forward(f) ); -} - -} // namespace mp11 -} // namespace boost - -#if BOOST_MP11_MSVC -# pragma warning( pop ) -#endif - -#endif // #ifndef BOOST_TUPLE_HPP_INCLUDED diff --git a/boost/mp11/utility.hpp b/boost/mp11/utility.hpp deleted file mode 100644 index 38989f4..0000000 --- a/boost/mp11/utility.hpp +++ /dev/null @@ -1,236 +0,0 @@ -#ifndef BOOST_MP11_UTILITY_HPP_INCLUDED -#define BOOST_MP11_UTILITY_HPP_INCLUDED - -// Copyright 2015, 2017, 2019 Peter Dimov. -// -// Distributed under the Boost Software License, Version 1.0. -// -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include - -namespace boost -{ -namespace mp11 -{ - -// mp_identity -template struct mp_identity -{ - using type = T; -}; - -// mp_identity_t -template using mp_identity_t = typename mp_identity::type; - -// mp_inherit -template struct mp_inherit: T... {}; - -// mp_if, mp_if_c -namespace detail -{ - -template struct mp_if_c_impl -{ -}; - -template struct mp_if_c_impl -{ - using type = T; -}; - -template struct mp_if_c_impl -{ - using type = E; -}; - -} // namespace detail - -template using mp_if_c = typename detail::mp_if_c_impl::type; -template using mp_if = typename detail::mp_if_c_impl(C::value), T, E...>::type; - -// mp_valid - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_INTEL, != 0 ) // tested at 1800 - -// contributed by Roland Schulz in https://github.com/boostorg/mp11/issues/17 - -namespace detail -{ - -template using void_t = void; - -template class F, class... T> -struct mp_valid_impl: mp_false {}; - -template class F, class... T> -struct mp_valid_impl>, F, T...>: mp_true {}; - -} // namespace detail - -template class F, class... T> using mp_valid = typename detail::mp_valid_impl; - -#else - -// implementation by Bruno Dutra (by the name is_evaluable) -namespace detail -{ - -template class F, class... T> struct mp_valid_impl -{ - template class G, class = G> static mp_true check(int); - template class> static mp_false check(...); - - using type = decltype(check(0)); -}; - -} // namespace detail - -template class F, class... T> using mp_valid = typename detail::mp_valid_impl::type; - -#endif - -template using mp_valid_q = mp_valid; - -// mp_defer -namespace detail -{ - -template class F, class... T> struct mp_defer_impl -{ - using type = F; -}; - -struct mp_no_type -{ -}; - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 ) - -template class F, class... T> struct mp_defer_cuda_workaround -{ - using type = mp_if, detail::mp_defer_impl, detail::mp_no_type>; -}; - -#endif - -} // namespace detail - -#if BOOST_MP11_WORKAROUND( BOOST_MP11_CUDA, >= 9000000 && BOOST_MP11_CUDA < 10000000 ) - -template class F, class... T> using mp_defer = typename detail::mp_defer_cuda_workaround< F, T...>::type; - -#else - -template class F, class... T> using mp_defer = mp_if, detail::mp_defer_impl, detail::mp_no_type>; - -#endif - -// mp_eval_if, mp_eval_if_c -namespace detail -{ - -template class F, class... U> struct mp_eval_if_c_impl; - -template class F, class... U> struct mp_eval_if_c_impl -{ - using type = T; -}; - -template class F, class... U> struct mp_eval_if_c_impl: mp_defer -{ -}; - -} // namespace detail - -template class F, class... U> using mp_eval_if_c = typename detail::mp_eval_if_c_impl::type; -template class F, class... U> using mp_eval_if = typename detail::mp_eval_if_c_impl(C::value), T, F, U...>::type; -template using mp_eval_if_q = typename detail::mp_eval_if_c_impl(C::value), T, Q::template fn, U...>::type; - -// mp_eval_if_not -template class F, class... U> using mp_eval_if_not = mp_eval_if, T, F, U...>; -template using mp_eval_if_not_q = mp_eval_if, T, Q::template fn, U...>; - -// mp_eval_or -template class F, class... U> using mp_eval_or = mp_eval_if_not, T, F, U...>; -template using mp_eval_or_q = mp_eval_or; - -// mp_cond - -// so elegant; so doesn't work -// template using mp_cond = mp_eval_if; - -namespace detail -{ - -template struct mp_cond_impl; - -} // namespace detail - -template using mp_cond = typename detail::mp_cond_impl::type; - -namespace detail -{ - -template using mp_cond_ = mp_eval_if; - -template struct mp_cond_impl: mp_defer -{ -}; - -} // namespace detail - -// mp_quote -template class F> struct mp_quote -{ - // the indirection through mp_defer works around the language inability - // to expand T... into a fixed parameter list of an alias template - - template using fn = typename mp_defer::type; -}; - -// mp_quote_trait -template class F> struct mp_quote_trait -{ - template using fn = typename F::type; -}; - -// mp_invoke_q -#if BOOST_MP11_WORKAROUND( BOOST_MP11_MSVC, < 1900 ) - -namespace detail -{ - -template struct mp_invoke_q_impl: mp_defer {}; - -} // namespace detail - -template using mp_invoke_q = typename detail::mp_invoke_q_impl::type; - -#elif BOOST_MP11_WORKAROUND( BOOST_MP11_GCC, < 50000 ) - -template using mp_invoke_q = typename mp_defer::type; - -#else - -template using mp_invoke_q = typename Q::template fn; - -#endif - -// old name for mp_invoke_q retained for compatibility, but deprecated -template using mp_invoke BOOST_MP11_DEPRECATED("please use mp_invoke_q") = mp_invoke_q; - -// mp_not_fn

-template class P> struct mp_not_fn -{ - template using fn = mp_not< mp_invoke_q, T...> >; -}; - -template using mp_not_fn_q = mp_not_fn; - -} // namespace mp11 -} // namespace boost - -#endif // #ifndef BOOST_MP11_UTILITY_HPP_INCLUDED diff --git a/boost/mp11/version.hpp b/boost/mp11/version.hpp deleted file mode 100644 index 3eba110..0000000 --- a/boost/mp11/version.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef BOOST_MP11_VERSION_HPP_INCLUDED -#define BOOST_MP11_VERSION_HPP_INCLUDED - -// Copyright 2019 Peter Dimov -// -// 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 - -// Same format as BOOST_VERSION: -// major * 100000 + minor * 100 + patch - -#define BOOST_MP11_VERSION 107300 - -#endif // #ifndef BOOST_MP11_VERSION_HPP_INCLUDED diff --git a/boost/pool/detail/mutex.hpp b/boost/pool/detail/mutex.hpp new file mode 100644 index 0000000..6190f65 --- /dev/null +++ b/boost/pool/detail/mutex.hpp @@ -0,0 +1,144 @@ +// Copyright (C) 2000 Stephen Cleary +// Copyright (C) 2018 Peter Dimov +// +// 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_POOL_MUTEX_HPP +#define BOOST_POOL_MUTEX_HPP + +#include + +namespace boost{ namespace details{ namespace pool{ + +class null_mutex +{ +private: + + null_mutex(const null_mutex &); + void operator=(const null_mutex &); + +public: + + null_mutex() {} + + static void lock() {} + static void unlock() {} +}; + +}}} // namespace boost::details::pool + +#if !defined(BOOST_HAS_THREADS) || defined(BOOST_NO_MT) || defined(BOOST_POOL_NO_MT) + +namespace boost{ namespace details{ namespace pool{ + +typedef null_mutex default_mutex; + +}}} // namespace boost::details::pool + +#elif !defined(BOOST_NO_CXX11_HDR_MUTEX) + +#include + +namespace boost{ namespace details{ namespace pool{ + +typedef std::mutex default_mutex; + +}}} // namespace boost::details::pool + +#elif defined(BOOST_HAS_PTHREADS) + +#include +#include + +namespace boost{ namespace details{ namespace pool{ + +class pt_mutex +{ +private: + + pthread_mutex_t m_; + + pt_mutex(pt_mutex const &); + pt_mutex & operator=(pt_mutex const &); + +public: + + pt_mutex() + { + BOOST_VERIFY( pthread_mutex_init( &m_, 0 ) == 0 ); + } + + ~pt_mutex() + { + BOOST_VERIFY( pthread_mutex_destroy( &m_ ) == 0 ); + } + + void lock() + { + BOOST_VERIFY( pthread_mutex_lock( &m_ ) == 0 ); + } + + void unlock() + { + BOOST_VERIFY( pthread_mutex_unlock( &m_ ) == 0 ); + } +}; + +typedef pt_mutex default_mutex; + +}}} // namespace boost::details::pool + +#elif defined(BOOST_HAS_WINTHREADS) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) + +#include + +namespace boost{ namespace details{ namespace pool{ + +class cs_mutex +{ +private: + + boost::winapi::CRITICAL_SECTION_ cs_; + + cs_mutex(cs_mutex const &); + cs_mutex & operator=(cs_mutex const &); + +public: + + cs_mutex() + { + boost::winapi::InitializeCriticalSection( &cs_ ); + } + + ~cs_mutex() + { + boost::winapi::DeleteCriticalSection( &cs_ ); + } + + void lock() + { + boost::winapi::EnterCriticalSection( &cs_ ); + } + + void unlock() + { + boost::winapi::LeaveCriticalSection( &cs_ ); + } +}; + +typedef cs_mutex default_mutex; + +}}} // namespace boost::details::pool + +#else + +// Use #define BOOST_DISABLE_THREADS to avoid this error +# error Unrecognized threading platform + +#endif + +#endif // #ifndef BOOST_POOL_MUTEX_HPP diff --git a/boost/pool/pool.hpp b/boost/pool/pool.hpp new file mode 100644 index 0000000..c47b11f --- /dev/null +++ b/boost/pool/pool.hpp @@ -0,0 +1,1024 @@ +// Copyright (C) 2000, 2001 Stephen Cleary +// +// 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_POOL_HPP +#define BOOST_POOL_HPP + +#include // for workarounds + +// std::less, std::less_equal, std::greater +#include +// new[], delete[], std::nothrow +#include +// std::size_t, std::ptrdiff_t +#include +// std::malloc, std::free +#include +// std::invalid_argument +#include +// std::max +#include + +#include + +// boost::integer::static_lcm +#include +// boost::simple_segregated_storage +#include +// boost::alignment_of +#include +// BOOST_ASSERT +#include + +#ifdef BOOST_POOL_INSTRUMENT +#include +#include +#endif +#ifdef BOOST_POOL_VALGRIND +#include +#include +#endif + +#ifdef BOOST_NO_STDC_NAMESPACE + namespace std { using ::malloc; using ::free; } +#endif + +// There are a few places in this file where the expression "this->m" is used. +// This expression is used to force instantiation-time name lookup, which I am +// informed is required for strict Standard compliance. It's only necessary +// if "m" is a member of a base class that is dependent on a template +// parameter. +// Thanks to Jens Maurer for pointing this out! + +/*! + \file + \brief Provides class \ref pool: a fast memory allocator that guarantees proper alignment of all allocated chunks, + and which extends and generalizes the framework provided by the simple segregated storage solution. + Also provides two UserAllocator classes which can be used in conjuction with \ref pool. +*/ + +/*! + \mainpage Boost.Pool Memory Allocation Scheme + + \section intro_sec Introduction + + Pool allocation is a memory allocation scheme that is very fast, but limited in its usage. + + This Doxygen-style documentation is complementary to the + full Quickbook-generated html and pdf documentation at www.boost.org. + + This page generated from file pool.hpp. + +*/ + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) // Conditional expression is constant +#endif + + namespace boost +{ + +//! \brief Allocator used as the default template parameter for +//! a UserAllocator +//! template parameter. Uses new and delete. +struct default_user_allocator_new_delete +{ + typedef std::size_t size_type; //!< An unsigned integral type that can represent the size of the largest object to be allocated. + typedef std::ptrdiff_t difference_type; //!< A signed integral type that can represent the difference of any two pointers. + + static char * malloc BOOST_PREVENT_MACRO_SUBSTITUTION(const size_type bytes) + { //! Attempts to allocate n bytes from the system. Returns 0 if out-of-memory + return new (std::nothrow) char[bytes]; + } + static void free BOOST_PREVENT_MACRO_SUBSTITUTION(char * const block) + { //! Attempts to de-allocate block. + //! \pre Block must have been previously returned from a call to UserAllocator::malloc. + delete [] block; + } +}; + +//! \brief UserAllocator +//! used as template parameter for \ref pool and \ref object_pool. +//! Uses malloc and free internally. +struct default_user_allocator_malloc_free +{ + typedef std::size_t size_type; //!< An unsigned integral type that can represent the size of the largest object to be allocated. + typedef std::ptrdiff_t difference_type; //!< A signed integral type that can represent the difference of any two pointers. + + static char * malloc BOOST_PREVENT_MACRO_SUBSTITUTION(const size_type bytes) + { return static_cast((std::malloc)(bytes)); } + static void free BOOST_PREVENT_MACRO_SUBSTITUTION(char * const block) + { (std::free)(block); } +}; + +namespace details +{ //! Implemention only. + +template +class PODptr +{ //! PODptr is a class that pretends to be a "pointer" to different class types + //! that don't really exist. It provides member functions to access the "data" + //! of the "object" it points to. Since these "class" types are of variable + //! size, and contains some information at the *end* of its memory + //! (for alignment reasons), + //! PODptr must contain the size of this "class" as well as the pointer to this "object". + + /*! \details A PODptr holds the location and size of a memory block allocated from the system. + Each memory block is split logically into three sections: + + Chunk area. This section may be different sizes. PODptr does not care what the size of the chunks is, + but it does care (and keep track of) the total size of the chunk area. + + Next pointer. This section is always the same size for a given SizeType. It holds a pointer + to the location of the next memory block in the memory block list, or 0 if there is no such block. + + Next size. This section is always the same size for a given SizeType. It holds the size of the + next memory block in the memory block list. + +The PODptr class just provides cleaner ways of dealing with raw memory blocks. + +A PODptr object is either valid or invalid. An invalid PODptr is analogous to a null pointer. +The default constructor for PODptr will result in an invalid object. +Calling the member function invalidate will result in that object becoming invalid. +The member function valid can be used to test for validity. +*/ + public: + typedef SizeType size_type; + + private: + char * ptr; + size_type sz; + + char * ptr_next_size() const + { + return (ptr + sz - sizeof(size_type)); + } + char * ptr_next_ptr() const + { + return (ptr_next_size() - + integer::static_lcm::value); + } + + public: + PODptr(char * const nptr, const size_type nsize) + :ptr(nptr), sz(nsize) + { + //! A PODptr may be created to point to a memory block by passing + //! the address and size of that memory block into the constructor. + //! A PODptr constructed in this way is valid. + } + PODptr() + : ptr(0), sz(0) + { //! default constructor for PODptr will result in an invalid object. + } + + bool valid() const + { //! A PODptr object is either valid or invalid. + //! An invalid PODptr is analogous to a null pointer. + //! \returns true if PODptr is valid, false if invalid. + return (begin() != 0); + } + void invalidate() + { //! Make object invalid. + begin() = 0; + } + char * & begin() + { //! Each PODptr keeps the address and size of its memory block. + //! \returns The address of its memory block. + return ptr; + } + char * begin() const + { //! Each PODptr keeps the address and size of its memory block. + //! \return The address of its memory block. + return ptr; + } + char * end() const + { //! \returns begin() plus element_size (a 'past the end' value). + return ptr_next_ptr(); + } + size_type total_size() const + { //! Each PODptr keeps the address and size of its memory block. + //! The address may be read or written by the member functions begin. + //! The size of the memory block may only be read, + //! \returns size of the memory block. + return sz; + } + size_type element_size() const + { //! \returns size of element pointer area. + return static_cast(sz - sizeof(size_type) - + integer::static_lcm::value); + } + + size_type & next_size() const + { //! + //! \returns next_size. + return *(static_cast(static_cast((ptr_next_size())))); + } + char * & next_ptr() const + { //! \returns pointer to next pointer area. + return *(static_cast(static_cast(ptr_next_ptr()))); + } + + PODptr next() const + { //! \returns next PODptr. + return PODptr(next_ptr(), next_size()); + } + void next(const PODptr & arg) const + { //! Sets next PODptr. + next_ptr() = arg.begin(); + next_size() = arg.total_size(); + } +}; // class PODptr +} // namespace details + +#ifndef BOOST_POOL_VALGRIND +/*! + \brief A fast memory allocator that guarantees proper alignment of all allocated chunks. + + \details Whenever an object of type pool needs memory from the system, + it will request it from its UserAllocator template parameter. + The amount requested is determined using a doubling algorithm; + that is, each time more system memory is allocated, + the amount of system memory requested is doubled. + + Users may control the doubling algorithm by using the following extensions: + + Users may pass an additional constructor parameter to pool. + This parameter is of type size_type, + and is the number of chunks to request from the system + the first time that object needs to allocate system memory. + The default is 32. This parameter may not be 0. + + Users may also pass an optional third parameter to pool's + constructor. This parameter is of type size_type, + and sets a maximum size for allocated chunks. When this + parameter takes the default value of 0, then there is no upper + limit on chunk size. + + Finally, if the doubling algorithm results in no memory + being allocated, the pool will backtrack just once, halving + the chunk size and trying again. + + UserAllocator type - the method that the Pool will use to allocate memory from the system. + + There are essentially two ways to use class pool: the client can call \ref malloc() and \ref free() to allocate + and free single chunks of memory, this is the most efficient way to use a pool, but does not allow for + the efficient allocation of arrays of chunks. Alternatively, the client may call \ref ordered_malloc() and \ref + ordered_free(), in which case the free list is maintained in an ordered state, and efficient allocation of arrays + of chunks are possible. However, this latter option can suffer from poor performance when large numbers of + allocations are performed. + +*/ +template +class pool: protected simple_segregated_storage < typename UserAllocator::size_type > +{ + public: + typedef UserAllocator user_allocator; //!< User allocator. + typedef typename UserAllocator::size_type size_type; //!< An unsigned integral type that can represent the size of the largest object to be allocated. + typedef typename UserAllocator::difference_type difference_type; //!< A signed integral type that can represent the difference of any two pointers. + + private: + BOOST_STATIC_CONSTANT(size_type, min_alloc_size = + (::boost::integer::static_lcm::value) ); + BOOST_STATIC_CONSTANT(size_type, min_align = + (::boost::integer::static_lcm< ::boost::alignment_of::value, ::boost::alignment_of::value>::value) ); + + //! \returns 0 if out-of-memory. + //! Called if malloc/ordered_malloc needs to resize the free list. + void * malloc_need_resize(); //! Called if malloc needs to resize the free list. + void * ordered_malloc_need_resize(); //! Called if ordered_malloc needs to resize the free list. + + protected: + details::PODptr list; //!< List structure holding ordered blocks. + + simple_segregated_storage & store() + { //! \returns pointer to store. + return *this; + } + const simple_segregated_storage & store() const + { //! \returns pointer to store. + return *this; + } + const size_type requested_size; + size_type next_size; + size_type start_size; + size_type max_size; + + //! finds which POD in the list 'chunk' was allocated from. + details::PODptr find_POD(void * const chunk) const; + + // is_from() tests a chunk to determine if it belongs in a block. + static bool is_from(void * const chunk, char * const i, + const size_type sizeof_i) + { //! \param chunk chunk to check if is from this pool. + //! \param i memory chunk at i with element sizeof_i. + //! \param sizeof_i element size (size of the chunk area of that block, not the total size of that block). + //! \returns true if chunk was allocated or may be returned. + //! as the result of a future allocation. + //! + //! Returns false if chunk was allocated from some other pool, + //! or may be returned as the result of a future allocation from some other pool. + //! Otherwise, the return value is meaningless. + //! + //! Note that this function may not be used to reliably test random pointer values. + + // We use std::less_equal and std::less to test 'chunk' + // against the array bounds because standard operators + // may return unspecified results. + // This is to ensure portability. The operators < <= > >= are only + // defined for pointers to objects that are 1) in the same array, or + // 2) subobjects of the same object [5.9/2]. + // The functor objects guarantee a total order for any pointer [20.3.3/8] + std::less_equal lt_eq; + std::less lt; + return (lt_eq(i, chunk) && lt(chunk, i + sizeof_i)); + } + + size_type alloc_size() const + { //! Calculated size of the memory chunks that will be allocated by this Pool. + //! \returns allocated size. + // For alignment reasons, this used to be defined to be lcm(requested_size, sizeof(void *), sizeof(size_type)), + // but is now more parsimonious: just rounding up to the minimum required alignment of our housekeeping data + // when required. This works provided all alignments are powers of two. + size_type s = (std::max)(requested_size, min_alloc_size); + size_type rem = s % min_align; + if(rem) + s += min_align - rem; + BOOST_ASSERT(s >= min_alloc_size); + BOOST_ASSERT(s % min_align == 0); + return s; + } + + static void * & nextof(void * const ptr) + { //! \returns Pointer dereferenced. + //! (Provided and used for the sake of code readability :) + return *(static_cast(ptr)); + } + + public: + // pre: npartition_size != 0 && nnext_size != 0 + explicit pool(const size_type nrequested_size, + const size_type nnext_size = 32, + const size_type nmax_size = 0) + : + list(0, 0), requested_size(nrequested_size), next_size(nnext_size), start_size(nnext_size),max_size(nmax_size) + { //! Constructs a new empty Pool that can be used to allocate chunks of size RequestedSize. + //! \param nrequested_size Requested chunk size + //! \param nnext_size parameter is of type size_type, + //! is the number of chunks to request from the system + //! the first time that object needs to allocate system memory. + //! The default is 32. This parameter may not be 0. + //! \param nmax_size is the maximum number of chunks to allocate in one block. + } + + ~pool() + { //! Destructs the Pool, freeing its list of memory blocks. + purge_memory(); + } + + // Releases memory blocks that don't have chunks allocated + // pre: lists are ordered + // Returns true if memory was actually deallocated + bool release_memory(); + + // Releases *all* memory blocks, even if chunks are still allocated + // Returns true if memory was actually deallocated + bool purge_memory(); + + size_type get_next_size() const + { //! Number of chunks to request from the system the next time that object needs to allocate system memory. This value should never be 0. + //! \returns next_size; + return next_size; + } + void set_next_size(const size_type nnext_size) + { //! Set number of chunks to request from the system the next time that object needs to allocate system memory. This value should never be set to 0. + //! \returns nnext_size. + next_size = start_size = nnext_size; + } + size_type get_max_size() const + { //! \returns max_size. + return max_size; + } + void set_max_size(const size_type nmax_size) + { //! Set max_size. + max_size = nmax_size; + } + size_type get_requested_size() const + { //! \returns the requested size passed into the constructor. + //! (This value will not change during the lifetime of a Pool object). + return requested_size; + } + + // Both malloc and ordered_malloc do a quick inlined check first for any + // free chunks. Only if we need to get another memory block do we call + // the non-inlined *_need_resize() functions. + // Returns 0 if out-of-memory + void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION() + { //! Allocates a chunk of memory. Searches in the list of memory blocks + //! for a block that has a free chunk, and returns that free chunk if found. + //! Otherwise, creates a new memory block, adds its free list to pool's free list, + //! \returns a free chunk from that block. + //! If a new memory block cannot be allocated, returns 0. Amortized O(1). + // Look for a non-empty storage + if (!store().empty()) + return (store().malloc)(); + return malloc_need_resize(); + } + + void * ordered_malloc() + { //! Same as malloc, only merges the free lists, to preserve order. Amortized O(1). + //! \returns a free chunk from that block. + //! If a new memory block cannot be allocated, returns 0. Amortized O(1). + // Look for a non-empty storage + if (!store().empty()) + return (store().malloc)(); + return ordered_malloc_need_resize(); + } + + // Returns 0 if out-of-memory + // Allocate a contiguous section of n chunks + void * ordered_malloc(size_type n); + //! Same as malloc, only allocates enough contiguous chunks to cover n * requested_size bytes. Amortized O(n). + //! \returns a free chunk from that block. + //! If a new memory block cannot be allocated, returns 0. Amortized O(1). + + // pre: 'chunk' must have been previously + // returned by *this.malloc(). + void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const chunk) + { //! Deallocates a chunk of memory. Note that chunk may not be 0. O(1). + //! + //! Chunk must have been previously returned by t.malloc() or t.ordered_malloc(). + //! Assumes that chunk actually refers to a block of chunks + //! spanning n * partition_sz bytes. + //! deallocates each chunk in that block. + //! Note that chunk may not be 0. O(n). + (store().free)(chunk); + } + + // pre: 'chunk' must have been previously + // returned by *this.malloc(). + void ordered_free(void * const chunk) + { //! Same as above, but is order-preserving. + //! + //! Note that chunk may not be 0. O(N) with respect to the size of the free list. + //! chunk must have been previously returned by t.malloc() or t.ordered_malloc(). + store().ordered_free(chunk); + } + + // pre: 'chunk' must have been previously + // returned by *this.malloc(n). + void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const chunks, const size_type n) + { //! Assumes that chunk actually refers to a block of chunks. + //! + //! chunk must have been previously returned by t.ordered_malloc(n) + //! spanning n * partition_sz bytes. + //! Deallocates each chunk in that block. + //! Note that chunk may not be 0. O(n). + const size_type partition_size = alloc_size(); + const size_type total_req_size = n * requested_size; + const size_type num_chunks = total_req_size / partition_size + + ((total_req_size % partition_size) ? true : false); + + store().free_n(chunks, num_chunks, partition_size); + } + + // pre: 'chunk' must have been previously + // returned by *this.malloc(n). + void ordered_free(void * const chunks, const size_type n) + { //! Assumes that chunk actually refers to a block of chunks spanning n * partition_sz bytes; + //! deallocates each chunk in that block. + //! + //! Note that chunk may not be 0. Order-preserving. O(N + n) where N is the size of the free list. + //! chunk must have been previously returned by t.malloc() or t.ordered_malloc(). + + const size_type partition_size = alloc_size(); + const size_type total_req_size = n * requested_size; + const size_type num_chunks = total_req_size / partition_size + + ((total_req_size % partition_size) ? true : false); + + store().ordered_free_n(chunks, num_chunks, partition_size); + } + + // is_from() tests a chunk to determine if it was allocated from *this + bool is_from(void * const chunk) const + { //! \returns Returns true if chunk was allocated from u or + //! may be returned as the result of a future allocation from u. + //! Returns false if chunk was allocated from some other pool or + //! may be returned as the result of a future allocation from some other pool. + //! Otherwise, the return value is meaningless. + //! Note that this function may not be used to reliably test random pointer values. + return (find_POD(chunk).valid()); + } +}; + +#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION +template +typename pool::size_type const pool::min_alloc_size; +template +typename pool::size_type const pool::min_align; +#endif + +template +bool pool::release_memory() +{ //! pool must be ordered. Frees every memory block that doesn't have any allocated chunks. + //! \returns true if at least one memory block was freed. + + // ret is the return value: it will be set to true when we actually call + // UserAllocator::free(..) + bool ret = false; + + // This is a current & previous iterator pair over the memory block list + details::PODptr ptr = list; + details::PODptr prev; + + // This is a current & previous iterator pair over the free memory chunk list + // Note that "prev_free" in this case does NOT point to the previous memory + // chunk in the free list, but rather the last free memory chunk before the + // current block. + void * free_p = this->first; + void * prev_free_p = 0; + + const size_type partition_size = alloc_size(); + + // Search through all the all the allocated memory blocks + while (ptr.valid()) + { + // At this point: + // ptr points to a valid memory block + // free_p points to either: + // 0 if there are no more free chunks + // the first free chunk in this or some next memory block + // prev_free_p points to either: + // the last free chunk in some previous memory block + // 0 if there is no such free chunk + // prev is either: + // the PODptr whose next() is ptr + // !valid() if there is no such PODptr + + // If there are no more free memory chunks, then every remaining + // block is allocated out to its fullest capacity, and we can't + // release any more memory + if (free_p == 0) + break; + + // We have to check all the chunks. If they are *all* free (i.e., present + // in the free list), then we can free the block. + bool all_chunks_free = true; + + // Iterate 'i' through all chunks in the memory block + // if free starts in the memory block, be careful to keep it there + void * saved_free = free_p; + for (char * i = ptr.begin(); i != ptr.end(); i += partition_size) + { + // If this chunk is not free + if (i != free_p) + { + // We won't be able to free this block + all_chunks_free = false; + + // free_p might have travelled outside ptr + free_p = saved_free; + // Abort searching the chunks; we won't be able to free this + // block because a chunk is not free. + break; + } + + // We do not increment prev_free_p because we are in the same block + free_p = nextof(free_p); + } + + // post: if the memory block has any chunks, free_p points to one of them + // otherwise, our assertions above are still valid + + const details::PODptr next = ptr.next(); + + if (!all_chunks_free) + { + if (is_from(free_p, ptr.begin(), ptr.element_size())) + { + std::less lt; + void * const end = ptr.end(); + do + { + prev_free_p = free_p; + free_p = nextof(free_p); + } while (free_p && lt(free_p, end)); + } + // This invariant is now restored: + // free_p points to the first free chunk in some next memory block, or + // 0 if there is no such chunk. + // prev_free_p points to the last free chunk in this memory block. + + // We are just about to advance ptr. Maintain the invariant: + // prev is the PODptr whose next() is ptr, or !valid() + // if there is no such PODptr + prev = ptr; + } + else + { + // All chunks from this block are free + + // Remove block from list + if (prev.valid()) + prev.next(next); + else + list = next; + + // Remove all entries in the free list from this block + if (prev_free_p != 0) + nextof(prev_free_p) = free_p; + else + this->first = free_p; + + // And release memory + (UserAllocator::free)(ptr.begin()); + ret = true; + } + + // Increment ptr + ptr = next; + } + + next_size = start_size; + return ret; +} + +template +bool pool::purge_memory() +{ //! pool must be ordered. + //! Frees every memory block. + //! + //! This function invalidates any pointers previously returned + //! by allocation functions of t. + //! \returns true if at least one memory block was freed. + + details::PODptr iter = list; + + if (!iter.valid()) + return false; + + do + { + // hold "next" pointer + const details::PODptr next = iter.next(); + + // delete the storage + (UserAllocator::free)(iter.begin()); + + // increment iter + iter = next; + } while (iter.valid()); + + list.invalidate(); + this->first = 0; + next_size = start_size; + + return true; +} + +template +void * pool::malloc_need_resize() +{ //! No memory in any of our storages; make a new storage, + //! Allocates chunk in newly malloc aftert resize. + //! \returns pointer to chunk. + size_type partition_size = alloc_size(); + size_type POD_size = static_cast(next_size * partition_size + + integer::static_lcm::value + sizeof(size_type)); + char * ptr = (UserAllocator::malloc)(POD_size); + if (ptr == 0) + { + if(next_size > 4) + { + next_size >>= 1; + partition_size = alloc_size(); + POD_size = static_cast(next_size * partition_size + + integer::static_lcm::value + sizeof(size_type)); + ptr = (UserAllocator::malloc)(POD_size); + } + if(ptr == 0) + return 0; + } + const details::PODptr node(ptr, POD_size); + + BOOST_USING_STD_MIN(); + if(!max_size) + next_size <<= 1; + else if( next_size*partition_size/requested_size < max_size) + next_size = min BOOST_PREVENT_MACRO_SUBSTITUTION(next_size << 1, max_size*requested_size/ partition_size); + + // initialize it, + store().add_block(node.begin(), node.element_size(), partition_size); + + // insert it into the list, + node.next(list); + list = node; + + // and return a chunk from it. + return (store().malloc)(); +} + +template +void * pool::ordered_malloc_need_resize() +{ //! No memory in any of our storages; make a new storage, + //! \returns pointer to new chunk. + size_type partition_size = alloc_size(); + size_type POD_size = static_cast(next_size * partition_size + + integer::static_lcm::value + sizeof(size_type)); + char * ptr = (UserAllocator::malloc)(POD_size); + if (ptr == 0) + { + if(next_size > 4) + { + next_size >>= 1; + partition_size = alloc_size(); + POD_size = static_cast(next_size * partition_size + + integer::static_lcm::value + sizeof(size_type)); + ptr = (UserAllocator::malloc)(POD_size); + } + if(ptr == 0) + return 0; + } + const details::PODptr node(ptr, POD_size); + + BOOST_USING_STD_MIN(); + if(!max_size) + next_size <<= 1; + else if( next_size*partition_size/requested_size < max_size) + next_size = min BOOST_PREVENT_MACRO_SUBSTITUTION(next_size << 1, max_size*requested_size/ partition_size); + + // initialize it, + // (we can use "add_block" here because we know that + // the free list is empty, so we don't have to use + // the slower ordered version) + store().add_ordered_block(node.begin(), node.element_size(), partition_size); + + // insert it into the list, + // handle border case + if (!list.valid() || std::greater()(list.begin(), node.begin())) + { + node.next(list); + list = node; + } + else + { + details::PODptr prev = list; + + while (true) + { + // if we're about to hit the end or + // if we've found where "node" goes + if (prev.next_ptr() == 0 + || std::greater()(prev.next_ptr(), node.begin())) + break; + + prev = prev.next(); + } + + node.next(prev.next()); + prev.next(node); + } + // and return a chunk from it. + return (store().malloc)(); +} + +template +void * pool::ordered_malloc(const size_type n) +{ //! Gets address of a chunk n, allocating new memory if not already available. + //! \returns Address of chunk n if allocated ok. + //! \returns 0 if not enough memory for n chunks. + + const size_type partition_size = alloc_size(); + const size_type total_req_size = n * requested_size; + const size_type num_chunks = total_req_size / partition_size + + ((total_req_size % partition_size) ? true : false); + + void * ret = store().malloc_n(num_chunks, partition_size); + +#ifdef BOOST_POOL_INSTRUMENT + std::cout << "Allocating " << n << " chunks from pool of size " << partition_size << std::endl; +#endif + if ((ret != 0) || (n == 0)) + return ret; + +#ifdef BOOST_POOL_INSTRUMENT + std::cout << "Cache miss, allocating another chunk...\n"; +#endif + + // Not enough memory in our storages; make a new storage, + BOOST_USING_STD_MAX(); + next_size = max BOOST_PREVENT_MACRO_SUBSTITUTION(next_size, num_chunks); + size_type POD_size = static_cast(next_size * partition_size + + integer::static_lcm::value + sizeof(size_type)); + char * ptr = (UserAllocator::malloc)(POD_size); + if (ptr == 0) + { + if(num_chunks < next_size) + { + // Try again with just enough memory to do the job, or at least whatever we + // allocated last time: + next_size >>= 1; + next_size = max BOOST_PREVENT_MACRO_SUBSTITUTION(next_size, num_chunks); + POD_size = static_cast(next_size * partition_size + + integer::static_lcm::value + sizeof(size_type)); + ptr = (UserAllocator::malloc)(POD_size); + } + if(ptr == 0) + return 0; + } + const details::PODptr node(ptr, POD_size); + + // Split up block so we can use what wasn't requested. + if (next_size > num_chunks) + store().add_ordered_block(node.begin() + num_chunks * partition_size, + node.element_size() - num_chunks * partition_size, partition_size); + + BOOST_USING_STD_MIN(); + if(!max_size) + next_size <<= 1; + else if( next_size*partition_size/requested_size < max_size) + next_size = min BOOST_PREVENT_MACRO_SUBSTITUTION(next_size << 1, max_size*requested_size/ partition_size); + + // insert it into the list, + // handle border case. + if (!list.valid() || std::greater()(list.begin(), node.begin())) + { + node.next(list); + list = node; + } + else + { + details::PODptr prev = list; + + while (true) + { + // if we're about to hit the end, or if we've found where "node" goes. + if (prev.next_ptr() == 0 + || std::greater()(prev.next_ptr(), node.begin())) + break; + + prev = prev.next(); + } + + node.next(prev.next()); + prev.next(node); + } + + // and return it. + return node.begin(); +} + +template +details::PODptr::size_type> +pool::find_POD(void * const chunk) const +{ //! find which PODptr storage memory that this chunk is from. + //! \returns the PODptr that holds this chunk. + // Iterate down list to find which storage this chunk is from. + details::PODptr iter = list; + while (iter.valid()) + { + if (is_from(chunk, iter.begin(), iter.element_size())) + return iter; + iter = iter.next(); + } + + return iter; +} + +#else // BOOST_POOL_VALGRIND + +template +class pool +{ +public: + // types + typedef UserAllocator user_allocator; // User allocator. + typedef typename UserAllocator::size_type size_type; // An unsigned integral type that can represent the size of the largest object to be allocated. + typedef typename UserAllocator::difference_type difference_type; // A signed integral type that can represent the difference of any two pointers. + + // construct/copy/destruct + explicit pool(const size_type s, const size_type = 32, const size_type m = 0) : chunk_size(s), max_alloc_size(m) {} + ~pool() + { + purge_memory(); + } + + bool release_memory() + { + bool ret = free_list.empty() ? false : true; + for(std::set::iterator pos = free_list.begin(); pos != free_list.end(); ++pos) + { + (user_allocator::free)(static_cast(*pos)); + } + free_list.clear(); + return ret; + } + bool purge_memory() + { + bool ret = free_list.empty() && used_list.empty() ? false : true; + for(std::set::iterator pos = free_list.begin(); pos != free_list.end(); ++pos) + { + (user_allocator::free)(static_cast(*pos)); + } + free_list.clear(); + for(std::set::iterator pos = used_list.begin(); pos != used_list.end(); ++pos) + { + (user_allocator::free)(static_cast(*pos)); + } + used_list.clear(); + return ret; + } + size_type get_next_size() const + { + return 1; + } + void set_next_size(const size_type){} + size_type get_max_size() const + { + return max_alloc_size; + } + void set_max_size(const size_type s) + { + max_alloc_size = s; + } + size_type get_requested_size() const + { + return chunk_size; + } + void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION() + { + void* ret; + if(free_list.empty()) + { + ret = (user_allocator::malloc)(chunk_size); + VALGRIND_MAKE_MEM_UNDEFINED(ret, chunk_size); + } + else + { + ret = *free_list.begin(); + free_list.erase(free_list.begin()); + VALGRIND_MAKE_MEM_UNDEFINED(ret, chunk_size); + } + used_list.insert(ret); + return ret; + } + void * ordered_malloc() + { + return (this->malloc)(); + } + void * ordered_malloc(size_type n) + { + if(max_alloc_size && (n > max_alloc_size)) + return 0; + void* ret = (user_allocator::malloc)(chunk_size * n); + used_list.insert(ret); + return ret; + } + void free BOOST_PREVENT_MACRO_SUBSTITUTION(void *const chunk) + { + BOOST_ASSERT(used_list.count(chunk) == 1); + BOOST_ASSERT(free_list.count(chunk) == 0); + used_list.erase(chunk); + free_list.insert(chunk); + VALGRIND_MAKE_MEM_NOACCESS(chunk, chunk_size); + } + void ordered_free(void *const chunk) + { + return (this->free)(chunk); + } + void free BOOST_PREVENT_MACRO_SUBSTITUTION(void *const chunk, const size_type) + { + BOOST_ASSERT(used_list.count(chunk) == 1); + BOOST_ASSERT(free_list.count(chunk) == 0); + used_list.erase(chunk); + (user_allocator::free)(static_cast(chunk)); + } + void ordered_free(void *const chunk, const size_type n) + { + (this->free)(chunk, n); + } + bool is_from(void *const chunk) const + { + return used_list.count(chunk) || free_list.count(chunk); + } + +protected: + size_type chunk_size, max_alloc_size; + std::set free_list, used_list; +}; + +#endif + +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif // #ifdef BOOST_POOL_HPP + diff --git a/boost/pool/poolfwd.hpp b/boost/pool/poolfwd.hpp new file mode 100644 index 0000000..0f330fc --- /dev/null +++ b/boost/pool/poolfwd.hpp @@ -0,0 +1,82 @@ +// Copyright (C) 2000, 2001 Stephen Cleary +// +// 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_POOLFWD_HPP +#define BOOST_POOLFWD_HPP + +/*! + \file + \brief Forward declarations of all public (non-implemention) classes. +*/ + + +#include // for workarounds + +// std::size_t +#include + +// boost::details::pool::default_mutex +#include + +namespace boost { + +// +// Location: +// +template +class simple_segregated_storage; + +// +// Location: +// +struct default_user_allocator_new_delete; +struct default_user_allocator_malloc_free; + +template +class pool; + +// +// Location: +// +template +class object_pool; + +// +// Location: +// +template +class singleton_pool; + +// +// Location: +// +struct pool_allocator_tag; + +template +class pool_allocator; + +struct fast_pool_allocator_tag; + +template +class fast_pool_allocator; + +} // namespace boost + +#endif diff --git a/boost/pool/simple_segregated_storage.hpp b/boost/pool/simple_segregated_storage.hpp new file mode 100644 index 0000000..fffd4ee --- /dev/null +++ b/boost/pool/simple_segregated_storage.hpp @@ -0,0 +1,377 @@ +// Copyright (C) 2000, 2001 Stephen Cleary +// +// 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_SIMPLE_SEGREGATED_STORAGE_HPP +#define BOOST_SIMPLE_SEGREGATED_STORAGE_HPP + +/*! + \file + \brief Simple Segregated Storage. + \details A simple segregated storage implementation: + simple segregated storage is the basic idea behind the Boost Pool library. + Simple segregated storage is the simplest, and probably the fastest, + memory allocation/deallocation algorithm. + It begins by partitioning a memory block into fixed-size chunks. + Where the block comes from is not important until implementation time. + A Pool is some object that uses Simple Segregated Storage in this fashion. +*/ + +// std::greater +#include + +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) // Conditional expression is constant +#endif + +#ifdef BOOST_POOL_VALIDATE +# define BOOST_POOL_VALIDATE_INTERNALS validate(); +#else +# define BOOST_POOL_VALIDATE_INTERNALS +#endif + +namespace boost { + +/*! + +\brief Simple Segregated Storage is the simplest, and probably the fastest, +memory allocation/deallocation algorithm. It is responsible for +partitioning a memory block into fixed-size chunks: where the block comes from +is determined by the client of the class. + +\details Template class simple_segregated_storage controls access to a free list of memory chunks. +Please note that this is a very simple class, with preconditions on almost all its functions. It is intended to +be the fastest and smallest possible quick memory allocator - e.g., something to use in embedded systems. +This class delegates many difficult preconditions to the user (i.e., alignment issues). + +An object of type simple_segregated_storage is empty if its free list is empty. +If it is not empty, then it is ordered if its free list is ordered. A free list is ordered if repeated calls +to malloc() will result in a constantly-increasing sequence of values, as determined by std::less. +A member function is order-preserving if the free list maintains its order orientation (that is, an +ordered free list is still ordered after the member function call). + +*/ +template +class simple_segregated_storage +{ + public: + typedef SizeType size_type; + + private: + simple_segregated_storage(const simple_segregated_storage &); + void operator=(const simple_segregated_storage &); + + static void * try_malloc_n(void * & start, size_type n, + size_type partition_size); + + protected: + void * first; /*!< This data member is the free list. + It points to the first chunk in the free list, + or is equal to 0 if the free list is empty. + */ + + void * find_prev(void * ptr); + + // for the sake of code readability :) + static void * & nextof(void * const ptr) + { //! The return value is just *ptr cast to the appropriate type. ptr must not be 0. (For the sake of code readability :) + //! As an example, let us assume that we want to truncate the free list after the first chunk. + //! That is, we want to set *first to 0; this will result in a free list with only one entry. + //! The normal way to do this is to first cast first to a pointer to a pointer to void, + //! and then dereference and assign (*static_cast(first) = 0;). + //! This can be done more easily through the use of this convenience function (nextof(first) = 0;). + //! \returns dereferenced pointer. + return *(static_cast(ptr)); + } + + public: + // Post: empty() + simple_segregated_storage() + :first(0) + { //! Construct empty storage area. + //! \post empty() + } + + static void * segregate(void * block, + size_type nsz, size_type npartition_sz, + void * end = 0); + + // Same preconditions as 'segregate' + // Post: !empty() + void add_block(void * const block, + const size_type nsz, const size_type npartition_sz) + { //! Add block + //! Segregate this block and merge its free list into the + //! free list referred to by "first". + //! \pre Same as segregate. + //! \post !empty() + BOOST_POOL_VALIDATE_INTERNALS + first = segregate(block, nsz, npartition_sz, first); + BOOST_POOL_VALIDATE_INTERNALS + } + + // Same preconditions as 'segregate' + // Post: !empty() + void add_ordered_block(void * const block, + const size_type nsz, const size_type npartition_sz) + { //! add block (ordered into list) + //! This (slower) version of add_block segregates the + //! block and merges its free list into our free list + //! in the proper order. + BOOST_POOL_VALIDATE_INTERNALS + // Find where "block" would go in the free list + void * const loc = find_prev(block); + + // Place either at beginning or in middle/end + if (loc == 0) + add_block(block, nsz, npartition_sz); + else + nextof(loc) = segregate(block, nsz, npartition_sz, nextof(loc)); + BOOST_POOL_VALIDATE_INTERNALS + } + + // default destructor. + + bool empty() const + { //! \returns true only if simple_segregated_storage is empty. + return (first == 0); + } + + void * malloc BOOST_PREVENT_MACRO_SUBSTITUTION() + { //! Create a chunk. + //! \pre !empty() + //! Increment the "first" pointer to point to the next chunk. + BOOST_POOL_VALIDATE_INTERNALS + void * const ret = first; + + // Increment the "first" pointer to point to the next chunk. + first = nextof(first); + BOOST_POOL_VALIDATE_INTERNALS + return ret; + } + + void free BOOST_PREVENT_MACRO_SUBSTITUTION(void * const chunk) + { //! Free a chunk. + //! \pre chunk was previously returned from a malloc() referring to the same free list. + //! \post !empty() + BOOST_POOL_VALIDATE_INTERNALS + nextof(chunk) = first; + first = chunk; + BOOST_POOL_VALIDATE_INTERNALS + } + + void ordered_free(void * const chunk) + { //! This (slower) implementation of 'free' places the memory + //! back in the list in its proper order. + //! \pre chunk was previously returned from a malloc() referring to the same free list + //! \post !empty(). + + // Find where "chunk" goes in the free list + BOOST_POOL_VALIDATE_INTERNALS + void * const loc = find_prev(chunk); + + // Place either at beginning or in middle/end. + if (loc == 0) + (free)(chunk); + else + { + nextof(chunk) = nextof(loc); + nextof(loc) = chunk; + } + BOOST_POOL_VALIDATE_INTERNALS + } + + void * malloc_n(size_type n, size_type partition_size); + + //! \pre chunks was previously allocated from *this with the same + //! values for n and partition_size. + //! \post !empty() + //! \note If you're allocating/deallocating n a lot, you should + //! be using an ordered pool. + void free_n(void * const chunks, const size_type n, + const size_type partition_size) + { + BOOST_POOL_VALIDATE_INTERNALS + if(n != 0) + add_block(chunks, n * partition_size, partition_size); + BOOST_POOL_VALIDATE_INTERNALS + } + + // pre: chunks was previously allocated from *this with the same + // values for n and partition_size. + // post: !empty() + void ordered_free_n(void * const chunks, const size_type n, + const size_type partition_size) + { //! Free n chunks from order list. + //! \pre chunks was previously allocated from *this with the same + //! values for n and partition_size. + + //! \pre n should not be zero (n == 0 has no effect). + BOOST_POOL_VALIDATE_INTERNALS + if(n != 0) + add_ordered_block(chunks, n * partition_size, partition_size); + BOOST_POOL_VALIDATE_INTERNALS + } +#ifdef BOOST_POOL_VALIDATE + void validate() + { + int index = 0; + void* old = 0; + void* ptr = first; + while(ptr) + { + void* pt = nextof(ptr); // trigger possible segfault *before* we update variables + ++index; + old = ptr; + ptr = nextof(ptr); + } + } +#endif +}; + +//! Traverses the free list referred to by "first", +//! and returns the iterator previous to where +//! "ptr" would go if it was in the free list. +//! Returns 0 if "ptr" would go at the beginning +//! of the free list (i.e., before "first"). + +//! \note Note that this function finds the location previous to where ptr would go +//! if it was in the free list. +//! It does not find the entry in the free list before ptr +//! (unless ptr is already in the free list). +//! Specifically, find_prev(0) will return 0, +//! not the last entry in the free list. +//! \returns location previous to where ptr would go if it was in the free list. +template +void * simple_segregated_storage::find_prev(void * const ptr) +{ + // Handle border case. + if (first == 0 || std::greater()(first, ptr)) + return 0; + + void * iter = first; + while (true) + { + // if we're about to hit the end, or if we've found where "ptr" goes. + if (nextof(iter) == 0 || std::greater()(nextof(iter), ptr)) + return iter; + + iter = nextof(iter); + } +} + +//! Segregate block into chunks. +//! \pre npartition_sz >= sizeof(void *) +//! \pre npartition_sz = sizeof(void *) * i, for some integer i +//! \pre nsz >= npartition_sz +//! \pre Block is properly aligned for an array of object of +//! size npartition_sz and array of void *. +//! The requirements above guarantee that any pointer to a chunk +//! (which is a pointer to an element in an array of npartition_sz) +//! may be cast to void **. +template +void * simple_segregated_storage::segregate( + void * const block, + const size_type sz, + const size_type partition_sz, + void * const end) +{ + // Get pointer to last valid chunk, preventing overflow on size calculations + // The division followed by the multiplication just makes sure that + // old == block + partition_sz * i, for some integer i, even if the + // block size (sz) is not a multiple of the partition size. + char * old = static_cast(block) + + ((sz - partition_sz) / partition_sz) * partition_sz; + + // Set it to point to the end + nextof(old) = end; + + // Handle border case where sz == partition_sz (i.e., we're handling an array + // of 1 element) + if (old == block) + return block; + + // Iterate backwards, building a singly-linked list of pointers + for (char * iter = old - partition_sz; iter != block; + old = iter, iter -= partition_sz) + nextof(iter) = old; + + // Point the first pointer, too + nextof(block) = old; + + return block; +} + +//! \pre (n > 0), (start != 0), (nextof(start) != 0) +//! \post (start != 0) +//! The function attempts to find n contiguous chunks +//! of size partition_size in the free list, starting at start. +//! If it succeds, it returns the last chunk in that contiguous +//! sequence, so that the sequence is known by [start, {retval}] +//! If it fails, it does do either because it's at the end of the +//! free list or hits a non-contiguous chunk. In either case, +//! it will return 0, and set start to the last considered +//! chunk. You are at the end of the free list if +//! nextof(start) == 0. Otherwise, start points to the last +//! chunk in the contiguous sequence, and nextof(start) points +//! to the first chunk in the next contiguous sequence (assuming +//! an ordered free list). +template +void * simple_segregated_storage::try_malloc_n( + void * & start, size_type n, const size_type partition_size) +{ + void * iter = nextof(start); + while (--n != 0) + { + void * next = nextof(iter); + if (next != static_cast(iter) + partition_size) + { + // next == 0 (end-of-list) or non-contiguous chunk found + start = iter; + return 0; + } + iter = next; + } + return iter; +} + +//! Attempts to find a contiguous sequence of n partition_sz-sized chunks. If found, removes them +//! all from the free list and returns a pointer to the first. If not found, returns 0. It is strongly +//! recommended (but not required) that the free list be ordered, as this algorithm will fail to find +//! a contiguous sequence unless it is contiguous in the free list as well. Order-preserving. +//! O(N) with respect to the size of the free list. +template +void * simple_segregated_storage::malloc_n(const size_type n, + const size_type partition_size) +{ + BOOST_POOL_VALIDATE_INTERNALS + if(n == 0) + return 0; + void * start = &first; + void * iter; + do + { + if (nextof(start) == 0) + return 0; + iter = try_malloc_n(start, n, partition_size); + } while (iter == 0); + void * const ret = nextof(start); + nextof(start) = nextof(iter); + BOOST_POOL_VALIDATE_INTERNALS + return ret; +} + +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif diff --git a/boost/preprocessor/config/config.hpp b/boost/preprocessor/config/config.hpp index 2c1e72f..7abaaf0 100644 --- a/boost/preprocessor/config/config.hpp +++ b/boost/preprocessor/config/config.hpp @@ -80,7 +80,7 @@ # if !defined BOOST_PP_VARIADICS # /* variadic support explicitly disabled for all untested compilers */ -# if defined __GCCXML__ || defined __CUDACC__ || defined __PATHSCALE__ || defined __DMC__ || defined __CODEGEARC__ || defined __BORLANDC__ || defined __MWERKS__ || ( defined __SUNPRO_CC && __SUNPRO_CC < 0x5120 ) || defined __HP_aCC && !defined __EDG__ || defined __MRC__ || defined __SC__ || (defined(__PGI) && !defined(__EDG__)) +# if defined __GCCXML__ || (defined __CUDACC__ && !(defined(__clang__) && defined(__CUDA__))) || defined __PATHSCALE__ || defined __DMC__ || defined __CODEGEARC__ || defined __BORLANDC__ || defined __MWERKS__ || ( defined __SUNPRO_CC && __SUNPRO_CC < 0x5120 ) || (defined __HP_aCC && !defined __EDG__) || defined __MRC__ || defined __SC__ || (defined(__PGI) && !defined(__EDG__)) # define BOOST_PP_VARIADICS 0 # elif defined(_MSC_VER) && defined(__clang__) # define BOOST_PP_VARIADICS 1 diff --git a/boost/preprocessor/facilities/detail/is_empty.hpp b/boost/preprocessor/facilities/detail/is_empty.hpp index e044970..ce16732 100644 --- a/boost/preprocessor/facilities/detail/is_empty.hpp +++ b/boost/preprocessor/facilities/detail/is_empty.hpp @@ -31,8 +31,8 @@ #if BOOST_PP_VARIADICS_MSVC && _MSC_VER <= 1400 #define BOOST_PP_DETAIL_IS_EMPTY_PROCESS(param) \ - BOOST_PP_IS_BEGIN_PARENS \ - ( \ + BOOST_PP_IS_BEGIN_PARENS \ + ( \ BOOST_PP_DETAIL_IS_EMPTY_NON_FUNCTION_C param () \ ) \ /**/ @@ -40,7 +40,7 @@ #else #define BOOST_PP_DETAIL_IS_EMPTY_PROCESS(...) \ - BOOST_PP_IS_BEGIN_PARENS \ + BOOST_PP_IS_BEGIN_PARENS \ ( \ BOOST_PP_DETAIL_IS_EMPTY_NON_FUNCTION_C __VA_ARGS__ () \ ) \ diff --git a/boost/preprocessor/facilities/is_empty_variadic.hpp b/boost/preprocessor/facilities/is_empty_variadic.hpp index eee4062..77ebf6d 100644 --- a/boost/preprocessor/facilities/is_empty_variadic.hpp +++ b/boost/preprocessor/facilities/is_empty_variadic.hpp @@ -1,6 +1,6 @@ # /* ************************************************************************** # * * -# * (C) Copyright Edward Diener 2014. +# * (C) Copyright Edward Diener 2014,2019. # * 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) @@ -37,7 +37,34 @@ /**/ #define BOOST_PP_IS_EMPTY_ZERO(param) 0 # else +# if defined(__cplusplus) && __cplusplus > 201703L +# include #define BOOST_PP_IS_EMPTY(...) \ + BOOST_PP_DETAIL_IS_EMPTY_IIF \ + ( \ + BOOST_PP_VARIADIC_HAS_OPT() \ + ) \ + ( \ + BOOST_PP_IS_EMPTY_OPT, \ + BOOST_PP_IS_EMPTY_NO_OPT \ + ) \ + (__VA_ARGS__) \ +/**/ +#define BOOST_PP_IS_EMPTY_FUNCTION2(...) \ + __VA_OPT__(0,) 1 \ +/**/ +#define BOOST_PP_IS_EMPTY_FUNCTION(...) \ + BOOST_PP_IS_EMPTY_FUNCTION2(__VA_ARGS__) \ +/**/ +#define BOOST_PP_IS_EMPTY_OPT(...) \ + BOOST_PP_VARIADIC_HAS_OPT_ELEM0(BOOST_PP_IS_EMPTY_FUNCTION(__VA_ARGS__),) \ +/**/ +# else +#define BOOST_PP_IS_EMPTY(...) \ + BOOST_PP_IS_EMPTY_NO_OPT(__VA_ARGS__) \ +/**/ +# endif /* defined(__cplusplus) && __cplusplus > 201703L */ +#define BOOST_PP_IS_EMPTY_NO_OPT(...) \ BOOST_PP_DETAIL_IS_EMPTY_IIF \ ( \ BOOST_PP_IS_BEGIN_PARENS \ diff --git a/boost/preprocessor/repetition/for.hpp b/boost/preprocessor/repetition/for.hpp index c38946b..3c5048a 100644 --- a/boost/preprocessor/repetition/for.hpp +++ b/boost/preprocessor/repetition/for.hpp @@ -52,13 +52,13 @@ # define BOOST_PP_FOR_257_ERROR() BOOST_PP_ERROR(0x0002) # define BOOST_PP_FOR_257(s, p, o, m) \ - BOOST_PP_IIF \ - ( \ - BOOST_PP_FOR_257_PR(s,p), \ - BOOST_PP_FOR_257_ERROR, \ - BOOST_PP_EMPTY \ - ) \ - () \ + BOOST_PP_IIF \ + ( \ + BOOST_PP_FOR_257_PR(s,p), \ + BOOST_PP_FOR_257_ERROR, \ + BOOST_PP_EMPTY \ + ) \ + () \ /**/ // # define BOOST_PP_FOR_257(s, p, o, m) BOOST_PP_ERROR(0x0002) # diff --git a/boost/preprocessor/seq/detail/is_empty.hpp b/boost/preprocessor/seq/detail/is_empty.hpp index 1a80a2f..14461ba 100644 --- a/boost/preprocessor/seq/detail/is_empty.hpp +++ b/boost/preprocessor/seq/detail/is_empty.hpp @@ -21,29 +21,29 @@ /* An empty seq is one that is just BOOST_PP_SEQ_NIL */ # # define BOOST_PP_SEQ_DETAIL_IS_EMPTY(seq) \ - BOOST_PP_COMPL \ - ( \ - BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY(seq) \ - ) \ + BOOST_PP_COMPL \ + ( \ + BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY(seq) \ + ) \ /**/ # # define BOOST_PP_SEQ_DETAIL_IS_EMPTY_SIZE(size) \ - BOOST_PP_COMPL \ - ( \ - BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY_SIZE(size) \ - ) \ + BOOST_PP_COMPL \ + ( \ + BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY_SIZE(size) \ + ) \ /**/ # # define BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY(seq) \ - BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY_SIZE(BOOST_PP_SEQ_DETAIL_EMPTY_SIZE(seq)) \ + BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY_SIZE(BOOST_PP_SEQ_DETAIL_EMPTY_SIZE(seq)) \ /**/ # # define BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY_SIZE(size) \ - BOOST_PP_BOOL(size) \ + BOOST_PP_BOOL(size) \ /**/ # # define BOOST_PP_SEQ_DETAIL_EMPTY_SIZE(seq) \ - BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(seq (nil))) \ + BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(seq (nil))) \ /**/ # # endif diff --git a/boost/preprocessor/seq/for_each_i.hpp b/boost/preprocessor/seq/for_each_i.hpp index 81028d7..d29d4c1 100644 --- a/boost/preprocessor/seq/for_each_i.hpp +++ b/boost/preprocessor/seq/for_each_i.hpp @@ -37,13 +37,13 @@ # define BOOST_PP_SEQ_FOR_EACH_I_DETAIL_CHECK_EMPTY(macro, data, seq) # # define BOOST_PP_SEQ_FOR_EACH_I_DETAIL_CHECK(macro, data, seq) \ - BOOST_PP_IIF \ - ( \ - BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY(seq), \ - BOOST_PP_SEQ_FOR_EACH_I_DETAIL_CHECK_EXEC, \ - BOOST_PP_SEQ_FOR_EACH_I_DETAIL_CHECK_EMPTY \ - ) \ - (macro, data, seq) \ + BOOST_PP_IIF \ + ( \ + BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY(seq), \ + BOOST_PP_SEQ_FOR_EACH_I_DETAIL_CHECK_EXEC, \ + BOOST_PP_SEQ_FOR_EACH_I_DETAIL_CHECK_EMPTY \ + ) \ + (macro, data, seq) \ /**/ # # define BOOST_PP_SEQ_FOR_EACH_I_P(r, x) BOOST_PP_TUPLE_ELEM(5, 4, x) @@ -55,22 +55,22 @@ # endif # # define BOOST_PP_SEQ_FOR_EACH_I_O_I(macro, data, seq, i, sz) \ - BOOST_PP_SEQ_FOR_EACH_I_O_I_DEC(macro, data, seq, i, BOOST_PP_DEC(sz)) \ + BOOST_PP_SEQ_FOR_EACH_I_O_I_DEC(macro, data, seq, i, BOOST_PP_DEC(sz)) \ /**/ # define BOOST_PP_SEQ_FOR_EACH_I_O_I_DEC(macro, data, seq, i, sz) \ - ( \ - macro, \ - data, \ - BOOST_PP_IF \ - ( \ - sz, \ - BOOST_PP_SEQ_FOR_EACH_I_O_I_TAIL, \ - BOOST_PP_SEQ_FOR_EACH_I_O_I_NIL \ - ) \ - (seq), \ - BOOST_PP_INC(i), \ - sz \ - ) \ + ( \ + macro, \ + data, \ + BOOST_PP_IF \ + ( \ + sz, \ + BOOST_PP_SEQ_FOR_EACH_I_O_I_TAIL, \ + BOOST_PP_SEQ_FOR_EACH_I_O_I_NIL \ + ) \ + (seq), \ + BOOST_PP_INC(i), \ + sz \ + ) \ /**/ # define BOOST_PP_SEQ_FOR_EACH_I_O_I_TAIL(seq) BOOST_PP_SEQ_TAIL(seq) # define BOOST_PP_SEQ_FOR_EACH_I_O_I_NIL(seq) BOOST_PP_NIL @@ -97,13 +97,13 @@ # define BOOST_PP_SEQ_FOR_EACH_I_R_DETAIL_CHECK_EMPTY(r, macro, data, seq) # # define BOOST_PP_SEQ_FOR_EACH_I_R_DETAIL_CHECK(r, macro, data, seq) \ - BOOST_PP_IIF \ - ( \ - BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY(seq), \ - BOOST_PP_SEQ_FOR_EACH_I_R_DETAIL_CHECK_EXEC, \ - BOOST_PP_SEQ_FOR_EACH_I_R_DETAIL_CHECK_EMPTY \ - ) \ - (r, macro, data, seq) \ + BOOST_PP_IIF \ + ( \ + BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY(seq), \ + BOOST_PP_SEQ_FOR_EACH_I_R_DETAIL_CHECK_EXEC, \ + BOOST_PP_SEQ_FOR_EACH_I_R_DETAIL_CHECK_EMPTY \ + ) \ + (r, macro, data, seq) \ /**/ # # endif diff --git a/boost/preprocessor/seq/rest_n.hpp b/boost/preprocessor/seq/rest_n.hpp index 4aefba4..cac52cf 100644 --- a/boost/preprocessor/seq/rest_n.hpp +++ b/boost/preprocessor/seq/rest_n.hpp @@ -32,15 +32,15 @@ # endif # # define BOOST_PP_SEQ_REST_N_DETAIL_EXEC(n, seq, size) \ - BOOST_PP_EXPR_IIF \ - ( \ - BOOST_PP_BITAND \ - ( \ - BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY_SIZE(size), \ - BOOST_PP_NOT_EQUAL(n,size) \ - ), \ - BOOST_PP_TUPLE_ELEM(2, 1, BOOST_PP_SEQ_SPLIT(BOOST_PP_INC(n), BOOST_PP_IDENTITY( (nil) seq )))() \ - ) \ + BOOST_PP_EXPR_IIF \ + ( \ + BOOST_PP_BITAND \ + ( \ + BOOST_PP_SEQ_DETAIL_IS_NOT_EMPTY_SIZE(size), \ + BOOST_PP_NOT_EQUAL(n,size) \ + ), \ + BOOST_PP_TUPLE_ELEM(2, 1, BOOST_PP_SEQ_SPLIT(BOOST_PP_INC(n), BOOST_PP_IDENTITY( (nil) seq )))() \ + ) \ /**/ # # endif diff --git a/boost/preprocessor/tuple/detail/is_single_return.hpp b/boost/preprocessor/tuple/detail/is_single_return.hpp index 02a4fb2..bcdb544 100644 --- a/boost/preprocessor/tuple/detail/is_single_return.hpp +++ b/boost/preprocessor/tuple/detail/is_single_return.hpp @@ -20,9 +20,9 @@ # include # include # include -# define BOOST_PP_TUPLE_IS_SINGLE_RETURN(sr,nsr,tuple) \ - BOOST_PP_IIF(BOOST_PP_IS_1(BOOST_PP_TUPLE_SIZE(tuple)),sr,nsr) \ - /**/ +# define BOOST_PP_TUPLE_IS_SINGLE_RETURN(sr,nsr,tuple) \ + BOOST_PP_IIF(BOOST_PP_IS_1(BOOST_PP_TUPLE_SIZE(tuple)),sr,nsr) \ + /**/ # endif /* BOOST_PP_VARIADICS && BOOST_PP_VARIADICS_MSVC */ # # endif /* BOOST_PREPROCESSOR_TUPLE_DETAIL_IS_SINGLE_RETURN_HPP */ diff --git a/boost/preprocessor/tuple/elem.hpp b/boost/preprocessor/tuple/elem.hpp index 88044d3..148e6bd 100644 --- a/boost/preprocessor/tuple/elem.hpp +++ b/boost/preprocessor/tuple/elem.hpp @@ -33,12 +33,12 @@ else use BOOST_PP_REM. This fixes a VC++ problem with an empty tuple and BOOST_PP_TUPLE_ELEM functionality. See tuple_elem_bug_test.cxx. */ -# define BOOST_PP_TUPLE_ELEM_O_2(n, tuple) \ - BOOST_PP_VARIADIC_ELEM(n, BOOST_PP_EXPAND(BOOST_PP_TUPLE_IS_SINGLE_RETURN(BOOST_PP_REM_CAT,BOOST_PP_REM,tuple) tuple)) \ - /**/ +# define BOOST_PP_TUPLE_ELEM_O_2(n, tuple) \ + BOOST_PP_VARIADIC_ELEM(n, BOOST_PP_EXPAND(BOOST_PP_TUPLE_IS_SINGLE_RETURN(BOOST_PP_REM_CAT,BOOST_PP_REM,tuple) tuple)) \ + /**/ # else # define BOOST_PP_TUPLE_ELEM(...) BOOST_PP_OVERLOAD(BOOST_PP_TUPLE_ELEM_O_, __VA_ARGS__)(__VA_ARGS__) -# define BOOST_PP_TUPLE_ELEM_O_2(n, tuple) BOOST_PP_VARIADIC_ELEM(n, BOOST_PP_REM tuple) +# define BOOST_PP_TUPLE_ELEM_O_2(n, tuple) BOOST_PP_VARIADIC_ELEM(n, BOOST_PP_REM tuple) # endif # define BOOST_PP_TUPLE_ELEM_O_3(size, n, tuple) BOOST_PP_TUPLE_ELEM_O_2(n, tuple) # else diff --git a/boost/preprocessor/tuple/rem.hpp b/boost/preprocessor/tuple/rem.hpp index c934447..e99008d 100644 --- a/boost/preprocessor/tuple/rem.hpp +++ b/boost/preprocessor/tuple/rem.hpp @@ -22,10 +22,10 @@ # /* BOOST_PP_REM */ # # if BOOST_PP_VARIADICS -# if BOOST_PP_VARIADICS_MSVC - /* To be used internally when __VA_ARGS__ could be empty ( or is a single element ) */ -# define BOOST_PP_REM_CAT(...) BOOST_PP_CAT(__VA_ARGS__,) -# endif +# if BOOST_PP_VARIADICS_MSVC + /* To be used internally when __VA_ARGS__ could be empty ( or is a single element ) */ +# define BOOST_PP_REM_CAT(...) BOOST_PP_CAT(__VA_ARGS__,) +# endif # define BOOST_PP_REM(...) __VA_ARGS__ # else # define BOOST_PP_REM(x) x @@ -37,10 +37,10 @@ VC++8.0 cannot handle the variadic version of BOOST_PP_TUPLE_REM(size) */ # if BOOST_PP_VARIADICS && !(BOOST_PP_VARIADICS_MSVC && _MSC_VER <= 1400) -# if BOOST_PP_VARIADICS_MSVC - /* To be used internally when the size could be 0 ( or 1 ) */ -# define BOOST_PP_TUPLE_REM_CAT(size) BOOST_PP_REM_CAT -# endif +# if BOOST_PP_VARIADICS_MSVC + /* To be used internally when the size could be 0 ( or 1 ) */ +# define BOOST_PP_TUPLE_REM_CAT(size) BOOST_PP_REM_CAT +# endif # define BOOST_PP_TUPLE_REM(size) BOOST_PP_REM # else # if ~BOOST_PP_CONFIG_FLAGS() & BOOST_PP_CONFIG_MWCC() @@ -124,10 +124,10 @@ # define BOOST_PP_TUPLE_REM_CTOR(...) BOOST_PP_TUPLE_REM_CTOR_I(BOOST_PP_OVERLOAD(BOOST_PP_TUPLE_REM_CTOR_O_, __VA_ARGS__), (__VA_ARGS__)) # define BOOST_PP_TUPLE_REM_CTOR_I(m, args) BOOST_PP_TUPLE_REM_CTOR_II(m, args) # define BOOST_PP_TUPLE_REM_CTOR_II(m, args) BOOST_PP_CAT(m ## args,) -# define BOOST_PP_TUPLE_REM_CTOR_O_1(tuple) BOOST_PP_EXPAND(BOOST_PP_TUPLE_IS_SINGLE_RETURN(BOOST_PP_REM_CAT,BOOST_PP_REM,tuple) tuple) +# define BOOST_PP_TUPLE_REM_CTOR_O_1(tuple) BOOST_PP_EXPAND(BOOST_PP_TUPLE_IS_SINGLE_RETURN(BOOST_PP_REM_CAT,BOOST_PP_REM,tuple) tuple) # else # define BOOST_PP_TUPLE_REM_CTOR(...) BOOST_PP_OVERLOAD(BOOST_PP_TUPLE_REM_CTOR_O_, __VA_ARGS__)(__VA_ARGS__) -# define BOOST_PP_TUPLE_REM_CTOR_O_1(tuple) BOOST_PP_REM tuple +# define BOOST_PP_TUPLE_REM_CTOR_O_1(tuple) BOOST_PP_REM tuple # endif # define BOOST_PP_TUPLE_REM_CTOR_O_2(size, tuple) BOOST_PP_TUPLE_REM_CTOR_O_1(tuple) # else diff --git a/boost/preprocessor/tuple/to_list.hpp b/boost/preprocessor/tuple/to_list.hpp index da7828f..25d9b09 100644 --- a/boost/preprocessor/tuple/to_list.hpp +++ b/boost/preprocessor/tuple/to_list.hpp @@ -28,10 +28,10 @@ # define BOOST_PP_TUPLE_TO_LIST(...) BOOST_PP_TUPLE_TO_LIST_I(BOOST_PP_OVERLOAD(BOOST_PP_TUPLE_TO_LIST_O_, __VA_ARGS__), (__VA_ARGS__)) # define BOOST_PP_TUPLE_TO_LIST_I(m, args) BOOST_PP_TUPLE_TO_LIST_II(m, args) # define BOOST_PP_TUPLE_TO_LIST_II(m, args) BOOST_PP_CAT(m ## args,) -# define BOOST_PP_TUPLE_TO_LIST_O_1(tuple) BOOST_PP_CAT(BOOST_PP_TUPLE_TO_LIST_, BOOST_PP_TUPLE_SIZE(tuple)) tuple +# define BOOST_PP_TUPLE_TO_LIST_O_1(tuple) BOOST_PP_CAT(BOOST_PP_TUPLE_TO_LIST_, BOOST_PP_TUPLE_SIZE(tuple)) tuple # else # define BOOST_PP_TUPLE_TO_LIST(...) BOOST_PP_OVERLOAD(BOOST_PP_TUPLE_TO_LIST_O_, __VA_ARGS__)(__VA_ARGS__) -# define BOOST_PP_TUPLE_TO_LIST_O_1(tuple) BOOST_PP_CAT(BOOST_PP_TUPLE_TO_LIST_, BOOST_PP_VARIADIC_SIZE tuple) tuple +# define BOOST_PP_TUPLE_TO_LIST_O_1(tuple) BOOST_PP_CAT(BOOST_PP_TUPLE_TO_LIST_, BOOST_PP_VARIADIC_SIZE tuple) tuple # endif # define BOOST_PP_TUPLE_TO_LIST_O_2(size, tuple) BOOST_PP_TUPLE_TO_LIST_O_1(tuple) # else diff --git a/boost/preprocessor/variadic/detail/has_opt.hpp b/boost/preprocessor/variadic/detail/has_opt.hpp new file mode 100644 index 0000000..79edf3b --- /dev/null +++ b/boost/preprocessor/variadic/detail/has_opt.hpp @@ -0,0 +1,39 @@ +# /* ************************************************************************** +# * * +# * (C) Copyright Edward Diener 2019. * +# * 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 most recent version. */ +# +# ifndef BOOST_PREPROCESSOR_VARIADIC_DETAIL_HAS_OPT_HPP +# define BOOST_PREPROCESSOR_VARIADIC_DETAIL_HAS_OPT_HPP +# +# include +# +# if BOOST_PP_VARIADICS && defined(__cplusplus) && __cplusplus > 201703L +# +# if BOOST_PP_VARIADICS_MSVC +# include +# endif +# +# define BOOST_PP_VARIADIC_HAS_OPT_FUNCTION(...) \ + __VA_OPT__(,) , 1, 0 \ +/**/ +# +# if BOOST_PP_VARIADICS_MSVC +# define BOOST_PP_VARIADIC_HAS_OPT_ELEM0(e0, ...) BOOST_PP_CAT(BOOST_PP_VARIADIC_HAS_OPT_ELEM_0(e0,__VA_ARGS__),) +# define BOOST_PP_VARIADIC_HAS_OPT_ELEM2(e0, ...) BOOST_PP_CAT(BOOST_PP_VARIADIC_HAS_OPT_ELEM_2(e0,__VA_ARGS__),) +# else +# define BOOST_PP_VARIADIC_HAS_OPT_ELEM0(e0, ...) BOOST_PP_VARIADIC_HAS_OPT_ELEM_0(e0,__VA_ARGS__) +# define BOOST_PP_VARIADIC_HAS_OPT_ELEM2(e0, ...) BOOST_PP_VARIADIC_HAS_OPT_ELEM_2(e0,__VA_ARGS__) +# endif +# define BOOST_PP_VARIADIC_HAS_OPT_ELEM_0(e0, ...) e0 +# define BOOST_PP_VARIADIC_HAS_OPT_ELEM_2(e0, e1, e2, ...) e2 +# +# endif +# +# endif diff --git a/boost/preprocessor/variadic/has_opt.hpp b/boost/preprocessor/variadic/has_opt.hpp new file mode 100644 index 0000000..3ab0890 --- /dev/null +++ b/boost/preprocessor/variadic/has_opt.hpp @@ -0,0 +1,28 @@ +# /* ************************************************************************** +# * * +# * (C) Copyright Edward Diener 2019. * +# * 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 most recent version. */ +# +# ifndef BOOST_PREPROCESSOR_VARIADIC_HAS_OPT_HPP +# define BOOST_PREPROCESSOR_VARIADIC_HAS_OPT_HPP +# +# include +# +# /* BOOST_PP_VARIADIC_HAS_OPT */ +# +# if BOOST_PP_VARIADICS && defined(__cplusplus) && __cplusplus > 201703L +# include +# define BOOST_PP_VARIADIC_HAS_OPT() \ + BOOST_PP_VARIADIC_HAS_OPT_ELEM2(BOOST_PP_VARIADIC_HAS_OPT_FUNCTION(?),) \ +/**/ +# else +# define BOOST_PP_VARIADIC_HAS_OPT() 0 +# endif +# +# endif diff --git a/boost/ratio/detail/ratio_io.hpp b/boost/ratio/detail/ratio_io.hpp new file mode 100644 index 0000000..636dbc2 --- /dev/null +++ b/boost/ratio/detail/ratio_io.hpp @@ -0,0 +1,1342 @@ +// ratio_io +// +// (C) Copyright Howard Hinnant +// (C) Copyright 2010 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o under lvm/libc++ to Boost + +#ifndef BOOST_RATIO_DETAIL_RATIO_IO_HPP +#define BOOST_RATIO_DETAIL_RATIO_IO_HPP + +/* + + ratio_io synopsis + +#include +#include + +namespace boost +{ + +template +struct ratio_string +{ + static basic_string short_name(); + static basic_string long_name(); +}; + +} // boost + +*/ + +#include +#include +#include +#include +#include + +#if defined(BOOST_NO_CXX11_UNICODE_LITERALS) || defined(BOOST_NO_CXX11_CHAR16_T) || defined(BOOST_NO_CXX11_CHAR32_T) || defined(BOOST_NO_CXX11_U16STRING) || defined(BOOST_NO_CXX11_U32STRING) +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT +#undef BOOST_RATIO_HAS_UNICODE_SUPPORT +#endif +#else +#define BOOST_RATIO_HAS_UNICODE_SUPPORT 1 +#endif + +namespace boost { + +//template +//struct ratio_string_is_localizable : false_type {}; +//template +//struct ratio_string_id : integral_constant {}; + +template +struct ratio_string +{ + static std::basic_string short_name() {return long_name();} + static std::basic_string long_name(); + static std::basic_string symbol() {return short_name();} + static std::basic_string prefix() {return long_name();} +}; + +template +std::basic_string +ratio_string::long_name() +{ + std::basic_ostringstream os; + os << CharT('[') << Ratio::num << CharT('/') + << Ratio::den << CharT(']'); + return os.str(); +} + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +namespace ratio_detail { +template +struct ratio_string_static +{ + static std::string short_name() { + return std::basic_string( + static_string::c_str< + typename ratio_static_string::short_name + >::value); + } + static std::string long_name() { + return std::basic_string( + static_string::c_str< + typename ratio_static_string::long_name + >::value); + } + static std::basic_string symbol() {return short_name();} + static std::basic_string prefix() {return long_name();} +}; +} +#endif +// atto +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'a');} + static std::string long_name() {return std::string("atto");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'a');} + static std::u16string long_name() {return std::u16string(u"atto");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'a');} + static std::u32string long_name() {return std::u32string(U"atto");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'a');} + static std::wstring long_name() {return std::wstring(L"atto");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// femto + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else + +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'f');} + static std::string long_name() {return std::string("femto");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'f');} + static std::u16string long_name() {return std::u16string(u"femto");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'f');} + static std::u32string long_name() {return std::u32string(U"femto");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'f');} + static std::wstring long_name() {return std::wstring(L"femto");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// pico + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'p');} + static std::string long_name() {return std::string("pico");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'p');} + static std::u16string long_name() {return std::u16string(u"pico");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'p');} + static std::u32string long_name() {return std::u32string(U"pico");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'p');} + static std::wstring long_name() {return std::wstring(L"pico");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// nano + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'n');} + static std::string long_name() {return std::string("nano");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'n');} + static std::u16string long_name() {return std::u16string(u"nano");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'n');} + static std::u32string long_name() {return std::u32string(U"nano");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'n');} + static std::wstring long_name() {return std::wstring(L"nano");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// micro + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string("\xC2\xB5");} + static std::string long_name() {return std::string("micro");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'\xB5');} + static std::u16string long_name() {return std::u16string(u"micro");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'\xB5');} + static std::u32string long_name() {return std::u32string(U"micro");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'\xB5');} + static std::wstring long_name() {return std::wstring(L"micro");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// milli + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'm');} + static std::string long_name() {return std::string("milli");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'm');} + static std::u16string long_name() {return std::u16string(u"milli");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'm');} + static std::u32string long_name() {return std::u32string(U"milli");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'm');} + static std::wstring long_name() {return std::wstring(L"milli");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// centi + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'c');} + static std::string long_name() {return std::string("centi");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'c');} + static std::u16string long_name() {return std::u16string(u"centi");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'c');} + static std::u32string long_name() {return std::u32string(U"centi");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'c');} + static std::wstring long_name() {return std::wstring(L"centi");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// deci + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else + +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'd');} + static std::string long_name() {return std::string("deci");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'd');} + static std::u16string long_name() {return std::u16string(u"deci");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'd');} + static std::u32string long_name() {return std::u32string(U"deci");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'd');} + static std::wstring long_name() {return std::wstring(L"deci");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// unit + +//template <> +//struct ratio_string_is_localizable > : true_type {}; +// +//template <> +//struct ratio_string_id > : integral_constant {}; +// deca + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string("da");} + static std::string long_name() {return std::string("deca");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(u"da");} + static std::u16string long_name() {return std::u16string(u"deca");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(U"da");} + static std::u32string long_name() {return std::u32string(U"deca");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(L"da");} + static std::wstring long_name() {return std::wstring(L"deca");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// hecto + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'h');} + static std::string long_name() {return std::string("hecto");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'h');} + static std::u16string long_name() {return std::u16string(u"hecto");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'h');} + static std::u32string long_name() {return std::u32string(U"hecto");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'h');} + static std::wstring long_name() {return std::wstring(L"hecto");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// kilo + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'k');} + static std::string long_name() {return std::string("kilo");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'k');} + static std::u16string long_name() {return std::u16string(u"kilo");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'k');} + static std::u32string long_name() {return std::u32string(U"kilo");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'k');} + static std::wstring long_name() {return std::wstring(L"kilo");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// mega + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else + +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'M');} + static std::string long_name() {return std::string("mega");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'M');} + static std::u16string long_name() {return std::u16string(u"mega");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'M');} + static std::u32string long_name() {return std::u32string(U"mega");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'M');} + static std::wstring long_name() {return std::wstring(L"mega");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// giga + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else + +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'G');} + static std::string long_name() {return std::string("giga");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'G');} + static std::u16string long_name() {return std::u16string(u"giga");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'G');} + static std::u32string long_name() {return std::u32string(U"giga");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'G');} + static std::wstring long_name() {return std::wstring(L"giga");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// tera + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'T');} + static std::string long_name() {return std::string("tera");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'T');} + static std::u16string long_name() {return std::u16string(u"tera");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'T');} + static std::u32string long_name() {return std::u32string(U"tera");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'T');} + static std::wstring long_name() {return std::wstring(L"tera");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// peta + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'P');} + static std::string long_name() {return std::string("peta");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'P');} + static std::u16string long_name() {return std::u16string(u"peta");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'P');} + static std::u32string long_name() {return std::u32string(U"peta");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'P');} + static std::wstring long_name() {return std::wstring(L"peta");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +// exa + +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string(1, 'E');} + static std::string long_name() {return std::string("exa");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(1, u'E');} + static std::u16string long_name() {return std::u16string(u"exa");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(1, U'E');} + static std::u32string long_name() {return std::u32string(U"exa");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(1, L'E');} + static std::wstring long_name() {return std::wstring(L"exa");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +#ifdef BOOST_RATIO_EXTENSIONS + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string("Ki");} + static std::string long_name() {return std::string("kibi");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(u"Ki");} + static std::u16string long_name() {return std::u16string(u"kibi");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(U"Ki");} + static std::u32string long_name() {return std::u32string(U"kibi");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(L"Ki");} + static std::wstring long_name() {return std::wstring(L"kibi");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string("Mi");} + static std::string long_name() {return std::string("mebi");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(u"Mi");} + static std::u16string long_name() {return std::u16string(u"mebi");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(U"Mi");} + static std::u32string long_name() {return std::u32string(U"mebi");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(L"Mi");} + static std::wstring long_name() {return std::wstring(L"mebi");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string("Gi");} + static std::string long_name() {return std::string("gibi");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(u"Gi");} + static std::u16string long_name() {return std::u16string(u"gibi");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(U"Gi");} + static std::u32string long_name() {return std::u32string(U"gibi");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(L"Gi");} + static std::wstring long_name() {return std::wstring(L"gibi");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string("Ti");} + static std::string long_name() {return std::string("tebi");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(u"Ti");} + static std::u16string long_name() {return std::u16string(u"tebi");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(U"Ti");} + static std::u32string long_name() {return std::u32string(U"tebi");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(L"Ti");} + static std::wstring long_name() {return std::wstring(L"tebi");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string("Pi");} + static std::string long_name() {return std::string("pebi");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(u"Pi");} + static std::u16string long_name() {return std::u16string(u"pebi");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(U"Pi");} + static std::u32string long_name() {return std::u32string(U"pebi");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(L"Pi");} + static std::wstring long_name() {return std::wstring(L"pebi");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string short_name() {return std::string("Ei");} + static std::string long_name() {return std::string("exbi");} + static std::string symbol() {return short_name();} + static std::string prefix() {return long_name();} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string short_name() {return std::u16string(u"Ei");} + static std::u16string long_name() {return std::u16string(u"exbi");} + static std::u16string symbol() {return short_name();} + static std::u16string prefix() {return long_name();} +}; + +template <> +struct ratio_string +{ + static std::u32string short_name() {return std::u32string(U"Ei");} + static std::u32string long_name() {return std::u32string(U"exbi");} + static std::u32string symbol() {return short_name();} + static std::u32string prefix() {return long_name();} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring short_name() {return std::wstring(L"Ei");} + static std::wstring long_name() {return std::wstring(L"exbi");} + static std::wstring symbol() {return short_name();} + static std::wstring prefix() {return long_name();} +}; +#endif +#endif +#endif +} + +#endif // BOOST_RATIO_RATIO_IO_HPP diff --git a/boost/ratio/ratio_io.hpp b/boost/ratio/ratio_io.hpp new file mode 100644 index 0000000..e39cbaf --- /dev/null +++ b/boost/ratio/ratio_io.hpp @@ -0,0 +1,1076 @@ +// ratio_io +// +// (C) Copyright Howard Hinnant +// (C) Copyright 2010 Vicente J. Botet Escriba +// Use, modification and distribution are subject to 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). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o under lvm/libc++ to Boost + +#ifndef BOOST_RATIO_RATIO_IO_HPP +#define BOOST_RATIO_RATIO_IO_HPP + +/* + + ratio_io synopsis + +#include +#include + +namespace boost +{ + +template +struct ratio_string +{ + static basic_string prefix(); + static basic_string symbol(); +}; + +} // boost + +*/ +#include + +#ifdef BOOST_RATIO_PROVIDES_DEPRECATED_FEATURES_SINCE_V2_0_0 +#include +#else + +#include +#include +#include +#include +#include + + +#if defined(BOOST_NO_CXX11_UNICODE_LITERALS) || defined(BOOST_NO_CXX11_CHAR16_T) || defined(BOOST_NO_CXX11_CHAR32_T) || defined(BOOST_NO_CXX11_U16STRING) || defined(BOOST_NO_CXX11_U32STRING) +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT +#undef BOOST_RATIO_HAS_UNICODE_SUPPORT +#endif +#else +#define BOOST_RATIO_HAS_UNICODE_SUPPORT 1 +#endif + +namespace boost { + +//template +//struct ratio_string_is_localizable : false_type {}; +//template +//struct ratio_string_id : integral_constant {}; + +template +struct ratio_string +{ + static std::basic_string symbol() {return prefix();} + static std::basic_string prefix(); +}; + +template +std::basic_string +ratio_string::prefix() +{ + std::basic_ostringstream os; + os << CharT('[') << Ratio::num << CharT('/') + << Ratio::den << CharT(']'); + return os.str(); +} + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +namespace ratio_detail { +template +struct ratio_string_static +{ + static std::string symbol() { + return std::basic_string( + static_string::c_str< + typename ratio_static_string::symbol + >::value); + } + static std::string prefix() { + return std::basic_string( + static_string::c_str< + typename ratio_static_string::prefix + >::value); + } +}; +} +#endif +// atto +//template <> +//struct ratio_string_is_localizable : true_type {}; +// +//template <> +//struct ratio_string_id : integral_constant {}; + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'a');} + static std::string prefix() {return std::string("atto");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'a');} + static std::u16string prefix() {return std::u16string(u"atto");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'a');} + static std::u32string prefix() {return std::u32string(U"atto");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'a');} + static std::wstring prefix() {return std::wstring(L"atto");} +}; +#endif +#endif + +// femto + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else + +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'f');} + static std::string prefix() {return std::string("femto");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'f');} + static std::u16string prefix() {return std::u16string(u"femto");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'f');} + static std::u32string prefix() {return std::u32string(U"femto");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'f');} + static std::wstring prefix() {return std::wstring(L"femto");} +}; +#endif +#endif + +// pico + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'p');} + static std::string prefix() {return std::string("pico");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'p');} + static std::u16string prefix() {return std::u16string(u"pico");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'p');} + static std::u32string prefix() {return std::u32string(U"pico");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'p');} + static std::wstring prefix() {return std::wstring(L"pico");} +}; +#endif +#endif + +// nano + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'n');} + static std::string prefix() {return std::string("nano");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'n');} + static std::u16string prefix() {return std::u16string(u"nano");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'n');} + static std::u32string prefix() {return std::u32string(U"nano");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'n');} + static std::wstring prefix() {return std::wstring(L"nano");} +}; +#endif +#endif + +// micro + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string("\xC2\xB5");} + static std::string prefix() {return std::string("micro");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'\xB5');} + static std::u16string prefix() {return std::u16string(u"micro");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'\xB5');} + static std::u32string prefix() {return std::u32string(U"micro");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'\xB5');} + static std::wstring prefix() {return std::wstring(L"micro");} +}; +#endif +#endif + +// milli + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'm');} + static std::string prefix() {return std::string("milli");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'm');} + static std::u16string prefix() {return std::u16string(u"milli");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'm');} + static std::u32string prefix() {return std::u32string(U"milli");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'm');} + static std::wstring prefix() {return std::wstring(L"milli");} +}; +#endif +#endif + +// centi + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'c');} + static std::string prefix() {return std::string("centi");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'c');} + static std::u16string prefix() {return std::u16string(u"centi");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'c');} + static std::u32string prefix() {return std::u32string(U"centi");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'c');} + static std::wstring prefix() {return std::wstring(L"centi");} +}; +#endif +#endif + +// deci + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else + +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'd');} + static std::string prefix() {return std::string("deci");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'd');} + static std::u16string prefix() {return std::u16string(u"deci");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'd');} + static std::u32string prefix() {return std::u32string(U"deci");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'd');} + static std::wstring prefix() {return std::wstring(L"deci");} +}; +#endif +#endif + +// unit + +// deca + + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string("da");} + static std::string prefix() {return std::string("deca");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(u"da");} + static std::u16string prefix() {return std::u16string(u"deca");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(U"da");} + static std::u32string prefix() {return std::u32string(U"deca");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(L"da");} + static std::wstring prefix() {return std::wstring(L"deca");} +}; +#endif +#endif + +// hecto + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'h');} + static std::string prefix() {return std::string("hecto");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'h');} + static std::u16string prefix() {return std::u16string(u"hecto");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'h');} + static std::u32string prefix() {return std::u32string(U"hecto");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'h');} + static std::wstring prefix() {return std::wstring(L"hecto");} +}; +#endif +#endif + +// kilo + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'k');} + static std::string prefix() {return std::string("kilo");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'k');} + static std::u16string prefix() {return std::u16string(u"kilo");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'k');} + static std::u32string prefix() {return std::u32string(U"kilo");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'k');} + static std::wstring prefix() {return std::wstring(L"kilo");} +}; +#endif +#endif + +// mega + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else + +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'M');} + static std::string prefix() {return std::string("mega");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'M');} + static std::u16string prefix() {return std::u16string(u"mega");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'M');} + static std::u32string prefix() {return std::u32string(U"mega");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'M');} + static std::wstring prefix() {return std::wstring(L"mega");} +}; +#endif +#endif + +// giga + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else + +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'G');} + static std::string prefix() {return std::string("giga");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'G');} + static std::u16string prefix() {return std::u16string(u"giga");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'G');} + static std::u32string prefix() {return std::u32string(U"giga");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'G');} + static std::wstring prefix() {return std::wstring(L"giga");} +}; +#endif +#endif + +// tera + +//template <> +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'T');} + static std::string prefix() {return std::string("tera");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'T');} + static std::u16string prefix() {return std::u16string(u"tera");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'T');} + static std::u32string prefix() {return std::u32string(U"tera");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'T');} + static std::wstring prefix() {return std::wstring(L"tera");} +}; +#endif +#endif + +// peta + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'P');} + static std::string prefix() {return std::string("peta");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'P');} + static std::u16string prefix() {return std::u16string(u"peta");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'P');} + static std::u32string prefix() {return std::u32string(U"peta");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'P');} + static std::wstring prefix() {return std::wstring(L"peta");} +}; +#endif +#endif + +// exa + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string(1, 'E');} + static std::string prefix() {return std::string("exa");} +}; + +#if defined BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(1, u'E');} + static std::u16string prefix() {return std::u16string(u"exa");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(1, U'E');} + static std::u32string prefix() {return std::u32string(U"exa");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(1, L'E');} + static std::wstring prefix() {return std::wstring(L"exa");} +}; +#endif +#endif + + +#ifdef BOOST_RATIO_EXTENSIONS + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string("Ki");} + static std::string prefix() {return std::string("kibi");} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(u"Ki");} + static std::u16string prefix() {return std::u16string(u"kibi");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(U"Ki");} + static std::u32string prefix() {return std::u32string(U"kibi");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(L"Ki");} + static std::wstring prefix() {return std::wstring(L"kibi");} +}; +#endif +#endif + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string("Mi");} + static std::string prefix() {return std::string("mebi");} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(u"Mi");} + static std::u16string prefix() {return std::u16string(u"mebi");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(U"Mi");} + static std::u32string prefix() {return std::u32string(U"mebi");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(L"Mi");} + static std::wstring prefix() {return std::wstring(L"mebi");} +}; +#endif +#endif + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string("Gi");} + static std::string prefix() {return std::string("gibi");} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(u"Gi");} + static std::u16string prefix() {return std::u16string(u"gibi");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(U"Gi");} + static std::u32string prefix() {return std::u32string(U"gibi");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(L"Gi");} + static std::wstring prefix() {return std::wstring(L"gibi");} +}; +#endif +#endif + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string("Ti");} + static std::string prefix() {return std::string("tebi");} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(u"Ti");} + static std::u16string prefix() {return std::u16string(u"tebi");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(U"Ti");} + static std::u32string prefix() {return std::u32string(U"tebi");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(L"Ti");} + static std::wstring prefix() {return std::wstring(L"tebi");} +}; +#endif +#endif + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string("Pi");} + static std::string prefix() {return std::string("pebi");} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(u"Pi");} + static std::u16string prefix() {return std::u16string(u"pebi");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(U"Pi");} + static std::u32string prefix() {return std::u32string(U"pebi");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(L"Pi");} + static std::wstring prefix() {return std::wstring(L"pebi");} +}; +#endif +#endif + +#ifdef BOOST_RATIO_HAS_STATIC_STRING +template +struct ratio_string : + ratio_detail::ratio_string_static +{}; + +#else +template <> +struct ratio_string +{ + static std::string symbol() {return std::string("Ei");} + static std::string prefix() {return std::string("exbi");} +}; + +#if BOOST_RATIO_HAS_UNICODE_SUPPORT + +template <> +struct ratio_string +{ + static std::u16string symbol() {return std::u16string(u"Ei");} + static std::u16string prefix() {return std::u16string(u"exbi");} +}; + +template <> +struct ratio_string +{ + static std::u32string symbol() {return std::u32string(U"Ei");} + static std::u32string prefix() {return std::u32string(U"exbi");} +}; + +#endif + +#ifndef BOOST_NO_STD_WSTRING +template <> +struct ratio_string +{ + static std::wstring symbol() {return std::wstring(L"Ei");} + static std::wstring prefix() {return std::wstring(L"exbi");} +}; +#endif +#endif +#endif + +} + +#endif // BOOST_RATIO_PROVIDES_DEPRECATED_FEATURES_SINCE_V2_0_0 +#endif // BOOST_RATIO_RATIO_IO_HPP diff --git a/boost/regex/v4/basic_regex.hpp b/boost/regex/v4/basic_regex.hpp index 1962372..b3bb1fe 100644 --- a/boost/regex/v4/basic_regex.hpp +++ b/boost/regex/v4/basic_regex.hpp @@ -20,7 +20,7 @@ #define BOOST_REGEX_V4_BASIC_REGEX_HPP #include -#include +#include #ifdef BOOST_MSVC #pragma warning(push) diff --git a/boost/regex/v4/perl_matcher_non_recursive.hpp b/boost/regex/v4/perl_matcher_non_recursive.hpp index db883f1..eb470a7 100644 --- a/boost/regex/v4/perl_matcher_non_recursive.hpp +++ b/boost/regex/v4/perl_matcher_non_recursive.hpp @@ -67,7 +67,7 @@ struct saved_matched_paren : public saved_state { int index; sub_match sub; - saved_matched_paren(int i, const sub_match& s) : saved_state(1), index(i), sub(s){}; + saved_matched_paren(int i, const sub_match& s) : saved_state(1), index(i), sub(s){} }; template @@ -75,7 +75,7 @@ struct saved_position : public saved_state { const re_syntax_base* pstate; BidiIterator position; - saved_position(const re_syntax_base* ps, BidiIterator pos, int i) : saved_state(i), pstate(ps), position(pos){}; + saved_position(const re_syntax_base* ps, BidiIterator pos, int i) : saved_state(i), pstate(ps), position(pos){} }; template @@ -83,7 +83,7 @@ struct saved_assertion : public saved_position { bool positive; saved_assertion(bool p, const re_syntax_base* ps, BidiIterator pos) - : saved_position(ps, pos, saved_type_assertion), positive(p){}; + : saved_position(ps, pos, saved_type_assertion), positive(p){} }; template diff --git a/boost/safe_numerics/CMakeLists.txt b/boost/safe_numerics/CMakeLists.txt deleted file mode 100644 index cd94725..0000000 --- a/boost/safe_numerics/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -#################### -# add include headers to IDE - -file(GLOB include_files - RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" - "*.hpp" -) -add_custom_target(safe_numerics SOURCES ${include_files}) - -add_subdirectory("concept") - -# end headers in IDE -#################### diff --git a/boost/safe_numerics/automatic.hpp b/boost/safe_numerics/automatic.hpp deleted file mode 100644 index df63bf8..0000000 --- a/boost/safe_numerics/automatic.hpp +++ /dev/null @@ -1,479 +0,0 @@ -#ifndef BOOST_NUMERIC_AUTOMATIC_HPP -#define BOOST_NUMERIC_AUTOMATIC_HPP - -// Copyright (c) 2012 Robert Ramey -// -// 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) - -// policy which creates expanded results types designed -// to avoid overflows. - -#include -#include // (u)intmax_t, -#include // conditional -#include - -#include "safe_common.hpp" -#include "checked_result.hpp" -#include "checked_default.hpp" -#include "checked_integer.hpp" -#include "checked_result_operations.hpp" -#include "interval.hpp" -#include "utility.hpp" - -namespace boost { -namespace safe_numerics { - -struct automatic { -private: - // the following returns the "true" type. After calculating the new max and min - // these return the minimum size type which can hold the expected result. - struct defer_stored_signed_lazily { - template - using type = utility::signed_stored_type; - }; - - struct defer_stored_unsigned_lazily { - template - using type = utility::unsigned_stored_type; - }; - - template - struct result_type { - using type = typename std::conditional< - std::numeric_limits::is_signed, - defer_stored_signed_lazily, - defer_stored_unsigned_lazily - >::type::template type; - }; - -public: - /////////////////////////////////////////////////////////////////////// - template - struct addition_result { - using temp_base_type = typename std::conditional< - // if both arguments are unsigned - ! std::numeric_limits::is_signed - && ! std::numeric_limits::is_signed, - // result is unsigned - std::uintmax_t, - // otherwise result is signed - std::intmax_t - >::type; - - using r_type = checked_result; - using r_interval_type = interval; - - constexpr static const r_interval_type t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type u_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type r_interval = t_interval + u_interval; - - constexpr static auto rl = r_interval.l; - constexpr static auto ru = r_interval.u; - - using type = typename result_type< - temp_base_type, - rl.exception() - ? std::numeric_limits::min() - : static_cast(rl), - ru.exception() - ? std::numeric_limits::max() - : static_cast(ru) - >::type; - }; - - /////////////////////////////////////////////////////////////////////// - template - struct subtraction_result { - // result of subtraction are always signed. - using temp_base_type = intmax_t; - - using r_type = checked_result; - using r_interval_type = interval; - - constexpr static const r_interval_type t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type u_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type r_interval = t_interval - u_interval; - - constexpr static auto rl = r_interval.l; - constexpr static auto ru = r_interval.u; - - using type = typename result_type< - temp_base_type, - rl.exception() - ? std::numeric_limits::min() - : static_cast(rl), - ru.exception() - ? std::numeric_limits::max() - : static_cast(ru) - >::type; - }; - - /////////////////////////////////////////////////////////////////////// - template - struct multiplication_result { - using temp_base_type = typename std::conditional< - // if both arguments are unsigned - ! std::numeric_limits::is_signed - && ! std::numeric_limits::is_signed, - // result is unsigned - std::uintmax_t, - // otherwise result is signed - std::intmax_t - >::type; - - using r_type = checked_result; - using r_interval_type = interval; - - constexpr static const r_interval_type t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type u_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type r_interval = t_interval * u_interval; - - constexpr static auto rl = r_interval.l; - constexpr static auto ru = r_interval.u; - - using type = typename result_type< - temp_base_type, - rl.exception() - ? std::numeric_limits::min() - : static_cast(rl), - ru.exception() - ? std::numeric_limits::max() - : static_cast(ru) - >::type; - }; - - /////////////////////////////////////////////////////////////////////// - template - struct division_result { - using temp_base_type = typename std::conditional< - // if both arguments are unsigned - ! std::numeric_limits::is_signed - && ! std::numeric_limits::is_signed, - // result is unsigned - std::uintmax_t, - // otherwise result is signed - std::intmax_t - >::type; - - using r_type = checked_result; - using r_interval_type = interval; - - constexpr static const r_interval_type t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type u_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type rx(){ - if(u_interval.u < r_type(0) - || u_interval.l > r_type(0)) - return t_interval / u_interval; - return utility::minmax( - std::initializer_list { - t_interval.l / u_interval.l, - t_interval.l / r_type(-1), - t_interval.l / r_type(1), - t_interval.l / u_interval.u, - t_interval.u / u_interval.l, - t_interval.u / r_type(-1), - t_interval.u / r_type(1), - t_interval.u / u_interval.u, - } - ); - } - - constexpr static const r_interval_type r_interval = rx(); - - constexpr static auto rl = r_interval.l; - constexpr static auto ru = r_interval.u; - - using type = typename result_type< - temp_base_type, - rl.exception() - ? std::numeric_limits::min() - : static_cast(rl), - ru.exception() - ? std::numeric_limits::max() - : static_cast(ru) - >::type; - }; - - /////////////////////////////////////////////////////////////////////// - template - struct modulus_result { - using temp_base_type = typename std::conditional< - // if both arguments are unsigned - ! std::numeric_limits::is_signed - && ! std::numeric_limits::is_signed, - // result is unsigned - std::uintmax_t, - // otherwise result is signed - std::intmax_t - >::type; - - using r_type = checked_result; - using r_interval_type = interval; - - constexpr static const r_interval_type t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type u_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type rx(){ - if(u_interval.u < r_type(0) - || u_interval.l > r_type(0)) - return t_interval / u_interval; - return utility::minmax( - std::initializer_list { - t_interval.l % u_interval.l, - t_interval.l % r_type(-1), - t_interval.l % r_type(1), - t_interval.l % u_interval.u, - t_interval.u % u_interval.l, - t_interval.u % r_type(-1), - t_interval.u % r_type(1), - t_interval.u % u_interval.u, - } - ); - } - - constexpr static const r_interval_type r_interval = rx(); - - constexpr static auto rl = r_interval.l; - constexpr static auto ru = r_interval.u; - - using type = typename result_type< - temp_base_type, - rl.exception() - ? std::numeric_limits::min() - : static_cast(rl), - ru.exception() - ? std::numeric_limits::max() - : static_cast(ru) - >::type; - }; - - /////////////////////////////////////////////////////////////////////// - // note: comparison_result (<, >, ...) is special. - // The return value is always a bool. The type returned here is - // the intermediate type applied to make the values comparable. - template - struct comparison_result { - using temp_base_type = typename std::conditional< - // if both arguments are unsigned - ! std::numeric_limits::is_signed - && ! std::numeric_limits::is_signed, - // result is unsigned - std::uintmax_t, - // otherwise result is signed - std::intmax_t - >::type; - - using r_type = checked_result; - using r_interval_type = interval; - - constexpr static const r_interval_type t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type u_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - // workaround some microsoft problem - #if 0 - constexpr static r_type min(const r_type & t, const r_type & u){ - // assert(! u.exception()); - // assert(! t.exception()); - return static_cast(t < u) ? t : u; - } - - constexpr static r_type max(const r_type & t, const r_type & u){ - // assert(! u.exception()); - // assert(! t.exception()); - return static_cast(t < u) ? u : t; - } - #endif - - // union of two intervals - // note: we can't use t_interval | u_interval because it - // depends on max and min which in turn depend on < which in turn - // depends on implicit conversion of tribool to bool - constexpr static r_interval_type union_interval( - const r_interval_type & t, - const r_interval_type & u - ){ - //const r_type & rl = min(t.l, u.l); - const r_type & rmin = static_cast(t.l < u.l) ? t.l : u.l; - //const r_type & ru = max(t.u, u.u); - const r_type & rmax = static_cast(t.u < u.u) ? u.u : t.u; - return r_interval_type(rmin, rmax); - } - - constexpr static const r_interval_type r_interval = - union_interval(t_interval, u_interval); - - constexpr static auto rl = r_interval.l; - constexpr static auto ru = r_interval.u; - - using type = typename result_type< - temp_base_type, - rl.exception() - ? std::numeric_limits::min() - : static_cast(rl), - ru.exception() - ? std::numeric_limits::max() - : static_cast(ru) - >::type; - }; - - /////////////////////////////////////////////////////////////////////// - // shift operations - template - struct left_shift_result { - using temp_base_type = typename std::conditional< - std::numeric_limits::is_signed, - std::intmax_t, - std::uintmax_t - >::type; - - using r_type = checked_result; - using r_interval_type = interval; - - constexpr static const r_interval_type t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type u_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type r_interval = - t_interval << u_interval; - - constexpr static auto rl = r_interval.l; - constexpr static auto ru = r_interval.u; - - using type = typename result_type< - temp_base_type, - rl.exception() - ? std::numeric_limits::min() - : static_cast(rl), - ru.exception() - ? std::numeric_limits::max() - : static_cast(ru) - >::type; - }; - - /////////////////////////////////////////////////////////////////////// - template - struct right_shift_result { - using temp_base_type = typename std::conditional< - std::numeric_limits::is_signed, - std::intmax_t, - std::uintmax_t - >::type; - - using r_type = checked_result; - using r_interval_type = interval; - - constexpr static const r_interval_type t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_type u_min - = checked::cast(base_value(std::numeric_limits::min())); - - constexpr static const r_interval_type u_interval{ - u_min.exception() - ? r_type(0) - : u_min, - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr static const r_interval_type r_interval = t_interval >> u_interval; - - constexpr static auto rl = r_interval.l; - constexpr static auto ru = r_interval.u; - - using type = typename result_type< - temp_base_type, - rl.exception() - ? std::numeric_limits::min() - : static_cast(rl), - ru.exception() - ? std::numeric_limits::max() - : static_cast(ru) - >::type; - - }; - - /////////////////////////////////////////////////////////////////////// - template - struct bitwise_and_result { - using type = decltype( - typename base_type::type() - & typename base_type::type() - ); - }; - template - struct bitwise_or_result { - using type = decltype( - typename base_type::type() - | typename base_type::type() - ); - }; - template - struct bitwise_xor_result { - using type = decltype( - typename base_type::type() - ^ typename base_type::type() - ); - }; -}; - -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_AUTOMATIC_HPP diff --git a/boost/safe_numerics/checked_default.hpp b/boost/safe_numerics/checked_default.hpp deleted file mode 100644 index 1b13fa5..0000000 --- a/boost/safe_numerics/checked_default.hpp +++ /dev/null @@ -1,217 +0,0 @@ -#ifndef BOOST_NUMERIC_CHECKED_DEFAULT_HPP -#define BOOST_NUMERIC_CHECKED_DEFAULT_HPP - -// Copyright (c) 2017 Robert Ramey -// -// 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) - -// contains operation implementation of arithmetic operators -// on built-in types. The default implementation is to just -// invoke the operation with no checking. These are overloaded -// for specific types such as integer, etc. - -// implement the equivant of template partial specialization for functions - -// what we need is -// a) a default implementation of add, subtract, etc which just -// implements the standard operations and returns the result -// b) specific implementations to be called from safe implementation -// such as safe ... and someday maybe money ... -// -// What we need is partial function specialization - but this doesn't -// exist in C++ (yet?). But particial specialization of structures DOES -// exist. So put our functions into a class which can then be -// partially specialized. Finally. add a function interface to so that -// data types can be deduced from the function call. We now have -// the equivalent of partial function template specialization. - -// usage example: checked::add(t, u) ... - -#include -#include "checked_result.hpp" - -namespace boost { -namespace safe_numerics { - -// main function object which contains functions which handle -// primitives which haven't been overriden. For now, these -// implement the default operation. But I see this as an indicator -// that there is more work to be done. For example float * int should -// never be called because promotions on operands should occur before -// the operation is invoked. So rather than returning the default operation -// it should trap with a static_assert. This occurs at compile time while -// calculating result interval. This needs more investigation. - -template< - typename R, - R Min, - R Max, - typename T, - class F = make_checked_result, - class Default = void -> -struct heterogeneous_checked_operation { - constexpr static checked_result - cast(const T & t) /* noexcept */ { - return static_cast(t); - } -}; - -template< - typename R, - class F = make_checked_result, - class Default = void -> -struct checked_operation{ - constexpr static checked_result - minus(const R & t) noexcept { - return - t; - } - constexpr static checked_result - add(const R & t, const R & u) noexcept { - return t + u; - } - constexpr static checked_result - subtract(const R & t, const R & u) noexcept { - return t - u; - } - constexpr static checked_result - multiply(const R & t, const R & u) noexcept { - return t * u; - } - constexpr static checked_result - divide(const R & t, const R & u) noexcept { - return t / u; - } - constexpr static checked_result - modulus(const R & t, const R & u) noexcept { - return t % u; - } - constexpr static boost::logic::tribool - less_than(const R & t, const R & u) noexcept { - return t < u; - } - constexpr static boost::logic::tribool - greater_than(const R & t, const R & u) noexcept { - return t > u; - } - constexpr static boost::logic::tribool - equal(const R & t, const R & u) noexcept { - return t < u; - } - constexpr static checked_result - left_shift(const R & t, const R & u) noexcept { - return t << u; - } - constexpr static checked_result - right_shift(const R & t, const R & u) noexcept { - return t >> u; - } - constexpr static checked_result - bitwise_or(const R & t, const R & u) noexcept { - return t | u; - } - constexpr static checked_result - bitwise_xor(const R & t, const R & u) noexcept { - return t ^ u; - } - constexpr static checked_result - bitwise_and(const R & t, const R & u) noexcept { - return t & u; - } - constexpr static checked_result - bitwise_not(const R & t) noexcept { - return ~t; - } -}; - -namespace checked { - -// implement function call interface so that types other than -// the result type R can be deduced from the function parameters. - -template -constexpr checked_result cast(const T & t) /* noexcept */ { - return heterogeneous_checked_operation< - R, - std::numeric_limits::min(), - std::numeric_limits::max(), - T - >::cast(t); -} -template -constexpr checked_result minus(const R & t) noexcept { - return checked_operation::minus(t); -} -template -constexpr checked_result add(const R & t, const R & u) noexcept { - return checked_operation::add(t, u); -} -template -constexpr checked_result subtract(const R & t, const R & u) noexcept { - return checked_operation::subtract(t, u); -} -template -constexpr checked_result multiply(const R & t, const R & u) noexcept { - return checked_operation::multiply(t, u); -} -template -constexpr checked_result divide(const R & t, const R & u) noexcept { - return checked_operation::divide(t, u); -} -template -constexpr checked_result modulus(const R & t, const R & u) noexcept { - return checked_operation::modulus(t, u); -} -template -constexpr checked_result less_than(const R & t, const R & u) noexcept { - return checked_operation::less_than(t, u); -} -template -constexpr checked_result greater_than_equal(const R & t, const R & u) noexcept { - return ! checked_operation::less_than(t, u); -} -template -constexpr checked_result greater_than(const R & t, const R & u) noexcept { - return checked_operation::greater_than(t, u); -} -template -constexpr checked_result less_than_equal(const R & t, const R & u) noexcept { - return ! checked_operation::greater_than(t, u); -} -template -constexpr checked_result equal(const R & t, const R & u) noexcept { - return checked_operation::equal(t, u); -} -template -constexpr checked_result left_shift(const R & t, const R & u) noexcept { - return checked_operation::left_shift(t, u); -} -template -constexpr checked_result right_shift(const R & t, const R & u) noexcept { - return checked_operation::right_shift(t, u); -} -template -constexpr checked_result bitwise_or(const R & t, const R & u) noexcept { - return checked_operation::bitwise_or(t, u); -} -template -constexpr checked_result bitwise_xor(const R & t, const R & u) noexcept { - return checked_operation::bitwise_xor(t, u); -} -template -constexpr checked_result bitwise_and(const R & t, const R & u) noexcept { - return checked_operation::bitwise_and(t, u); -} -template -constexpr checked_result bitwise_not(const R & t) noexcept { - return checked_operation::bitwise_not(t); -} - -} // checked -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_CHECKED_DEFAULT_HPP diff --git a/boost/safe_numerics/checked_float.hpp b/boost/safe_numerics/checked_float.hpp deleted file mode 100644 index bbd7d86..0000000 --- a/boost/safe_numerics/checked_float.hpp +++ /dev/null @@ -1,214 +0,0 @@ -#ifndef BOOST_NUMERIC_CHECKED_FLOAT_HPP -#define BOOST_NUMERIC_CHECKED_FLOAT_HPP - -// Copyright (c) 2017 Robert Ramey -// -// 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) - -// contains operation implementation of arithmetic operators -// on built-in floating point types. The default implementation is to just -// invoke the operation with no checking. These are overloaded -// for specific types such as integer, etc. - -#include // std::is_floating_point, make_unsigned - -namespace boost { -namespace safe_numerics { -namespace checked { - -//////////////////////////////////////////////////// -// layer 0 - implement safe operations for floating - -template< - typename R, - R Min, - R Max, - typename T, - class F -> -struct heterogeneous_checked_operation< - R, - Min, - Max, - T, - F, - typename std::enable_if< - std::is_floating_point::value - && std::is_floating_point::value - >::type ->{ - constexpr static checked_result - cast(const T & t) noexcept { - return t; - }; -}; // checked_unary_operation - -template< - typename R, - R Min, - R Max, - typename T, - class - F -> -struct heterogeneous_checked_operation< - R, - Min, - Max, - T, - F, - typename std::enable_if< - std::is_floating_point::value - && std::is_integralt::value - >::type ->{ - constexpr static checked_result - cast(const T & t) noexcept { - return t; - }; -}; // checked_unary_operation - -template -struct checked_operation::value - >::type ->{ - constexpr static checked_result cast(const T & t) { - return - cast_impl_detail::cast_impl( - t, - std::is_signed(), - std::is_signed() - ); - } - constexpr static checked_result add(const T & t, const U & u) { - return t + u; - } - - constexpr static checked_result subtract( - const T & t, - const U & u - ) { - return t - u; - } - - constexpr static checked_result multiply( - const T & t, - const U & u - ) noexcept { - return t * u; - } - - constexpr static checked_result divide( - const T & t, - const U & u - ) noexcept { - return t / u; - } - - constexpr static checked_result modulus( - const T & t, - const U & u - ) noexcept { - return t % u; - } - - constexpr static bool less_than(const T & t, const U & u) noexcept { - return t < u; - } - - constexpr static bool greater_than(const T & t, const U & u) noexcept { - return t > u; - } - - constexpr static bool equal(const T & t, const U & u) noexcept { - return t < u; - } - -}; // checked_binary_operation -template -typename std::enable_if< - std::is_floating_point::value - && std::is_floating_point::value - && std::is_floating_point::value, - checked_result ->::type -constexpr bool less_than(const T & t, const U & u) noexcept { - return t < u; -} - -template -typename std::enable_if< - std::is_floating_point::value - && std::is_floating_point::value - && std::is_floating_point::value, - checked_result ->::type -constexpr bool equal(const T & t, const U & u) noexcept { - return t < u; -} - -template -typename std::enable_if< - std::is_floating_point::value - && std::is_floating_point::value - && std::is_floating_point::value, - checked_result ->::type -constexpr checked_result left_shift(const T & t, const U & u) noexcept { - return t << u; -} - -template -typename std::enable_if< - std::is_floating_point::value - && std::is_floating_point::value - && std::is_floating_point::value, - checked_result ->::type -constexpr checked_result right_shift(const T & t, const U & u) noexcept { - return t >> u; -} - -template -typename std::enable_if< - std::is_floating_point::value - && std::is_floating_point::value - && std::is_floating_point::value, - checked_result ->::type -constexpr checked_result bitwise_or(const T & t, const U & u) noexcept { - return t | u; -} - -template -typename std::enable_if< - std::is_floating_point::value - && std::is_floating_point::value - && std::is_floating_point::value, - checked_result ->::type -constexpr checked_result bitwise_xor(const T & t, const U & u) noexcept { - return t ^ u; -} - -template -typename std::enable_if< - std::is_floating_point::value - && std::is_floating_point::value - && std::is_floating_point::value, - checked_result ->::type -constexpr checked_result bitwise_and(const T & t, const U & u) noexcept { - return t & u; -} - -} // checked -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_CHECKED_DEFAULT_HPP - diff --git a/boost/safe_numerics/checked_integer.hpp b/boost/safe_numerics/checked_integer.hpp deleted file mode 100644 index c6e0790..0000000 --- a/boost/safe_numerics/checked_integer.hpp +++ /dev/null @@ -1,819 +0,0 @@ -#ifndef BOOST_NUMERIC_CHECKED_INTEGER_HPP -#define BOOST_NUMERIC_CHECKED_INTEGER_HPP - -// Copyright (c) 2012 Robert Ramey -// -// 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) - -// contains operations for doing checked aritmetic on NATIVE -// C++ types. - -#include -#include // is_integral, make_unsigned, enable_if -#include // std::max - -#include "checked_result.hpp" -#include "checked_default.hpp" -#include "safe_compare.hpp" -#include "utility.hpp" -#include "exception.hpp" - -namespace boost { -namespace safe_numerics { - -// utility - -template -using bool_type = typename std::conditional::type; - -//////////////////////////////////////////////////// -// layer 0 - implement safe operations for intrinsic integers -// Note presumption of twos complement integer arithmetic - -// convert an integral value to some other integral type -template< - typename R, - R Min, - R Max, - typename T, - class F -> -struct heterogeneous_checked_operation< - R, - Min, - Max, - T, - F, - typename std::enable_if< - std::is_integral::value - && std::is_integral::value - >::type ->{ - //////////////////////////////////////////////////// - // safe casting on primitive types - - struct cast_impl_detail { - constexpr static checked_result - cast_impl( - const T & t, - std::true_type, // R is signed - std::true_type // T is signed - ){ - // INT32-C Ensure that operations on signed - // integers do not overflow - return - boost::safe_numerics::safe_compare::greater_than( - t, - Max - ) ? - F::template invoke( - "converted signed value too large" - ) - : - boost::safe_numerics::safe_compare::less_than( - t, - Min - ) ? - F::template invoke( - "converted signed value too small" - ) - : - checked_result(static_cast(t)) - ; - } - constexpr static checked_result - cast_impl( - const T & t, - std::true_type, // R is signed - std::false_type // T is unsigned - ){ - // INT30-C Ensure that unsigned integer operations - // do not wrap - return - boost::safe_numerics::safe_compare::greater_than( - t, - Max - ) ? - F::template invoke( - "converted unsigned value too large" - ) - : - checked_result(static_cast(t)) - ; - } - constexpr static checked_result - cast_impl( - const T & t, - std::false_type, // R is unsigned - std::false_type // T is unsigned - ){ - // INT32-C Ensure that operations on unsigned - // integers do not overflow - return - boost::safe_numerics::safe_compare::greater_than( - t, - Max - ) ? - F::template invoke( - "converted unsigned value too large" - ) - : - checked_result(static_cast(t)) - ; - } - constexpr static checked_result - cast_impl( - const T & t, - std::false_type, // R is unsigned - std::true_type // T is signed - ){ - return - boost::safe_numerics::safe_compare::less_than(t, 0) ? - F::template invoke( - "converted negative value to unsigned" - ) - : - boost::safe_numerics::safe_compare::greater_than( - t, - Max - ) ? - F::template invoke( - "converted signed value too large" - ) - : - checked_result(static_cast(t)) - ; - } - }; // cast_impl_detail - - constexpr static checked_result - cast(const T & t){ - return - cast_impl_detail::cast_impl( - t, - std::is_signed(), - std::is_signed() - ); - } -}; - -// converting floating point value to integral type -template< - typename R, - R Min, - R Max, - typename T, - class F -> -struct heterogeneous_checked_operation< - R, - Min, - Max, - T, - F, - typename std::enable_if< - std::is_integral::value - && std::is_floating_point::value - >::type ->{ - constexpr static checked_result - cast(const T & t){ - return static_cast(t); - } -}; - -// converting integral value to floating point type - -// INT35-C. Use correct integer precisions -template< - typename R, - R Min, - R Max, - typename T, - class F -> -struct heterogeneous_checked_operation< - R, - Min, - Max, - T, - F, - typename std::enable_if< - std::is_floating_point::value - && std::is_integral::value - >::type - >{ - constexpr static checked_result - cast(const T & t){ - if(std::numeric_limits::digits < std::numeric_limits::digits){ - if(utility::significant_bits(t) > std::numeric_limits::digits){ - return F::invoke( - safe_numerics_error::precision_overflow_error, - "keep precision" - ); - } - } - return t; - } -}; - -// binary operations on primitive integer types - -template< - typename R, - class F -> -struct checked_operation::value - >::type ->{ - //////////////////////////////////////////////////// - // safe addition on primitive types - - struct add_impl_detail { - // result unsigned - constexpr static checked_result add( - const R t, - const R u, - std::false_type // R unsigned - ){ - return - // INT30-C. Ensure that unsigned integer operations do not wrap - std::numeric_limits::max() - u < t ? - F::template invoke( - "addition result too large" - ) - : - checked_result(t + u) - ; - } - - // result signed - constexpr static checked_result add( - const R t, - const R u, - std::true_type // R signed - ){ - // INT32-C. Ensure that operations on signed integers do not result in overflow - return - // INT32-C. Ensure that operations on signed integers do not result in overflow - ((u > 0) && (t > (std::numeric_limits::max() - u))) ? - F::template invoke( - "addition result too large" - ) - : - ((u < 0) && (t < (std::numeric_limits::min() - u))) ? - F::template invoke( - "addition result too low" - ) - : - checked_result(t + u) - ; - } - }; // add_impl_detail - - constexpr static checked_result - add(const R & t, const R & u){ - return add_impl_detail::add(t, u, std::is_signed()); - } - - //////////////////////////////////////////////////// - // safe subtraction on primitive types - struct subtract_impl_detail { - - // result unsigned - constexpr static checked_result subtract( - const R t, - const R u, - std::false_type // R is unsigned - ){ - // INT30-C. Ensure that unsigned integer operations do not wrap - return - t < u ? - F::template invoke( - "subtraction result cannot be negative" - ) - : - checked_result(t - u) - ; - } - - // result signed - constexpr static checked_result subtract( - const R t, - const R u, - std::true_type // R is signed - ){ // INT32-C - return - // INT32-C. Ensure that operations on signed integers do not result in overflow - ((u > 0) && (t < (std::numeric_limits::min() + u))) ? - F::template invoke( - "subtraction result overflows result type" - ) - : - ((u < 0) && (t > (std::numeric_limits::max() + u))) ? - F::template invoke( - "subtraction result overflows result type" - ) - : - checked_result(t - u) - ; - } - - }; // subtract_impl_detail - - constexpr static checked_result subtract(const R & t, const R & u){ - return subtract_impl_detail::subtract(t, u, std::is_signed()); - } - - //////////////////////////////////////////////////// - // safe minus on primitive types - struct minus_impl_detail { - - // result unsigned - constexpr static checked_result minus( - const R t, - std::false_type // R is unsigned - ){ - return t > 0 ? - F::template invoke( - "minus unsigned would be negative" - ) - : - // t == 0 - checked_result(0) - ; - } - - // result signed - constexpr static checked_result minus( - const R t, - std::true_type // R is signed - ){ // INT32-C - return t == std::numeric_limits::min() ? - F::template invoke( - "subtraction result overflows result type" - ) - : - checked_result(-t) - ; - } - - }; // minus_impl_detail - - constexpr static checked_result minus(const R & t){ - return minus_impl_detail::minus(t, std::is_signed()); - } - - //////////////////////////////////////////////////// - // safe multiplication on primitive types - - struct multiply_impl_detail { - - // result unsigned - constexpr static checked_result multiply( - const R t, - const R u, - std::false_type, // R is unsigned - std::false_type // !(sizeochecked_resultR) > sizeochecked_resultstd::uintmax_t) / 2) - - ){ - // INT30-C - // fast method using intermediate result guaranteed not to overflow - // todo - replace std::uintmax_t with a size double the size of R - using i_type = std::uintmax_t; - return - static_cast(t) * static_cast(u) - > std::numeric_limits::max() ? - F::template invoke( - "multiplication overflow" - ) - : - checked_result(t * u) - ; - } - constexpr static checked_result multiply( - const R t, - const R u, - std::false_type, // R is unsigned - std::true_type // (sizeochecked_resultR) > sizeochecked_resultstd::uintmax_t) / 2) - - ){ - // INT30-C - return - u > 0 && t > std::numeric_limits::max() / u ? - F::template invoke( - "multiplication overflow" - ) - : - checked_result(t * u) - ; - } - - // result signed - constexpr static checked_result multiply( - const R t, - const R u, - std::true_type, // R is signed - std::false_type // ! (sizeochecked_resultR) > (sizeochecked_resultstd::intmax_t) / 2)) - - ){ - // INT30-C - // fast method using intermediate result guaranteed not to overflow - // todo - replace std::intmax_t with a size double the size of R - using i_type = std::intmax_t; - return - ( - static_cast(t) * static_cast(u) - > static_cast(std::numeric_limits::max()) - ) ? - F::template invoke( - "multiplication overflow" - ) - : - ( - static_cast(t) * static_cast(u) - < static_cast(std::numeric_limits::min()) - ) ? - F::template invoke( - "multiplication overflow" - ) - : - checked_result(t * u) - ; - } - constexpr static checked_result multiply( - const R t, - const R u, - std::true_type, // R is signed - std::true_type // (sizeochecked_resultR) > (sizeochecked_resultstd::intmax_t) / 2)) - ){ // INT32-C - return t > 0 ? - u > 0 ? - t > std::numeric_limits::max() / u ? - F::template invoke( - "multiplication overflow" - ) - : - checked_result(t * u) - : // u <= 0 - u < std::numeric_limits::min() / t ? - F::template invoke( - "multiplication overflow" - ) - : - checked_result(t * u) - : // t <= 0 - u > 0 ? - t < std::numeric_limits::min() / u ? - F::template invoke( - "multiplication overflow" - ) - : - checked_result(t * u) - : // u <= 0 - t != 0 && u < std::numeric_limits::max() / t ? - F::template invoke( - "multiplication overflow" - ) - : - checked_result(t * u) - ; - } - }; // multiply_impl_detail - - constexpr static checked_result multiply(const R & t, const R & u){ - return multiply_impl_detail::multiply( - t, - u, - std::is_signed(), - std::integral_constant< - bool, - (sizeof(R) > sizeof(std::uintmax_t) / 2) - >() - ); - } - - //////////////////////////////// - // safe division on unsafe types - - struct divide_impl_detail { - constexpr static checked_result divide( - const R & t, - const R & u, - std::false_type // R is unsigned - ){ - return t / u; - } - - constexpr static checked_result divide( - const R & t, - const R & u, - std::true_type // R is signed - ){ - return - (u == -1 && t == std::numeric_limits::min()) ? - F::template invoke( - "result cannot be represented" - ) - : - checked_result(t / u) - ; - } - }; // divide_impl_detail - - // note that we presume that the size of R >= size of T - constexpr static checked_result divide(const R & t, const R & u){ - if(u == 0){ - return F::template invoke( - "divide by zero" - ); - } - return divide_impl_detail::divide(t, u, std::is_signed()); - } - - //////////////////////////////// - // safe modulus on unsafe types - - struct modulus_impl_detail { - constexpr static checked_result modulus( - const R & t, - const R & u, - std::false_type // R is unsigned - ){ - return t % u; - } - - constexpr static checked_result modulus( - const R & t, - const R & u, - std::true_type // R is signed - ){ - if(u >= 0) - return t % u; - checked_result ux = checked::minus(u); - if(ux.exception()) - return t; - return t % static_cast(ux); - } - }; // modulus_impl_detail - - constexpr static checked_result modulus(const R & t, const R & u){ - if(0 == u) - return F::template invoke( - "denominator is zero" - ); - - // why to we need abs here? the sign of the modulus is the sign of the - // dividend. Consider -128 % -1 The result of this operation should be -1 - // but if I use t % u the x86 hardware uses the divide instruction - // capturing the modulus as a side effect. When it does this, it - // invokes the operation -128 / -1 -> 128 which overflows a signed type - // and provokes a hardware exception. We can fix this using abs() - // since -128 % -1 = -128 % 1 = 0 - return modulus_impl_detail::modulus(t, u, typename std::is_signed::type()); - } - - /////////////////////////////////// - // shift operations - - struct left_shift_integer_detail { - - #if 0 - // todo - optimize for gcc to exploit builtin - /* for gcc compilers - int __builtin_clz (unsigned int x) - Returns the number of leading 0-bits in x, starting at the - most significant bit position. If x is 0, the result is undefined. - */ - - #ifndef __has_feature // Optional of course. - #define __has_feature(x) 0 // Compatibility with non-clang compilers. - #endif - - template - constexpr unsigned int leading_zeros(const T & t){ - if(0 == t) - return 0; - #if __has_feature(builtin_clz) - return __builtin_clz(t); - #else - #endif - } - #endif - - // INT34-C C++ - - // standard paragraph 5.8 / 2 - // The value of E1 << E2 is E1 left-shifted E2 bit positions; - // vacated bits are zero-filled. - constexpr static checked_result left_shift( - const R & t, - const R & u, - std::false_type // R is unsigned - ){ - // the value of the result is E1 x 2^E2, reduced modulo one more than - // the maximum value representable in the result type. - - // see 5.8 & 1 - // if right operand is - // greater than or equal to the length in bits of the promoted left operand. - if( - safe_compare::greater_than( - u, - std::numeric_limits::digits - utility::significant_bits(t) - ) - ){ - // behavior is undefined - return F::template invoke( - "shifting left more bits than available is undefined behavior" - ); - } - return t << u; - } - - constexpr static checked_result left_shift( - const R & t, - const R & u, - std::true_type // R is signed - ){ - // and [E1] has a non-negative value - if(t >= 0){ - // and E1 x 2^E2 is representable in the corresponding - // unsigned type of the result type, - - // see 5.8 & 1 - // if right operand is - // greater than or equal to the length in bits of the promoted left operand. - if( - safe_compare::greater_than( - u, - std::numeric_limits::digits - utility::significant_bits(t) - ) - ){ - // behavior is undefined - return F::template invoke( - "shifting left more bits than available" - ); - } - else{ - return t << u; - } - } - // otherwise, the behavior is undefined. - return F::template invoke( - "shifting a negative value" - ); - } - - }; // left_shift_integer_detail - - constexpr static checked_result left_shift( - const R & t, - const R & u - ){ - // INT34-C - Do not shift an expression by a negative number of bits - - // standard paragraph 5.8 & 1 - // if the right operand is negative - if(u == 0){ - return t; - } - if(u < 0){ - return F::template invoke( - "shifting negative amount" - ); - } - if(u > std::numeric_limits::digits){ - // behavior is undefined - return F::template invoke( - "shifting more bits than available" - ); - } - return left_shift_integer_detail::left_shift(t, u, std::is_signed()); - } - -// right shift - - struct right_shift_integer_detail { - - // INT34-C C++ - - // standard paragraph 5.8 / 3 - // The value of E1 << E2 is E1 left-shifted E2 bit positions; - // vacated bits are zero-filled. - constexpr static checked_result right_shift( - const R & t, - const R & u, - std::false_type // T is unsigned - ){ - // the value of the result is the integral part of the - // quotient of E1/2E2 - return t >> u; - } - - constexpr static checked_result right_shift( - const R & t, - const R & u, - std::true_type // T is signed; - ){ - if(t < 0){ - // note that the C++ standard considers this case is "implemenation - // defined" rather than "undefined". - return F::template invoke( - "shifting a negative value" - ); - } - - // the value is the integral part of E1 / 2^E2, - return t >> u; - } - }; // right_shift_integer_detail - -constexpr static checked_result right_shift( - const R & t, - const R & u -){ - // INT34-C - Do not shift an expression by a negative number of bits - - // standard paragraph 5.8 & 1 - // if the right operand is negative - if(u < 0){ - return F::template invoke( - "shifting negative amount" - ); - } - if(u > std::numeric_limits::digits){ - // behavior is undefined - return F::template invoke( - "shifting more bits than available" - ); - } - return right_shift_integer_detail::right_shift(t, u ,std::is_signed()); -} - -/////////////////////////////////// -// bitwise operations - -// INT13-C Note: We don't enforce recommendation as acually written -// as it would break too many programs. Specifically, we permit signed -// integer operands. - -constexpr static checked_result bitwise_or(const R & t, const R & u){ - using namespace boost::safe_numerics::utility; - const unsigned int result_size - = std::max(significant_bits(t), significant_bits(u)); - - if(result_size > bits_type::value){ - return F::template invoke( - "result type too small to hold bitwise or" - ); - } - return t | u; -} - -constexpr static checked_result bitwise_xor(const R & t, const R & u){ - using namespace boost::safe_numerics::utility; - const unsigned int result_size - = std::max(significant_bits(t), significant_bits(u)); - - if(result_size > bits_type::value){ - return F::template invoke( - "result type too small to hold bitwise or" - ); - } - return t ^ u; -} - -constexpr static checked_result bitwise_and(const R & t, const R & u){ - using namespace boost::safe_numerics::utility; - const unsigned int result_size - = std::min(significant_bits(t), significant_bits(u)); - - if(result_size > bits_type::value){ - return F::template invoke( - "result type too small to hold bitwise and" - ); - } - return t & u; -} - -constexpr static checked_result bitwise_not(const R & t){ - using namespace boost::safe_numerics::utility; - - if(significant_bits(t) > bits_type::value){ - return F::template invoke( - "result type too small to hold bitwise inverse" - ); - } - return ~t; -} - -}; // checked_operation -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_CHECKED_INTEGER_HPP diff --git a/boost/safe_numerics/checked_result.hpp b/boost/safe_numerics/checked_result.hpp deleted file mode 100644 index 10bd7a6..0000000 --- a/boost/safe_numerics/checked_result.hpp +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef BOOST_NUMERIC_CHECKED_RESULT -#define BOOST_NUMERIC_CHECKED_RESULT - -// Copyright (c) 2012 Robert Ramey -// -// 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) - -// contains operations for doing checked aritmetic on NATIVE -// C++ types. -#include -#include // is_convertible -#include "exception.hpp" - -namespace boost { -namespace safe_numerics { - -template -struct checked_result { - const safe_numerics_error m_e; - const union { - R m_r; - char const * m_msg; - }; - - // don't permit construction without initial value; - checked_result() = delete; - - // note: I implemented the following non-default copy and move - // constructors because I thought I needed to do this in order - // to make them constexpr. Turns out though that doing this creates - // a syntax error because the assignment results in error due - // to assignment "outside of object lifetime". I think this could - // be addressed by replacing the anonymous union above with a - // named union. This would create some syntax changes which would - // ripple through some parts of th program. So for now, we'll just - // rely on the default copy and move constructors. - #if 0 - // copy constructor - constexpr /*explicit*/ checked_result(const checked_result & r) noexpect : - m_e(r.m_e) - { - if(safe_numerics_error::success == r.m_e) - m_r = r.m_r; - else - m_msg = r.m_msg; - } - - // move constructor - constexpr /*explicit*/ checked_result(checked_result && r) noexcept : - m_e(r.m_e) - { - if(safe_numerics_error::success == r.m_e) - m_r = r.m_r; - else - m_msg = r.m_msg; - } - #endif - checked_result(const checked_result & r) = default; - checked_result(checked_result && r) = default; - - constexpr /*explicit*/ checked_result(const R & r) : - m_e(safe_numerics_error::success), - m_r(r) - {} - #if 0 - template - constexpr /*explicit*/ checked_result(const T & t) noexcept : - m_e(safe_numerics_error::success), - m_r(t) - {} - #endif - constexpr /*explicit*/ checked_result( - const safe_numerics_error & e, - const char * msg = "" - ) noexcept : - m_e(e), - m_msg(msg) - { - assert(m_e != safe_numerics_error::success); - } - // permit construct from another checked result type - template - constexpr /*explicit*/ checked_result(const checked_result & t) noexcept : - m_e(t.m_e) - { - static_assert( - std::is_convertible::value, - "T must be convertible to R" - ); - if(safe_numerics_error::success == t.m_e) - m_r = t.m_r; - else - m_msg = t.m_msg; - } - constexpr bool exception() const { - return m_e != safe_numerics_error::success; - } - - // accesors - constexpr operator R() const noexcept{ - // don't assert here. Let the library catch these errors - assert(! exception()); - return m_r; - } - - constexpr operator safe_numerics_error () const noexcept{ - // note that this is a legitimate operation even when - // the operation was successful - it will return success - return m_e; - } - constexpr operator const char *() const noexcept{ - assert(exception()); - return m_msg; - } - - // disallow assignment - checked_result & operator=(const checked_result &) = delete; -}; - -#if 0 -template -constexpr checked_result make_checked_result( - const safe_numerics_error & e, - char const * const & m -) noexcept { - return checked_result(e, m); -} -#endif - -template -class make_checked_result { -public: - template - constexpr static checked_result invoke( - char const * const & m - ) noexcept { - return checked_result(E, m); - } -}; - -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_CHECKED_RESULT diff --git a/boost/safe_numerics/checked_result_operations.hpp b/boost/safe_numerics/checked_result_operations.hpp deleted file mode 100644 index 0492cab..0000000 --- a/boost/safe_numerics/checked_result_operations.hpp +++ /dev/null @@ -1,1217 +0,0 @@ -#ifndef BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS -#define BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS - -// Copyright (c) 2012 Robert Ramey -// -// 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) - -// Implemenation of arithmetic on "extended" integers. -// Extended integers are defined in terms of C++ primitive integers as -// a) an interger range -// b) extra elements +inf, -inf, indeterminate -// -// Integer operations are closed on the set of extended integers -// but operations are not necessarily associative when they result in the -// extensions +inf, -inf, and indeterminate -// -// in this code, the type "checked_result" where T is some -// integer type is an "extended" integer. - -#include - -#include - -#include "checked_result.hpp" -#include "checked_integer.hpp" - -////////////////////////////////////////////////////////////////////////// -// the following idea of "value_type" is used by several of the operations -// defined by checked_result arithmetic. - -namespace boost { -namespace safe_numerics { - -template -constexpr void display(const boost::safe_numerics::checked_result & c){ - switch(c.m_e){ - case safe_numerics_error::success: - std::terminate(); - case safe_numerics_error::positive_overflow_error: // result is above representational maximum - std::terminate(); - case safe_numerics_error::negative_overflow_error: // result is below representational minimum - std::terminate(); - case safe_numerics_error::domain_error: // one operand is out of valid range - std::terminate(); - case safe_numerics_error::range_error: // result cannot be produced for this operation - std::terminate(); - case safe_numerics_error::precision_overflow_error: // result lost precision - std::terminate(); - case safe_numerics_error::underflow_error: // result is too small to be represented - std::terminate(); - case safe_numerics_error::negative_value_shift: // negative value in shift operator - std::terminate(); - case safe_numerics_error::negative_shift: // shift a negative value - std::terminate(); - case safe_numerics_error::shift_too_large: // l/r shift exceeds variable size - std::terminate(); - case safe_numerics_error::uninitialized_value: // creating of uninitialized value - std::terminate(); - } -} - -////////////////////////////////////////////////////////////////////////// -// implement C++ operators for check_result - -struct sum_value_type { - // characterization of various values - const enum flag { - known_value = 0, - less_than_min, - greater_than_max, - indeterminate, - count - } m_flag; - template - constexpr flag to_flag(const checked_result & t) const { - switch(static_cast(t)){ - case safe_numerics_error::success: - return known_value; - case safe_numerics_error::negative_overflow_error: - // result is below representational minimum - return less_than_min; - case safe_numerics_error::positive_overflow_error: - // result is above representational maximum - return greater_than_max; - default: - return indeterminate; - } - } - template - constexpr sum_value_type(const checked_result & t) : - m_flag(to_flag(t)) - {} - constexpr operator std::uint8_t () const { - return static_cast(m_flag); - } -}; - -// integers addition -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator+( - const checked_result & t, - const checked_result & u -){ - using value_type = sum_value_type; - const std::uint8_t order = static_cast(value_type::count); - - // note major pain. Clang constexpr multi-dimensional array is fine. - // but gcc doesn't permit a multi-dimensional array to be be constexpr. - // so we need to some ugly gymnastics to make our system work for all - // all systems. - const enum safe_numerics_error result[order * order] = { - // t == known_value - //{ - // u == ... - safe_numerics_error::success, // known_value, - safe_numerics_error::negative_overflow_error, // less_than_min, - safe_numerics_error::positive_overflow_error, // greater_than_max, - safe_numerics_error::range_error, // indeterminate, - //}, - // t == less_than_min, - //{ - // u == ... - safe_numerics_error::negative_overflow_error, // known_value, - safe_numerics_error::negative_overflow_error, // less_than_min, - safe_numerics_error::range_error, // greater_than_max, - safe_numerics_error::range_error, // indeterminate, - //}, - // t == greater_than_max, - //{ - // u == ... - safe_numerics_error::positive_overflow_error, // known_value, - safe_numerics_error::range_error, // less_than_min, - safe_numerics_error::positive_overflow_error, // greater_than_max, - safe_numerics_error::range_error, // indeterminate, - //}, - // t == indeterminate, - //{ - // u == ... - safe_numerics_error::range_error, // known_value, - safe_numerics_error::range_error, // less_than_min, - safe_numerics_error::range_error, // greater_than_max, - safe_numerics_error::range_error, // indeterminate, - //}, - }; - - const value_type tx(t); - const value_type ux(u); - - const safe_numerics_error e = result[tx * order + ux]; - if(safe_numerics_error::success == e) - return checked::add(t, u); - return checked_result(e, "addition result"); -} - -// unary + -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator+( - const checked_result & t -){ - return t; -} - -// integers subtraction -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator-( - const checked_result & t, - const checked_result & u -){ - using value_type = sum_value_type; - constexpr const std::uint8_t order = static_cast(value_type::count); - - constexpr const enum safe_numerics_error result[order * order] = { - // t == known_value - //{ - // u == ... - safe_numerics_error::success, // known_value, - safe_numerics_error::positive_overflow_error, // less_than_min, - safe_numerics_error::negative_overflow_error, // greater_than_max, - safe_numerics_error::range_error, // indeterminate, - //}, - // t == less_than_min, - //{ - // u == ... - safe_numerics_error::negative_overflow_error, // known_value, - safe_numerics_error::range_error, // less_than_min, - safe_numerics_error::negative_overflow_error, // greater_than_max, - safe_numerics_error::range_error, // indeterminate, - //}, - // t == greater_than_max, - //{ - // u == ... - safe_numerics_error::positive_overflow_error, // known_value, - safe_numerics_error::positive_overflow_error, // less_than_min, - safe_numerics_error::range_error, // greater_than_max, - safe_numerics_error::range_error, // indeterminate, - //}, - // t == indeterminate, - //{ - // u == ... - safe_numerics_error::range_error, // known_value, - safe_numerics_error::range_error, // less_than_min, - safe_numerics_error::range_error, // greater_than_max, - safe_numerics_error::range_error, // indeterminate, - //}, - }; - - const value_type tx(t); - const value_type ux(u); - - const safe_numerics_error e = result[tx * order + ux]; - if(safe_numerics_error::success == e) - return checked::subtract(t, u); - return checked_result(e, "subtraction result"); -} - -// unary - -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator-( - const checked_result & t -){ -// assert(false); - return checked_result(0) - t; -} - -struct product_value_type { - // characterization of various values - const enum flag { - less_than_min = 0, - less_than_zero, - zero, - greater_than_zero, - greater_than_max, - indeterminate, - // count of number of cases for values - count, - // temporary values for special cases - t_value, - u_value, - z_value - } m_flag; - template - constexpr flag to_flag(const checked_result & t) const { - switch(static_cast(t)){ - case safe_numerics_error::success: - return (t < checked_result(0)) - ? less_than_zero - : (t > checked_result(0)) - ? greater_than_zero - : zero; - case safe_numerics_error::negative_overflow_error: - // result is below representational minimum - return less_than_min; - case safe_numerics_error::positive_overflow_error: - // result is above representational maximum - return greater_than_max; - default: - return indeterminate; - } - } - template - constexpr product_value_type(const checked_result & t) : - m_flag(to_flag(t)) - {} - constexpr operator std::uint8_t () const { - return static_cast(m_flag); - } -}; - -// integers multiplication -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator*( - const checked_result & t, - const checked_result & u -){ - using value_type = product_value_type; - const std::uint8_t order = static_cast(value_type::count); - - constexpr const enum value_type::flag result[order * order] = { - // t == less_than_min - //{ - // u == ... - value_type::greater_than_max, // less_than_min, - value_type::greater_than_max, // less_than_zero, - value_type::zero, // zero, - value_type::less_than_min, // greater_than_zero, - value_type::less_than_min, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == less_than_zero, - //{ - // u == ... - value_type::greater_than_max, // less_than_min, - value_type::greater_than_zero, // less_than_zero, - value_type::zero, // zero, - value_type::less_than_zero, // greater_than_zero, - value_type::less_than_min, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == zero, - //{ - // u == ... - value_type::zero, // less_than_min, - value_type::zero, // less_than_zero, - value_type::zero, // zero, - value_type::zero, // greater_than_zero, - value_type::zero, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == greater_than_zero, - //{ - // u == ... - value_type::less_than_min, // less_than_min, - value_type::less_than_zero, // less_than_zero, - value_type::zero, // zero, - value_type::greater_than_zero, // greater_than_zero, - value_type::greater_than_max, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == greater_than_max - //{ - value_type::less_than_min, // less_than_min, - value_type::less_than_min, // less_than_zero, - value_type::zero, // zero, - value_type::greater_than_max, // greater_than_zero, - value_type::greater_than_max, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == indeterminate - //{ - value_type::indeterminate, // less_than_min, - value_type::indeterminate, // less_than_zero, - value_type::indeterminate, // zero, - value_type::indeterminate, // greater_than_zero, - value_type::indeterminate, // greater than max, - value_type::indeterminate, // indeterminate, - //} - }; - - const value_type tx(t); - const value_type ux(u); - - switch(result[tx * order + ux]){ - case value_type::less_than_min: - return safe_numerics_error::negative_overflow_error; - case value_type::zero: - return T(0); - case value_type::greater_than_max: - return safe_numerics_error::positive_overflow_error; - case value_type::less_than_zero: - case value_type::greater_than_zero: - return checked::multiply(t, u); - case value_type::indeterminate: - return safe_numerics_error::range_error; - default: - assert(false); - } - return checked_result(0); // to suppress msvc warning -} - -// integers division -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator/( - const checked_result & t, - const checked_result & u -){ - using value_type = product_value_type; - const std::uint8_t order = static_cast(value_type::count); - - constexpr const enum value_type::flag result[order * order] = { - // t == less_than_min - //{ - // u == ... - value_type::indeterminate, // less_than_min, - value_type::greater_than_max, // less_than_zero, - value_type::less_than_min, // zero, - value_type::less_than_min, // greater_than_zero, - value_type::less_than_min, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == less_than_zero, - //{ - // u == ... - value_type::zero, // less_than_min, - value_type::greater_than_zero, // less_than_zero, - value_type::less_than_min, // zero, - value_type::less_than_zero, // greater_than_zero, - value_type::zero, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == zero, - //{ - // u == ... - value_type::zero, // less_than_min, - value_type::zero, // less_than_zero, - value_type::indeterminate, // zero, - value_type::zero, // greater_than_zero, - value_type::zero, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == greater_than_zero, - //{ - // u == ... - value_type::zero, // less_than_min, - value_type::less_than_zero, // less_than_zero, - value_type::greater_than_max, // zero, - value_type::greater_than_zero, // greater_than_zero, - value_type::zero, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == greater_than_max - //{ - value_type::less_than_min, // less_than_min, - value_type::less_than_min, // less_than_zero, - value_type::greater_than_max, // zero, - value_type::greater_than_max, // greater_than_zero, - value_type::indeterminate, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == indeterminate - //{ - value_type::indeterminate, // less_than_min, - value_type::indeterminate, // less_than_zero, - value_type::indeterminate, // zero, - value_type::indeterminate, // greater_than_zero, - value_type::indeterminate, // greater than max, - value_type::indeterminate, // indeterminate, - //} - }; - - const value_type tx(t); - const value_type ux(u); - - switch(result[tx * order + ux]){ - case value_type::less_than_min: - return safe_numerics_error::negative_overflow_error; - case value_type::zero: - return 0; - case value_type::greater_than_max: - return safe_numerics_error::positive_overflow_error; - case value_type::less_than_zero: - case value_type::greater_than_zero: - return checked::divide(t, u); - case value_type::indeterminate: - return safe_numerics_error::range_error; - default: - assert(false); - } - return checked_result(0); // to suppress msvc warning -} - -// integers modulus -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator%( - const checked_result & t, - const checked_result & u -){ - using value_type = product_value_type; - const std::uint8_t order = static_cast(value_type::count); - - constexpr const enum value_type::flag result[order * order] = { - // t == less_than_min - //{ - // u == ... - value_type::indeterminate, // less_than_min, - value_type::z_value, // less_than_zero, - value_type::indeterminate, // zero, - value_type::z_value, // greater_than_zero, - value_type::indeterminate, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == less_than_zero, - //{ - // u == ... - value_type::t_value, // less_than_min, - value_type::greater_than_zero, // less_than_zero, - value_type::indeterminate, // zero, - value_type::less_than_zero, // greater_than_zero, - value_type::t_value, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == zero, - //{ - // u == ... - value_type::zero, // less_than_min, - value_type::zero, // less_than_zero, - value_type::indeterminate, // zero, - value_type::zero, // greater_than_zero, - value_type::zero, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == greater_than_zero, - //{ - // u == ... - value_type::t_value, // less_than_min, - value_type::less_than_zero, // less_than_zero, - value_type::indeterminate, // zero, - value_type::greater_than_zero, // greater_than_zero, - value_type::t_value, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == greater_than_max - //{ - value_type::indeterminate, // less_than_min, - value_type::u_value, // less_than_zero, - value_type::indeterminate, // zero, - value_type::u_value, // greater_than_zero, - value_type::indeterminate, // greater than max, - value_type::indeterminate, // indeterminate, - //}, - // t == indeterminate - //{ - value_type::indeterminate, // less_than_min, - value_type::indeterminate, // less_than_zero, - value_type::indeterminate, // zero, - value_type::indeterminate, // greater_than_zero, - value_type::indeterminate, // greater than max, - value_type::indeterminate, // indeterminate, - //} - }; - - const value_type tx(t); - const value_type ux(u); - - switch(result[tx * order + ux]){ - case value_type::zero: - return 0; - case value_type::less_than_zero: - case value_type::greater_than_zero: - return checked::modulus(t, u); - case value_type::indeterminate: - return safe_numerics_error::range_error; - case value_type::t_value: - return t; - case value_type::u_value: - return checked::subtract(u, 1); - case value_type::z_value: - return checked::subtract(1, u); - case value_type::greater_than_max: - case value_type::less_than_min: - default: - assert(false); - } - // suppress msvc warning - return checked_result(0); -} - -// comparison operators - -template -constexpr boost::logic::tribool operator<( - const checked_result & t, - const checked_result & u -){ - using value_type = sum_value_type; - constexpr const std::uint8_t order = static_cast(value_type::count); - - // the question arises about how to order values of type greater_than_min. - // that is: what should greater_than_min < greater_than_min return. - // - // a) return indeterminate because we're talking about the "true" values for - // which greater_than_min is a placholder. - // - // b) return false because the two values are "equal" - // - // for our purposes, a) seems the better interpretation. - - enum class result_type : std::uint8_t { - runtime, - false_value, - true_value, - indeterminate, - }; - constexpr const result_type resultx[order * order]{ - // t == known_value - //{ - // u == ... - result_type::runtime, // known_value, - result_type::false_value, // less_than_min, - result_type::true_value, // greater_than_max, - result_type::indeterminate, // indeterminate, - //}, - // t == less_than_min - //{ - // u == ... - result_type::true_value, // known_value, - result_type::indeterminate, // less_than_min, see above argument - result_type::true_value, // greater_than_max, - result_type::indeterminate, // indeterminate, - //}, - // t == greater_than_max - //{ - // u == ... - result_type::false_value, // known_value, - result_type::false_value, // less_than_min, - result_type::indeterminate, // greater_than_max, see above argument - result_type::indeterminate, // indeterminate, - //}, - // t == indeterminate - //{ - // u == ... - result_type::indeterminate, // known_value, - result_type::indeterminate, // less_than_min, - result_type::indeterminate, // greater_than_max, - result_type::indeterminate, // indeterminate, - //}, - }; - - const value_type tx(t); - const value_type ux(u); - - switch(resultx[tx * order + ux]){ - case result_type::runtime: - return static_cast(t) < static_cast(u); - case result_type::false_value: - return false; - case result_type::true_value: - return true; - case result_type::indeterminate: - return boost::logic::indeterminate; - default: - assert(false); - } - return true; -} - -template -constexpr boost::logic::tribool -operator>=( - const checked_result & t, - const checked_result & u -){ - return !(t < u); -} - -template -constexpr boost::logic::tribool -operator>( - const checked_result & t, - const checked_result & u -){ - return u < t; -} - -template -constexpr boost::logic::tribool -operator<=( - const checked_result & t, - const checked_result & u -){ - return !(u < t); -} - -template -constexpr boost::logic::tribool -operator==( - const checked_result & t, - const checked_result & u -){ - using value_type = sum_value_type; - constexpr const std::uint8_t order = static_cast(value_type::count); - - enum class result_type : std::uint8_t { - runtime, - false_value, - true_value, - indeterminate, - }; - - constexpr const result_type result[order * order]{ - // t == known_value - //{ - // u == ... - result_type::runtime, // known_value, - result_type::false_value, // less_than_min, - result_type::false_value, // greater_than_max, - result_type::indeterminate, // indeterminate, - //}, - // t == less_than_min - //{ - // u == ... - result_type::false_value, // known_value, - result_type::indeterminate, // less_than_min, - result_type::false_value, // greater_than_max, - result_type::indeterminate, // indeterminate, - //}, - // t == greater_than_max - //{ - // u == ... - result_type::false_value, // known_value, - result_type::false_value, // less_than_min, - result_type::indeterminate, // greater_than_max, - result_type::indeterminate, // indeterminate, - //}, - // t == indeterminate - //{ - // u == ... - result_type::indeterminate, // known_value, - result_type::indeterminate, // less_than_min, - result_type::indeterminate, // greater_than_max, - result_type::indeterminate, // indeterminate, - //}, - }; - - const value_type tx(t); - const value_type ux(u); - - switch(result[tx * order + ux]){ - case result_type::runtime: - return static_cast(t) == static_cast(u); - case result_type::false_value: - return false; - case result_type::true_value: - return true; - case result_type::indeterminate: - return boost::logic::indeterminate; - default: - assert(false); - } - // suppress msvc warning - not all control paths return a value - return false; -} - -template -constexpr boost::logic::tribool -operator!=( - const checked_result & t, - const checked_result & u -){ - return ! (t == u); -} - -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator>>( - const checked_result & t, - const checked_result & u -); - -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator~( - const checked_result & t -){ -// assert(false); - return ~t.m_r; -} - -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator<<( - const checked_result & t, - const checked_result & u -){ - using value_type = product_value_type; - const std::uint8_t order = static_cast(value_type::count); - - constexpr const std::uint8_t result[order * order] = { - // t == less_than_min - //{ - // u == ... - 1, // -1, // less_than_min, - 2, // safe_numerics_error::negative_overflow_error, // less_than_zero, - 2, // safe_numerics_error::negative_overflow_error, // zero, - 2, // safe_numerics_error::negative_overflow_error, // greater_than_zero, - 2, // safe_numerics_error::negative_overflow_error, // greater than max, - 1, // safe_numerics_error::range_error, // indeterminate, - //}, - // t == less_than_zero, - //{ - // u == ... - 3, // -1, // less_than_min, - 4, // - (-t >> -u), // less_than_zero, - 5, // safe_numerics_error::negative_overflow_error, // zero, - 6, // - (-t << u), // greater_than_zero, - 2, // safe_numerics_error::negative_overflow_error, // greater than max, - 1, // safe_numerics_error::range_error, // indeterminate, - //}, - // t == zero, - //{ - // u == ... - 3, // 0 // less_than_min, - 3, // 0 // less_than_zero, - 3, // 0, // zero, - 3, // 0, // greater_than_zero, - 3, // 0, // greater than max, - 3, // safe_numerics_error::range_error, // indeterminate, - //}, - // t == greater_than_zero, - //{ - // u == ... - 3, // 0, // less_than_min, - 7, // t << -u, // less_than_zero, - 5, // t, // zero, - 8, // t << u // greater_than_zero, - 9, // safe_numerics_error::positive_overflow_error, // greater than max, - 1, // safe_numerics_error::range_error, // indeterminate, - //}, - // t == greater_than_max - //{ - // u == ... - 1, // safe_numerics_error::range_error, // less_than_min, - 9, // safe_numerics_error::positive_overflow_error), // less_than_zero, - 9, // safe_numerics_error::positive_overflow_error, // zero, - 9, // safe_numerics_error::positive_overflow_error), // greater_than_zero, - 9, // safe_numerics_error::positive_overflow_error, // greater than max, - 1, // safe_numerics_error::range_error, // indeterminate, - //}, - // t == indeterminate - //{ - 1, // safe_numerics_error::range_error, // indeterminate, - 1, // safe_numerics_error::range_error, // indeterminate, - 1, // safe_numerics_error::range_error, // indeterminate, - 1, // safe_numerics_error::range_error, // indeterminate, - 1, // safe_numerics_error::range_error, // indeterminate, - 1, // safe_numerics_error::range_error, // indeterminate, - //} - }; - - const value_type tx(t); - const value_type ux(u); - assert(tx * order + ux < order * order); - - // I had a switch(i) statment here - but it results in an ICE - // on multiple versions of gcc. So make the equivalent in - // nested if statments - should be the same (more or less) - // performancewise. - const unsigned int i = result[tx * order + ux]; - assert(i <= 9); - if(1 == i){ - return safe_numerics_error::range_error; - } - else - if(2 == i){ - return safe_numerics_error::negative_overflow_error; - } - else - if(3 == i){ - return checked_result(0); - // the following gymnastics are to handle the case where - // a value is changed from a negative to a positive number. - // For example, and 8 bit number t == -128. Then -t also - // equals -128 since 128 cannot be held in an 8 bit signed - // integer. - } - else - if(4 == i){ // - (-t >> -u) - assert(static_cast(t < checked_result(0))); - assert(static_cast(u < checked_result(0))); - return t >> -u; - } - else - if(5 == i){ - return t; - } - else - if(6 == i){ // - (-t << u) - assert(static_cast(t < checked_result(0))); - assert(static_cast(u > checked_result(0))); - const checked_result temp_t = t * checked_result(2); - const checked_result temp_u = u - checked_result(1); - return - (-temp_t << temp_u); - } - else - if(7 == i){ // t >> -u - assert(static_cast(t > checked_result(0))); - assert(static_cast(u < checked_result(0))); - return t >> -u; - } - else - if(8 == i){ // t << u - assert(static_cast(t > checked_result(0))); - assert(static_cast(u > checked_result(0))); - checked_result r = checked::left_shift(t, u); - return (r.m_e == safe_numerics_error::shift_too_large) - ? checked_result(safe_numerics_error::positive_overflow_error) - : r; - } - else - if(9 == i){ - return safe_numerics_error::positive_overflow_error; - } - else{ - assert(false); - }; - return checked_result(0); // to suppress msvc warning -} - -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator>>( - const checked_result & t, - const checked_result & u -){ - using value_type = product_value_type; - const std::uint8_t order = static_cast(value_type::count); - - const std::uint8_t result[order * order] = { - // t == less_than_min - //{ - // u == ... - 2, // safe_numerics_error::negative_overflow_error, // less_than_min, - 2, // safe_numerics_error::negative_overflow_error, // less_than_zero, - 2, // safe_numerics_error::negative_overflow_error, // zero, - 2, // safe_numerics_error::negative_overflow_error, // greater_than_zero, - 1, // safe_numerics_error::range_error, // greater than max, - 1, // safe_numerics_error::range_error, // indeterminate, - //}, - // t == less_than_zero, - //{ - // u == ... - 2, // safe_numerics_error::negative_overflow_error // less_than_min, - 4, // - (-t << -u), // less_than_zero, - 5, // safe_numerics_error::negative_overflow_error. // zero, - 6, // - (-t >> u), // greater_than_zero, - 3, // 0, ? or -1 // greater than max, - 1, // safe_numerics_error::range_error, // indeterminate, - //}, - // t == zero, - //{ - // u == ... - 3, // 0 // less_than_min, - 3, // 0 // less_than_zero, - 3, // 0, // zero, - 3, // 0, // greater_than_zero, - 3, // 0, // greater than max, - 3, // safe_numerics_error::range_error, // indeterminate, - //}, - // t == greater_than_zero, - //{ - // u == ... - 9, // safe_numerics_error::positive_overflow_error // less_than_min, - 7, // t << -u, // less_than_zero, - 5, // t, // zero, - 8, // t >> u // greater_than_zero, - 3, // 0, // greater than max, - 1, // safe_numerics_error::range_error, // indeterminate, - //}, - // t == greater_than_max - //{ - // u == ... - 9, // safe_numerics_error::positive_overflow_error, // less_than_min, - 9, // safe_numerics_error::positive_overflow_error, // less_than_zero, - 9, // safe_numerics_error::positive_overflow_error, // zero, - 9, // safe_numerics_error::positive_overflow_error, // greater_than_zero, - 1, // safe_numerics_error::range_error, // greater than max, - 1, // safe_numerics_error::range_error, // indeterminate, - //}, - // t == indeterminate - //{ - 1, // safe_numerics_error::range_error, // indeterminate, - 1, // safe_numerics_error::range_error, // indeterminate, - 1, // safe_numerics_error::range_error, // indeterminate, - 1, // safe_numerics_error::range_error, // indeterminate, - 1, // safe_numerics_error::range_error, // indeterminate, - 1, // safe_numerics_error::range_error, // indeterminate, - //} - }; - - const value_type tx(t); - const value_type ux(u); - assert(tx * order + ux < order * order); - - // I had a switch(i) statment here - but it results in an ICE - // on multiple versions of gcc. So make the equivalent in - // nested if statments - should be the same (more or less) - // performancewise. - const unsigned int i = result[tx * order + ux]; - assert(i <= 9); - if(1 == i){ - return safe_numerics_error::range_error; - } - else - if(2 == i){ - return safe_numerics_error::negative_overflow_error; - } - else - if(3 == i){ - return checked_result(0); - } - else - if(4 == i){ // - (-t << -u) - assert(static_cast(t < checked_result(0))); - assert(static_cast(u < checked_result(0))); - return t << -u; - } - else - if(5 == i){ - return t; - } - else - if(6 == i){ // - (-t >> u) - assert(static_cast(t < checked_result(0))); - assert(static_cast(u > checked_result(0))); - const checked_result temp_t = t / checked_result(2); - const checked_result temp_u = u - checked_result(1); - return - (-temp_t >> temp_u); - } - else - if(7 == i){ // t << -u, - assert(static_cast(t > checked_result(0))); - assert(static_cast(u < checked_result(0))); - return t << -u; - } - else - if(8 == i){ // t >> u - assert(static_cast(t > checked_result(0))); - assert(static_cast(u > checked_result(0))); - checked_result r = checked::right_shift(t, u); - return (r.m_e == safe_numerics_error::shift_too_large) - ? checked_result(0) - : r; - } - else - if(9 == i){ - return safe_numerics_error::positive_overflow_error; - } - else{ - assert(false); - }; - return checked_result(0); // to suppress msvc warning -} - -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator|( - const checked_result & t, - const checked_result & u -){ - return - t.exception() || u.exception() - ? checked_result(safe_numerics_error::range_error) - : checked::bitwise_or( - static_cast(t), - static_cast(u) - ); -} -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator^( - const checked_result & t, - const checked_result & u -){ - return - t.exception() || u.exception() - ? checked_result(safe_numerics_error::range_error) - : checked::bitwise_xor( - static_cast(t), - static_cast(u) - ); -} - -template -typename std::enable_if< - std::is_integral::value, - checked_result ->::type -constexpr inline operator&( - const checked_result & t, - const checked_result & u -){ - return - t.exception() || u.exception() - ? checked_result(safe_numerics_error::range_error) - : checked::bitwise_and( - static_cast(t), - static_cast(u) - ); -} - -} // safe_numerics -} // boost - -#include - -namespace std { - -template -inline std::basic_ostream & operator<<( - std::basic_ostream & os, - const boost::safe_numerics::checked_result & r -){ - if(!r.exception()) - os << static_cast(r); - else - os << std::error_code(r.m_e).message() << ':' << r.m_msg; - return os; -} - -template -inline std::basic_ostream & operator<<( - std::basic_ostream & os, - const boost::safe_numerics::checked_result & r -){ - if(! r.exception()) - os << static_cast(r); - else - os << std::error_code(r.m_e).message() << ':' << r.m_msg; - return os; -} - -template -inline std::basic_ostream & operator<<( - std::basic_ostream & os, - const boost::safe_numerics::checked_result & r -){ - if(! r.exception()) - os << static_cast(r); - else - os << std::error_code(r.m_e).message() << ':' << r.m_msg; - return os; -} - -template -inline std::basic_istream & operator>>( - std::basic_istream & is, - boost::safe_numerics::checked_result & r -){ - is >> r.m_r; - return is; -} - -template -inline std::basic_istream & operator>>( - std::basic_istream & is, - boost::safe_numerics::checked_result & r -){ - std::int16_t i; - is >> i; - r.m_r = i; - return is; -} - -template -inline std::basic_istream & operator>>( - std::basic_istream & is, - boost::safe_numerics::checked_result & r -){ - std::uint16_t i; - is >> i; - r.m_r = i; - return is; -} - -} // std - -///////////////////////////////////////////////////////////////// -// numeric limits for checked - -#include - -namespace std { - -template -class numeric_limits > - : public std::numeric_limits -{ - using this_type = boost::safe_numerics::checked_result; -public: - constexpr static this_type min() noexcept { - return this_type(std::numeric_limits::min()); - } - constexpr static this_type max() noexcept { - return this_type(std::numeric_limits::max()); - } -}; - -} // std - -#endif // BOOST_NUMERIC_CHECKED_RESULT_OPERATIONS diff --git a/boost/safe_numerics/concept/CMakeLists.txt b/boost/safe_numerics/concept/CMakeLists.txt deleted file mode 100644 index dd2832b..0000000 --- a/boost/safe_numerics/concept/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -#################### -# add include headers to IDE - -set(USE_FOLDERS TRUE) - -file(GLOB include_files - RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" - "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp" -) -add_custom_target(concepts SOURCES ${include_files}) -set_target_properties(concepts PROPERTIES FOLDER "safe_numerics") - -# end headers in IDE -#################### diff --git a/boost/safe_numerics/concept/exception_policy.hpp b/boost/safe_numerics/concept/exception_policy.hpp deleted file mode 100644 index 134ed25..0000000 --- a/boost/safe_numerics/concept/exception_policy.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef BOOST_NUMERIC_CONCEPT_EXCEPTION_POLICY_HPP -#define BOOST_NUMERIC_CONCEPT_EXCEPTION_POLICY_HPP - -// Copyright (c) 2015 Robert Ramey -// -// 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) - -namespace boost { -namespace safe_numerics { - -template -struct ExceptionPolicy { - const char * message; - /* - BOOST_CONCEPT_USAGE(ExceptionPolicy){ - EP::on_arithmetic_error(e, message); - EP::on_undefined_behavior(e, message) - EP::on_implementation_defined_behavior(e, message) - EP::on_uninitialized_value(e, message) - } - */ -}; - -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_CONCEPT_EXCEPTION_POLICY_HPP diff --git a/boost/safe_numerics/concept/integer.hpp b/boost/safe_numerics/concept/integer.hpp deleted file mode 100644 index 79d0791..0000000 --- a/boost/safe_numerics/concept/integer.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef BOOST_NUMERIC_CONCEPT_INTEGER_HPP -#define BOOST_NUMERIC_CONCEPT_INTEGER_HPP - -// Copyright (c) 2012 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include "numeric.hpp" - -namespace boost { -namespace safe_numerics { - -template -class Integer : public Numeric { - // integer types must have the corresponding numeric trait. - static_assert( - std::numeric_limits::is_integer, - "Fails to fulfill requirements for an integer type" - ); -}; - -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_CONCEPT_INTEGER_HPP diff --git a/boost/safe_numerics/concept/numeric.hpp b/boost/safe_numerics/concept/numeric.hpp deleted file mode 100644 index d7f0f34..0000000 --- a/boost/safe_numerics/concept/numeric.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef BOOST_NUMERIC_CONCEPT_NUMERIC_HPP -#define BOOST_NUMERIC_CONCEPT_NUMERIC_HPP - -// Copyright (c) 2012 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include - -namespace boost { -namespace safe_numerics { - -template -struct Numeric { - // if your program traps here, you need to create a - // std::numeric_limits class for your type T. see - // see C++ standard 18.3.2.2 - static_assert( - std::numeric_limits::is_specialized, - "std::numeric_limits has not been specialized for this type" - ); -}; - -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_CONCEPT_NUMERIC_HPP diff --git a/boost/safe_numerics/concept/promotion_policy.hpp b/boost/safe_numerics/concept/promotion_policy.hpp deleted file mode 100644 index 14bbb3c..0000000 --- a/boost/safe_numerics/concept/promotion_policy.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef BOOST_NUMERIC_CONCEPT_PROMOTION_POLICY_HPP -#define BOOST_NUMERIC_CONCEPT_PROMOTION_POLICY_HPP - -// Copyright (c) 2015 Robert Ramey -// -// 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) - -namespace boost { -namespace safe_numerics { - -template -struct PromotionPolicy { - using T = int; - using U = int; - using a_type = typename PP::template addition_result; - using s_type = typename PP::template subtraction_result; - using m_type = typename PP::template multiplication_result; - using d_type = typename PP::template division_result; - using mod_type = typename PP::template modulus_result; - using ls_type = typename PP::template left_shift_result; - using rs_type = typename PP::template right_shift_result; - using cc_type = typename PP::template comparison_result; - using baw_type = typename PP::template bitwise_and_result; - using bow_type = typename PP::template bitwise_or_result; - using bxw_type = typename PP::template bitwise_xor_result; -}; - -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_CONCEPT_EXCEPTION_POLICY_HPP diff --git a/boost/safe_numerics/concept/safe_numeric.hpp b/boost/safe_numerics/concept/safe_numeric.hpp deleted file mode 100644 index 0b6ac12..0000000 --- a/boost/safe_numerics/concept/safe_numeric.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef BOOST_NUMERIC_CONCEPT_SAFE_NUMERIC_HPP -#define BOOST_NUMERIC_CONCEPT_SAFE_NUMERIC_HPP - -// Copyright (c) 2015 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include "concept/numeric.hpp" - -namespace boost { -namespace safe_numerics { - -template -struct SafeNumeric : public Numeric { - static_assert( - is_safe::value, - "std::numeric_limits has not been specialized for this type" - ); - BOOST_CONCEPT_USAGE(SafeNumeric){ - using t1 = get_exception_policy; - using t2 = get_promotion_policy; - using t3 = base_type; - } -}; - -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_CONCEPT_SAFE_NUMERIC_HPP diff --git a/boost/safe_numerics/cpp.hpp b/boost/safe_numerics/cpp.hpp deleted file mode 100644 index 077fbfc..0000000 --- a/boost/safe_numerics/cpp.hpp +++ /dev/null @@ -1,197 +0,0 @@ -#ifndef BOOST_NUMERIC_CPP_HPP -#define BOOST_NUMERIC_CPP_HPP - -// Copyright (c) 2012 Robert Ramey -// -// 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) - -// policy which creates results types equal to that of C++ promotions. -// Using the policy will permit the program to build and run in release -// mode which is identical to that in debug mode except for the fact -// that errors aren't trapped. - -#include // integral constant, remove_cv, conditional -#include -#include // integer type selection - -#include "safe_common.hpp" -#include "checked_result.hpp" - -namespace boost { -namespace safe_numerics { - -// in C++ the following rules govern integer arithmetic - -// This policy is use to emulate another compiler/machine architecture -// For example, a Z80 has 8 bit char, 16 bit short, 16 bit int, 32 bit long. So one -// would use cpp<8, 16, 16, 32, 32> to test programs destined to run on a Z80 - -// Follow section 5 of the standard. -template< - int CharBits, - int ShortBits, - int IntBits, - int LongBits, - int LongLongBits -> -struct cpp { -public: - using local_char_type = typename boost::int_t::exact; - using local_short_type = typename boost::int_t::exact; - using local_int_type = typename boost::int_t::exact; - using local_long_type = typename boost::int_t::exact; - using local_long_long_type = typename boost::int_t::exact; - - template - using rank = - typename std::conditional< - std::is_same::type>::value, - std::integral_constant, - typename std::conditional< - std::is_same::type>::value, - std::integral_constant, - typename std::conditional< - std::is_same::type>::value, - std::integral_constant, - typename std::conditional< - std::is_same::type>::value, - std::integral_constant, - typename std::conditional< - std::is_same::type>::value, - std::integral_constant, - std::integral_constant // catch all - never promote integral - >::type >::type >::type >::type >::type; - - // section 4.5 integral promotions - - // convert smaller of two types to the size of the larger - template - using higher_ranked_type = typename std::conditional< - (rank::value < rank::value), - U, - T - >::type; - - template - using copy_sign = typename std::conditional< - std::is_signed::value, - typename std::make_signed::type, - typename std::make_unsigned::type - >::type; - - template - using integral_promotion = copy_sign< - higher_ranked_type, - T - >; - - // note presumption that T & U don't have he same sign - // if that's not true, these won't work - template - using select_signed = typename std::conditional< - std::numeric_limits::is_signed, - T, - U - >::type; - - template - using select_unsigned = typename std::conditional< - std::numeric_limits::is_signed, - U, - T - >::type; - - // section 5 clause 11 - usual arithmetic conversions - template - using usual_arithmetic_conversions = - // clause 0 - if both operands have the same type - typename std::conditional< - std::is_same::value, - // no further conversion is needed - T, - // clause 1 - otherwise if both operands have the same sign - typename std::conditional< - std::numeric_limits::is_signed - == std::numeric_limits::is_signed, - // convert to the higher ranked type - higher_ranked_type, - // clause 2 - otherwise if the rank of he unsigned type exceeds - // the rank of the of the signed type - typename std::conditional< - rank>::value - >= rank< select_signed>::value, - // use unsigned type - select_unsigned, - // clause 3 - otherwise if the type of the signed integer type can - // represent all the values of the unsigned type - typename std::conditional< - std::numeric_limits< select_signed>::digits >= - std::numeric_limits< select_unsigned>::digits, - // use signed type - select_signed, - // clause 4 - otherwise use unsigned version of the signed type - std::make_signed< select_signed> - >::type >::type >::type - >; - - template - using result_type = typename usual_arithmetic_conversions< - integral_promotion::type>, - integral_promotion::type> - >::type; -public: - template - struct addition_result { - using type = result_type; - }; - template - struct subtraction_result { - using type = result_type; - }; - template - struct multiplication_result { - using type = result_type; - }; - template - struct division_result { - using type = result_type; - }; - template - struct modulus_result { - using type = result_type; - }; - // note: comparison_result (<, >, ...) is special. - // The return value is always a bool. The type returned here is - // the intermediate type applied to make the values comparable. - template - struct comparison_result { - using type = result_type; - }; - template - struct left_shift_result { - using type = result_type; - }; - template - struct right_shift_result { - using type = result_type; - }; - template - struct bitwise_and_result { - using type = result_type; - }; - template - struct bitwise_or_result { - using type = result_type; - }; - template - struct bitwise_xor_result { - using type = result_type; - }; -}; - -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_cpp_HPP diff --git a/boost/safe_numerics/exception.hpp b/boost/safe_numerics/exception.hpp deleted file mode 100644 index d7da5c2..0000000 --- a/boost/safe_numerics/exception.hpp +++ /dev/null @@ -1,190 +0,0 @@ -#ifndef BOOST_NUMERIC_EXCEPTION -#define BOOST_NUMERIC_EXCEPTION - -// Copyright (c) 2012 Robert Ramey -// -// 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) - -// contains error indicators for results of doing checked -// arithmetic on native C++ types - -#include -#include // error_code, system_error -#include -#include -#include // std::uint8_t - -// Using the system_error code facility. This facility is more complex -// than meets the eye. To fully understand what out intent here is, -// review http://blog.think-async.com/2010/04/system-error-support-in-c0x-part-5.html -// "Giving context-specific meaning to generic error codes" - -namespace boost { -namespace safe_numerics { - -// errors codes for safe numerics - -// in spite of the similarity, this list is distinct from the exceptions -// listed in documentation for std::exception. - -// note: Don't reorder these. Code in the file checked_result_operations.hpp -// depends upon this order !!! -enum class safe_numerics_error : std::uint8_t { - success = 0, - positive_overflow_error, // result is above representational maximum - negative_overflow_error, // result is below representational minimum - domain_error, // one operand is out of valid range - range_error, // result cannot be produced for this operation - precision_overflow_error, // result lost precision - underflow_error, // result is too small to be represented - negative_value_shift, // negative value in shift operator - negative_shift, // shift a negative value - shift_too_large, // l/r shift exceeds variable size - uninitialized_value // creating of uninitialized value -}; - -const std::uint8_t safe_numerics_casting_error_count = - static_cast(safe_numerics_error::domain_error) + 1; - -const std::uint8_t safe_numerics_error_count = - static_cast(safe_numerics_error::uninitialized_value) + 1; - -} // safe_numerics -} // boost - -namespace std { - template <> - struct is_error_code_enum - : public true_type {}; -} // std - -namespace boost { -namespace safe_numerics { - -const class : public std::error_category { -public: - virtual const char* name() const noexcept{ - return "safe numerics error"; - } - virtual std::string message(int ev) const { - switch(static_cast(ev)){ - case safe_numerics_error::success: - return "success"; - case safe_numerics_error::positive_overflow_error: - return "positive overflow error"; - case safe_numerics_error::negative_overflow_error: - return "negative overflow error"; - case safe_numerics_error::underflow_error: - return "underflow error"; - case safe_numerics_error::range_error: - return "range error"; - case safe_numerics_error::precision_overflow_error: - return "precision_overflow_error"; - case safe_numerics_error::domain_error: - return "domain error"; - case safe_numerics_error::negative_shift: - return "negative shift"; - case safe_numerics_error::negative_value_shift: - return "negative value shift"; - case safe_numerics_error::shift_too_large: - return "shift too large"; - case safe_numerics_error::uninitialized_value: - return "uninitialized value"; - default: - assert(false); - } - return ""; // suppress bogus warning - } -} safe_numerics_error_category {}; - -// constexpr - damn, can't use constexpr due to std::error_code -inline std::error_code make_error_code(const safe_numerics_error & e){ - return std::error_code(static_cast(e), safe_numerics_error_category); -} - -// actions for error_codes for safe numerics. I've leveraged on -// error_condition in order to do this. I'm not sure this is a good -// idea or not. - -enum class safe_numerics_actions { - no_action = 0, - uninitialized_value, - arithmetic_error, - implementation_defined_behavior, - undefined_behavior -}; - -} // safe_numerics -} // boost - -namespace std { - template <> - struct is_error_condition_enum - : public true_type {}; -} // std - -namespace boost { -namespace safe_numerics { - -const class : public std::error_category { -public: - virtual const char* name() const noexcept { - return "safe numerics error group"; - } - virtual std::string message(int) const { - return "safe numerics error group"; - } - // return true if a given error code corresponds to a - // given safe numeric action - virtual bool equivalent( - const std::error_code & code, - int condition - ) const noexcept { - if(code.category() != safe_numerics_error_category) - return false; - switch (static_cast(condition)){ - case safe_numerics_actions::no_action: - return code == safe_numerics_error::success; - case safe_numerics_actions::uninitialized_value: - return code == safe_numerics_error::uninitialized_value; - case safe_numerics_actions::arithmetic_error: - return code == safe_numerics_error::positive_overflow_error - || code == safe_numerics_error::negative_overflow_error - || code == safe_numerics_error::underflow_error - || code == safe_numerics_error::range_error - || code == safe_numerics_error::domain_error; - case safe_numerics_actions::implementation_defined_behavior: - return code == safe_numerics_error::negative_value_shift - || code == safe_numerics_error::negative_shift - || code == safe_numerics_error::shift_too_large; - case safe_numerics_actions::undefined_behavior: - return false; - default: - ; - } - // should never arrive here - assert(false); - // suppress bogus warning - return false; - } -} safe_numerics_actions_category {}; - -// the following function is used to "finish" implementation of conversion -// of safe_numerics_error to std::error_condition. At least for now, this -// isn't being used and defining here it can lead duplicate symbol errors -// depending on the compiler. So suppress it until further notice -#if 0 -std::error_condition make_error_condition(const safe_numerics_error & e) { - return std::error_condition( - static_cast(e), - safe_numerics_error_category - ); -} -#endif - -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_CHECKED_RESULT diff --git a/boost/safe_numerics/exception_policies.hpp b/boost/safe_numerics/exception_policies.hpp deleted file mode 100644 index e07f7e6..0000000 --- a/boost/safe_numerics/exception_policies.hpp +++ /dev/null @@ -1,230 +0,0 @@ -#ifndef BOOST_NUMERIC_EXCEPTION_POLICIES_HPP -#define BOOST_NUMERIC_EXCEPTION_POLICIES_HPP - -// Copyright (c) 2015 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include // BOOST_NO_EXCEPTIONS -#include "exception.hpp" - -namespace boost { -namespace safe_numerics { - -template< - typename AE, - typename IDB, - typename UB, - typename UV -> -struct exception_policy { - static constexpr void on_arithmetic_error( - const safe_numerics_error & e, - const char * msg - ){ - AE(e, msg); - } - static constexpr void on_implementation_defined_behavior( - const safe_numerics_error & e, - const char * msg - ){ - IDB(e, msg); - } - static constexpr void on_undefined_behavior( - const safe_numerics_error & e, - const char * msg - ){ - UB(e, msg); - } - static constexpr void on_uninitialized_value( - const safe_numerics_error & e, - const char * msg - ){ - UV(e, msg); - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// pre-made error action handers - -// ignore any error and just return. -struct ignore_exception { - constexpr ignore_exception(const safe_numerics_error &, const char * ){} -}; - -// emit compile time error if this is invoked. -struct trap_exception { -#if 1 - //constexpr trap_exception(const safe_numerics_error & e, const char * ); - trap_exception() = delete; - trap_exception(const trap_exception &) = delete; - trap_exception(trap_exception &&) = delete; -#endif -}; - -// If an exceptional condition is detected at runtime throw the exception. -struct throw_exception { - #ifndef BOOST_NO_EXCEPTIONS - throw_exception(const safe_numerics_error & e, const char * message){ - throw std::system_error(std::error_code(e), message); - } - #else - trap_exception(const safe_numerics_error & e, const char * message); - #endif -}; - -// given an error code - return the action code which it corresponds to. -constexpr safe_numerics_actions -make_safe_numerics_action(const safe_numerics_error & e){ - // we can't use standard algorithms since we want this to be constexpr - // this brute force solution is simple and pretty fast anyway - switch(e){ - case safe_numerics_error::negative_overflow_error: - case safe_numerics_error::underflow_error: - case safe_numerics_error::range_error: - case safe_numerics_error::domain_error: - case safe_numerics_error::positive_overflow_error: - case safe_numerics_error::precision_overflow_error: - return safe_numerics_actions::arithmetic_error; - - case safe_numerics_error::negative_value_shift: - case safe_numerics_error::negative_shift: - case safe_numerics_error::shift_too_large: - return safe_numerics_actions::implementation_defined_behavior; - - case safe_numerics_error::uninitialized_value: - return safe_numerics_actions::uninitialized_value; - - case safe_numerics_error::success: - return safe_numerics_actions::no_action; - default: - assert(false); - } - // should never arrive here - //include to suppress bogus warning - return safe_numerics_actions::no_action; -} - -//////////////////////////////////////////////////////////////////////////////// -// compile time error dispatcher - -// note slightly baroque implementation of a compile time switch statement -// which instatiates only those cases which are actually invoked. This is -// motivated to implement the "trap" functionality which will generate a syntax -// error if and only a function which might fail is called. - -namespace dispatch_switch { - - template - struct dispatch_case {}; - - template - struct dispatch_case { - constexpr static void invoke(const safe_numerics_error & e, const char * msg){ - EP::on_uninitialized_value(e, msg); - } - }; - template - struct dispatch_case { - constexpr static void invoke(const safe_numerics_error & e, const char * msg){ - EP::on_arithmetic_error(e, msg); - } - }; - template - struct dispatch_case { - constexpr static void invoke(const safe_numerics_error & e, const char * msg){ - EP::on_implementation_defined_behavior(e, msg); - } - }; - template - struct dispatch_case { - constexpr static void invoke(const safe_numerics_error & e, const char * msg){ - EP::on_undefined_behavior(e, msg); - } - }; - -} // dispatch_switch - -template -constexpr void -dispatch(const char * msg){ - constexpr safe_numerics_actions a = make_safe_numerics_action(E); - dispatch_switch::dispatch_case::invoke(E, msg); -} - -template -class dispatch_and_return { -public: - template - constexpr static checked_result invoke( - char const * const & msg - ) { - dispatch(msg); - return checked_result(E, msg); - } -}; - -//////////////////////////////////////////////////////////////////////////////// -// pre-made error policy classes - -// loose exception -// - throw on arithmetic errors -// - ignore other errors. -// Some applications ignore these issues and still work and we don't -// want to update them. -using loose_exception_policy = exception_policy< - throw_exception, // arithmetic error - ignore_exception, // implementation defined behavior - ignore_exception, // undefined behavior - ignore_exception // uninitialized value ->; - -// loose trap -// same as above in that it doesn't check for various undefined behaviors -// but traps at compile time for hard arithmetic errors. This policy -// would be suitable for older embedded systems which depend on -// bit manipulation operations to work. -using loose_trap_policy = exception_policy< - trap_exception, // arithmetic error - ignore_exception, // implementation defined behavior - ignore_exception, // undefined behavior - ignore_exception // uninitialized value ->; - -// strict exception -// - throw at runtime on any kind of error -// recommended for new code. Check everything at compile time -// if possible and runtime if necessary. Trap or Throw as -// appropriate. Should guarantee code to be portable across -// architectures. -using strict_exception_policy = exception_policy< - throw_exception, - throw_exception, - throw_exception, - ignore_exception ->; - -// strict trap -// Same as above but requires code to be written in such a way as to -// make it impossible for errors to occur. This naturally will require -// extra coding effort but might be justified for embedded and/or -// safety critical systems. -using strict_trap_policy = exception_policy< - trap_exception, - trap_exception, - trap_exception, - trap_exception ->; - -// default policy -// One would use this first. After experimentation, one might -// replace some actions with ignore_exception -using default_exception_policy = strict_exception_policy; - -} // namespace safe_numerics -} // namespace boost - -#endif // BOOST_NUMERIC_EXCEPTION_POLICIES_HPP diff --git a/boost/safe_numerics/interval.hpp b/boost/safe_numerics/interval.hpp deleted file mode 100644 index 4c8fc3c..0000000 --- a/boost/safe_numerics/interval.hpp +++ /dev/null @@ -1,310 +0,0 @@ -#ifndef BOOST_NUMERIC_INTERVAL_HPP -#define BOOST_NUMERIC_INTERVAL_HPP - -// Copyright (c) 2012 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include -#include -#include -#include // minmax, min, max - -#include - -#include "utility.hpp" // log - -// from stack overflow -// http://stackoverflow.com/questions/23815138/implementing-variadic-min-max-functions - -namespace boost { -namespace safe_numerics { - -template -struct interval { - const R l; - const R u; - - template - constexpr interval(const T & lower, const T & upper) : - l(lower), - u(upper) - { - // assert(static_cast(l <= u)); - } - template - constexpr interval(const std::pair & p) : - l(p.first), - u(p.second) - {} - template - constexpr interval(const interval & rhs) : - l(rhs.l), - u(rhs.u) - {} - - constexpr interval(); - - // return true if this interval contains the given point - constexpr tribool includes(const R & t) const { - return l <= t && t <= u; - } - // if this interval contains every point found in some other inteval t - // return true - // otherwise - // return false or indeterminate - constexpr tribool includes(const interval & t) const { - return u >= t.u && l <= t.l; - } - - // return true if this interval contains the given point - constexpr tribool excludes(const R & t) const { - return t < l || t > u; - } - // if this interval excludes every point found in some other inteval t - // return true - // otherwise - // return false or indeterminate - constexpr tribool excludes(const interval & t) const { - return t.u < l || u < t.l; - } - -}; - -template -constexpr interval make_interval(){ - return interval(); -} -template -constexpr interval make_interval(const R & r){ - return interval(r, r); -} -template -constexpr interval::interval() : - l(std::numeric_limits::lowest()), - u(std::numeric_limits::max()) -{} -// account for the fact that for floats and doubles -// the most negative value is called "lowest" rather -// than min -template<> -constexpr interval::interval() : - l(std::numeric_limits::lowest()), - u(std::numeric_limits::max()) -{} -template<> -constexpr interval::interval() : - l(std::numeric_limits::lowest()), - u(std::numeric_limits::max()) -{} - -template -constexpr interval operator+(const interval & t, const interval & u){ - // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic - return {t.l + u.l, t.u + u.u}; -} - -template -constexpr interval operator-(const interval & t, const interval & u){ - // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic - return {t.l - u.u, t.u - u.l}; -} - -template -constexpr interval operator*(const interval & t, const interval & u){ - // adapted from https://en.wikipedia.org/wiki/Interval_arithmetic - return utility::minmax( - std::initializer_list { - t.l * u.l, - t.l * u.u, - t.u * u.l, - t.u * u.u - } - ); -} - -// interval division -// note: presumes 0 is not included in the range of the denominator -template -constexpr interval operator/(const interval & t, const interval & u){ - assert(static_cast(u.excludes(T(0)))); - return utility::minmax( - std::initializer_list { - t.l / u.l, - t.l / u.u, - t.u / u.l, - t.u / u.u - } - ); -} - -// modulus of two intervals. This will give a new range of for the modulus. -// note: presumes 0 is not included in the range of the denominator -template -constexpr interval operator%(const interval & t, const interval & u){ - assert(static_cast(u.excludes(T(0)))); - return utility::minmax( - std::initializer_list { - t.l % u.l, - t.l % u.u, - t.u % u.l, - t.u % u.u - } - ); -} - -template -constexpr interval operator<<(const interval & t, const interval & u){ -// static_assert(std::is_integral::value, "left shift only defined for integral type"); - //return interval{t.l << u.l, t.u << u.u}; - return utility::minmax( - std::initializer_list { - t.l << u.l, - t.l << u.u, - t.u << u.l, - t.u << u.u - } - ); -} - -template -constexpr interval operator>>(const interval & t, const interval & u){ -// static_assert(std::is_integral::value, "right shift only defined for integral type"); - //return interval{t.l >> u.u, t.u >> u.l}; - return utility::minmax( - std::initializer_list { - t.l >> u.l, - t.l >> u.u, - t.u >> u.l, - t.u >> u.u - } - ); -} - -// union of two intervals -template -constexpr interval operator|(const interval & t, const interval & u){ - const T & rl = std::min(t.l, u.l); - const T & ru = std::max(t.u, u.u); - return interval(rl, ru); -} - -// intersection of two intervals -template -constexpr interval operator&(const interval & t, const interval & u){ - const T & rl = std::max(t.l, u.l); - const T & ru = std::min(t.u, u.u); - return interval(rl, ru); -} - -// determine whether two intervals intersect -template -constexpr boost::logic::tribool intersect(const interval & t, const interval & u){ - return t.u >= u.l || t.l <= u.u; -} - -template -constexpr boost::logic::tribool operator<( - const interval & t, - const interval & u -){ - return - // if every element in t is less than every element in u - t.u < u.l ? boost::logic::tribool(true): - // if every element in t is greater than every element in u - t.l > u.u ? boost::logic::tribool(false): - // otherwise some element(s) in t are greater than some element in u - boost::logic::indeterminate - ; -} - -template -constexpr boost::logic::tribool operator>( - const interval & t, - const interval & u -){ - return - // if every element in t is greater than every element in u - t.l > u.u ? boost::logic::tribool(true) : - // if every element in t is less than every element in u - t.u < u.l ? boost::logic::tribool(false) : - // otherwise some element(s) in t are greater than some element in u - boost::logic::indeterminate - ; -} - -template -constexpr bool operator==( - const interval & t, - const interval & u -){ - // intervals have the same limits - return t.l == u.l && t.u == u.u; -} - -template -constexpr bool operator!=( - const interval & t, - const interval & u -){ - return ! (t == u); -} - -template -constexpr boost::logic::tribool operator<=( - const interval & t, - const interval & u -){ - return ! (t > u); -} - -template -constexpr boost::logic::tribool operator>=( - const interval & t, - const interval & u -){ - return ! (t < u); -} - -} // safe_numerics -} // boost - -#include - -namespace std { - -template -inline std::basic_ostream & -operator<<( - std::basic_ostream & os, - const boost::safe_numerics::interval & i -){ - return os << '[' << i.l << ',' << i.u << ']'; -} -template -inline std::basic_ostream & -operator<<( - std::basic_ostream & os, - const boost::safe_numerics::interval & i -){ - os << "[" << (unsigned)i.l << "," << (unsigned)i.u << "]"; - return os; -} - -template -inline std::basic_ostream & -operator<<( - std::basic_ostream & os, - const boost::safe_numerics::interval & i -){ - os << "[" << (int)i.l << "," << (int)i.u << "]"; - return os; -} - -} // std - - -#endif // BOOST_NUMERIC_INTERVAL_HPP diff --git a/boost/safe_numerics/native.hpp b/boost/safe_numerics/native.hpp deleted file mode 100644 index 78d34fd..0000000 --- a/boost/safe_numerics/native.hpp +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef BOOST_NUMERIC_NATIVE_HPP -#define BOOST_NUMERIC_NATIVE_HPP - -// Copyright (c) 2012 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include - -// policy which creates results types and values equal to that of C++ promotions. -// When used in conjunction with a desired exception policy, traps errors but -// does not otherwise alter the results produced by the program using it. -namespace boost { -namespace safe_numerics { - -struct native { -public: - // arithmetic operators - template - struct addition_result { - using type = decltype( - typename base_type::type() - + typename base_type::type() - ); - }; - template - struct subtraction_result { - using type = decltype( - typename base_type::type() - - typename base_type::type() - ); - }; - template - struct multiplication_result { - using type = decltype( - typename base_type::type() - * typename base_type::type() - ); - }; - template - struct division_result { - using type = decltype( - typename base_type::type() - / typename base_type::type() - ); - }; - template - struct modulus_result { - using type = decltype( - typename base_type::type() - % typename base_type::type() - ); - }; - // note: comparison_result (<, >, ...) is special. - // The return value is always a bool. The type returned here is - // the intermediate type applied to make the values comparable. - template - struct comparison_result { - using type = decltype( - typename base_type::type() - + typename base_type::type() - ); - }; - - // shift operators - template - struct left_shift_result { - using type = decltype( - typename base_type::type() - << typename base_type::type() - ); - }; - template - struct right_shift_result { - using type = decltype( - typename base_type::type() - >> typename base_type::type() - ); - }; - // bitwise operators - template - struct bitwise_or_result { - using type = decltype( - typename base_type::type() - | typename base_type::type() - ); - }; - template - struct bitwise_and_result { - using type = decltype( - typename base_type::type() - & typename base_type::type() - ); - }; - template - struct bitwise_xor_result { - using type = decltype( - typename base_type::type() - ^ typename base_type::type() - ); - }; -}; - -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_NATIVE_HPP diff --git a/boost/safe_numerics/range_value.hpp b/boost/safe_numerics/range_value.hpp deleted file mode 100644 index ceef19e..0000000 --- a/boost/safe_numerics/range_value.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef BOOST_RANGE_VALUE_HPP -#define BOOST_RANGE_VALUE_HPP - -// Copyright (c) 2015 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include - -// print range and value to a standard stream -// make a simple wrapper -template -struct range_value { - // type requirement - a numeric type - const T & m_t; - - constexpr range_value(const T & t) - : m_t(t) - {} - -}; - -template -constexpr range_value make_range_value(const T & t){ - return range_value(t); -} - -#include "interval.hpp" - -template< - class CharT, - class Traits, - class T -> -std::basic_ostream & operator<<( - std::basic_ostream & os, - const range_value & t -){ - return os - << boost::safe_numerics::make_interval() - << t.m_t; -} - -template -struct result_display { - const T & m_t; - result_display(const T & t) : - m_t(t) - {} -}; - -template -result_display make_result_display(const T & t){ - return result_display(t); -} - -template -inline std::basic_ostream & -operator<<( - std::basic_ostream & os, - const result_display & r -){ - return os - << std::hex - << make_range_value(r.m_t) - << "(" << std::dec << r.m_t << ")"; -} - -#endif // BOOST_RANGE_VALUE_HPP diff --git a/boost/safe_numerics/safe_base.hpp b/boost/safe_numerics/safe_base.hpp deleted file mode 100644 index 55508d0..0000000 --- a/boost/safe_numerics/safe_base.hpp +++ /dev/null @@ -1,349 +0,0 @@ -#ifndef BOOST_NUMERIC_SAFE_BASE_HPP -#define BOOST_NUMERIC_SAFE_BASE_HPP - -// Copyright (c) 2012 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include // is_integral, enable_if, conditional -#include // BOOST_CLANG -#include "concept/exception_policy.hpp" -#include "concept/promotion_policy.hpp" - -#include "safe_common.hpp" -#include "exception_policies.hpp" - -#include "boost/concept/assert.hpp" - -namespace boost { -namespace safe_numerics { - -///////////////////////////////////////////////////////////////// -// forward declarations to support friend function declarations -// in safe_base - -template< - class Stored, - Stored Min, - Stored Max, - class P, // promotion polic - class E // exception policy -> -class safe_base; - -template< - class T, - T Min, - T Max, - class P, - class E -> -struct is_safe > : public std::true_type -{}; - -template< - class T, - T Min, - T Max, - class P, - class E -> -struct get_promotion_policy > { - using type = P; -}; - -template< - class T, - T Min, - T Max, - class P, - class E -> -struct get_exception_policy > { - using type = E; -}; - -template< - class T, - T Min, - T Max, - class P, - class E -> -struct base_type > { - using type = T; -}; - -template< - class T, - T Min, - T Max, - class P, - class E -> -constexpr T base_value( - const safe_base & st -) { - return static_cast(st); -} - -template< - typename T, - T N, - class P, // promotion policy - class E // exception policy -> -class safe_literal_impl; - -// works for both GCC and clang -#if BOOST_CLANG==1 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wmismatched-tags" -#endif - -///////////////////////////////////////////////////////////////// -// Main implementation - -template< - class Stored, - Stored Min, - Stored Max, - class P, // promotion polic - class E // exception policy -> -class safe_base { -private: - BOOST_CONCEPT_ASSERT((PromotionPolicy

)); - BOOST_CONCEPT_ASSERT((ExceptionPolicy)); - Stored m_t; - - template< - class StoredX, - StoredX MinX, - StoredX MaxX, - class PX, // promotion polic - class EX // exception policy - > - friend class safe_base; - - friend class std::numeric_limits; - - template - constexpr Stored validated_cast(const T & t) const; - - template - constexpr Stored validated_cast( - const safe_literal_impl & t - ) const; - - // stream support - - template - void output(std::basic_ostream & os) const; - - // note usage of friend declaration to mark function as - // a global function rather than a member function. If - // this is not done, the compiler will confuse this with - // a member operator overload on the << operator. Weird - // I know. But it's documented here - // http://en.cppreference.com/w/cpp/language/friend - // under the heading "Template friend operators" - template - friend std::basic_ostream & - operator<<( - std::basic_ostream & os, - const safe_base & t - ){ - t.output(os); - return os; - } - - template - void input(std::basic_istream & is); - - // see above - template - friend inline std::basic_istream & - operator>>( - std::basic_istream & is, - safe_base & t - ){ - t.input(is); - return is; - } - -public: - //////////////////////////////////////////////////////////// - // constructors - - struct skip_validation{}; - - constexpr explicit safe_base(const Stored & rhs, skip_validation); - - constexpr safe_base(); - - // construct an instance of a safe type - // from an instance of a convertible underlying type. - - template - constexpr /*explicit*/ safe_base( - const T & t, - typename std::enable_if< - is_safe::value, - bool - >::type = true - ); - - template - constexpr /*explicit*/ safe_base( - const T & t, - typename std::enable_if< - std::is_integral::value, - bool - >::type = true - ); - - template - constexpr /*explicit*/ safe_base( - const std::integral_constant & - ); - - // note: Rule of Five. Supply all or none of the following - // a) user-defined destructor - ~safe_base() = default; - // b) copy-constructor - constexpr safe_base(const safe_base &) = default; - // c) copy-assignment - constexpr safe_base & operator=(const safe_base &) = default; - // d) move constructor - constexpr safe_base(safe_base &&) = default; - // e) move assignment operator - constexpr safe_base & operator=(safe_base &&) = default; - - ///////////////////////////////////////////////////////////////// - // casting operators for intrinsic integers - // convert to any type which is not safe. safe types need to be - // excluded to prevent ambiguous function selection which - // would otherwise occur. validity of safe types is checked in - // the constructor of safe types - template< - class R, - typename std::enable_if< - ! boost::safe_numerics::is_safe::value, - int - >::type = 0 - > - constexpr /*explicit*/ operator R () const; - - constexpr /*explicit*/ operator Stored () const; - - ///////////////////////////////////////////////////////////////// - // modification binary operators - template - constexpr safe_base & - operator=(const T & rhs){ - m_t = validated_cast(rhs); - return *this; - } - - // required to passify VS2017 - constexpr safe_base & - operator=(const Stored & rhs){ - m_t = validated_cast(rhs); - return *this; - } - - // mutating unary operators - safe_base & operator++(){ // pre increment - return *this = *this + 1; - } - safe_base & operator--(){ // pre decrement - return *this = *this - 1; - } - safe_base operator++(int){ // post increment - safe_base old_t = *this; - ++(*this); - return old_t; - } - safe_base operator--(int){ // post decrement - safe_base old_t = *this; - --(*this); - return old_t; - } - // non mutating unary operators - constexpr auto operator+() const { // unary plus - return *this; - } - // after much consideration, I've permited the resulting value of a unary - // - to change the type. The C++ standard does invoke integral promotions - // so it's changing the type as well. - - /* section 5.3.1 &8 of the C++ standard - The operand of the unary - operator shall have arithmetic or unscoped - enumeration type and the result is the negation of its operand. Integral - promotion is performed on integral or enumeration operands. The negative - of an unsigned quantity is computed by subtracting its value from 2n, - where n is the number of bits in the promoted operand. The type of the - result is the type of the promoted operand. - */ - constexpr auto operator-() const { // unary minus - // if this is a unsigned type and the promotion policy is native - // the result will be unsigned. But then the operation will fail - // according to the requirements of arithmetic correctness. - // if this is an unsigned type and the promotion policy is automatic. - // the result will be signed. - return 0 - *this; - } - /* section 5.3.1 &10 of the C++ standard - The operand of ~ shall have integral or unscoped enumeration type; - the result is the ones’ complement of its operand. Integral promotions - are performed. The type of the result is the type of the promoted operand. - */ - constexpr auto operator~() const { // complement - return ~Stored(0u) ^ *this; - } -}; - -} // safe_numerics -} // boost - -///////////////////////////////////////////////////////////////// -// numeric limits for safe etc. - -#include - -namespace std { - -template< - class T, - T Min, - T Max, - class P, - class E -> -class numeric_limits > - : public std::numeric_limits -{ - using SB = boost::safe_numerics::safe_base; -public: - constexpr static SB lowest() noexcept { - return SB(Min, typename SB::skip_validation()); - } - constexpr static SB min() noexcept { - return SB(Min, typename SB::skip_validation()); - } - constexpr static SB max() noexcept { - return SB(Max, typename SB::skip_validation()); - } -}; - -} // std - -#if BOOST_CLANG==1 -#pragma GCC diagnostic pop -#endif - -#endif // BOOST_NUMERIC_SAFE_BASE_HPP diff --git a/boost/safe_numerics/safe_base_operations.hpp b/boost/safe_numerics/safe_base_operations.hpp deleted file mode 100644 index d97ac92..0000000 --- a/boost/safe_numerics/safe_base_operations.hpp +++ /dev/null @@ -1,1745 +0,0 @@ -#ifndef BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP -#define BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP - -// Copyright (c) 2012 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include // is_base_of, is_same, is_floating_point, conditional -#include // max -#include - -#include - -#include // lazy_enable_if -#include -#include - -#include "checked_integer.hpp" -#include "checked_result.hpp" -#include "safe_base.hpp" - -#include "interval.hpp" -#include "utility.hpp" - -namespace boost { -namespace safe_numerics { - -///////////////////////////////////////////////////////////////// -// validation - -template -struct validate_detail { - using r_type = checked_result; - - struct exception_possible { - template - constexpr static R return_value( - const T & t - ){ - // INT08-C - const r_type rx = heterogeneous_checked_operation< - R, - Min, - Max, - typename base_type::type, - dispatch_and_return - >::cast(t); - - return rx; - } - }; - struct exception_not_possible { - template - constexpr static R return_value( - const T & t - ){ - return static_cast(base_value(t)); - } - }; - - template - constexpr static R return_value(const T & t){ - - constexpr const interval t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - constexpr const interval r_interval{r_type(Min), r_type(Max)}; - - static_assert( - true != static_cast(r_interval.excludes(t_interval)), - "can't cast from ranges that don't overlap" - ); - - return std::conditional< - static_cast(r_interval.includes(t_interval)), - exception_not_possible, - exception_possible - >::type::return_value(t); - } -}; - -template -template -constexpr Stored safe_base:: -validated_cast(const T & t) const { - return validate_detail::return_value(t); -} - -template -template -constexpr Stored safe_base:: -validated_cast(const safe_literal_impl &) const { - constexpr const interval this_interval{}; - // if static values don't overlap, the program can never function - static_assert( - this_interval.includes(N), - "safe type cannot be constructed from this value" - ); - return static_cast(N); -} - -///////////////////////////////////////////////////////////////// -// constructors - -template - constexpr /*explicit*/ safe_base::safe_base( - const Stored & rhs, - skip_validation -) : - m_t(rhs) -{} - -template -constexpr /*explicit*/ safe_base::safe_base(){ - dispatch( - "safe values must be initialized" - ); -} - -// construct an instance of a safe type -// from an instance of a convertible underlying type. -template -template -constexpr /*explicit*/ safe_base::safe_base( - const T & t, - typename std::enable_if< - is_safe::value, - bool - >::type -) : - m_t(validated_cast(t)) -{} - -template -template -constexpr /*explicit*/ safe_base::safe_base( - const T & t, - typename std::enable_if< - std::is_integral::value, - bool - >::type -) : - m_t(validated_cast(t)) -{} - -template -template -constexpr /*explicit*/ safe_base::safe_base( - - const std::integral_constant & -) : - m_t(validated_cast(value)) -{} - -///////////////////////////////////////////////////////////////// -// casting operators - -// cast to a builtin type from a safe type -template< class Stored, Stored Min, Stored Max, class P, class E> -template< - class R, - typename std::enable_if< - ! boost::safe_numerics::is_safe::value, - int - >::type -> -constexpr safe_base:: -operator R () const { - // if static values don't overlap, the program can never function - #if 1 - constexpr const interval r_interval; - constexpr const interval this_interval(Min, Max); - static_assert( - ! r_interval.excludes(this_interval), - "safe type cannot be constructed with this type" - ); - #endif - - return validate_detail< - R, - std::numeric_limits::min(), - std::numeric_limits::max(), - E - >::return_value(*this); -} - -// cast to the underlying builtin type from a safe type -template -constexpr safe_base:: -operator Stored () const { - return m_t; -} - -///////////////////////////////////////////////////////////////// -// binary operators - -template -struct common_exception_policy { - static_assert(is_safe::value || is_safe::value, - "at least one type must be a safe type" - ); - - using t_exception_policy = typename get_exception_policy::type; - using u_exception_policy = typename get_exception_policy::type; - - static_assert( - std::is_same::value - || std::is_same::value - || std::is_same::value, - "if the exception policies are different, one must be void!" - ); - - static_assert( - ! (std::is_same::value - && std::is_same::value), - "at least one exception policy must not be void" - ); - - using type = - typename std::conditional< - !std::is_same::value, - u_exception_policy, - typename std::conditional< - !std::is_same::value, - t_exception_policy, - // - void - >::type >::type; - - static_assert( - !std::is_same::value, - "exception_policy is void" - ); -}; - -template -struct common_promotion_policy { - static_assert(is_safe::value || is_safe::value, - "at least one type must be a safe type" - ); - using t_promotion_policy = typename get_promotion_policy::type; - using u_promotion_policy = typename get_promotion_policy::type; - static_assert( - std::is_same::value - ||std::is_same::value - ||std::is_same::value, - "if the promotion policies are different, one must be void!" - ); - static_assert( - ! (std::is_same::value - && std::is_same::value), - "at least one promotion policy must not be void" - ); - - using type = - typename std::conditional< - ! std::is_same::value, - u_promotion_policy, - typename std::conditional< - ! std::is_same::value, - t_promotion_policy, - // - void - >::type >::type; - - static_assert( - ! std::is_same::value, - "promotion_policy is void" - ); - -}; - -// give the resultant base type, figure out what the final result -// type will be. Note we currently need this because we support -// return of only safe integer types. Someday ..., we'll support -// all other safe types including float and user defined ones. - -// helper - cast arguments to binary operators to a specified -// result type - -template -std::pair -constexpr static casting_helper(const T & t, const U & u){ - using r_type = checked_result; - const r_type tx = heterogeneous_checked_operation< - R, - std::numeric_limits::min(), - std::numeric_limits::max(), - typename base_type::type, - dispatch_and_return - >::cast(base_value(t)); - const R tr = tx.exception() - ? static_cast(t) - : tx.m_r; - - const r_type ux = heterogeneous_checked_operation< - R, - std::numeric_limits::min(), - std::numeric_limits::max(), - typename base_type::type, - dispatch_and_return - >::cast(base_value(u)); - const R ur = ux.exception() - ? static_cast(u) - : ux.m_r; - return std::pair(tr, ur); -} - -// Note: the following global operators will be found via -// argument dependent lookup. - -///////////////////////////////////////////////////////////////// -// addition - -template -struct addition_result { -private: - using promotion_policy = typename common_promotion_policy::type; - using result_base_type = - typename promotion_policy::template addition_result::type; - - // if exception not possible - constexpr static result_base_type - return_value(const T & t, const U & u, std::false_type){ - return - static_cast(base_value(t)) - + static_cast(base_value(u)); - } - - // if exception possible - using exception_policy = typename common_exception_policy::type; - - using r_type = checked_result; - - constexpr static result_base_type - return_value(const T & t, const U & u, std::true_type){ - const std::pair r = casting_helper< - exception_policy, - result_base_type - >(t, u); - - const r_type rx = checked_operation< - result_base_type, - dispatch_and_return - >::add(r.first, r.second); - - return - rx.exception() - ? r.first + r.second - : rx.m_r; - } - - using r_type_interval_t = interval; - - constexpr static const r_type_interval_t get_r_type_interval(){ - constexpr const r_type_interval_t t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - constexpr const r_type_interval_t u_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - return t_interval + u_interval; - } - constexpr static const r_type_interval_t r_type_interval = get_r_type_interval(); - - constexpr static const interval return_interval{ - r_type_interval.l.exception() - ? std::numeric_limits::min() - : static_cast(r_type_interval.l), - r_type_interval.u.exception() - ? std::numeric_limits::max() - : static_cast(r_type_interval.u) - }; - - constexpr static bool exception_possible(){ - if(r_type_interval.l.exception()) - return true; - if(r_type_interval.u.exception()) - return true; - if(! return_interval.includes(r_type_interval)) - return true; - return false; - } - - constexpr static auto rl = return_interval.l; - constexpr static auto ru = return_interval.u; - -public: - using type = - safe_base< - result_base_type, - rl, - ru, - promotion_policy, - exception_policy - >; - - constexpr static type return_value(const T & t, const U & u){ - return type( - return_value( - t, - u, - std::integral_constant() - ), - typename type::skip_validation() - ); - } -}; - -template -typename boost::lazy_enable_if_c< - is_safe::value || is_safe::value, - addition_result ->::type -constexpr operator+(const T & t, const U & u){ - return addition_result::return_value(t, u); -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - T ->::type -constexpr operator+=(T & t, const U & u){ - t = static_cast(t + u); - return t; -} - -///////////////////////////////////////////////////////////////// -// subtraction - -template -struct subtraction_result { -private: - using promotion_policy = typename common_promotion_policy::type; - using result_base_type = - typename promotion_policy::template subtraction_result::type; - - // if exception not possible - constexpr static result_base_type - return_value(const T & t, const U & u, std::false_type){ - return - static_cast(base_value(t)) - - static_cast(base_value(u)); - } - - // if exception possible - using exception_policy = typename common_exception_policy::type; - - using r_type = checked_result; - - constexpr static result_base_type - return_value(const T & t, const U & u, std::true_type){ - const std::pair r = casting_helper< - exception_policy, - result_base_type - >(t, u); - - const r_type rx = checked_operation< - result_base_type, - dispatch_and_return - >::subtract(r.first, r.second); - - return - rx.exception() - ? r.first + r.second - : rx.m_r; - } - using r_type_interval_t = interval; - - constexpr static const r_type_interval_t get_r_type_interval(){ - constexpr const r_type_interval_t t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr const r_type_interval_t u_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - return t_interval - u_interval; - } - static constexpr const r_type_interval_t r_type_interval = get_r_type_interval(); - - constexpr static const interval return_interval{ - r_type_interval.l.exception() - ? std::numeric_limits::min() - : static_cast(r_type_interval.l), - r_type_interval.u.exception() - ? std::numeric_limits::max() - : static_cast(r_type_interval.u) - }; - - constexpr static bool exception_possible(){ - if(r_type_interval.l.exception()) - return true; - if(r_type_interval.u.exception()) - return true; - if(! return_interval.includes(r_type_interval)) - return true; - return false; - } - -public: - constexpr static auto rl = return_interval.l; - constexpr static auto ru = return_interval.u; - - using type = - safe_base< - result_base_type, - rl, - ru, - promotion_policy, - exception_policy - >; - - constexpr static type return_value(const T & t, const U & u){ - return type( - return_value( - t, - u, - std::integral_constant() - ), - typename type::skip_validation() - ); - } -}; - -template -typename boost::lazy_enable_if_c< - is_safe::value || is_safe::value, - subtraction_result ->::type -constexpr operator-(const T & t, const U & u){ - return subtraction_result::return_value(t, u); -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - T ->::type -constexpr operator-=(T & t, const U & u){ - t = static_cast(t - u); - return t; -} - -///////////////////////////////////////////////////////////////// -// multiplication - -template -struct multiplication_result { -private: - using promotion_policy = typename common_promotion_policy::type; - using result_base_type = - typename promotion_policy::template multiplication_result::type; - - // if exception not possible - constexpr static result_base_type - return_value(const T & t, const U & u, std::false_type){ - return - static_cast(base_value(t)) - * static_cast(base_value(u)); - } - - // if exception possible - using exception_policy = typename common_exception_policy::type; - - using r_type = checked_result; - - constexpr static result_base_type - return_value(const T & t, const U & u, std::true_type){ - const std::pair r = casting_helper< - exception_policy, - result_base_type - >(t, u); - - const r_type rx = checked_operation< - result_base_type, - dispatch_and_return - >::multiply(r.first, r.second); - - return - rx.exception() - ? r.first * r.second - : rx.m_r; - } - - using r_type_interval_t = interval; - - constexpr static r_type_interval_t get_r_type_interval(){ - constexpr const r_type_interval_t t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr const r_type_interval_t u_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - return t_interval * u_interval; - } - - static constexpr const r_type_interval_t r_type_interval = get_r_type_interval(); - - constexpr static const interval return_interval{ - r_type_interval.l.exception() - ? std::numeric_limits::min() - : static_cast(r_type_interval.l), - r_type_interval.u.exception() - ? std::numeric_limits::max() - : static_cast(r_type_interval.u) - }; - - constexpr static bool exception_possible(){ - if(r_type_interval.l.exception()) - return true; - if(r_type_interval.u.exception()) - return true; - if(! return_interval.includes(r_type_interval)) - return true; - return false; - } - - constexpr static auto rl = return_interval.l; - constexpr static auto ru = return_interval.u; - -public: - using type = - safe_base< - result_base_type, - rl, - ru, - promotion_policy, - exception_policy - >; - - constexpr static type return_value(const T & t, const U & u){ - return type( - return_value( - t, - u, - std::integral_constant() - ), - typename type::skip_validation() - ); - } -}; - -template -typename boost::lazy_enable_if_c< - is_safe::value || is_safe::value, - multiplication_result ->::type -constexpr operator*(const T & t, const U & u){ - // argument dependent lookup should guarentee that we only get here - return multiplication_result::return_value(t, u); -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - T ->::type -constexpr operator*=(T & t, const U & u){ - t = static_cast(t * u); - return t; -} - -///////////////////////////////////////////////////////////////// -// division - -// key idea here - result will never be larger than T -template -struct division_result { -private: - using promotion_policy = typename common_promotion_policy::type; - using result_base_type = - typename promotion_policy::template division_result::type; - - // if exception not possible - constexpr static result_base_type - return_value(const T & t, const U & u, std::false_type){ - return - static_cast(base_value(t)) - / static_cast(base_value(u)); - } - - // if exception possible - using exception_policy = typename common_exception_policy::type; - - constexpr static int bits = std::min( - std::numeric_limits::digits, - std::max(std::initializer_list{ - std::numeric_limits::digits, - std::numeric_limits::type>::digits, - std::numeric_limits::type>::digits - }) + (std::numeric_limits::is_signed ? 1 : 0) - ); - - using r_type = checked_result; - - constexpr static result_base_type - return_value(const T & t, const U & u, std::true_type){ - using temp_base = typename std::conditional< - std::numeric_limits::is_signed, - typename boost::int_t::least, - typename boost::uint_t::least - >::type; - using t_type = checked_result; - - const std::pair r = casting_helper< - exception_policy, - temp_base - >(t, u); - - const t_type rx = checked_operation< - temp_base, - dispatch_and_return - >::divide(r.first, r.second); - - return - rx.exception() - ? r.first / r.second - : rx; - } - using r_type_interval_t = interval; - - constexpr static r_type_interval_t t_interval(){ - return r_type_interval_t{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - }; - - constexpr static r_type_interval_t u_interval(){ - return r_type_interval_t{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - }; - - constexpr static r_type_interval_t get_r_type_interval(){ - constexpr const r_type_interval_t t = t_interval(); - constexpr const r_type_interval_t u = u_interval(); - - if(u.u < r_type(0) || u.l > r_type(0)) - return t / u; - return utility::minmax( - std::initializer_list { - t.l / u.l, - t.l / r_type(-1), - t.l / r_type(1), - t.l / u.u, - t.u / u.l, - t.u / r_type(-1), - t.u / r_type(1), - t.u / u.u, - } - ); - } - - static constexpr const r_type_interval_t r_type_interval = get_r_type_interval(); - - constexpr static const interval return_interval{ - r_type_interval.l.exception() - ? std::numeric_limits::min() - : static_cast(r_type_interval.l), - r_type_interval.u.exception() - ? std::numeric_limits::max() - : static_cast(r_type_interval.u) - }; - - constexpr static bool exception_possible(){ - constexpr const r_type_interval_t ri = get_r_type_interval(); - constexpr const r_type_interval_t ui = u_interval(); - return - static_cast(ui.includes(r_type(0))) - || ri.l.exception() - || ri.u.exception(); - } - - constexpr static auto rl = return_interval.l; - constexpr static auto ru = return_interval.u; - -public: - using type = - safe_base< - result_base_type, - rl, - ru, - promotion_policy, - exception_policy - >; - - constexpr static type return_value(const T & t, const U & u){ - return type( - return_value( - t, - u, - std::integral_constant() - ), - typename type::skip_validation() - ); - } -}; - -template -typename boost::lazy_enable_if_c< - is_safe::value || is_safe::value, - division_result ->::type -constexpr operator/(const T & t, const U & u){ - return division_result::return_value(t, u); -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - T ->::type -constexpr operator/=(T & t, const U & u){ - t = static_cast(t / u); - return t; -} - -///////////////////////////////////////////////////////////////// -// modulus - -template -struct modulus_result { -private: - using promotion_policy = typename common_promotion_policy::type; - using result_base_type = typename promotion_policy::template modulus_result::type; - - // if exception not possible - constexpr static result_base_type - return_value(const T & t, const U & u, std::false_type){ - return - static_cast(base_value(t)) - % static_cast(base_value(u)); - } - - // if exception possible - using exception_policy = typename common_exception_policy::type; - - constexpr static int bits = std::min( - std::numeric_limits::digits, - std::max(std::initializer_list{ - std::numeric_limits::digits, - std::numeric_limits::type>::digits, - std::numeric_limits::type>::digits - }) + (std::numeric_limits::is_signed ? 1 : 0) - ); - - using r_type = checked_result; - - constexpr static result_base_type - return_value(const T & t, const U & u, std::true_type){ - using temp_base = typename std::conditional< - std::numeric_limits::is_signed, - typename boost::int_t::least, - typename boost::uint_t::least - >::type; - using t_type = checked_result; - - const std::pair r = casting_helper< - exception_policy, - temp_base - >(t, u); - - const t_type rx = checked_operation< - temp_base, - dispatch_and_return - >::modulus(r.first, r.second); - - return - rx.exception() - ? r.first % r.second - : rx; - } - - using r_type_interval_t = interval; - - constexpr static const r_type_interval_t t_interval(){ - return r_type_interval_t{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - }; - - constexpr static const r_type_interval_t u_interval(){ - return r_type_interval_t{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - }; - - constexpr static const r_type_interval_t get_r_type_interval(){ - constexpr const r_type_interval_t t = t_interval(); - constexpr const r_type_interval_t u = u_interval(); - - if(u.u < r_type(0) - || u.l > r_type(0)) - return t % u; - return utility::minmax( - std::initializer_list { - t.l % u.l, - t.l % r_type(-1), - t.l % r_type(1), - t.l % u.u, - t.u % u.l, - t.u % r_type(-1), - t.u % r_type(1), - t.u % u.u, - } - ); - } - - static constexpr const r_type_interval_t r_type_interval = get_r_type_interval(); - - constexpr static const interval return_interval{ - r_type_interval.l.exception() - ? std::numeric_limits::min() - : static_cast(r_type_interval.l), - r_type_interval.u.exception() - ? std::numeric_limits::max() - : static_cast(r_type_interval.u) - }; - - constexpr static bool exception_possible(){ - constexpr const r_type_interval_t ri = get_r_type_interval(); - constexpr const r_type_interval_t ui = u_interval(); - return - static_cast(ui.includes(r_type(0))) - || ri.l.exception() - || ri.u.exception(); - } - - constexpr static auto rl = return_interval.l; - constexpr static auto ru = return_interval.u; - -public: - using type = - safe_base< - result_base_type, - rl, - ru, - promotion_policy, - exception_policy - >; - - constexpr static type return_value(const T & t, const U & u){ - return type( - return_value( - t, - u, - std::integral_constant() - ), - typename type::skip_validation() - ); - } -}; - -template -typename boost::lazy_enable_if_c< - is_safe::value || is_safe::value, - modulus_result ->::type -constexpr operator%(const T & t, const U & u){ - // see https://en.wikipedia.org/wiki/Modulo_operation - return modulus_result::return_value(t, u); -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - T ->::type -constexpr operator%=(T & t, const U & u){ - t = static_cast(t % u); - return t; -} - -///////////////////////////////////////////////////////////////// -// comparison - -// less than - -template -struct less_than_result { -private: - using promotion_policy = typename common_promotion_policy::type; - - using result_base_type = - typename promotion_policy::template comparison_result::type; - - // if exception not possible - constexpr static bool - return_value(const T & t, const U & u, std::false_type){ - return - static_cast(base_value(t)) - < static_cast(base_value(u)); - } - - using exception_policy = typename common_exception_policy::type; - - using r_type = checked_result; - - // if exception possible - constexpr static bool - return_value(const T & t, const U & u, std::true_type){ - const std::pair r = casting_helper< - exception_policy, - result_base_type - >(t, u); - - return safe_compare::less_than(r.first, r.second); - } - - using r_type_interval_t = interval; - - constexpr static bool interval_open(const r_type_interval_t & t){ - return t.l.exception() || t.u.exception(); - } - -public: - constexpr static bool - return_value(const T & t, const U & u){ - constexpr const r_type_interval_t t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - constexpr const r_type_interval_t u_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - if(t_interval < u_interval) - return true; - if(t_interval > u_interval) - return false; - - constexpr bool exception_possible - = interval_open(t_interval) || interval_open(u_interval); - - return return_value( - t, - u, - std::integral_constant() - ); - } -}; - -template -typename std::enable_if< - is_safe::value || is_safe::value, - bool ->::type -constexpr operator<(const T & lhs, const U & rhs) { - return less_than_result::return_value(lhs, rhs); -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - bool ->::type -constexpr operator>(const T & lhs, const U & rhs) { - return rhs < lhs; -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - bool ->::type -constexpr operator>=(const T & lhs, const U & rhs) { - return ! ( lhs < rhs ); -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - bool ->::type -constexpr operator<=(const T & lhs, const U & rhs) { - return ! ( lhs > rhs ); -} - -// equal - -template -struct equal_result { -private: - using promotion_policy = typename common_promotion_policy::type; - - using result_base_type = - typename promotion_policy::template comparison_result::type; - - // if exception not possible - constexpr static bool - return_value(const T & t, const U & u, std::false_type){ - return - static_cast(base_value(t)) - == static_cast(base_value(u)); - } - - using exception_policy = typename common_exception_policy::type; - - using r_type = checked_result; - - // exception possible - constexpr static bool - return_value(const T & t, const U & u, std::true_type){ - const std::pair r = casting_helper< - exception_policy, - result_base_type - >(t, u); - - return safe_compare::equal(r.first, r.second); - } - - using r_type_interval = interval; - - constexpr static bool interval_open(const r_type_interval & t){ - return t.l.exception() || t.u.exception(); - } - -public: - constexpr static bool - return_value(const T & t, const U & u){ - constexpr const r_type_interval t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr const r_type_interval u_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - if(! intersect(t_interval, u_interval)) - return false; - - constexpr bool exception_possible - = interval_open(t_interval) || interval_open(u_interval); - - return return_value( - t, - u, - std::integral_constant() - ); - } -}; - -template -typename std::enable_if< - is_safe::value || is_safe::value, - bool ->::type -constexpr operator==(const T & lhs, const U & rhs) { - return equal_result::return_value(lhs, rhs); -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - bool ->::type -constexpr operator!=(const T & lhs, const U & rhs) { - return ! (lhs == rhs); -} - -///////////////////////////////////////////////////////////////// -// shift operators - -// left shift -template -struct left_shift_result { -private: - using promotion_policy = typename common_promotion_policy::type; - using result_base_type = - typename promotion_policy::template left_shift_result::type; - - // if exception not possible - constexpr static result_base_type - return_value(const T & t, const U & u, std::false_type){ - return - static_cast(base_value(t)) - << static_cast(base_value(u)); - } - - // exception possible - using exception_policy = typename common_exception_policy::type; - - using r_type = checked_result; - - constexpr static result_base_type - return_value(const T & t, const U & u, std::true_type){ - const std::pair r = casting_helper< - exception_policy, - result_base_type - >(t, u); - - const r_type rx = checked_operation< - result_base_type, - dispatch_and_return - >::left_shift(r.first, r.second); - - return - rx.exception() - ? r.first << r.second - : rx.m_r; - } - - using r_type_interval_t = interval; - - constexpr static r_type_interval_t get_r_type_interval(){ - constexpr const r_type_interval_t t_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - - constexpr const r_type_interval_t u_interval{ - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - }; - return (t_interval << u_interval); - } - - static constexpr const r_type_interval_t r_type_interval = get_r_type_interval(); - - constexpr static const interval return_interval{ - r_type_interval.l.exception() - ? std::numeric_limits::min() - : static_cast(r_type_interval.l), - r_type_interval.u.exception() - ? std::numeric_limits::max() - : static_cast(r_type_interval.u) - }; - - constexpr static bool exception_possible(){ - if(r_type_interval.l.exception()) - return true; - if(r_type_interval.u.exception()) - return true; - if(! return_interval.includes(r_type_interval)) - return true; - return false; - } - - constexpr static auto rl = return_interval.l; - constexpr static auto ru = return_interval.u; - -public: - using type = - safe_base< - result_base_type, - rl, - ru, - promotion_policy, - exception_policy - >; - - constexpr static type return_value(const T & t, const U & u){ - return type( - return_value( - t, - u, - std::integral_constant() - ), - typename type::skip_validation() - ); - } -}; - -template -typename boost::lazy_enable_if_c< - // handle safe << int, int << safe, safe << safe - // exclude std::ostream << ... - (! std::is_base_of::value) - && (is_safe::value || is_safe::value), - left_shift_result ->::type -constexpr operator<<(const T & t, const U & u){ - // INT13-CPP - // C++ standards document N4618 & 5.8.2 - static_assert( - std::numeric_limits::is_integer, "shifted value must be an integer" - ); - static_assert( - std::numeric_limits::is_integer, "shift amount must be an integer" - ); - return left_shift_result::return_value(t, u); -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - T ->::type -constexpr operator<<=(T & t, const U & u){ - t = static_cast(t << u); - return t; -} - -// right shift -template -struct right_shift_result { - using promotion_policy = typename common_promotion_policy::type; - using result_base_type = - typename promotion_policy::template right_shift_result::type; - - // if exception not possible - constexpr static result_base_type - return_value(const T & t, const U & u, std::false_type){ - return - static_cast(base_value(t)) - >> static_cast(base_value(u)); - } - - // exception possible - using exception_policy = typename common_exception_policy::type; - - using r_type = checked_result; - - constexpr static result_base_type - return_value(const T & t, const U & u, std::true_type){ - const std::pair r = casting_helper< - exception_policy, - result_base_type - >(t, u); - - const r_type rx = checked_operation< - result_base_type, - dispatch_and_return - >::right_shift(r.first, r.second); - - return - rx.exception() - ? r.first >> r.second - : rx.m_r; - } - - using r_type_interval_t = interval; - - constexpr static r_type_interval_t t_interval(){ - return r_type_interval_t( - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - ); - }; - - constexpr static r_type_interval_t u_interval(){ - return r_type_interval_t( - checked::cast(base_value(std::numeric_limits::min())), - checked::cast(base_value(std::numeric_limits::max())) - ); - } - constexpr static r_type_interval_t get_r_type_interval(){; - return (t_interval() >> u_interval()); - } - - static constexpr const r_type_interval_t r_type_interval = get_r_type_interval(); - - constexpr static const interval return_interval{ - r_type_interval.l.exception() - ? std::numeric_limits::min() - : static_cast(r_type_interval.l), - r_type_interval.u.exception() - ? std::numeric_limits::max() - : static_cast(r_type_interval.u) - }; - - constexpr static bool exception_possible(){ - constexpr const r_type_interval_t ri = r_type_interval; - constexpr const r_type_interval_t ti = t_interval(); - constexpr const r_type_interval_t ui = u_interval(); - return static_cast( - // note undesirable coupling with checked::shift right here ! - ui.u > checked_result( - std::numeric_limits::digits - ) - || ti.l < checked_result(0) - || ui.l < checked_result(0) - || ri.l.exception() - || ri.u.exception() - ); - } - - constexpr static auto rl = return_interval.l; - constexpr static auto ru = return_interval.u; - -public: - using type = - safe_base< - result_base_type, - rl, - ru, - promotion_policy, - exception_policy - >; - - constexpr static type return_value(const T & t, const U & u){ - return type( - return_value( - t, - u, - std::integral_constant() - ), - typename type::skip_validation() - ); - } -}; - -template -typename boost::lazy_enable_if_c< - (! std::is_base_of::value) - && (is_safe::value || is_safe::value), - right_shift_result ->::type -constexpr operator>>(const T & t, const U & u){ - // INT13-CPP - static_assert( - std::numeric_limits::is_integer, "shifted value must be an integer" - ); - static_assert( - std::numeric_limits::is_integer, "shift amount must be an integer" - ); - return right_shift_result::return_value(t, u); -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - T ->::type -constexpr operator>>=(T & t, const U & u){ - t = static_cast(t >> u); - return t; -} - -///////////////////////////////////////////////////////////////// -// bitwise operators - -// operator | -template -struct bitwise_or_result { -private: - using promotion_policy = typename common_promotion_policy::type; - using result_base_type = - typename promotion_policy::template bitwise_or_result::type; - - // according to the C++ standard, the bitwise operators are executed as if - // the operands are consider a logical array of bits. That is, there is no - // sense that these are signed numbers. - - using r_type = typename std::make_unsigned::type; - using r_type_interval_t = interval; - - #if 0 - // breaks compilation for earlier versions of clant - constexpr static const r_type_interval_t r_interval{ - r_type(0), - utility::round_out( - std::max( - static_cast(base_value(std::numeric_limits::max())), - static_cast(base_value(std::numeric_limits::max())) - ) - ) - }; - #endif - - using exception_policy = typename common_exception_policy::type; - -public: - // lazy_enable_if_c depends on this - using type = safe_base< - result_base_type, - //r_interval.l, - r_type(0), - //r_interval.u, - utility::round_out( - std::max( - static_cast(base_value(std::numeric_limits::max())), - static_cast(base_value(std::numeric_limits::max())) - ) - ), - promotion_policy, - exception_policy - >; - - constexpr static type return_value(const T & t, const U & u){ - return type( - static_cast(base_value(t)) - | static_cast(base_value(u)), - typename type::skip_validation() - ); - } -}; - -template -typename boost::lazy_enable_if_c< - is_safe::value || is_safe::value, - bitwise_or_result ->::type -constexpr operator|(const T & t, const U & u){ - return bitwise_or_result::return_value(t, u); -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - T ->::type -constexpr operator|=(T & t, const U & u){ - t = static_cast(t | u); - return t; -} - -// operator & -template -struct bitwise_and_result { -private: - using promotion_policy = typename common_promotion_policy::type; - using result_base_type = - typename promotion_policy::template bitwise_and_result::type; - - // according to the C++ standard, the bitwise operators are executed as if - // the operands are consider a logical array of bits. That is, there is no - // sense that these are signed numbers. - - using r_type = typename std::make_unsigned::type; - using r_type_interval_t = interval; - - #if 0 - // breaks compilation for earlier versions of clant - constexpr static const r_type_interval_t r_interval{ - r_type(0), - utility::round_out( - std::min( - static_cast(base_value(std::numeric_limits::max())), - static_cast(base_value(std::numeric_limits::max())) - ) - ) - }; - #endif - using exception_policy = typename common_exception_policy::type; - -public: - // lazy_enable_if_c depends on this - using type = safe_base< - result_base_type, - //r_interval.l, - r_type(0), - //r_interval.u, - utility::round_out( - std::min( - static_cast(base_value(std::numeric_limits::max())), - static_cast(base_value(std::numeric_limits::max())) - ) - ), - promotion_policy, - exception_policy - >; - - constexpr static type return_value(const T & t, const U & u){ - return type( - static_cast(base_value(t)) - & static_cast(base_value(u)), - typename type::skip_validation() - ); - } -}; - -template -typename boost::lazy_enable_if_c< - is_safe::value || is_safe::value, - bitwise_and_result ->::type -constexpr operator&(const T & t, const U & u){ - return bitwise_and_result::return_value(t, u); -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - T ->::type -constexpr operator&=(T & t, const U & u){ - t = static_cast(t & u); - return t; -} - -// operator ^ -template -struct bitwise_xor_result { - using promotion_policy = typename common_promotion_policy::type; - using result_base_type = - typename promotion_policy::template bitwise_xor_result::type; - - // according to the C++ standard, the bitwise operators are executed as if - // the operands are consider a logical array of bits. That is, there is no - // sense that these are signed numbers. - - using r_type = typename std::make_unsigned::type; - using r_type_interval_t = interval; - - #if 0 - // breaks compilation for earlier versions of clant - constexpr static const r_type_interval_t r_interval{ - r_type(0), - utility::round_out( - std::max( - static_cast(base_value(std::numeric_limits::max())), - static_cast(base_value(std::numeric_limits::max())) - ) - ) - }; - #endif - - using exception_policy = typename common_exception_policy::type; - -public: - // lazy_enable_if_c depends on this - using type = safe_base< - result_base_type, - //r_interval.l, - r_type(0), - //r_interval.u, - utility::round_out( - std::max( - static_cast(base_value(std::numeric_limits::max())), - static_cast(base_value(std::numeric_limits::max())) - ) - ), - promotion_policy, - exception_policy - >; - - constexpr static type return_value(const T & t, const U & u){ - return type( - static_cast(base_value(t)) - ^ static_cast(base_value(u)), - typename type::skip_validation() - ); - } -}; - -template -typename boost::lazy_enable_if_c< - is_safe::value || is_safe::value, - bitwise_xor_result ->::type -constexpr operator^(const T & t, const U & u){ - return bitwise_xor_result::return_value(t, u); -} - -template -typename std::enable_if< - is_safe::value || is_safe::value, - T ->::type -constexpr operator^=(T & t, const U & u){ - t = static_cast(t ^ u); - return t; -} - -///////////////////////////////////////////////////////////////// -// stream helpers - -template< - class T, - T Min, - T Max, - class P, // promotion polic - class E // exception policy -> -template< - class CharT, - class Traits -> -void safe_base::output( - std::basic_ostream & os -) const { - os << ( - (std::is_same::value - || std::is_same::value - || std::is_same::value - ) ? - static_cast(m_t) - : - m_t - ); -} - -template< - class T, - T Min, - T Max, - class P, // promotion polic - class E // exception policy -> -template< - class CharT, - class Traits -> -void safe_base::input( - std::basic_istream & is -){ - if(std::is_same::value - || std::is_same::value - || std::is_same::value - ){ - int x; - is >> x; - m_t = validated_cast(x); - } - else{ - is >> m_t; - validated_cast(m_t); - } - if(is.fail()){ - boost::safe_numerics::dispatch< - E, - boost::safe_numerics::safe_numerics_error::domain_error - >( - "error in file input" - ); - } -} - -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_SAFE_BASE_OPERATIONS_HPP diff --git a/boost/safe_numerics/safe_common.hpp b/boost/safe_numerics/safe_common.hpp deleted file mode 100644 index 71a00ad..0000000 --- a/boost/safe_numerics/safe_common.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef BOOST_NUMERIC_SAFE_COMMON_HPP -#define BOOST_NUMERIC_SAFE_COMMON_HPP - -// Copyright (c) 2012 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include - -namespace boost { -namespace safe_numerics { - -// default implementations for required meta-functions -template -struct is_safe : public std::false_type -{}; - -template -struct base_type { - using type = T; -}; - -template -constexpr const typename base_type::type & base_value(const T & t) { - return static_cast::type & >(t); -} - -template -struct get_promotion_policy { - using type = void; -}; - -template -struct get_exception_policy { - using type = void; -}; - - -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_SAFE_COMMON_HPP diff --git a/boost/safe_numerics/safe_compare.hpp b/boost/safe_numerics/safe_compare.hpp deleted file mode 100644 index 2b52c2d..0000000 --- a/boost/safe_numerics/safe_compare.hpp +++ /dev/null @@ -1,180 +0,0 @@ -#ifndef BOOST_NUMERIC_SAFE_COMPARE_HPP -#define BOOST_NUMERIC_SAFE_COMPARE_HPP - -// Copyright (c) 2012 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include -#include - -namespace boost { -namespace safe_numerics { -namespace safe_compare { - -//////////////////////////////////////////////////// -// safe comparison on primitive integral types -namespace safe_compare_detail { - template - using make_unsigned = typename std::conditional< - std::is_signed::value, - std::make_unsigned, - T - >::type; - - // both arguments unsigned or signed - template - struct less_than { - template - constexpr static bool invoke(const T & t, const U & u){ - return t < u; - } - }; - - // T unsigned, U signed - template<> - struct less_than { - template - constexpr static bool invoke(const T & t, const U & u){ - return - (u < 0) ? - false - : - less_than::invoke( - t, - static_cast::type &>(u) - ) - ; - } - }; - // T signed, U unsigned - template<> - struct less_than { - template - constexpr static bool invoke(const T & t, const U & u){ - return - (t < 0) ? - true - : - less_than::invoke( - static_cast::type &>(t), - u - ) - ; - } - }; -} // safe_compare_detail - -template -typename std::enable_if< - std::is_integral::value && std::is_integral::value, - bool ->::type -constexpr less_than(const T & lhs, const U & rhs) { - return safe_compare_detail::less_than< - std::is_signed::value, - std::is_signed::value - >::template invoke(lhs, rhs); -} - -template -typename std::enable_if< - std::is_floating_point::value && std::is_floating_point::value, - bool ->::type -constexpr less_than(const T & lhs, const U & rhs) { - return lhs < rhs; -} - -template -constexpr bool greater_than(const T & lhs, const U & rhs) { - return less_than(rhs, lhs); -} - -template -constexpr bool less_than_equal(const T & lhs, const U & rhs) { - return ! greater_than(lhs, rhs); -} - -template -constexpr bool greater_than_equal(const T & lhs, const U & rhs) { - return ! less_than(lhs, rhs); -} - -namespace safe_compare_detail { - // both arguments unsigned or signed - template - struct equal { - template - constexpr static bool invoke(const T & t, const U & u){ - return t == u; - } - }; - - // T unsigned, U signed - template<> - struct equal { - template - constexpr static bool invoke(const T & t, const U & u){ - return - (u < 0) ? - false - : - equal::invoke( - t, - static_cast::type &>(u) - ) - ; - } - }; - // T signed, U unsigned - template<> - struct equal { - template - constexpr static bool invoke(const T & t, const U & u){ - return - (t < 0) ? - false - : - equal::invoke( - static_cast::type &>(t), - u - ) - ; - } - }; -} // safe_compare_detail - -template -typename std::enable_if< - std::is_integral::value && std::is_integral::value, - bool ->::type -constexpr equal(const T & lhs, const U & rhs) { - return safe_compare_detail::equal< - std::numeric_limits::is_signed, - std::numeric_limits::is_signed - >::template invoke(lhs, rhs); -} - -template -typename std::enable_if< - std::is_floating_point::value && std::is_floating_point::value, - bool ->::type -constexpr equal(const T & lhs, const U & rhs) { - return lhs == rhs; -} - -template -constexpr bool not_equal(const T & lhs, const U & rhs) { - return ! equal(lhs, rhs); -} - -} // safe_compare -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_SAFE_COMPARE_HPP diff --git a/boost/safe_numerics/safe_integer.hpp b/boost/safe_numerics/safe_integer.hpp deleted file mode 100644 index a6f1983..0000000 --- a/boost/safe_numerics/safe_integer.hpp +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef BOOST_NUMERIC_SAFE_INTEGER_HPP -#define BOOST_NUMERIC_SAFE_INTEGER_HPP - -// Copyright (c) 2012 Robert Ramey -// -// 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) - -// not actually used here - but needed for integer arithmetic -// so this is a good place to include it -#include "checked_integer.hpp" -#include "checked_result_operations.hpp" - -#include "safe_base.hpp" -#include "safe_base_operations.hpp" - -#include "native.hpp" -#include "exception_policies.hpp" - -// specialization for meta functions with safe argument -namespace boost { -namespace safe_numerics { - -template < - class T, - class P = native, - class E = default_exception_policy -> -using safe = safe_base< - T, - ::std::numeric_limits::min(), - ::std::numeric_limits::max(), - P, - E ->; - -} // safe_numerics -} // boost - - -#endif // BOOST_NUMERIC_SAFE_INTEGER_HPP diff --git a/boost/safe_numerics/safe_integer_literal.hpp b/boost/safe_numerics/safe_integer_literal.hpp deleted file mode 100644 index 1e0922c..0000000 --- a/boost/safe_numerics/safe_integer_literal.hpp +++ /dev/null @@ -1,260 +0,0 @@ -#ifndef BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP -#define BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP - -// Copyright (c) 2012 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include // for intmax_t/uintmax_t -#include -#include // conditional, enable_if -#include - -#include "utility.hpp" -#include "safe_integer.hpp" -#include "checked_integer.hpp" - -namespace boost { -namespace safe_numerics { - -template -class safe_literal_impl; - -template -struct is_safe > : public std::true_type -{}; - -template -struct get_promotion_policy > { - using type = P; -}; - -template -struct get_exception_policy > { - using type = E; -}; -template -struct base_type > { - using type = T; -}; - -template -constexpr T base_value( - const safe_literal_impl & -) { - return N; -} - -template -inline std::basic_ostream & operator<<( - std::basic_ostream & os, - const safe_literal_impl & -){ - return os << ( - (std::is_same::value - || std::is_same::value - ) ? - static_cast(N) - : - N - ); -} - -template -class safe_literal_impl { - - template< - class CharT, - class Traits - > - friend std::basic_ostream & operator<<( - std::basic_ostream & os, - const safe_literal_impl & - ){ - return os << ( - (::std::is_same::value - || ::std::is_same::value - || ::std::is_same::value - ) ? - static_cast(N) - : - N - ); - }; - -public: - - //////////////////////////////////////////////////////////// - // constructors - // default constructor - constexpr safe_literal_impl(){} - - ///////////////////////////////////////////////////////////////// - // casting operators for intrinsic integers - // convert to any type which is not safe. safe types need to be - // excluded to prevent ambiguous function selection which - // would otherwise occur - template< - class R, - typename std::enable_if< - ! boost::safe_numerics::is_safe::value, - int - >::type = 0 - > - constexpr operator R () const { - // if static values don't overlap, the program can never function - #if 1 - constexpr const interval r_interval; - static_assert( - ! r_interval.excludes(N), - "safe type cannot be constructed with this type" - ); - #endif - - return validate_detail< - R, - std::numeric_limits::min(), - std::numeric_limits::max(), - E - >::return_value(*this); - } - - // non mutating unary operators - constexpr safe_literal_impl operator+() const { // unary plus - return safe_literal_impl(); - } - // after much consideration, I've permitted the resulting value of a unary - // - to change the type in accordance with the promotion policy. - // The C++ standard does invoke integral promotions so it's changing the type as well. - - /* section 5.3.1 &8 of the C++ standard - The operand of the unary - operator shall have arithmetic or unscoped - enumeration type and the result is the negation of its operand. Integral - promotion is performed on integral or enumeration operands. The negative - of an unsigned quantity is computed by subtracting its value from 2n, - where n is the number of bits in the promoted operand. The type of the - result is the type of the promoted operand. - */ - template< - typename Tx, Tx Nx, typename = std::enable_if_t - > - constexpr auto minus_helper() const { - return safe_literal_impl(); - } - - constexpr auto operator-() const { // unary minus - return minus_helper(); - } - - /* section 5.3.1 &10 of the C++ standard - The operand of ~ shall have integral or unscoped enumeration type; - the result is the ones’ complement of its operand. Integral promotions - are performed. The type of the result is the type of the promoted operand. - constexpr safe_literal_impl operator~() const { // invert bits - return safe_literal_impl(); - } - */ - template< - typename Tx, Tx Nx, typename = std::enable_if_t - > - constexpr auto not_helper() const { - return safe_literal_impl(); - } - - constexpr auto operator~() const { // unary minus - return not_helper(); - } -}; - -template< - std::intmax_t N, - class P = void, - class E = void -> -using safe_signed_literal = safe_literal_impl< - typename utility::signed_stored_type, - N, - P, - E ->; - -template< - std::uintmax_t N, - class P = void, - class E = void -> -using safe_unsigned_literal = safe_literal_impl< - typename utility::unsigned_stored_type, - N, - P, - E ->; - -template< - class T, - T N, - class P = void, - class E = void, - typename std::enable_if< - std::is_signed::value, - int - >::type = 0 -> -constexpr auto make_safe_literal_impl() { - return boost::safe_numerics::safe_signed_literal(); -} - -template< - class T, - T N, - class P = void, - class E = void, - typename std::enable_if< - ! std::is_signed::value, - int - >::type = 0 -> -constexpr auto make_safe_literal_impl() { - return boost::safe_numerics::safe_unsigned_literal(); -} - -} // safe_numerics -} // boost - -#define make_safe_literal(n, P, E) \ - boost::safe_numerics::make_safe_literal_impl() - -///////////////////////////////////////////////////////////////// -// numeric limits for safe_literal etc. - -#include - -namespace std { - -template< - typename T, - T N, - class P, - class E -> -class numeric_limits > - : public std::numeric_limits -{ - using SL = boost::safe_numerics::safe_literal_impl; -public: - constexpr static SL lowest() noexcept { - return SL(); - } - constexpr static SL min() noexcept { - return SL(); - } - constexpr static SL max() noexcept { - return SL(); - } -}; - -} // std - -#endif // BOOST_NUMERIC_SAFE_INTEGER_LITERAL_HPP diff --git a/boost/safe_numerics/safe_integer_range.hpp b/boost/safe_numerics/safe_integer_range.hpp deleted file mode 100644 index e9fce84..0000000 --- a/boost/safe_numerics/safe_integer_range.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef BOOST_NUMERIC_SAFE_INTEGER_RANGE_HPP -#define BOOST_NUMERIC_SAFE_INTEGER_RANGE_HPP - -// Copyright (c) 2012 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include // intmax_t, uintmax_t - -#include "utility.hpp" -#include "safe_integer.hpp" -#include "native.hpp" -#include "exception_policies.hpp" - -///////////////////////////////////////////////////////////////// -// higher level types implemented in terms of safe_base - -namespace boost { -namespace safe_numerics { - -///////////////////////////////////////////////////////////////// -// safe_signed_range - -template < - std::intmax_t Min, - std::intmax_t Max, - class P = native, - class E = default_exception_policy -> -using safe_signed_range = safe_base< - typename utility::signed_stored_type, - static_cast >(Min), - static_cast >(Max), - P, - E ->; - -///////////////////////////////////////////////////////////////// -// safe_unsigned_range - -template < - std::uintmax_t Min, - std::uintmax_t Max, - class P = native, - class E = default_exception_policy -> -using safe_unsigned_range = safe_base< - typename utility::unsigned_stored_type, - static_cast >(Min), - static_cast >(Max), - P, - E ->; - -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_SAFE_RANGE_HPP diff --git a/boost/safe_numerics/utility.hpp b/boost/safe_numerics/utility.hpp deleted file mode 100644 index c0cc2dd..0000000 --- a/boost/safe_numerics/utility.hpp +++ /dev/null @@ -1,280 +0,0 @@ -#ifndef BOOST_NUMERIC_UTILITY_HPP -#define BOOST_NUMERIC_UTILITY_HPP - -// Copyright (c) 2015 Robert Ramey -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#include // intmax_t, uintmax_t, uint8_t, ... -#include -#include // conditional -#include -#include -#include // pair - -#include // (u)int_t<>::least, exact - -namespace boost { -namespace safe_numerics { -namespace utility { - -/////////////////////////////////////////////////////////////////////////////// -// used for debugging - -// provokes warning message with names of type T -// usage - print_types; -// see https://cukic.co/2019/02/19/tmp-testing-and-debugging-templates - -/* -template -using print_type = typename Tx::error_message; -*/ -template -struct [[deprecated]] print_types {}; - -// display value of constexpr during compilation -// usage print_value(N) pn; -template -struct print_value -{ - enum test : char { - value = N < 0 ? N - 256 : N + 256 - }; -}; - -#if 0 -// static warning - same as static_assert but doesn't -// stop compilation. -template -struct static_test{}; - -template <> -struct static_test{ - [[deprecated]] static_test(){} -}; - -template -constexpr void static_warning(const T){ - //using x = static_test; - const static_test x; -} - -#endif - -/* -// can be called by constexpr to produce a compile time -// trap of parameter passed is false. -// usage constexpr_assert(bool) -constexpr int constexpr_assert(const bool tf){ - return 1 / tf; -} -*/ - -/////////////////////////////////////////////////////////////////////////////// -// return an integral constant equal to the the number of bits -// held by some integer type (including the sign bit) - -template -using bits_type = std::integral_constant< - int, - std::numeric_limits::digits - + (std::numeric_limits::is_signed ? 1 : 0) ->; - -/* -From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious -Find the log base 2 of an integer with a lookup table - - static const char LogTable256[256] = - { - #define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n - -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, - LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6), - LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7) - }; - - unsigned int v; // 32-bit word to find the log of - unsigned r; // r will be lg(v) - register unsigned int t, tt; // temporaries - - if (tt = v >> 16) - { - r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt]; - } - else - { - r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v]; - } - -The lookup table method takes only about 7 operations to find the log of a 32-bit value. -If extended for 64-bit quantities, it would take roughly 9 operations. Another operation -can be trimmed off by using four tables, with the possible additions incorporated into each. -Using int table elements may be faster, depending on your architecture. -*/ - -namespace ilog2_detail { - - // I've "improved" the above and recast as C++ code which depends upon - // the optimizer to minimize the operations. This should result in - // nine operations to calculate the position of the highest order - // bit in a 64 bit number. RR - - constexpr static unsigned int ilog2(const boost::uint_t<8>::exact & t){ - #define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n - const char LogTable256[256] = { - static_cast(-1), 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, - LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6), - LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7) - }; - return LogTable256[t]; - } - constexpr static unsigned int ilog2(const boost::uint_t<16>::exact & t){ - const boost::uint_t<8>::exact upper_half = (t >> 8); - return upper_half == 0 - ? ilog2(static_cast::exact>(t)) - : 8 + ilog2(upper_half); - } - constexpr static unsigned int ilog2(const boost::uint_t<32>::exact & t){ - const boost::uint_t<16>::exact upper_half = (t >> 16); - return upper_half == 0 - ? ilog2(static_cast::exact>(t)) - : 16 + ilog2(upper_half); - } - constexpr static unsigned int ilog2(const boost::uint_t<64>::exact & t){ - const boost::uint_t<32>::exact upper_half = (t >> 32); - return upper_half == 0 - ? ilog2(static_cast::exact>(t)) - : 32 + ilog2(upper_half); - } - -} // ilog2_detail - -template -constexpr unsigned int ilog2(const T & t){ -// log not defined for negative numbers -// assert(t > 0); - if(t == 0) - return 0; - return ilog2_detail::ilog2( - static_cast< - typename boost::uint_t< - bits_type::value - >::least - >(t) - ); -} - -// the number of bits required to render the value in x -// including sign bit -template -constexpr unsigned int significant_bits(const T & t){ - return 1 + ((t < 0) ? ilog2(~t) : ilog2(t)); -} - -/* -// give the value t, return the number which corresponds -// to all 1's which is higher than that number -template -constexpr unsigned int bits_value(const T & t){ - const unsigned int sb = significant_bits(t); - const unsigned int sb_max = significant_bits(std::numeric_limits::max()); - return sb < sb_max ? ((sb << 1) - 1) : std::numeric_limits::max(); -} -*/ - -/////////////////////////////////////////////////////////////////////////////// -// meta functions returning types - -// If we use std::max in here we get internal compiler errors -// with MSVC (tested VC2017) ... - -// Notes from https://en.cppreference.com/w/cpp/algorithm/max -// Capturing the result of std::max by reference if one of the parameters -// is rvalue produces a dangling reference if that parameter is returned. - -template -// turns out this problem crashes all versions of gcc compilers. So -// make sure we return by value -//constexpr const T & max( -constexpr T max( - const T & lhs, - const T & rhs -){ - return lhs > rhs ? lhs : rhs; -} - -// given a signed range, return type required to hold all the values -// in the range -template< - std::intmax_t Min, - std::intmax_t Max -> -using signed_stored_type = typename boost::int_t< - max( - significant_bits(Min), - significant_bits(Max) - ) + 1 ->::least ; - -// given an unsigned range, return type required to hold all the values -// in the range -template< - std::uintmax_t Min, - std::uintmax_t Max -> -// unsigned range -using unsigned_stored_type = typename boost::uint_t< - significant_bits(Max) ->::least; - -/////////////////////////////////////////////////////////////////////////////// -// constexpr functions - -// need our own version because official version -// a) is not constexpr -// b) is not guarenteed to handle non-assignable types -template -constexpr std::pair -minmax(const std::initializer_list l){ - assert(l.size() > 0); - const T * minimum = l.begin(); - const T * maximum = l.begin(); - for(const T * i = l.begin(); i != l.end(); ++i){ - if(*i < * minimum) - minimum = i; - else - if(* maximum < *i) - maximum = i; - } - return std::pair{* minimum, * maximum}; -} - -// for any given t -// a) figure number of significant bits -// b) return a value with all significant bits set -// so for example: -// 3 == round_out(2) because -// 2 == 10 and 3 == 11 -template -constexpr T round_out(const T & t){ - if(t >= 0){ - const std::uint8_t sb = utility::significant_bits(t); - return (sb < sizeof(T) * 8) - ? ((T)1 << sb) - 1 - : std::numeric_limits::max(); - } - else{ - const std::uint8_t sb = utility::significant_bits(~t); - return (sb < sizeof(T) * 8) - ? ~(((T)1 << sb) - 1) - : std::numeric_limits::min(); - } -} - -} // utility -} // safe_numerics -} // boost - -#endif // BOOST_NUMERIC_UTILITY_HPP diff --git a/boost/smart_ptr/allocate_shared_array.hpp b/boost/smart_ptr/allocate_shared_array.hpp new file mode 100644 index 0000000..bca9865 --- /dev/null +++ b/boost/smart_ptr/allocate_shared_array.hpp @@ -0,0 +1,362 @@ +/* +Copyright 2012-2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_SMART_PTR_ALLOCATE_SHARED_ARRAY_HPP +#define BOOST_SMART_PTR_ALLOCATE_SHARED_ARRAY_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace detail { + +template +struct sp_array_element { + typedef typename boost::remove_cv::type>::type type; +}; + +template +struct sp_array_count { + enum { + value = 1 + }; +}; + +template +struct sp_array_count { + enum { + value = N * sp_array_count::value + }; +}; + +template +struct sp_max_size { + enum { + value = N < M ? M : N + }; +}; + +template +struct sp_align_up { + enum { + value = (N + M - 1) & ~(M - 1) + }; +}; + +#if !defined(BOOST_NO_CXX11_ALLOCATOR) +template +struct sp_bind_allocator { + typedef typename std::allocator_traits::template rebind_alloc type; +}; +#else +template +struct sp_bind_allocator { + typedef typename A::template rebind::other type; +}; +#endif + +template +BOOST_CONSTEXPR inline std::size_t +sp_objects(std::size_t size) BOOST_SP_NOEXCEPT +{ + return (size + sizeof(T) - 1) / sizeof(T); +} + +template +class sp_array_state { +public: + typedef A type; + + template + sp_array_state(const U& _allocator, std::size_t _size) BOOST_SP_NOEXCEPT + : allocator_(_allocator), + size_(_size) { } + + A& allocator() BOOST_SP_NOEXCEPT { + return allocator_; + } + + std::size_t size() const BOOST_SP_NOEXCEPT { + return size_; + } + +private: + A allocator_; + std::size_t size_; +}; + +template +class sp_size_array_state { +public: + typedef A type; + + template + sp_size_array_state(const U& _allocator, std::size_t) BOOST_SP_NOEXCEPT + : allocator_(_allocator) { } + + A& allocator() BOOST_SP_NOEXCEPT { + return allocator_; + } + + BOOST_CONSTEXPR std::size_t size() const BOOST_SP_NOEXCEPT { + return N; + } + +private: + A allocator_; +}; + +template +struct sp_array_alignment { + enum { + value = sp_max_size::value, + boost::alignment_of::value>::value + }; +}; + +template +struct sp_array_offset { + enum { + value = sp_align_up::value>::value + }; +}; + +template +inline U* +sp_array_start(T* base) BOOST_SP_NOEXCEPT +{ + enum { + size = sp_array_offset::value + }; + return reinterpret_cast(reinterpret_cast(base) + size); +} + +template +class sp_array_creator { + typedef typename A::value_type element; + + enum { + offset = sp_array_offset::value + }; + + typedef typename boost::type_with_alignment::value>::type type; + +public: + template + sp_array_creator(const U& other, std::size_t size) BOOST_SP_NOEXCEPT + : other_(other), + size_(sp_objects(offset + sizeof(element) * size)) { } + + T* create() { + return reinterpret_cast(other_.allocate(size_)); + } + + void destroy(T* base) { + other_.deallocate(reinterpret_cast(base), size_); + } + +private: + typename sp_bind_allocator::type other_; + std::size_t size_; +}; + +template +class BOOST_SYMBOL_VISIBLE sp_array_base + : public sp_counted_base { + typedef typename T::type allocator; + +public: + typedef typename allocator::value_type type; + + template + sp_array_base(const A& other, type* start, std::size_t size) + : state_(other, size) { + boost::alloc_construct_n(state_.allocator(), + boost::first_scalar(start), + state_.size() * sp_array_count::value); + } + + template + sp_array_base(const A& other, type* start, std::size_t size, const U& list) + : state_(other, size) { + enum { + count = sp_array_count::value + }; + boost::alloc_construct_n(state_.allocator(), + boost::first_scalar(start), state_.size() * count, + boost::first_scalar(&list), count); + } + + T& state() BOOST_SP_NOEXCEPT { + return state_; + } + + virtual void dispose() BOOST_SP_NOEXCEPT { + boost::alloc_destroy_n(state_.allocator(), + boost::first_scalar(sp_array_start(this)), + state_.size() * sp_array_count::value); + } + + virtual void destroy() BOOST_SP_NOEXCEPT { + sp_array_creator other(state_.allocator(), + state_.size()); + this->~sp_array_base(); + other.destroy(this); + } + + virtual void* get_deleter(const sp_typeinfo_&) BOOST_SP_NOEXCEPT { + return 0; + } + + virtual void* get_local_deleter(const sp_typeinfo_&) BOOST_SP_NOEXCEPT { + return 0; + } + + virtual void* get_untyped_deleter() BOOST_SP_NOEXCEPT { + return 0; + } + +private: + T state_; +}; + +template +struct sp_array_result { +public: + template + sp_array_result(const U& other, std::size_t size) + : creator_(other, size), + result_(creator_.create()) { } + + ~sp_array_result() { + if (result_) { + creator_.destroy(result_); + } + } + + T* get() const BOOST_SP_NOEXCEPT { + return result_; + } + + void release() BOOST_SP_NOEXCEPT { + result_ = 0; + } + +private: + sp_array_result(const sp_array_result&); + sp_array_result& operator=(const sp_array_result&); + + sp_array_creator creator_; + T* result_; +}; + +} /* detail */ + +template +inline typename enable_if_::value, shared_ptr >::type +allocate_shared(const A& allocator, std::size_t count) +{ + typedef typename detail::sp_array_element::type element; + typedef typename detail::sp_bind_allocator::type other; + typedef detail::sp_array_state state; + typedef detail::sp_array_base base; + detail::sp_array_result result(allocator, count); + base* node = result.get(); + element* start = detail::sp_array_start(node); + ::new(static_cast(node)) base(allocator, start, count); + result.release(); + return shared_ptr(detail::sp_internal_constructor_tag(), start, + detail::shared_count(static_cast(node))); +} + +template +inline typename enable_if_::value, shared_ptr >::type +allocate_shared(const A& allocator) +{ + enum { + count = extent::value + }; + typedef typename detail::sp_array_element::type element; + typedef typename detail::sp_bind_allocator::type other; + typedef detail::sp_size_array_state::value> state; + typedef detail::sp_array_base base; + detail::sp_array_result result(allocator, count); + base* node = result.get(); + element* start = detail::sp_array_start(node); + ::new(static_cast(node)) base(allocator, start, count); + result.release(); + return shared_ptr(detail::sp_internal_constructor_tag(), start, + detail::shared_count(static_cast(node))); +} + +template +inline typename enable_if_::value, shared_ptr >::type +allocate_shared(const A& allocator, std::size_t count, + const typename remove_extent::type& value) +{ + typedef typename detail::sp_array_element::type element; + typedef typename detail::sp_bind_allocator::type other; + typedef detail::sp_array_state state; + typedef detail::sp_array_base base; + detail::sp_array_result result(allocator, count); + base* node = result.get(); + element* start = detail::sp_array_start(node); + ::new(static_cast(node)) base(allocator, start, count, value); + result.release(); + return shared_ptr(detail::sp_internal_constructor_tag(), start, + detail::shared_count(static_cast(node))); +} + +template +inline typename enable_if_::value, shared_ptr >::type +allocate_shared(const A& allocator, + const typename remove_extent::type& value) +{ + enum { + count = extent::value + }; + typedef typename detail::sp_array_element::type element; + typedef typename detail::sp_bind_allocator::type other; + typedef detail::sp_size_array_state::value> state; + typedef detail::sp_array_base base; + detail::sp_array_result result(allocator, count); + base* node = result.get(); + element* start = detail::sp_array_start(node); + ::new(static_cast(node)) base(allocator, start, count, value); + result.release(); + return shared_ptr(detail::sp_internal_constructor_tag(), start, + detail::shared_count(static_cast(node))); +} + +template +inline typename enable_if_::value, shared_ptr >::type +allocate_shared_noinit(const A& allocator, std::size_t count) +{ + return boost::allocate_shared(boost::noinit_adapt(allocator), count); +} + +template +inline typename enable_if_::value, shared_ptr >::type +allocate_shared_noinit(const A& allocator) +{ + return boost::allocate_shared(boost::noinit_adapt(allocator)); +} + +} /* boost */ + +#endif diff --git a/boost/smart_ptr/detail/sp_forward.hpp b/boost/smart_ptr/detail/sp_forward.hpp new file mode 100644 index 0000000..8fdec65 --- /dev/null +++ b/boost/smart_ptr/detail/sp_forward.hpp @@ -0,0 +1,52 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_FORWARD_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_FORWARD_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// detail/sp_forward.hpp +// +// Copyright 2008,2012 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include + +namespace boost +{ + +namespace detail +{ + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + +#if defined( BOOST_GCC ) && __GNUC__ * 100 + __GNUC_MINOR__ <= 404 + +// GCC 4.4 supports an outdated version of rvalue references and creates a copy of the forwarded object. +// This results in warnings 'returning reference to temporary'. Therefore we use a special version similar to std::forward. +template< class T > T&& sp_forward( T && t ) BOOST_NOEXCEPT +{ + return t; +} + +#else + +template< class T > T&& sp_forward( T & t ) BOOST_NOEXCEPT +{ + return static_cast< T&& >( t ); +} + +#endif + +#endif + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_FORWARD_HPP_INCLUDED diff --git a/boost/smart_ptr/enable_shared_from_this.hpp b/boost/smart_ptr/enable_shared_from_this.hpp new file mode 100644 index 0000000..fc4de0b --- /dev/null +++ b/boost/smart_ptr/enable_shared_from_this.hpp @@ -0,0 +1,90 @@ +#ifndef BOOST_SMART_PTR_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED +#define BOOST_SMART_PTR_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED + +// +// enable_shared_from_this.hpp +// +// Copyright 2002, 2009 Peter Dimov +// +// 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/libs/smart_ptr/ for documentation. +// + +#include +#include +#include +#include +#include + +namespace boost +{ + +template class enable_shared_from_this +{ +protected: + + BOOST_CONSTEXPR enable_shared_from_this() BOOST_SP_NOEXCEPT + { + } + + BOOST_CONSTEXPR enable_shared_from_this(enable_shared_from_this const &) BOOST_SP_NOEXCEPT + { + } + + enable_shared_from_this & operator=(enable_shared_from_this const &) BOOST_SP_NOEXCEPT + { + return *this; + } + + ~enable_shared_from_this() BOOST_SP_NOEXCEPT // ~weak_ptr newer throws, so this call also must not throw + { + } + +public: + + shared_ptr shared_from_this() + { + shared_ptr p( weak_this_ ); + BOOST_ASSERT( p.get() == this ); + return p; + } + + shared_ptr shared_from_this() const + { + shared_ptr p( weak_this_ ); + BOOST_ASSERT( p.get() == this ); + return p; + } + + weak_ptr weak_from_this() BOOST_SP_NOEXCEPT + { + return weak_this_; + } + + weak_ptr weak_from_this() const BOOST_SP_NOEXCEPT + { + return weak_this_; + } + +public: // actually private, but avoids compiler template friendship issues + + // Note: invoked automatically by shared_ptr; do not call + template void _internal_accept_owner( shared_ptr const * ppx, Y * py ) const BOOST_SP_NOEXCEPT + { + if( weak_this_.expired() ) + { + weak_this_ = shared_ptr( *ppx, py ); + } + } + +private: + + mutable weak_ptr weak_this_; +}; + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED diff --git a/boost/smart_ptr/make_shared.hpp b/boost/smart_ptr/make_shared.hpp new file mode 100644 index 0000000..dd9191c --- /dev/null +++ b/boost/smart_ptr/make_shared.hpp @@ -0,0 +1,21 @@ +#ifndef BOOST_SMART_PTR_MAKE_SHARED_HPP_INCLUDED +#define BOOST_SMART_PTR_MAKE_SHARED_HPP_INCLUDED + +// make_shared.hpp +// +// Copyright (c) 2007, 2008, 2012 Peter Dimov +// +// 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/libs/smart_ptr/ for documentation. + +#include + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) && !defined( BOOST_NO_SFINAE ) +# include +# include +#endif + +#endif // #ifndef BOOST_SMART_PTR_MAKE_SHARED_HPP_INCLUDED diff --git a/boost/smart_ptr/make_shared_array.hpp b/boost/smart_ptr/make_shared_array.hpp new file mode 100644 index 0000000..785eb87 --- /dev/null +++ b/boost/smart_ptr/make_shared_array.hpp @@ -0,0 +1,66 @@ +/* +Copyright 2012-2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_SMART_PTR_MAKE_SHARED_ARRAY_HPP +#define BOOST_SMART_PTR_MAKE_SHARED_ARRAY_HPP + +#include +#include + +namespace boost { + +template +inline typename enable_if_::value, shared_ptr >::type +make_shared() +{ + return boost::allocate_shared(boost::default_allocator::type>()); +} + +template +inline typename enable_if_::value, shared_ptr >::type +make_shared(const typename remove_extent::type& value) +{ + return boost::allocate_shared(boost::default_allocator::type>(), value); +} + +template +inline typename enable_if_::value, shared_ptr >::type +make_shared(std::size_t size) +{ + return boost::allocate_shared(boost::default_allocator::type>(), size); +} + +template +inline typename enable_if_::value, shared_ptr >::type +make_shared(std::size_t size, const typename remove_extent::type& value) +{ + return boost::allocate_shared(boost::default_allocator::type>(), size, value); +} + +template +inline typename enable_if_::value, shared_ptr >::type +make_shared_noinit() +{ + return boost::allocate_shared_noinit(boost::default_allocator::type>()); +} + +template +inline typename enable_if_::value, shared_ptr >::type +make_shared_noinit(std::size_t size) +{ + return boost::allocate_shared_noinit(boost::default_allocator::type>(), size); +} + +} /* boost */ + +#endif diff --git a/boost/smart_ptr/make_shared_object.hpp b/boost/smart_ptr/make_shared_object.hpp new file mode 100644 index 0000000..c681602 --- /dev/null +++ b/boost/smart_ptr/make_shared_object.hpp @@ -0,0 +1,801 @@ +#ifndef BOOST_SMART_PTR_MAKE_SHARED_OBJECT_HPP_INCLUDED +#define BOOST_SMART_PTR_MAKE_SHARED_OBJECT_HPP_INCLUDED + +// make_shared_object.hpp +// +// Copyright (c) 2007, 2008, 2012 Peter Dimov +// +// 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/libs/smart_ptr/ for documentation. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + +namespace detail +{ + +template< std::size_t N, std::size_t A > struct sp_aligned_storage +{ + union type + { + char data_[ N ]; + typename boost::type_with_alignment< A >::type align_; + }; +}; + +template< class T > class sp_ms_deleter +{ +private: + + typedef typename sp_aligned_storage< sizeof( T ), ::boost::alignment_of< T >::value >::type storage_type; + + bool initialized_; + storage_type storage_; + +private: + + void destroy() BOOST_SP_NOEXCEPT + { + if( initialized_ ) + { +#if defined( __GNUC__ ) + + // fixes incorrect aliasing warning + T * p = reinterpret_cast< T* >( storage_.data_ ); + p->~T(); + +#else + + reinterpret_cast< T* >( storage_.data_ )->~T(); + +#endif + + initialized_ = false; + } + } + +public: + + sp_ms_deleter() BOOST_SP_NOEXCEPT : initialized_( false ) + { + } + + template explicit sp_ms_deleter( A const & ) BOOST_SP_NOEXCEPT : initialized_( false ) + { + } + + // optimization: do not copy storage_ + sp_ms_deleter( sp_ms_deleter const & ) BOOST_SP_NOEXCEPT : initialized_( false ) + { + } + + ~sp_ms_deleter() BOOST_SP_NOEXCEPT + { + destroy(); + } + + void operator()( T * ) BOOST_SP_NOEXCEPT + { + destroy(); + } + + static void operator_fn( T* ) BOOST_SP_NOEXCEPT // operator() can't be static + { + } + + void * address() BOOST_SP_NOEXCEPT + { + return storage_.data_; + } + + void set_initialized() BOOST_SP_NOEXCEPT + { + initialized_ = true; + } +}; + +template< class T, class A > class sp_as_deleter +{ +private: + + typedef typename sp_aligned_storage< sizeof( T ), ::boost::alignment_of< T >::value >::type storage_type; + + storage_type storage_; + A a_; + bool initialized_; + +private: + + void destroy() BOOST_SP_NOEXCEPT + { + if( initialized_ ) + { + T * p = reinterpret_cast< T* >( storage_.data_ ); + +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + std::allocator_traits::destroy( a_, p ); + +#else + + p->~T(); + +#endif + + initialized_ = false; + } + } + +public: + + sp_as_deleter( A const & a ) BOOST_SP_NOEXCEPT : a_( a ), initialized_( false ) + { + } + + // optimization: do not copy storage_ + sp_as_deleter( sp_as_deleter const & r ) BOOST_SP_NOEXCEPT : a_( r.a_), initialized_( false ) + { + } + + ~sp_as_deleter() BOOST_SP_NOEXCEPT + { + destroy(); + } + + void operator()( T * ) BOOST_SP_NOEXCEPT + { + destroy(); + } + + static void operator_fn( T* ) BOOST_SP_NOEXCEPT // operator() can't be static + { + } + + void * address() BOOST_SP_NOEXCEPT + { + return storage_.data_; + } + + void set_initialized() BOOST_SP_NOEXCEPT + { + initialized_ = true; + } +}; + +template< class T > struct sp_if_not_array +{ + typedef boost::shared_ptr< T > type; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template< class T > struct sp_if_not_array< T[] > +{ +}; + +#if !defined( __BORLANDC__ ) || !BOOST_WORKAROUND( __BORLANDC__, < 0x600 ) + +template< class T, std::size_t N > struct sp_if_not_array< T[N] > +{ +}; + +#endif + +#endif + +} // namespace detail + +#if !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING ) +# define BOOST_SP_MSD( T ) boost::detail::sp_inplace_tag< boost::detail::sp_ms_deleter< T > >() +#else +# define BOOST_SP_MSD( T ) boost::detail::sp_ms_deleter< T >() +#endif + +// _noinit versions + +template< class T > typename boost::detail::sp_if_not_array< T >::type make_shared_noinit() +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T; + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A > typename boost::detail::sp_if_not_array< T >::type allocate_shared_noinit( A const & a ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T; + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +#if !defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + +// Variadic templates, rvalue reference + +template< class T, class... Args > typename boost::detail::sp_if_not_array< T >::type make_shared( Args && ... args ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( boost::detail::sp_forward( args )... ); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class... Args > typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, Args && ... args ) +{ +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + typedef typename std::allocator_traits::template rebind_alloc A2; + A2 a2( a ); + + typedef boost::detail::sp_as_deleter< T, A2 > D; + + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), boost::detail::sp_inplace_tag(), a2 ); + +#else + + typedef boost::detail::sp_ms_deleter< T > D; + + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), boost::detail::sp_inplace_tag(), a ); + +#endif + + D * pd = static_cast< D* >( pt._internal_get_untyped_deleter() ); + void * pv = pd->address(); + +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + std::allocator_traits::construct( a2, static_cast< T* >( pv ), boost::detail::sp_forward( args )... ); + +#else + + ::new( pv ) T( boost::detail::sp_forward( args )... ); + +#endif + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +#else // !defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + +// Common zero-argument versions + +template< class T > typename boost::detail::sp_if_not_array< T >::type make_shared() +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T(); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A > typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T(); + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +// C++03 version + +template< class T, class A1 > +typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1 > +typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2 > +typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2 > +typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3 > +typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3 > +typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3, class A4 > +typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ), + boost::forward( a4 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3, class A4 > +typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ), + boost::forward( a4 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3, class A4, class A5 > +typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ), + boost::forward( a4 ), + boost::forward( a5 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3, class A4, class A5 > +typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ), + boost::forward( a4 ), + boost::forward( a5 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3, class A4, class A5, class A6 > +typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ), + boost::forward( a4 ), + boost::forward( a5 ), + boost::forward( a6 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6 > +typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ), + boost::forward( a4 ), + boost::forward( a5 ), + boost::forward( a6 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7 > +typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6, BOOST_FWD_REF(A7) a7 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ), + boost::forward( a4 ), + boost::forward( a5 ), + boost::forward( a6 ), + boost::forward( a7 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7 > +typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6, BOOST_FWD_REF(A7) a7 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ), + boost::forward( a4 ), + boost::forward( a5 ), + boost::forward( a6 ), + boost::forward( a7 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 > +typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6, BOOST_FWD_REF(A7) a7, BOOST_FWD_REF(A8) a8 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ), + boost::forward( a4 ), + boost::forward( a5 ), + boost::forward( a6 ), + boost::forward( a7 ), + boost::forward( a8 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 > +typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6, BOOST_FWD_REF(A7) a7, BOOST_FWD_REF(A8) a8 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ), + boost::forward( a4 ), + boost::forward( a5 ), + boost::forward( a6 ), + boost::forward( a7 ), + boost::forward( a8 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9 > +typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6, BOOST_FWD_REF(A7) a7, BOOST_FWD_REF(A8) a8, BOOST_FWD_REF(A9) a9 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ), + boost::forward( a4 ), + boost::forward( a5 ), + boost::forward( a6 ), + boost::forward( a7 ), + boost::forward( a8 ), + boost::forward( a9 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9 > +typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6, BOOST_FWD_REF(A7) a7, BOOST_FWD_REF(A8) a8, BOOST_FWD_REF(A9) a9 ) +{ + boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a ); + + boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() ); + + void * pv = pd->address(); + + ::new( pv ) T( + boost::forward( a1 ), + boost::forward( a2 ), + boost::forward( a3 ), + boost::forward( a4 ), + boost::forward( a5 ), + boost::forward( a6 ), + boost::forward( a7 ), + boost::forward( a8 ), + boost::forward( a9 ) + ); + + pd->set_initialized(); + + T * pt2 = static_cast< T* >( pv ); + + boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 ); + return boost::shared_ptr< T >( pt, pt2 ); +} + +#endif // !defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + +#undef BOOST_SP_MSD + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_MAKE_SHARED_OBJECT_HPP_INCLUDED diff --git a/boost/system/error_code.hpp b/boost/system/error_code.hpp index f0a151e..9fb7de3 100644 --- a/boost/system/error_code.hpp +++ b/boost/system/error_code.hpp @@ -335,8 +335,11 @@ template struct BOOST_SYMBOL_VISIBLE cat_holder static constexpr generic_error_category generic_category_instance{}; }; +// Before C++17 it was mandatory to redeclare all static constexpr +#if defined(BOOST_NO_CXX17_INLINE_VARIABLES) template constexpr system_error_category cat_holder::system_category_instance; template constexpr generic_error_category cat_holder::generic_category_instance; +#endif } // namespace detail diff --git a/boost/thread.hpp b/boost/thread.hpp new file mode 100644 index 0000000..892bbb8 --- /dev/null +++ b/boost/thread.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// (C) Copyright 2008-9 Anthony Williams +// +// 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/thread for documentation. + +#if !defined(BOOST_THREAD_WEK01082003_HPP) +#define BOOST_THREAD_WEK01082003_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/boost/thread/barrier.hpp b/boost/thread/barrier.hpp new file mode 100644 index 0000000..4c1b1b5 --- /dev/null +++ b/boost/thread/barrier.hpp @@ -0,0 +1,255 @@ +// Copyright (C) 2002-2003 +// David Moore, William E. Kempf +// Copyright (C) 2007-8 Anthony Williams +// (C) Copyright 2013 Vicente J. Botet Escriba +// +// 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_BARRIER_JDM030602_HPP +#define BOOST_BARRIER_JDM030602_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost +{ + namespace thread_detail + { + typedef detail::nullary_function void_completion_function; + typedef detail::nullary_function size_completion_function; + + struct default_barrier_reseter + { + unsigned int size_; + default_barrier_reseter(unsigned int size) : + size_(size) + { + } + BOOST_THREAD_MOVABLE(default_barrier_reseter) + //BOOST_THREAD_COPYABLE_AND_MOVABLE(default_barrier_reseter) + + default_barrier_reseter(default_barrier_reseter const& other) BOOST_NOEXCEPT : + size_(other.size_) + { + } + default_barrier_reseter(BOOST_THREAD_RV_REF(default_barrier_reseter) other) BOOST_NOEXCEPT : + size_(BOOST_THREAD_RV(other).size_) + { + } + + unsigned int operator()() + { + return size_; + } + }; + + struct void_functor_barrier_reseter + { + unsigned int size_; + void_completion_function fct_; + template + void_functor_barrier_reseter(unsigned int size, BOOST_THREAD_RV_REF(F) funct) + : size_(size), fct_(boost::move(funct)) + {} + template + void_functor_barrier_reseter(unsigned int size, F& funct) + : size_(size), fct_(funct) + {} + + BOOST_THREAD_MOVABLE(void_functor_barrier_reseter) + //BOOST_THREAD_COPYABLE_AND_MOVABLE(void_functor_barrier_reseter) + + void_functor_barrier_reseter(void_functor_barrier_reseter const& other) BOOST_NOEXCEPT : + size_(other.size_), fct_(other.fct_) + { + } + void_functor_barrier_reseter(BOOST_THREAD_RV_REF(void_functor_barrier_reseter) other) BOOST_NOEXCEPT : + size_(BOOST_THREAD_RV(other).size_), fct_(BOOST_THREAD_RV(other).fct_) + //size_(BOOST_THREAD_RV(other).size_), fct_(boost::move(BOOST_THREAD_RV(other).fct_)) + { + } + + unsigned int operator()() + { + fct_(); + return size_; + } + }; + struct void_fct_ptr_barrier_reseter + { + unsigned int size_; + void(*fct_)(); + void_fct_ptr_barrier_reseter(unsigned int size, void(*funct)()) : + size_(size), fct_(funct) + { + } + BOOST_THREAD_MOVABLE(void_fct_ptr_barrier_reseter) + //BOOST_THREAD_COPYABLE_AND_MOVABLE(void_fct_ptr_barrier_reseter) + + void_fct_ptr_barrier_reseter(void_fct_ptr_barrier_reseter const& other) BOOST_NOEXCEPT : + size_(other.size_), fct_(other.fct_) + { + } + void_fct_ptr_barrier_reseter(BOOST_THREAD_RV_REF(void_fct_ptr_barrier_reseter) other) BOOST_NOEXCEPT : + size_(BOOST_THREAD_RV(other).size_), fct_(BOOST_THREAD_RV(other).fct_) + { + } + unsigned int operator()() + { + fct_(); + return size_; + } + }; + } + //BOOST_THREAD_DCL_MOVABLE(thread_detail::default_barrier_reseter) + //BOOST_THREAD_DCL_MOVABLE(thread_detail::void_functor_barrier_reseter) + //BOOST_THREAD_DCL_MOVABLE(thread_detail::void_fct_ptr_barrier_reseter) + + class barrier + { + static inline unsigned int check_counter(unsigned int count) + { + if (count == 0) boost::throw_exception( + thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero.")); + return count; + } + struct dummy + { + }; + + public: + BOOST_THREAD_NO_COPYABLE( barrier) + + explicit barrier(unsigned int count) : + m_count(check_counter(count)), m_generation(0), fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count))) + { + } + + template + barrier( + unsigned int count, + BOOST_THREAD_RV_REF(F) funct, + typename enable_if< + typename is_void::type>::type, dummy* + >::type=0 + ) + : m_count(check_counter(count)), + m_generation(0), + fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_functor_barrier_reseter(count, + boost::move(funct))) + ) + { + } + template + barrier( + unsigned int count, + F &funct, + typename enable_if< + typename is_void::type>::type, dummy* + >::type=0 + ) + : m_count(check_counter(count)), + m_generation(0), + fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_functor_barrier_reseter(count, + funct)) + ) + { + } + + template + barrier( + unsigned int count, + BOOST_THREAD_RV_REF(F) funct, + typename enable_if< + typename is_same::type, unsigned int>::type, dummy* + >::type=0 + ) + : m_count(check_counter(count)), + m_generation(0), + fct_(boost::move(funct)) + { + } + template + barrier( + unsigned int count, + F& funct, + typename enable_if< + typename is_same::type, unsigned int>::type, dummy* + >::type=0 + ) + : m_count(check_counter(count)), + m_generation(0), + fct_(funct) + { + } + + barrier(unsigned int count, void(*funct)()) : + m_count(check_counter(count)), m_generation(0), + fct_(funct + ? BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_fct_ptr_barrier_reseter(count, funct)))) + : BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count)))) + ) + { + } + barrier(unsigned int count, unsigned int(*funct)()) : + m_count(check_counter(count)), m_generation(0), + fct_(funct + ? BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(funct)) + : BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count)))) + ) + { + } + + bool wait() + { + boost::unique_lock < boost::mutex > lock(m_mutex); + unsigned int gen = m_generation; + + if (--m_count == 0) + { + m_generation++; + m_count = static_cast(fct_()); + BOOST_ASSERT(m_count != 0); + lock.unlock(); + m_cond.notify_all(); + return true; + } + + while (gen == m_generation) + m_cond.wait(lock); + return false; + } + + void count_down_and_wait() + { + wait(); + } + + private: + mutex m_mutex; + condition_variable m_cond; + unsigned int m_count; + unsigned int m_generation; + thread_detail::size_completion_function fct_; + }; + +} // namespace boost + +#include + +#endif diff --git a/boost/thread/condition_variable.hpp b/boost/thread/condition_variable.hpp new file mode 100644 index 0000000..8f8e9f2 --- /dev/null +++ b/boost/thread/condition_variable.hpp @@ -0,0 +1,21 @@ +#ifndef BOOST_THREAD_CONDITION_VARIABLE_HPP +#define BOOST_THREAD_CONDITION_VARIABLE_HPP + +// condition_variable.hpp +// +// (C) Copyright 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + +#endif diff --git a/boost/thread/csbl/functional.hpp b/boost/thread/csbl/functional.hpp new file mode 100644 index 0000000..7a7e928 --- /dev/null +++ b/boost/thread/csbl/functional.hpp @@ -0,0 +1,49 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_FUNCTIONAL_HPP +#define BOOST_CSBL_FUNCTIONAL_HPP + +#include + +#include + +#if defined BOOST_THREAD_USES_BOOST_FUNCTIONAL || defined BOOST_NO_CXX11_HDR_FUNCTIONAL || defined BOOST_NO_CXX11_RVALUE_REFERENCES +#ifndef BOOST_THREAD_USES_BOOST_FUNCTIONAL +#define BOOST_THREAD_USES_BOOST_FUNCTIONAL +#endif +#include +#endif + +namespace boost +{ + namespace csbl + { +#if defined BOOST_THREAD_USES_BOOST_FUNCTIONAL + using ::boost::function; +#else + // D.8.1, base (deprecated): + // 20.9.3, reference_wrapper: + // 20.9.4, arithmetic operations: + // 20.9.5, comparisons: + // 20.9.6, logical operations: + // 20.9.7, bitwise operations: + // 20.9.8, negators: + // 20.9.9, bind: + // D.9, binders (deprecated): + // D.8.2.1, adaptors (deprecated): + // D.8.2.2, adaptors (deprecated): + // 20.9.10, member function adaptors: + // 20.9.11 polymorphic function wrappers: + using ::std::function; + // 20.9.12, hash function primary template: +#endif + + } +} +#endif // header diff --git a/boost/thread/csbl/memory/allocator_arg.hpp b/boost/thread/csbl/memory/allocator_arg.hpp new file mode 100644 index 0000000..354cdae --- /dev/null +++ b/boost/thread/csbl/memory/allocator_arg.hpp @@ -0,0 +1,41 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_ALLOCATOR_ARG_HPP +#define BOOST_CSBL_MEMORY_ALLOCATOR_ARG_HPP + +#include + +// 20.7.6, allocator argument tag +#if defined BOOST_NO_CXX11_ALLOCATOR +#include + +namespace boost +{ + namespace csbl + { + using ::boost::container::allocator_arg_t; + using ::boost::container::allocator_arg; + } +} +#else +namespace boost +{ + namespace csbl + { + using ::std::allocator_arg_t; + using ::std::allocator_arg; + } +} +#endif // BOOST_NO_CXX11_ALLOCATOR +namespace boost +{ + using ::boost::csbl::allocator_arg_t; + using ::boost::csbl::allocator_arg; +} +#endif // header diff --git a/boost/thread/csbl/memory/allocator_traits.hpp b/boost/thread/csbl/memory/allocator_traits.hpp new file mode 100644 index 0000000..3737cd8 --- /dev/null +++ b/boost/thread/csbl/memory/allocator_traits.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_ALLOCATOR_TRAITS_HPP +#define BOOST_CSBL_MEMORY_ALLOCATOR_TRAITS_HPP + +#include + +// 20.7.8, allocator traits +#if defined BOOST_NO_CXX11_ALLOCATOR +#include + +namespace boost +{ + namespace csbl + { + using ::boost::container::allocator_traits; + } +} +#else +namespace boost +{ + namespace csbl + { + using ::std::allocator_traits; + } +} +#endif // BOOST_NO_CXX11_POINTER_TRAITS + +#endif // header diff --git a/boost/thread/csbl/memory/config.hpp b/boost/thread/csbl/memory/config.hpp new file mode 100644 index 0000000..7b0596a --- /dev/null +++ b/boost/thread/csbl/memory/config.hpp @@ -0,0 +1,16 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_CONFIG_HPP +#define BOOST_CSBL_MEMORY_CONFIG_HPP + +#include + +#include + +#endif // header diff --git a/boost/thread/csbl/memory/pointer_traits.hpp b/boost/thread/csbl/memory/pointer_traits.hpp new file mode 100644 index 0000000..320f8e9 --- /dev/null +++ b/boost/thread/csbl/memory/pointer_traits.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_POINTER_TRAITS_HPP +#define BOOST_CSBL_MEMORY_POINTER_TRAITS_HPP + +#include + +// 20.7.3, pointer traits +#if defined BOOST_NO_CXX11_ALLOCATOR +#include + +namespace boost +{ + namespace csbl + { + using ::boost::intrusive::pointer_traits; + } +} +#else +namespace boost +{ + namespace csbl + { + using ::std::pointer_traits; + } +} +#endif // BOOST_NO_CXX11_ALLOCATOR + +#endif // header diff --git a/boost/thread/csbl/memory/scoped_allocator.hpp b/boost/thread/csbl/memory/scoped_allocator.hpp new file mode 100644 index 0000000..a92f3d8 --- /dev/null +++ b/boost/thread/csbl/memory/scoped_allocator.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_SCOPED_ALLOCATOR_HPP +#define BOOST_CSBL_MEMORY_SCOPED_ALLOCATOR_HPP + +#include + +// 20.7.7, uses_allocator +#if defined BOOST_NO_CXX11_ALLOCATOR +#include + +namespace boost +{ + namespace csbl + { + using ::boost::container::uses_allocator; + } +} +#else +namespace boost +{ + namespace csbl + { + using ::std::uses_allocator; + } +} +#endif // BOOST_NO_CXX11_POINTER_TRAITS + +#endif // header diff --git a/boost/thread/csbl/memory/shared_ptr.hpp b/boost/thread/csbl/memory/shared_ptr.hpp new file mode 100644 index 0000000..e9a9383 --- /dev/null +++ b/boost/thread/csbl/memory/shared_ptr.hpp @@ -0,0 +1,42 @@ +// Copyright (C) 2014 Vicente J. Botet Escriba +// +// 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) +// +// 2014/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_MEMORY_SHARED_PTR_HPP +#define BOOST_CSBL_MEMORY_SHARED_PTR_HPP + +#include + +#if defined BOOST_NO_CXX11_SMART_PTR + +#include +#include + +namespace boost +{ + namespace csbl + { + using ::boost::shared_ptr; + using ::boost::make_shared; + } +} + +#else + +#include + +namespace boost +{ + namespace csbl + { + using std::shared_ptr; + using std::make_shared; + } +} + +#endif +#endif // header diff --git a/boost/thread/csbl/memory/unique_ptr.hpp b/boost/thread/csbl/memory/unique_ptr.hpp new file mode 100644 index 0000000..17abf54 --- /dev/null +++ b/boost/thread/csbl/memory/unique_ptr.hpp @@ -0,0 +1,28 @@ +// Copyright (C) 2013-2014 Vicente J. Botet Escriba +// +// 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) +// +// 2013/10 Vicente J. Botet Escriba +// Creation using interprocess::unique_ptr. +// 2014/09 Vicente J. Botet Escriba +// Adaptation to movelib::unique_ptr + +#ifndef BOOST_CSBL_MEMORY_UNIQUE_PTR_HPP +#define BOOST_CSBL_MEMORY_UNIQUE_PTR_HPP + +#include + +#include +#include + +namespace boost +{ + namespace csbl + { + using ::boost::movelib::unique_ptr; + using ::boost::movelib::make_unique; + + } +} +#endif // header diff --git a/boost/thread/csbl/tuple.hpp b/boost/thread/csbl/tuple.hpp new file mode 100644 index 0000000..860229e --- /dev/null +++ b/boost/thread/csbl/tuple.hpp @@ -0,0 +1,49 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_TUPLE_HPP +#define BOOST_CSBL_TUPLE_HPP + +#include + +#if defined BOOST_THREAD_USES_BOOST_TUPLE || defined BOOST_NO_CXX11_HDR_TUPLE || defined BOOST_NO_CXX11_RVALUE_REFERENCES +#include +#ifndef BOOST_THREAD_USES_BOOST_TUPLE +#define BOOST_THREAD_USES_BOOST_TUPLE +#endif + +#else +#include +#endif + +namespace boost +{ + namespace csbl + { +#if defined BOOST_THREAD_USES_BOOST_TUPLE + using ::boost::tuple; + using ::boost::get; + using ::boost::make_tuple; + //using ::boost::tuple_size; +#else + // 20.4.2, class template tuple: + using ::std::tuple; + using ::std::get; + using ::std::make_tuple; + using ::std::tuple_size; + // 20.4.2.4, tuple creation functions: + // 20.4.2.5, tuple helper classes: + // 20.4.2.6, element access: + // 20.4.2.7, relational operators: + // 20.4.2.8, allocator-related traits + // 20.4.2.9, specialized algorithms: +#endif + + } +} +#endif // header diff --git a/boost/thread/csbl/vector.hpp b/boost/thread/csbl/vector.hpp new file mode 100644 index 0000000..c77a5b1 --- /dev/null +++ b/boost/thread/csbl/vector.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) +// +// 2013/10 Vicente J. Botet Escriba +// Creation. + +#ifndef BOOST_CSBL_VECTOR_HPP +#define BOOST_CSBL_VECTOR_HPP + +#include + +#if defined BOOST_THREAD_USES_BOOST_VECTOR || defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_MSVC +#ifndef BOOST_THREAD_USES_BOOST_VECTOR +#define BOOST_THREAD_USES_BOOST_VECTOR +#endif +#include +#else +#include +#endif + +namespace boost +{ + namespace csbl + { +#if defined BOOST_THREAD_USES_BOOST_VECTOR + using ::boost::container::vector; +#else + using ::std::vector; +#endif + + } +} +#endif // header diff --git a/boost/thread/cv_status.hpp b/boost/thread/cv_status.hpp new file mode 100644 index 0000000..e52de4a --- /dev/null +++ b/boost/thread/cv_status.hpp @@ -0,0 +1,26 @@ +// cv_status.hpp +// +// Copyright (C) 2011 Vicente J. Botet Escriba +// +// 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_THREAD_CV_STATUS_HPP +#define BOOST_THREAD_CV_STATUS_HPP + +#include + +namespace boost +{ + + // enum class cv_status; + BOOST_SCOPED_ENUM_DECLARE_BEGIN(cv_status) + { + no_timeout, + timeout + } + BOOST_SCOPED_ENUM_DECLARE_END(cv_status) +} + +#endif // header diff --git a/boost/thread/detail/atomic_redef_macros.hpp b/boost/thread/detail/atomic_redef_macros.hpp new file mode 100644 index 0000000..dfd15f5 --- /dev/null +++ b/boost/thread/detail/atomic_redef_macros.hpp @@ -0,0 +1,19 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) + + +#if defined(BOOST_INTEL) + +#pragma pop_macro("atomic_compare_exchange") +#pragma pop_macro("atomic_compare_exchange_explicit") +#pragma pop_macro("atomic_exchange") +#pragma pop_macro("atomic_exchange_explicit") +#pragma pop_macro("atomic_is_lock_free") +#pragma pop_macro("atomic_load") +#pragma pop_macro("atomic_load_explicit") +#pragma pop_macro("atomic_store") +#pragma pop_macro("atomic_store_explicit") + +#endif // #if defined(BOOST_INTEL) diff --git a/boost/thread/detail/atomic_undef_macros.hpp b/boost/thread/detail/atomic_undef_macros.hpp new file mode 100644 index 0000000..18d840a --- /dev/null +++ b/boost/thread/detail/atomic_undef_macros.hpp @@ -0,0 +1,39 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) + + +#if defined(BOOST_INTEL) + +#pragma push_macro("atomic_compare_exchange") +#undef atomic_compare_exchange + +#pragma push_macro("atomic_compare_exchange_explicit") +#undef atomic_compare_exchange_explicit + +#pragma push_macro("atomic_exchange") +#undef atomic_exchange + +#pragma push_macro("atomic_exchange_explicit") +#undef atomic_exchange_explicit + +#pragma push_macro("atomic_is_lock_free") +#undef atomic_is_lock_free + +#pragma push_macro("atomic_load") +#undef atomic_load + +#pragma push_macro("atomic_load_explicit") +#undef atomic_load_explicit + +#pragma push_macro("atomic_store") +#undef atomic_store + +#pragma push_macro("atomic_store_explicit") +#undef atomic_store_explicit + + +#endif // #if defined(BOOST_INTEL) + + diff --git a/boost/thread/detail/config.hpp b/boost/thread/detail/config.hpp new file mode 100644 index 0000000..ed46b1f --- /dev/null +++ b/boost/thread/detail/config.hpp @@ -0,0 +1,539 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2011-2013 Vicente J. Botet Escriba +// +// 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_THREAD_CONFIG_WEK01032003_HPP +#define BOOST_THREAD_CONFIG_WEK01032003_HPP + +#include +#include +#include +#include + +//#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS +// ATTRIBUTE_MAY_ALIAS + +//#if defined(__GNUC__) && !defined(__INTEL_COMPILER) +#if !defined(BOOST_NO_MAY_ALIAS) + + // GCC since 3.3 and some other compilers have may_alias attribute that helps + // to alleviate optimizer issues with regard to violation of the strict aliasing rules. + + #define BOOST_THREAD_DETAIL_USE_ATTRIBUTE_MAY_ALIAS +#endif +#if defined(BOOST_MAY_ALIAS) +#define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS BOOST_MAY_ALIAS +#else +#define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS +#endif + +#if defined(BOOST_THREAD_CHRONO_WINDOWS_API) +# warning Boost.Thread will use the Windows API for time +#elif defined(BOOST_THREAD_CHRONO_MAC_API) +# warning Boost.Thread will use the Mac API for time +#elif defined(BOOST_THREAD_CHRONO_POSIX_API) +# warning Boost.Thread will use the POSIX API for time +#endif + +# if defined( BOOST_THREAD_CHRONO_WINDOWS_API ) && defined( BOOST_THREAD_CHRONO_POSIX_API ) +# error both BOOST_THREAD_CHRONO_WINDOWS_API and BOOST_THREAD_CHRONO_POSIX_API are defined +# elif defined( BOOST_THREAD_CHRONO_WINDOWS_API ) && defined( BOOST_THREAD_CHRONO_MAC_API ) +# error both BOOST_THREAD_CHRONO_WINDOWS_API and BOOST_THREAD_CHRONO_MAC_API are defined +# elif defined( BOOST_THREAD_CHRONO_MAC_API ) && defined( BOOST_THREAD_CHRONO_POSIX_API ) +# error both BOOST_THREAD_CHRONO_MAC_API and BOOST_THREAD_CHRONO_POSIX_API are defined +# elif !defined( BOOST_THREAD_CHRONO_WINDOWS_API ) && !defined( BOOST_THREAD_CHRONO_MAC_API ) && !defined( BOOST_THREAD_CHRONO_POSIX_API ) +# if defined(BOOST_THREAD_PLATFORM_WIN32) +# define BOOST_THREAD_CHRONO_WINDOWS_API +# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +# define BOOST_THREAD_CHRONO_MAC_API +# else +# define BOOST_THREAD_CHRONO_POSIX_API +# endif +# endif + +#if !defined(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS) +#define BOOST_THREAD_POLL_INTERVAL_MILLISECONDS 100 +#endif + +#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED +#define BOOST_THREAD_ASSERT_PRECONDITION(EXPR, EX) \ + if (EXPR) {} else boost::throw_exception(EX) +#define BOOST_THREAD_VERIFY_PRECONDITION(EXPR, EX) \ + if (EXPR) {} else boost::throw_exception(EX) +#define BOOST_THREAD_THROW_ELSE_RETURN(EX, RET) \ + boost::throw_exception(EX) +#else +#define BOOST_THREAD_ASSERT_PRECONDITION(EXPR, EX) +#define BOOST_THREAD_VERIFY_PRECONDITION(EXPR, EX) \ + (void)(EXPR) +#define BOOST_THREAD_THROW_ELSE_RETURN(EX, RET) \ + return (RET) +#endif + +// This compiler doesn't support Boost.Chrono +#if defined __IBMCPP__ && (__IBMCPP__ < 1100) \ + && ! defined BOOST_THREAD_DONT_USE_CHRONO +#define BOOST_THREAD_DONT_USE_CHRONO +#if ! defined BOOST_THREAD_USES_DATETIME +#define BOOST_THREAD_USES_DATETIME +#endif +#endif + +// This compiler doesn't support Boost.Move +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) \ + && ! defined BOOST_THREAD_DONT_USE_MOVE +#define BOOST_THREAD_DONT_USE_MOVE +#endif + +// This compiler doesn't support Boost.Container Allocators files +#if defined __SUNPRO_CC \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS +#define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS +#endif + +#if defined _WIN32_WCE && _WIN32_WCE==0x501 \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS +#define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS +#endif + + +#if defined BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX || defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#define BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST +#define BOOST_THREAD_NO_MAKE_LOCK_GUARD +#define BOOST_THREAD_NO_MAKE_STRICT_LOCK +#define BOOST_THREAD_NO_MAKE_NESTED_STRICT_LOCK +#endif + +#if defined(BOOST_NO_CXX11_HDR_TUPLE) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#define BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS +#define BOOST_THREAD_NO_SYNCHRONIZE +#elif defined _MSC_VER && _MSC_VER <= 1600 +// C++ features supported by VC++ 10 (aka 2010) +#define BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS +#define BOOST_THREAD_NO_SYNCHRONIZE +#endif + +/// BASIC_THREAD_ID +#if ! defined BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID \ + && ! defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID +#define BOOST_THREAD_PROVIDES_BASIC_THREAD_ID +#endif + +/// RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR +//#if defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_MSVC +#define BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR +//#endif + +// Default version +#if !defined BOOST_THREAD_VERSION +#define BOOST_THREAD_VERSION 2 +#else +#if BOOST_THREAD_VERSION!=2 && BOOST_THREAD_VERSION!=3 && BOOST_THREAD_VERSION!=4 && BOOST_THREAD_VERSION!=5 +#error "BOOST_THREAD_VERSION must be 2, 3, 4 or 5" +#endif +#endif + +// CHRONO +// Uses Boost.Chrono by default if not stated the opposite defining BOOST_THREAD_DONT_USE_CHRONO +#if ! defined BOOST_THREAD_DONT_USE_CHRONO \ + && ! defined BOOST_THREAD_USES_CHRONO +#define BOOST_THREAD_USES_CHRONO +#endif + +#if ! defined BOOST_THREAD_DONT_USE_ATOMIC \ + && ! defined BOOST_THREAD_USES_ATOMIC +#define BOOST_THREAD_USES_ATOMIC +//#define BOOST_THREAD_DONT_USE_ATOMIC +#endif + +#if defined BOOST_THREAD_USES_ATOMIC +// Andrey Semashev +#define BOOST_THREAD_ONCE_ATOMIC +#else +//#elif ! defined BOOST_NO_CXX11_THREAD_LOCAL && ! defined BOOST_NO_THREAD_LOCAL && ! defined BOOST_THREAD_NO_UINT32_PSEUDO_ATOMIC +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html#Appendix +#define BOOST_THREAD_ONCE_FAST_EPOCH +#endif +#if BOOST_THREAD_VERSION==2 + +// PROVIDE_PROMISE_LAZY +#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY \ + && ! defined BOOST_THREAD_PROVIDES_PROMISE_LAZY +#define BOOST_THREAD_PROVIDES_PROMISE_LAZY +#endif + +// PROVIDE_THREAD_EQ +#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_EQ \ + && ! defined BOOST_THREAD_PROVIDES_THREAD_EQ +#define BOOST_THREAD_PROVIDES_THREAD_EQ +#endif + +#endif + +#if BOOST_THREAD_VERSION>=3 + +// ONCE_CXX11 +// fixme BOOST_THREAD_PROVIDES_ONCE_CXX11 doesn't works when thread.cpp is compiled BOOST_THREAD_VERSION 3 +#if ! defined BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11 \ + && ! defined BOOST_THREAD_PROVIDES_ONCE_CXX11 +#define BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11 +#endif + +// THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE +#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE \ + && ! defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE +#define BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE +#endif + +// THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE +#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE \ + && ! defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE +#define BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE +#endif + +// PROVIDE_FUTURE +#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE \ + && ! defined BOOST_THREAD_PROVIDES_FUTURE +#define BOOST_THREAD_PROVIDES_FUTURE +#endif + +// FUTURE_CTOR_ALLOCATORS +#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS \ + && ! defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS +#define BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS +#endif + +// SHARED_MUTEX_UPWARDS_CONVERSIONS +#if ! defined BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSIONS \ + && ! defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS +#define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS +#endif + +// PROVIDE_EXPLICIT_LOCK_CONVERSION +#if ! defined BOOST_THREAD_DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION \ + && ! defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION +#define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION +#endif + +// GENERIC_SHARED_MUTEX_ON_WIN +#if ! defined BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN \ + && ! defined BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN +#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN +#endif + +// USE_MOVE +#if ! defined BOOST_THREAD_DONT_USE_MOVE \ + && ! defined BOOST_THREAD_USES_MOVE +#define BOOST_THREAD_USES_MOVE +#endif + +#endif + +// deprecated since version 4 +#if BOOST_THREAD_VERSION < 4 + +// NESTED_LOCKS +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS \ + && ! defined BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS +#define BOOST_THREAD_PROVIDES_NESTED_LOCKS +#endif + +// CONDITION +#if ! defined BOOST_THREAD_PROVIDES_CONDITION \ + && ! defined BOOST_THREAD_DONT_PROVIDE_CONDITION +#define BOOST_THREAD_PROVIDES_CONDITION +#endif + +// USE_DATETIME +#if ! defined BOOST_THREAD_DONT_USE_DATETIME \ + && ! defined BOOST_THREAD_USES_DATETIME +#define BOOST_THREAD_USES_DATETIME +#endif +#endif + +#if BOOST_THREAD_VERSION>=4 + +// SIGNATURE_PACKAGED_TASK +#if ! defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK \ + && ! defined BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKAGED_TASK +#define BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#endif + +// VARIADIC_THREAD +#if ! defined BOOST_THREAD_PROVIDES_VARIADIC_THREAD \ + && ! defined BOOST_THREAD_DONT_PROVIDE_VARIADIC_THREAD + +#if ! defined(BOOST_NO_SFINAE_EXPR) && \ + ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + ! defined(BOOST_NO_CXX11_DECLTYPE) && \ + ! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \ + ! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \ + ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ + ! defined(BOOST_NO_CXX11_HDR_TUPLE) + +#define BOOST_THREAD_PROVIDES_VARIADIC_THREAD +#endif +#endif + +#if ! defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_WHEN_ALL_WHEN_ANY + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + ! defined(BOOST_NO_CXX11_HDR_TUPLE) + +#define BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY +#endif +#endif + +// ! defined(BOOST_NO_SFINAE_EXPR) && +// ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && +// ! defined(BOOST_NO_CXX11_AUTO) && +// ! defined(BOOST_NO_CXX11_DECLTYPE) && +// ! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && + + +// MAKE_READY_AT_THREAD_EXIT +#if ! defined BOOST_THREAD_PROVIDES_MAKE_READY_AT_THREAD_EXIT \ + && ! defined BOOST_THREAD_DONT_PROVIDE_MAKE_READY_AT_THREAD_EXIT + +//#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) +#define BOOST_THREAD_PROVIDES_MAKE_READY_AT_THREAD_EXIT +//#endif +#endif + +// FUTURE_CONTINUATION +#if ! defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CONTINUATION +#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION +#endif + +#if ! defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_UNWRAP +#define BOOST_THREAD_PROVIDES_FUTURE_UNWRAP +#endif + +// FUTURE_INVALID_AFTER_GET +#if ! defined BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET +#define BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET +#endif + +// NESTED_LOCKS +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS \ + && ! defined BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS +#define BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS +#endif + +// CONDITION +#if ! defined BOOST_THREAD_PROVIDES_CONDITION \ + && ! defined BOOST_THREAD_DONT_PROVIDE_CONDITION +#define BOOST_THREAD_DONT_PROVIDE_CONDITION +#endif + +#endif // BOOST_THREAD_VERSION>=4 + + +#if BOOST_THREAD_VERSION>=5 +//#define BOOST_THREAD_FUTURE_BLOCKING + +#if ! defined BOOST_THREAD_PROVIDES_EXECUTORS \ + && ! defined BOOST_THREAD_DONT_PROVIDE_EXECUTORS +#define BOOST_THREAD_PROVIDES_EXECUTORS +#endif + +#else +//#define BOOST_THREAD_FUTURE_BLOCKING +#define BOOST_THREAD_ASYNC_FUTURE_WAITS +#endif + + +// INTERRUPTIONS +#if ! defined BOOST_THREAD_PROVIDES_INTERRUPTIONS \ + && ! defined BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS +#define BOOST_THREAD_PROVIDES_INTERRUPTIONS +#endif + +// CORRELATIONS + +// EXPLICIT_LOCK_CONVERSION. +#if defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION +#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION explicit +#else +#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION +#endif + +// BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS +#if defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS \ +&& ! defined BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN +#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN +#endif + +// For C++11 call_once interface the compiler MUST support constexpr. +// Otherwise once_flag would be initialized during dynamic initialization stage, which is not thread-safe. +#if defined(BOOST_THREAD_PROVIDES_ONCE_CXX11) +#if defined(BOOST_NO_CXX11_CONSTEXPR) +#undef BOOST_THREAD_PROVIDES_ONCE_CXX11 +#endif +#endif + +#if defined(BOOST_THREAD_PLATFORM_WIN32) && defined BOOST_THREAD_DONT_USE_DATETIME +#undef BOOST_THREAD_DONT_USE_DATETIME +#define BOOST_THREAD_USES_DATETIME +#endif + +#if defined(BOOST_THREAD_PLATFORM_WIN32) && defined BOOST_THREAD_DONT_USE_CHRONO +#undef BOOST_THREAD_DONT_USE_CHRONO +#define BOOST_THREAD_USES_CHRONO +#endif + +// BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55 +// BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55 +#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 + +#if ! defined BOOST_THREAD_PROVIDES_THREAD_EQ +#define BOOST_THREAD_PROVIDES_THREAD_EQ +#endif + +#endif + + +//#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_THREAD_USES_MOVE +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +#define BOOST_THREAD_FUTURE_USES_OPTIONAL +#endif + +#if BOOST_WORKAROUND(__BORLANDC__, < 0x600) +# pragma warn -8008 // Condition always true/false +# pragma warn -8080 // Identifier declared but never used +# pragma warn -8057 // Parameter never used +# pragma warn -8066 // Unreachable code +#endif + +#include + +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#else + # if defined(BOOST_HAS_PTHREAD_DELAY_NP) || defined(BOOST_HAS_NANOSLEEP) + # define BOOST_THREAD_SLEEP_FOR_IS_STEADY + # endif +#endif + +#if defined(BOOST_THREAD_CHRONO_WINDOWS_API) + #define BOOST_THREAD_HAS_MONO_CLOCK + #define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO +#elif defined(BOOST_THREAD_CHRONO_MAC_API) + #define BOOST_THREAD_HAS_MONO_CLOCK +#elif defined(__ANDROID__) + #define BOOST_THREAD_HAS_MONO_CLOCK + #if defined(__ANDROID_API__) && __ANDROID_API__ >= 21 + #define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + #endif +#else + #include // check for CLOCK_MONOTONIC + #if defined(CLOCK_MONOTONIC) + #define BOOST_THREAD_HAS_MONO_CLOCK + #define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + #endif +#endif + +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#elif ! defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO +#if defined BOOST_PTHREAD_HAS_TIMEDLOCK +#define BOOST_THREAD_USES_PTHREAD_TIMEDLOCK +#elif (defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS-0)>=200112L) \ + || (defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21) +#define BOOST_THREAD_USES_PTHREAD_TIMEDLOCK +#endif +#endif + +// provided for backwards compatibility, since this +// macro was used for several releases by mistake. +#if defined(BOOST_THREAD_DYN_DLL) && ! defined(BOOST_THREAD_DYN_LINK) +# define BOOST_THREAD_DYN_LINK +#endif + +// compatibility with the rest of Boost's auto-linking code: +#if defined(BOOST_THREAD_DYN_LINK) || defined(BOOST_ALL_DYN_LINK) +# undef BOOST_THREAD_USE_LIB +# if !defined(BOOST_THREAD_USE_DLL) +# define BOOST_THREAD_USE_DLL +# endif +#endif + +#if defined(BOOST_THREAD_BUILD_DLL) //Build dll +#elif defined(BOOST_THREAD_BUILD_LIB) //Build lib +#elif defined(BOOST_THREAD_USE_DLL) //Use dll +#elif defined(BOOST_THREAD_USE_LIB) //Use lib +#else //Use default +# if defined(BOOST_THREAD_PLATFORM_WIN32) +# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) \ + || defined(__MINGW32__) || defined(MINGW32) || defined(BOOST_MINGW32) + //For compilers supporting auto-tss cleanup + //with Boost.Threads lib, use Boost.Threads lib +# define BOOST_THREAD_USE_LIB +# else + //For compilers not yet supporting auto-tss cleanup + //with Boost.Threads lib, use Boost.Threads dll +# define BOOST_THREAD_USE_DLL +# endif +# else +# define BOOST_THREAD_USE_LIB +# endif +#endif + +#if defined(BOOST_HAS_DECLSPEC) +# if defined(BOOST_THREAD_BUILD_DLL) //Build dll +# define BOOST_THREAD_DECL BOOST_SYMBOL_EXPORT +//# define BOOST_THREAD_DECL __declspec(dllexport) + +# elif defined(BOOST_THREAD_USE_DLL) //Use dll +# define BOOST_THREAD_DECL BOOST_SYMBOL_IMPORT +//# define BOOST_THREAD_DECL __declspec(dllimport) +# else +# define BOOST_THREAD_DECL +# endif +#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# define BOOST_THREAD_DECL BOOST_SYMBOL_VISIBLE + +#else +# define BOOST_THREAD_DECL +#endif // BOOST_HAS_DECLSPEC + +// +// Automatically link to the correct build variant where possible. +// +#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_THREAD_NO_LIB) && !defined(BOOST_THREAD_BUILD_DLL) && !defined(BOOST_THREAD_BUILD_LIB) +// +// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#if defined(BOOST_THREAD_USE_DLL) & ! defined(BOOST_DYN_LINK) +# define BOOST_DYN_LINK +#endif +// +// Set the name of our library, this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#if defined(BOOST_THREAD_LIB_NAME) +# define BOOST_LIB_NAME BOOST_THREAD_LIB_NAME +#else +# define BOOST_LIB_NAME boost_thread +#endif +// +// If we're importing code from a dll, then tell auto_link.hpp about it: +// +// And include the header that does the work: +// +#include +#endif // auto-linking disabled + +#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP + +// Change Log: +// 22 Jan 05 Roland Schwarz (speedsnail) +// Usage of BOOST_HAS_DECLSPEC macro. +// Default again is static lib usage. +// BOOST_DYN_LINK only defined when autolink included. diff --git a/boost/thread/detail/delete.hpp b/boost/thread/detail/delete.hpp new file mode 100644 index 0000000..8f8113f --- /dev/null +++ b/boost/thread/detail/delete.hpp @@ -0,0 +1,58 @@ +// Copyright (C) 2012 Vicente J. Botet Escriba +// +// 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_THREAD_DETAIL_DELETE_HPP +#define BOOST_THREAD_DETAIL_DELETE_HPP + +#include + +/** + * BOOST_THREAD_DELETE_COPY_CTOR deletes the copy constructor when the compiler supports it or + * makes it private. + * + * BOOST_THREAD_DELETE_COPY_ASSIGN deletes the copy assignment when the compiler supports it or + * makes it private. + */ + +#if ! defined BOOST_NO_CXX11_DELETED_FUNCTIONS && ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \ + CLASS(CLASS const&) = delete; \ + +#define BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) \ + CLASS& operator=(CLASS const&) = delete; + +#else // BOOST_NO_CXX11_DELETED_FUNCTIONS +#if defined(BOOST_MSVC) && _MSC_VER >= 1600 +#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \ + private: \ + CLASS(CLASS const&); \ + public: + +#define BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) \ + private: \ + CLASS& operator=(CLASS const&); \ + public: +#else +#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \ + private: \ + CLASS(CLASS&); \ + public: + +#define BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) \ + private: \ + CLASS& operator=(CLASS&); \ + public: +#endif +#endif // BOOST_NO_CXX11_DELETED_FUNCTIONS + +/** + * BOOST_THREAD_NO_COPYABLE deletes the copy constructor and assignment when the compiler supports it or + * makes them private. + */ +#define BOOST_THREAD_NO_COPYABLE(CLASS) \ + BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \ + BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) + +#endif // BOOST_THREAD_DETAIL_DELETE_HPP diff --git a/boost/thread/detail/invoke.hpp b/boost/thread/detail/invoke.hpp new file mode 100644 index 0000000..e772da2 --- /dev/null +++ b/boost/thread/detail/invoke.hpp @@ -0,0 +1,1604 @@ +// Copyright (C) 2012-2013 Vicente J. Botet Escriba +// +// 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) + +// 2013/04 Vicente J. Botet Escriba +// Provide implementation up to 9 parameters when BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined. +// Make use of Boost.Move +// Make use of Boost.Tuple (movable) +// 2012 Vicente J. Botet Escriba +// Provide implementation _RET using bind when BOOST_NO_CXX11_HDR_FUNCTIONAL and BOOST_NO_SFINAE_EXPR are not defined +// 2012 Vicente J. Botet Escriba +// Adapt to boost libc++ implementation + +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// The invoke code is based on the one from libcxx. +//===----------------------------------------------------------------------===// + +#ifndef BOOST_THREAD_DETAIL_INVOKE_HPP +#define BOOST_THREAD_DETAIL_INVOKE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL +#include +#endif + +namespace boost +{ + namespace detail + { + + +#if ! defined(BOOST_NO_SFINAE_EXPR) && \ + ! defined(BOOST_NO_CXX11_DECLTYPE) && \ + ! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \ + ! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) + +#define BOOST_THREAD_PROVIDES_INVOKE + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + // bullets 1 and 2 + + template + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + -> decltype((boost::forward(a0).*f)(boost::forward(args)...)) + { + return (boost::forward(a0).*f)(boost::forward(args)...); + } + template + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + -> decltype((boost::forward(a0).*f)(boost::forward(args)...)) + { + return (boost::forward(a0).*f)(boost::forward(args)...); + } + + template + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + -> decltype(((*boost::forward(a0)).*f)(boost::forward(args)...)) + { + return ((*boost::forward(a0)).*f)(boost::forward(args)...); + } + template + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + -> decltype(((*boost::forward(a0)).*f)(boost::forward(args)...)) + { + return ((*boost::forward(a0)).*f)(boost::forward(args)...); + } + + // bullets 3 and 4 + + template + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype(boost::forward(a0).*f) + { + return boost::forward(a0).*f; + } + + template + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype((*boost::forward(a0)).*f) + { + return (*boost::forward(a0)).*f; + } + + template + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype(boost::forward(a0).*f) + { + return boost::forward(a0).*f; + } + + template + inline auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype((*boost::forward(a0)).*f) + { + return (*boost::forward(a0)).*f; + } + + + // bullet 5 + + template + inline auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args) + -> decltype(boost::forward(f)(boost::forward(args)...)) + { + return boost::forward(f)(boost::forward(args)...); + } + template + inline auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args) + -> decltype(boost::forward(f)(boost::forward(args)...)) + { + return boost::forward(f)(boost::forward(args)...); + } + +#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES + + // bullets 1 and 2 + + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype((boost::forward(a0).*f)()) + { + return (boost::forward(a0).*f)(); + } + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype((boost::forward(a0).*f)()) + { + return (boost::forward(a0).*f)(); + } + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + -> decltype((boost::forward(a0).*f)(boost::forward(a1))) + { + return (boost::forward(a0).*f)(boost::forward(a1)); + } + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + -> decltype((boost::forward(a0).*f)(boost::forward(a1))) + { + return (boost::forward(a0).*f)(boost::forward(a1)); + } + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + -> decltype((boost::forward(a0).*f)(boost::forward(a1), boost::forward(a2))) + { + return (boost::forward(a0).*f)(boost::forward(a1), boost::forward(a2)); + } + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + -> decltype((boost::forward(a0).*f)(boost::forward(a1), boost::forward(a2))) + { + return (boost::forward(a0).*f)(boost::forward(a1), boost::forward(a2)); + } + + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype(((*boost::forward(a0)).*f)()) + { + return ((*boost::forward(a0)).*f)(); + } + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype(((*boost::forward(a0)).*f)()) + { + return ((*boost::forward(a0)).*f)(); + } + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + -> decltype(((*boost::forward(a0)).*f)(boost::forward(a1))) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1)); + } + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + -> decltype(((*boost::forward(a0)).*f)(boost::forward(a1))) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1)); + } + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + -> decltype(((*boost::forward(a0)).*f)(boost::forward(a1), boost::forward(a2))) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1), boost::forward(a2)); + } + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + -> decltype(((*boost::forward(a0)).*f)(boost::forward(a1), boost::forward(a2))) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1), boost::forward(a2)); + } + + // bullets 3 and 4 + + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype(boost::forward(a0).*f) + { + return boost::forward(a0).*f; + } + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype(boost::forward(a0).*f) + { + return boost::forward(a0).*f; + } + + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype((*boost::forward(a0)).*f) + { + return (*boost::forward(a0)).*f; + } + template + inline + auto + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0) + -> decltype((*boost::forward(a0)).*f) + { + return (*boost::forward(a0)).*f; + } + + // bullet 5 + + template + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f) + -> decltype(boost::forward(f)()) + { + return boost::forward(f)(); + } + template + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1) + -> decltype(boost::forward(f)(boost::forward(a1))) + { + return boost::forward(f)(boost::forward(a1)); + } template + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + -> decltype(boost::forward(f)(boost::forward(a1), boost::forward(a2))) + { + return boost::forward(f)(boost::forward(a1), boost::forward(a2)); + } + template + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + -> decltype(boost::forward(f)(boost::forward(a1), boost::forward(a2), boost::forward(a3))) + { + return boost::forward(f)(boost::forward(a1), boost::forward(a2), boost::forward(a3)); + } + + + template + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f) + -> decltype(boost::forward(f)()) + { + return boost::forward(f)(); + } + template + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1) + -> decltype(boost::forward(f)(boost::forward(a1))) + { + return boost::forward(f)(boost::forward(a1)); + } + template + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + -> decltype(boost::forward(f)(boost::forward(a1), boost::forward(a2))) + { + return boost::forward(f)(boost::forward(a1), boost::forward(a2)); + } + template + inline + auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + -> decltype(boost::forward(f)(boost::forward(a1), boost::forward(a2), boost::forward(a3))) + { + return boost::forward(f)(boost::forward(a1), boost::forward(a2), boost::forward(a3)); + } + +#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES + +#elif ! defined(BOOST_NO_SFINAE_EXPR) && \ + ! defined BOOST_NO_CXX11_HDR_FUNCTIONAL && \ + defined BOOST_MSVC + + template + inline + Ret invoke(BOOST_THREAD_RV_REF(Fp) f) + { + return f(); + } + template + inline + Ret invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1) + { + return std::bind(boost::forward(f), boost::forward(a1))(); + } + template + inline + Ret invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return std::bind(boost::forward(f), boost::forward(a1), boost::forward(a2))(); + } + template + inline + Ret invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return std::bind(boost::forward(f), boost::forward(a1), boost::forward(a2), boost::forward(a3))(); + } + +#define BOOST_THREAD_PROVIDES_INVOKE_RET + +#elif ! defined BOOST_MSVC +//!!!!! WARNING !!!!! THIS DOESN'T WORKS YET +#define BOOST_THREAD_PROVIDES_INVOKE_RET + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + // bullet 1 + // (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of + // type T or a reference to an object of type T or a reference to an object of a type derived from T + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...), BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return (boost::forward(a0).*f)(boost::forward(args)...); + } + + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...) const, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return (boost::forward(a0).*f)(boost::forward(args)...); + } + + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...) volatile, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return (boost::forward(a0).*f)(boost::forward(args)...); + } + + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...) const volatile, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return (boost::forward(a0).*f)(boost::forward(args)...); + } + + // bullet 2 + // ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of + // the types described in the previous item; + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...), BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return ((*boost::forward(a0)).*f)(boost::forward(args)...); + } + + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...) const, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return ((*boost::forward(a0)).*f)(boost::forward(args)...); + } + + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...) volatile, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return ((*boost::forward(a0)).*f)(boost::forward(args)...); + } + + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(Args...) const volatile, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args) + { + return ((*boost::forward(a0)).*f)(boost::forward(args)...); + } + + // bullet 3 + // t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a + // reference to an object of type T or a reference to an object of a type derived from T; +// template +// inline +// typename enable_if_c +// < +// is_base_of::type>::value, +// typename detail::apply_cv::type& +// >::type +// invoke(Ret A::* f, BOOST_THREAD_RV_REF(A0) a0) +// { +// return boost::forward(a0).*f; +// } + + // bullet 4 + // (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types + //described in the previous item; + +// template +// struct d4th_helper +// { +// }; +// +// template +// struct d4th_helper +// { +// typedef typename apply_cv()), Ret>::type type; +// }; +// +// template +// inline +// typename detail::4th_helper::type +// >::value +// >::type& +// invoke(Ret A::* f, BOOST_THREAD_RV_REF(A0) a0) +// { +// return (*boost::forward(a0)).*f; +// } + +// template +// inline +// typename enable_if_c +// < +// !is_base_of::type>::value, +// typename detail::ref_return1::type +// >::type +// invoke(Ret A::* f, BOOST_THREAD_RV_REF(A0) a0) +// { +// return (*boost::forward(a0)).*f; +// } + + // bullet 5 + // f(t1, t2, ..., tN) in all other cases. + + template + inline Ret do_invoke(mpl::false_, BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args) + { + return boost::forward(f)(boost::forward(args)...); + } + + template + inline Ret do_invoke(mpl::true_, BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args) + { + return f(boost::forward(args)...); + } + + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args) + { + return boost::detail::do_invoke(boost::is_pointer(), boost::forward(f), boost::forward(args)...); + } +#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES + // bullet 1 + // (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of + // type T or a reference to an object of type T or a reference to an object of a type derived from T + + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(), A0& a0) + { + return (a0.*f)(); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(), A0* a0) + { + return ((*a0).*f)(); + } + + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1), + A0& a0, BOOST_THREAD_RV_REF(A1) a1 + ) + { + return (a0.*f)(boost::forward(a1)); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1), A0& a0, A1 a1) + { + return (a0.*f)(a1); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1), A0* a0, BOOST_THREAD_RV_REF(A1) a1 + ) + { + return (*(a0).*f)(boost::forward(a1)); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1), A0* a0, A1 a1) + { + return (*a0.*f)(a1); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2), + A0& a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2 + ) + { + return (a0.*f)(boost::forward(a1), boost::forward(a2)); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2), A0* a0, A1 a1, A2 a2) + { + return ((*a0).*f)(a1, a2); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3), + A0& a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return (a0.*f)(boost::forward(a1), boost::forward(a2), boost::forward(a3)); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3), A0* a0, A1 a1, A2 a2, A3 a3) + { + return ((*a0).*f)(a1, a2, a3); + } + +/// + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)() const, A0 const& a0) + { + return (a0.*f)(); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)() const, A0 const* a0) + { + return ((*a0).*f)(); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const, A0 const& a0, BOOST_THREAD_RV_REF(A1) a1) + { + return (a0.*f)(boost::forward(a1)); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const, A0 const* a0, BOOST_THREAD_RV_REF(A1) a1) + { + return ((*a0).*f)(boost::forward(a1)); + } + + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const, A0 const& a0, A1 a1) + { + return (a0.*f)(a1); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const, + A0 const& a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2 + ) + { + return (boost::forward(a0).*f)(boost::forward(a1), boost::forward(a2) + ); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const, A0 const& a0, A1 a1, A2 a2) + { + return (a0.*f)(a1, a2); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3 + ) + { + return (boost::forward(a0).*f)(boost::forward(a1), boost::forward(a2), boost::forward(a3)); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const, A0 a0, A1 a1, A2 a2, A3 a3) + { + return (a0.*f)(a1, a2, a3); + } + /// + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)() volatile, BOOST_THREAD_RV_REF(A0) a0) + { + return (boost::forward(a0).*f)(); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) volatile, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + { + return (boost::forward(a0).*f)(boost::forward(a1)); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) volatile, A0 a0, A1 a1) + { + return (a0.*f)(a1); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return (boost::forward(a0).*f)(boost::forward(a1), boost::forward(a2)); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) volatile, A0 a0, A1 a1, A2 a2 ) + { + return (a0.*f)(a1, a2); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3 + ) + { + return (boost::forward(a0).*f)(boost::forward(a1), boost::forward(a2), boost::forward(a3)); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) volatile, A0 a0, A1 a1, A2 a2, A3 a3) + { + return (a0.*f)(a1, a2, a3); + } + /// + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)() const volatile, BOOST_THREAD_RV_REF(A0) a0) + { + return (boost::forward(a0).*f)(); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const volatile, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + { + return (boost::forward(a0).*f)(boost::forward(a1)); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const volatile, A0 a0, A1 a1) + { + return (a0.*f)(a1); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2 + ) + { + return (boost::forward(a0).*f)(boost::forward(a1), boost::forward(a2)); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const volatile, + A0 a0, A1 a1, A2 a2 + ) + { + return (a0.*f)(a1, a2); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3 + ) + { + return (boost::forward(a0).*f)(boost::forward(a1), boost::forward(a2), boost::forward(a3)); + } + template + inline + typename enable_if_c + < + is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const volatile, + A0 a0, A1 a1, A2 a2, A3 a3 + ) + { + return (a0.*f)(a1, a2, a3); + } + + // bullet 2 + // ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of + // the types described in the previous item; + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(), BOOST_THREAD_RV_REF(A0) a0) + { + return ((*boost::forward(a0)).*f)(); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1), BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1)); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1), A0 a0, A1 a1) + { + return ((*a0).*f)(a1); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, BOOST_THREAD_RV_REF(A2)), + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1), boost::forward(a2)); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2), A0 a0, A1 a1, A2 a2) + { + return ((*a0).*f)(a1, a2); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, BOOST_THREAD_RV_REF(A2), BOOST_THREAD_RV_REF(A3)), + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1), boost::forward(a2), boost::forward(a3) + ); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3), A0 a0, A1 a1, A2 a2, A3 a3) + { + return ((*a0).*f)(a1, a2, a3); + } + +/// + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)() const, BOOST_THREAD_RV_REF(A0) a0) + { + return ((*boost::forward(a0)).*f)(); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1)); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const, BOOST_THREAD_RV_REF(A0) a0, A1 a1) + { + return ((*boost::forward(a0)).*f)(a1); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const, A0 a0, A1 a1) + { + return ((*a0).*f)(a1); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1), boost::forward(a2)); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const, A0 a0, A1 a1, A2 a2) + { + return ((*a0).*f)(a1, a2); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1), boost::forward(a2), boost::forward(a3)); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const, + A0 a0, A1 a1, A2 a2, A3 a3) + { + return ((*a0).*f)(a1, a2, a3); + } + /// + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)() volatile, BOOST_THREAD_RV_REF(A0) a0) + { + return ((*boost::forward(a0)).*f)(); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1)); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) volatile, A0 a0, A1 a1) + { + return ((*a0).*f)(a1); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1), boost::forward(a2)); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) volatile, A0 a0, A1 a1, A2 a2) + { + return ((*a0).*f)(a1, a2); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1), boost::forward(a2), boost::forward(a3)); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) volatile, A0 a0, A1 a1, A2 a2, A3 a3) + { + return ((*a0).*f)(a1, a2, a3); + } + /// + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)() const volatile, BOOST_THREAD_RV_REF(A0) a0) + { + return ((*boost::forward(a0)).*f)(); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)() const volatile, A0 a0) + { + return ((*a0).*f)(); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1)); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1) const volatile, A0 a0, A1 a1) + { + return ((*a0).*f)(a1); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1), boost::forward(a2)); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2) const volatile, + A0 a0, A1 a1, A2 a2) + { + return ((*a0).*f)(a1, a2); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const volatile, + BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return ((*boost::forward(a0)).*f)(boost::forward(a1), boost::forward(a2), boost::forward(a3)); + } + template + inline + typename enable_if_c + < + ! is_base_of::type>::value, + Ret + >::type + invoke(Ret (A::*f)(A1, A2, A3) const volatile, + A0 a0, A1 a1, A2 a2, A3 a3) + { + return ((*a0).*f)(a1, a2, a3); + } + // bullet 3 + // t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is an object of type T or a + // reference to an object of type T or a reference to an object of a type derived from T; +// template +// inline +// typename enable_if_c +// < +// is_base_of::type>::value, +// typename detail::apply_cv::type& +// >::type +// invoke(Ret A::* f, BOOST_THREAD_RV_REF(A0) a0) +// { +// return boost::forward(a0).*f; +// } + + // bullet 4 + // (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1 is not one of the types + //described in the previous item; + +// template +// struct d4th_helper +// { +// }; +// +// template +// struct d4th_helper +// { +// typedef typename apply_cv()), Ret>::type type; +// }; +// +// template +// inline +// typename detail::4th_helper::type +// >::value +// >::type& +// invoke(Ret A::* f, BOOST_THREAD_RV_REF(A0) a0) +// { +// return (*boost::forward(a0)).*f; +// } + +// template +// inline +// typename enable_if_c +// < +// !is_base_of::type>::value, +// typename detail::ref_return1::type +// >::type +// invoke(Ret A::* f, BOOST_THREAD_RV_REF(A0) a0) +// { +// return (*boost::forward(a0)).*f; +// } + + // bullet 5 + // f(t1, t2, ..., tN) in all other cases. + + template + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f) + { + return boost::forward(f)(); + } + template + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f) + { + return f(); + } + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f) + { + return boost::detail::do_invoke(boost::is_pointer(), boost::forward(f)); + } + + template + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1) + { + return boost::forward(f)(boost::forward(a1)); + } + template + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1) + { + return f(boost::forward(a1)); + } + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1) + { + return boost::detail::do_invoke(boost::is_pointer(), boost::forward(f), boost::forward(a1)); + } + + template + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return boost::forward(f)(boost::forward(a1), boost::forward(a2)); + } + template + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return f(boost::forward(a1), boost::forward(a2)); + } + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return boost::detail::do_invoke(boost::is_pointer(), boost::forward(f), boost::forward(a1), boost::forward(a2)); + } + + template + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return boost::forward(f)(boost::forward(a1), boost::forward(a2), boost::forward(a3)); + } + template + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return f(boost::forward(a1), boost::forward(a2), boost::forward(a3)); + } + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return boost::detail::do_invoke(boost::is_pointer(), boost::forward(f), boost::forward(a1), boost::forward(a2), boost::forward(a3)); + } + + + template + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1) + { + return boost::forward(f)(a1); + } + template + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1) + { + return f(a1); + } + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f, A1 a1) + { + return boost::detail::do_invoke(boost::is_pointer(), boost::forward(f), a1); + } + + template + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2) + { + return boost::forward(f)(a1, a2); + } + template + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2) + { + return f(a1, a2); + } + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2) + { + return boost::detail::do_invoke(boost::is_pointer(), boost::forward(f), a1, a2); + } + + template + inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3) + { + return boost::forward(f)(a1, a2, a3); + } + template + inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3) + { + return f(a1, a2, a3); + } + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3) + { + return boost::detail::do_invoke(boost::is_pointer(), boost::forward(f), a1, a2, a3); + } + + + /// + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(Fp &f) + { + return f(); + } + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(Fp &f, BOOST_THREAD_RV_REF(A1) a1) + { + return f(boost::forward(a1)); + } + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(Fp &f, A1 a1) + { + return f(a1); + } + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(Fp &f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2) + { + return f(boost::forward(a1), boost::forward(a2)); + } + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(Fp &f, A1 a1, A2 a2) + { + return f(a1, a2); + } + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(Fp &f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3) + { + return f(boost::forward(a1), boost::forward(a2), boost::forward(a3)); + } + template + inline + typename disable_if_c + < + is_member_function_pointer::value, + Ret + >::type + invoke(Fp &f, A1 a1, A2 a2, A3 a3) + { + return f(a1, a2, a3); + } + /// + +#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES + +#endif // all + } + } + +#endif // header diff --git a/boost/thread/detail/invoker.hpp b/boost/thread/detail/invoker.hpp new file mode 100644 index 0000000..9f38e97 --- /dev/null +++ b/boost/thread/detail/invoker.hpp @@ -0,0 +1,762 @@ +// Copyright (C) 2012 Vicente J. Botet Escriba +// +// 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) + +// 2013/04 Vicente J. Botet Escriba +// Provide implementation up to 9 parameters when BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined. +// Make use of Boost.Move +// Make use of Boost.Tuple (movable) +// 2012/11 Vicente J. Botet Escriba +// Adapt to boost libc++ implementation + +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// The invoker code is based on the one from libcxx. +//===----------------------------------------------------------------------===// + +#ifndef BOOST_THREAD_DETAIL_INVOKER_HPP +#define BOOST_THREAD_DETAIL_INVOKER_HPP + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost +{ + namespace detail + { + +#if defined(BOOST_THREAD_PROVIDES_INVOKE) && ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ! defined(BOOST_NO_CXX11_HDR_TUPLE) + + template + class invoker + { + //typedef typename decay::type Fpd; + //typedef tuple::type...> Argsd; + + //csbl::tuple f_; + csbl::tuple f_; + + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE( invoker) + //typedef typename invoke_of<_Fp, _Args...>::type Rp; + typedef typename result_of::type result_type; + + template + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(As)... args) + : f_(boost::forward(f), boost::forward(args)...) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) : f_(boost::move(BOOST_THREAD_RV(f).f_)) + {} + + BOOST_SYMBOL_VISIBLE + invoker( const invoker& f) : f_(f.f_) + {} + + BOOST_SYMBOL_VISIBLE + invoker& operator=(BOOST_THREAD_RV_REF(invoker) f) + { + if (this != &f) + { + f_ = boost::move(BOOST_THREAD_RV(f).f_); + } + return *this; + } + + BOOST_SYMBOL_VISIBLE + invoker& operator=( BOOST_THREAD_COPY_ASSIGN_REF(invoker) f) + { + if (this != &f) + { + f_ = f.f_; + } + return *this; + } + + result_type operator()() + { + typedef typename make_tuple_indices<1+sizeof...(Args), 1>::type Index; + return execute(Index()); + } + private: + template + result_type + execute(tuple_indices) + { + return detail::invoke(boost::move(csbl::get<0>(f_)), boost::move(csbl::get(f_))...); + } + }; + + template + class invoker_ret + { + //typedef typename decay::type Fpd; + //typedef tuple::type...> Argsd; + + //csbl::tuple f_; + csbl::tuple f_; + + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE( invoker_ret) + typedef R result_type; + + template + BOOST_SYMBOL_VISIBLE + explicit invoker_ret(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(As)... args) + : f_(boost::forward(f), boost::forward(args)...) + {} + + BOOST_SYMBOL_VISIBLE + invoker_ret(BOOST_THREAD_RV_REF(invoker_ret) f) : f_(boost::move(BOOST_THREAD_RV(f).f_)) + {} + + result_type operator()() + { + typedef typename make_tuple_indices<1+sizeof...(Args), 1>::type Index; + return execute(Index()); + } + private: + template + result_type + execute(tuple_indices) + { + return detail::invoke(boost::move(csbl::get<0>(f_)), boost::move(csbl::get(f_))...); + } + }; + //BOOST_THREAD_DCL_MOVABLE_BEG(X) invoker BOOST_THREAD_DCL_MOVABLE_END +#else + +#if ! defined BOOST_MSVC && defined(BOOST_THREAD_PROVIDES_INVOKE) + +#define BOOST_THREAD_RV_REF_ARG_T(z, n, unused) BOOST_PP_COMMA_IF(n) BOOST_THREAD_RV_REF(Arg##n) +#define BOOST_THREAD_RV_REF_A_T(z, n, unused) BOOST_PP_COMMA_IF(n) BOOST_THREAD_RV_REF(A##n) +#define BOOST_THREAD_RV_REF_ARG(z, n, unused) , BOOST_THREAD_RV_REF(Arg##n) arg##n +#define BOOST_THREAD_FWD_REF_A(z, n, unused) , BOOST_THREAD_FWD_REF(A##n) arg##n +#define BOOST_THREAD_FWD_REF_ARG(z, n, unused) , BOOST_THREAD_FWD_REF(Arg##n) arg##n +#define BOOST_THREAD_FWD_PARAM(z, n, unused) , boost::forward(arg##n) +#define BOOST_THREAD_FWD_PARAM_A(z, n, unused) , boost::forward(arg##n) +#define BOOST_THREAD_DCL(z, n, unused) Arg##n v##n; +#define BOOST_THREAD_MOVE_PARAM(z, n, unused) , v##n(boost::move(arg##n)) +#define BOOST_THREAD_FORWARD_PARAM_A(z, n, unused) , v##n(boost::forward(arg##n)) +#define BOOST_THREAD_MOVE_RHS_PARAM(z, n, unused) , v##n(boost::move(x.v##n)) +#define BOOST_THREAD_MOVE_DCL(z, n, unused) , boost::move(v##n) +#define BOOST_THREAD_MOVE_DCL_T(z, n, unused) BOOST_PP_COMMA_IF(n) boost::move(v##n) +#define BOOST_THREAD_ARG_DEF(z, n, unused) , class Arg##n = tuples::null_type + + template + class invoker; + +#define BOOST_THREAD_ASYNC_FUNCT(z, n, unused) \ + template \ + class invoker \ + { \ + Fp fp_; \ + BOOST_PP_REPEAT(n, BOOST_THREAD_DCL, ~) \ + public: \ + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) \ + typedef typename result_of::type result_type; \ + \ + template \ + BOOST_SYMBOL_VISIBLE \ + explicit invoker(BOOST_THREAD_FWD_REF(F) f \ + BOOST_PP_REPEAT(n, BOOST_THREAD_FWD_REF_A, ~) \ + ) \ + : fp_(boost::forward(f)) \ + BOOST_PP_REPEAT(n, BOOST_THREAD_FORWARD_PARAM_A, ~) \ + {} \ + \ + BOOST_SYMBOL_VISIBLE \ + invoker(BOOST_THREAD_RV_REF(invoker) x) \ + : fp_(boost::move(x.fp_)) \ + BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_RHS_PARAM, ~) \ + {} \ + \ + result_type operator()() { \ + return detail::invoke(boost::move(fp_) \ + BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_DCL, ~) \ + ); \ + } \ + }; \ + \ + template \ + class invoker \ + { \ + typedef R(*Fp)(BOOST_PP_REPEAT(n, BOOST_THREAD_RV_REF_ARG_T, ~)); \ + Fp fp_; \ + BOOST_PP_REPEAT(n, BOOST_THREAD_DCL, ~) \ + public: \ + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) \ + typedef typename result_of::type result_type; \ + \ + template \ + BOOST_SYMBOL_VISIBLE \ + explicit invoker(R2(*f)(BOOST_PP_REPEAT(n, BOOST_THREAD_RV_REF_A_T, ~)) \ + BOOST_PP_REPEAT(n, BOOST_THREAD_FWD_REF_A, ~) \ + ) \ + : fp_(f) \ + BOOST_PP_REPEAT(n, BOOST_THREAD_FORWARD_PARAM_A, ~) \ + {} \ + \ + BOOST_SYMBOL_VISIBLE \ + invoker(BOOST_THREAD_RV_REF(invoker) x) \ + : fp_(x.fp_) \ + BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_RHS_PARAM, ~) \ + {} \ + \ + result_type operator()() { \ + return fp_( \ + BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_DCL_T, ~) \ + ); \ + } \ + }; + + BOOST_PP_REPEAT(BOOST_THREAD_MAX_ARGS, BOOST_THREAD_ASYNC_FUNCT, ~) + + #undef BOOST_THREAD_RV_REF_ARG_T + #undef BOOST_THREAD_RV_REF_ARG + #undef BOOST_THREAD_FWD_REF_ARG + #undef BOOST_THREAD_FWD_REF_A + #undef BOOST_THREAD_FWD_PARAM + #undef BOOST_THREAD_FWD_PARAM_A + #undef BOOST_THREAD_DCL + #undef BOOST_THREAD_MOVE_PARAM + #undef BOOST_THREAD_MOVE_RHS_PARAM + #undef BOOST_THREAD_MOVE_DCL + #undef BOOST_THREAD_ARG_DEF + #undef BOOST_THREAD_ASYNC_FUNCT + +#else + + template + class invoker; + + template + class invoker + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + T3 v3_; + T4 v4_; + T5 v5_; + T6 v6_; + T7 v7_; + T8 v8_; + //::boost::tuple f_; + + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + , BOOST_THREAD_RV_REF(T3) a3 + , BOOST_THREAD_RV_REF(T4) a4 + , BOOST_THREAD_RV_REF(T5) a5 + , BOOST_THREAD_RV_REF(T6) a6 + , BOOST_THREAD_RV_REF(T7) a7 + , BOOST_THREAD_RV_REF(T8) a8 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + , v3_(boost::move(a3)) + , v4_(boost::move(a4)) + , v5_(boost::move(a5)) + , v6_(boost::move(a6)) + , v7_(boost::move(a7)) + , v8_(boost::move(a8)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + , v3_(boost::move(BOOST_THREAD_RV(f).v3_)) + , v4_(boost::move(BOOST_THREAD_RV(f).v4_)) + , v5_(boost::move(BOOST_THREAD_RV(f).v5_)) + , v6_(boost::move(BOOST_THREAD_RV(f).v6_)) + , v7_(boost::move(BOOST_THREAD_RV(f).v7_)) + , v8_(boost::move(BOOST_THREAD_RV(f).v8_)) + {} + + result_type operator()() + { + return detail::invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + , boost::move(v3_) + , boost::move(v4_) + , boost::move(v5_) + , boost::move(v6_) + , boost::move(v7_) + , boost::move(v8_) + ); + } + }; + template + class invoker + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + T3 v3_; + T4 v4_; + T5 v5_; + T6 v6_; + T7 v7_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + , BOOST_THREAD_RV_REF(T3) a3 + , BOOST_THREAD_RV_REF(T4) a4 + , BOOST_THREAD_RV_REF(T5) a5 + , BOOST_THREAD_RV_REF(T6) a6 + , BOOST_THREAD_RV_REF(T7) a7 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + , v3_(boost::move(a3)) + , v4_(boost::move(a4)) + , v5_(boost::move(a5)) + , v6_(boost::move(a6)) + , v7_(boost::move(a7)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + , v3_(boost::move(BOOST_THREAD_RV(f).v3_)) + , v4_(boost::move(BOOST_THREAD_RV(f).v4_)) + , v5_(boost::move(BOOST_THREAD_RV(f).v5_)) + , v6_(boost::move(BOOST_THREAD_RV(f).v6_)) + , v7_(boost::move(BOOST_THREAD_RV(f).v7_)) + {} + + result_type operator()() + { + return detail::invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + , boost::move(v3_) + , boost::move(v4_) + , boost::move(v5_) + , boost::move(v6_) + , boost::move(v7_) + ); + } + }; + template + class invoker + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + T3 v3_; + T4 v4_; + T5 v5_; + T6 v6_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + , BOOST_THREAD_RV_REF(T3) a3 + , BOOST_THREAD_RV_REF(T4) a4 + , BOOST_THREAD_RV_REF(T5) a5 + , BOOST_THREAD_RV_REF(T6) a6 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + , v3_(boost::move(a3)) + , v4_(boost::move(a4)) + , v5_(boost::move(a5)) + , v6_(boost::move(a6)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + , v3_(boost::move(BOOST_THREAD_RV(f).v3_)) + , v4_(boost::move(BOOST_THREAD_RV(f).v4_)) + , v5_(boost::move(BOOST_THREAD_RV(f).v5_)) + , v6_(boost::move(BOOST_THREAD_RV(f).v6_)) + {} + + result_type operator()() + { + return detail::invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + , boost::move(v3_) + , boost::move(v4_) + , boost::move(v5_) + , boost::move(v6_) + ); + } + }; + template + class invoker + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + T3 v3_; + T4 v4_; + T5 v5_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + , BOOST_THREAD_RV_REF(T3) a3 + , BOOST_THREAD_RV_REF(T4) a4 + , BOOST_THREAD_RV_REF(T5) a5 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + , v3_(boost::move(a3)) + , v4_(boost::move(a4)) + , v5_(boost::move(a5)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + , v3_(boost::move(BOOST_THREAD_RV(f).v3_)) + , v4_(boost::move(BOOST_THREAD_RV(f).v4_)) + , v5_(boost::move(BOOST_THREAD_RV(f).v5_)) + {} + + result_type operator()() + { + return detail::invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + , boost::move(v3_) + , boost::move(v4_) + , boost::move(v5_) + ); + } + }; + template + class invoker + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + T3 v3_; + T4 v4_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + , BOOST_THREAD_RV_REF(T3) a3 + , BOOST_THREAD_RV_REF(T4) a4 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + , v3_(boost::move(a3)) + , v4_(boost::move(a4)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + , v3_(boost::move(BOOST_THREAD_RV(f).v3_)) + , v4_(boost::move(BOOST_THREAD_RV(f).v4_)) + {} + + result_type operator()() + { + return detail::invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + , boost::move(v3_) + , boost::move(v4_) + ); + } + }; + template + class invoker + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + T3 v3_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + , BOOST_THREAD_RV_REF(T3) a3 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + , v3_(boost::move(a3)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + , v3_(boost::move(BOOST_THREAD_RV(f).v3_)) + {} + + result_type operator()() + { + return detail::invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + , boost::move(v3_) + ); + } + }; + template + class invoker + { + Fp fp_; + T0 v0_; + T1 v1_; + T2 v2_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + , BOOST_THREAD_RV_REF(T2) a2 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + , v2_(boost::move(a2)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + , v2_(boost::move(BOOST_THREAD_RV(f).v2_)) + {} + + result_type operator()() + { + return detail::invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + , boost::move(v2_) + ); + } + }; + template + class invoker + { + Fp fp_; + T0 v0_; + T1 v1_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + , BOOST_THREAD_RV_REF(T1) a1 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + , v1_(boost::move(a1)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + , v1_(boost::move(BOOST_THREAD_RV(f).v1_)) + {} + + result_type operator()() + { + return detail::invoke(boost::move(fp_) + , boost::move(v0_) + , boost::move(v1_) + ); + } + }; + template + class invoker + { + Fp fp_; + T0 v0_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f + , BOOST_THREAD_RV_REF(T0) a0 + ) + : fp_(boost::move(f)) + , v0_(boost::move(a0)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(BOOST_THREAD_RV(f).fp)) + , v0_(boost::move(BOOST_THREAD_RV(f).v0_)) + {} + + result_type operator()() + { + return detail::invoke(boost::move(fp_) + , boost::move(v0_) + ); + } + }; + template + class invoker + { + Fp fp_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of::type result_type; + BOOST_SYMBOL_VISIBLE + explicit invoker(BOOST_THREAD_FWD_REF(Fp) f) + : fp_(boost::move(f)) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(boost::move(f.fp_)) + {} + result_type operator()() + { + return fp_(); + } + }; + template + class invoker + { + typedef R(*Fp)(); + Fp fp_; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker) + typedef typename result_of::type result_type; + BOOST_SYMBOL_VISIBLE + explicit invoker(Fp f) + : fp_(f) + {} + + BOOST_SYMBOL_VISIBLE + invoker(BOOST_THREAD_RV_REF(invoker) f) + : fp_(f.fp_) + {} + result_type operator()() + { + return fp_(); + } + }; +#endif +#endif + + } +} + +#include + +#endif // header diff --git a/boost/thread/detail/is_convertible.hpp b/boost/thread/detail/is_convertible.hpp new file mode 100644 index 0000000..b77620c --- /dev/null +++ b/boost/thread/detail/is_convertible.hpp @@ -0,0 +1,49 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011-2013 Vicente J. Botet Escriba +// +// 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/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_DETAIL_IS_CONVERTIBLE_HPP +#define BOOST_THREAD_DETAIL_IS_CONVERTIBLE_HPP + +#include +#include + +namespace boost +{ + namespace thread_detail + { + template + struct is_convertible : boost::is_convertible {}; + +#if defined BOOST_NO_CXX11_RVALUE_REFERENCES + +#if defined(BOOST_INTEL_CXX_VERSION) && (BOOST_INTEL_CXX_VERSION <= 1300) + +#if defined BOOST_THREAD_USES_MOVE + template + struct is_convertible< + rv &, + rv > & + > : false_type {}; +#endif + +#elif defined __GNUC__ && (__GNUC__ < 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ <= 4 )) + + template + struct is_convertible : boost::is_convertible {}; +#endif + +#endif + } + +} // namespace boost + + +#endif // BOOST_THREAD_DETAIL_MEMORY_HPP diff --git a/boost/thread/detail/lockable_wrapper.hpp b/boost/thread/detail/lockable_wrapper.hpp new file mode 100644 index 0000000..8dc5a6c --- /dev/null +++ b/boost/thread/detail/lockable_wrapper.hpp @@ -0,0 +1,45 @@ +// 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) +// (C) Copyright 2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_DETAIL_LOCKABLE_WRAPPER_HPP +#define BOOST_THREAD_DETAIL_LOCKABLE_WRAPPER_HPP + +#include + +#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST +#include +#endif +#include + +namespace boost +{ + +#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST + namespace thread_detail + { + template + struct lockable_wrapper + { + Mutex* m; + explicit lockable_wrapper(Mutex& m_) : + m(&m_) + {} + }; + template + struct lockable_adopt_wrapper + { + Mutex* m; + explicit lockable_adopt_wrapper(Mutex& m_) : + m(&m_) + {} + }; + } +#endif + +} + +#include + +#endif // header diff --git a/boost/thread/detail/make_tuple_indices.hpp b/boost/thread/detail/make_tuple_indices.hpp new file mode 100644 index 0000000..73d54f1 --- /dev/null +++ b/boost/thread/detail/make_tuple_indices.hpp @@ -0,0 +1,224 @@ +// Copyright (C) 2012-2013 Vicente J. Botet Escriba +// +// 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) + +// 2013/04 Vicente J. Botet Escriba +// Provide implementation up to 10 parameters when BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined. +// 2012/11 Vicente J. Botet Escriba +// Adapt to boost libc++ implementation + +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// The make_tuple_indices C++11 code is based on the one from libcxx. +//===----------------------------------------------------------------------===// + +#ifndef BOOST_THREAD_DETAIL_MAKE_TUPLE_INDICES_HPP +#define BOOST_THREAD_DETAIL_MAKE_TUPLE_INDICES_HPP + +#include +#include + +namespace boost +{ + namespace detail + { + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + // make_tuple_indices + + template struct tuple_indices + {}; + + template + struct make_indices_imp; + + template + struct make_indices_imp, Ep> + { + typedef typename make_indices_imp, Ep>::type type; + }; + + template + struct make_indices_imp, Ep> + { + typedef tuple_indices type; + }; + + template + struct make_tuple_indices + { + BOOST_STATIC_ASSERT_MSG(Sp <= Ep, "make_tuple_indices input error"); + typedef typename make_indices_imp, Ep>::type type; + }; +#else + + // - tuple forward declaration ----------------------------------------------- + template < + std::size_t T0 = 0, std::size_t T1 = 0, std::size_t T2 = 0, + std::size_t T3 = 0, std::size_t T4 = 0, std::size_t T5 = 0, + std::size_t T6 = 0, std::size_t T7 = 0, std::size_t T8 = 0, + std::size_t T9 = 0> + class tuple_indices {}; + + template + struct make_indices_imp; + + template + struct make_indices_imp, Ep> + { + typedef typename make_indices_imp, Ep>::type type; + }; + template + struct make_indices_imp, Ep> + { + typedef typename make_indices_imp, Ep>::type type; + }; + template + struct make_indices_imp, Ep> + { + typedef typename make_indices_imp, Ep>::type type; + }; + template + struct make_indices_imp, Ep> + { + typedef typename make_indices_imp, Ep>::type type; + }; + template + struct make_indices_imp, Ep> + { + typedef typename make_indices_imp, Ep>::type type; + }; + template + struct make_indices_imp, Ep> + { + typedef typename make_indices_imp, Ep>::type type; + }; + template + struct make_indices_imp, Ep> + { + typedef typename make_indices_imp, Ep>::type type; + }; + template + struct make_indices_imp, Ep> + { + typedef typename make_indices_imp, Ep>::type type; + }; + template + struct make_indices_imp, Ep> + { + typedef typename make_indices_imp, Ep>::type type; + }; + template + struct make_indices_imp, Ep> + { + typedef typename make_indices_imp, Ep>::type type; + }; +// template +// struct make_indices_imp, Ep> +// { +// typedef typename make_indices_imp, Ep>::type type; +// }; + + template + struct make_indices_imp, Ep> + { + typedef tuple_indices<> type; + }; + template + struct make_indices_imp, Ep> + { + typedef tuple_indices type; + }; + template + struct make_indices_imp, Ep> + { + typedef tuple_indices type; + }; + template + struct make_indices_imp, Ep> + { + typedef tuple_indices type; + }; + template + struct make_indices_imp, Ep> + { + typedef tuple_indices type; + }; + template + struct make_indices_imp, Ep> + { + typedef tuple_indices type; + }; + template + struct make_indices_imp, Ep> + { + typedef tuple_indices type; + }; + template + struct make_indices_imp, Ep> + { + typedef tuple_indices type; + }; + template + struct make_indices_imp, Ep> + { + typedef tuple_indices type; + }; + template + struct make_indices_imp, Ep> + { + typedef tuple_indices type; + }; + + template + struct make_indices_imp, Ep> + { + typedef tuple_indices type; + }; + + template + struct make_tuple_indices + { + BOOST_STATIC_ASSERT_MSG(Sp <= Ep, "make_tuple_indices input error"); + typedef typename make_indices_imp, Ep>::type type; + }; + +#endif + } +} + +#endif // header diff --git a/boost/thread/detail/memory.hpp b/boost/thread/detail/memory.hpp new file mode 100644 index 0000000..51ce84f --- /dev/null +++ b/boost/thread/detail/memory.hpp @@ -0,0 +1,48 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2011-2013 Vicente J. Botet Escriba +// +// 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/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_DETAIL_MEMORY_HPP +#define BOOST_THREAD_DETAIL_MEMORY_HPP + +#include + +#include +#include +#include +#include + +namespace boost +{ + namespace thread_detail + { + template + class allocator_destructor + { + typedef csbl::allocator_traits<_Alloc> alloc_traits; + public: + typedef typename alloc_traits::pointer pointer; + typedef typename alloc_traits::size_type size_type; + private: + _Alloc alloc_; + size_type s_; + public: + allocator_destructor(_Alloc& a, size_type s)BOOST_NOEXCEPT + : alloc_(a), s_(s) + {} + void operator()(pointer p)BOOST_NOEXCEPT + { + alloc_traits::destroy(alloc_, p); + alloc_traits::deallocate(alloc_, p, s_); + } + }; + } //namespace thread_detail +} +#endif // BOOST_THREAD_DETAIL_MEMORY_HPP diff --git a/boost/thread/detail/move.hpp b/boost/thread/detail/move.hpp new file mode 100644 index 0000000..447247d --- /dev/null +++ b/boost/thread/detail/move.hpp @@ -0,0 +1,379 @@ +// 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) +// (C) Copyright 2007-8 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_MOVE_HPP +#define BOOST_THREAD_MOVE_HPP + +#include +#ifndef BOOST_NO_SFINAE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#include +#endif +namespace boost +{ + + namespace detail + { + template + struct enable_move_utility_emulation_dummy_specialization; + template + struct thread_move_t + { + T& t; + explicit thread_move_t(T& t_): + t(t_) + {} + + T& operator*() const + { + return t; + } + + T* operator->() const + { + return &t; + } + private: + void operator=(thread_move_t&); + }; + } + +#if !defined BOOST_THREAD_USES_MOVE + +#ifndef BOOST_NO_SFINAE + template + typename enable_if >, boost::detail::thread_move_t >::type move(T& t) + { + return boost::detail::thread_move_t(t); + } +#endif + + template + boost::detail::thread_move_t move(boost::detail::thread_move_t t) + { + return t; + } + +#endif //#if !defined BOOST_THREAD_USES_MOVE +} + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + +#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) BOOST_COPY_ASSIGN_REF(TYPE) +#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE) +#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE) +#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG +#define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END +#define BOOST_THREAD_RV(V) V +#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE +#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE) +#define BOOST_THREAD_DCL_MOVABLE(TYPE) +#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ + namespace detail { \ + template \ + struct enable_move_utility_emulation_dummy_specialization< + +#define BOOST_THREAD_DCL_MOVABLE_BEG2(T1, T2) \ + namespace detail { \ + template \ + struct enable_move_utility_emulation_dummy_specialization< + +#define BOOST_THREAD_DCL_MOVABLE_END > \ + : integral_constant \ + {}; \ + } + +#elif ! defined BOOST_NO_CXX11_RVALUE_REFERENCES && defined BOOST_MSVC + +#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) BOOST_COPY_ASSIGN_REF(TYPE) +#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE) +#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE) +#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG +#define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END +#define BOOST_THREAD_RV(V) V +#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE +#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE) +#define BOOST_THREAD_DCL_MOVABLE(TYPE) +#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ + namespace detail { \ + template \ + struct enable_move_utility_emulation_dummy_specialization< + +#define BOOST_THREAD_DCL_MOVABLE_BEG2(T1, T2) \ + namespace detail { \ + template \ + struct enable_move_utility_emulation_dummy_specialization< + +#define BOOST_THREAD_DCL_MOVABLE_END > \ + : integral_constant \ + {}; \ + } + +#else + +#if defined BOOST_THREAD_USES_MOVE +#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) BOOST_COPY_ASSIGN_REF(TYPE) +#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE) +#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE) +#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG +#define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END +#define BOOST_THREAD_RV(V) V +#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE) +#define BOOST_THREAD_DCL_MOVABLE(TYPE) +#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ + namespace detail { \ + template \ + struct enable_move_utility_emulation_dummy_specialization< + +#define BOOST_THREAD_DCL_MOVABLE_BEG2(T1, T2) \ + namespace detail { \ + template \ + struct enable_move_utility_emulation_dummy_specialization< + +#define BOOST_THREAD_DCL_MOVABLE_END > \ + : integral_constant \ + {}; \ + } + +#else + +#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) const TYPE& +#define BOOST_THREAD_RV_REF(TYPE) boost::detail::thread_move_t< TYPE > +#define BOOST_THREAD_RV_REF_BEG boost::detail::thread_move_t< +#define BOOST_THREAD_RV_REF_END > +#define BOOST_THREAD_RV(V) (*V) +#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE) + +#define BOOST_THREAD_DCL_MOVABLE(TYPE) \ +template <> \ +struct enable_move_utility_emulation< TYPE > \ +{ \ + static const bool value = false; \ +}; + +#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ +template \ +struct enable_move_utility_emulation< + +#define BOOST_THREAD_DCL_MOVABLE_BEG2(T1, T2) \ +template \ +struct enable_move_utility_emulation< + +#define BOOST_THREAD_DCL_MOVABLE_END > \ +{ \ + static const bool value = false; \ +}; + +#endif + +namespace boost +{ +namespace detail +{ + template + BOOST_THREAD_RV_REF(typename ::boost::remove_cv::type>::type) + make_rv_ref(T v) BOOST_NOEXCEPT + { + return (BOOST_THREAD_RV_REF(typename ::boost::remove_cv::type>::type))(v); + } +// template +// BOOST_THREAD_RV_REF(typename ::boost::remove_cv::type>::type) +// make_rv_ref(T &v) BOOST_NOEXCEPT +// { +// return (BOOST_THREAD_RV_REF(typename ::boost::remove_cv::type>::type))(v); +// } +// template +// const BOOST_THREAD_RV_REF(typename ::boost::remove_cv::type>::type) +// make_rv_ref(T const&v) BOOST_NOEXCEPT +// { +// return (const BOOST_THREAD_RV_REF(typename ::boost::remove_cv::type>::type))(v); +// } +} +} + +#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE.move() +//#define BOOST_THREAD_MAKE_RV_REF(RVALUE) boost::detail::make_rv_ref(RVALUE) +#endif + + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + +#define BOOST_THREAD_MOVABLE(TYPE) + +#define BOOST_THREAD_COPYABLE(TYPE) + +#else + +#if defined BOOST_THREAD_USES_MOVE + +#define BOOST_THREAD_MOVABLE(TYPE) \ + ::boost::rv& move() BOOST_NOEXCEPT \ + { \ + return *static_cast< ::boost::rv* >(this); \ + } \ + const ::boost::rv& move() const BOOST_NOEXCEPT \ + { \ + return *static_cast* >(this); \ + } \ + operator ::boost::rv&() \ + { \ + return *static_cast< ::boost::rv* >(this); \ + } \ + operator const ::boost::rv&() const \ + { \ + return *static_cast* >(this); \ + }\ + +#define BOOST_THREAD_COPYABLE(TYPE) \ + TYPE& operator=(TYPE &t)\ + { this->operator=(static_cast &>(const_cast(t))); return *this;} + + +#else + +#define BOOST_THREAD_MOVABLE(TYPE) \ + operator ::boost::detail::thread_move_t() BOOST_NOEXCEPT \ + { \ + return move(); \ + } \ + ::boost::detail::thread_move_t move() BOOST_NOEXCEPT \ + { \ + ::boost::detail::thread_move_t x(*this); \ + return x; \ + } \ + +#define BOOST_THREAD_COPYABLE(TYPE) + +#endif +#endif + +#define BOOST_THREAD_MOVABLE_ONLY(TYPE) \ + BOOST_THREAD_NO_COPYABLE(TYPE) \ + BOOST_THREAD_MOVABLE(TYPE) \ + typedef int boost_move_no_copy_constructor_or_assign; \ + + +#define BOOST_THREAD_COPYABLE_AND_MOVABLE(TYPE) \ + BOOST_THREAD_COPYABLE(TYPE) \ + BOOST_THREAD_MOVABLE(TYPE) \ + + + +namespace boost +{ + namespace thread_detail + { + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +#elif defined BOOST_THREAD_USES_MOVE + template + struct is_rv + : ::boost::move_detail::is_rv + {}; + +#else + template + struct is_rv + : ::boost::integral_constant + {}; + + template + struct is_rv< ::boost::detail::thread_move_t > + : ::boost::integral_constant + {}; + + template + struct is_rv< const ::boost::detail::thread_move_t > + : ::boost::integral_constant + {}; +#endif + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template + struct remove_reference : boost::remove_reference {}; + template + struct decay : boost::decay {}; +#else + template + struct remove_reference + { + typedef Tp type; + }; + template + struct remove_reference + { + typedef Tp type; + }; + template + struct remove_reference< rv > { + typedef Tp type; + }; + + template + struct decay + { + private: + typedef typename boost::move_detail::remove_rvalue_reference::type Up0; + typedef typename boost::remove_reference::type Up; + public: + typedef typename conditional + < + is_array::value, + typename remove_extent::type*, + typename conditional + < + is_function::value, + typename add_pointer::type, + typename remove_cv::type + >::type + >::type type; + }; +#endif + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template + typename decay::type + decay_copy(T&& t) + { + return boost::forward(t); + } + typedef void (*void_fct_ptr)(); + +// inline void_fct_ptr +// decay_copy(void (&t)()) +// { +// return &t; +// } +#else + template + typename decay::type + decay_copy(BOOST_THREAD_FWD_REF(T) t) + { + return boost::forward(t); + } +#endif + } +} + +#include + +#endif diff --git a/boost/thread/detail/nullary_function.hpp b/boost/thread/detail/nullary_function.hpp new file mode 100644 index 0000000..2950942 --- /dev/null +++ b/boost/thread/detail/nullary_function.hpp @@ -0,0 +1,239 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) +// +// 2013,2018 Vicente J. Botet Escriba +// Adapt to boost from CCIA C++11 implementation +// Make use of Boost.Move + +#ifndef BOOST_THREAD_DETAIL_NULLARY_FUNCTION_HPP +#define BOOST_THREAD_DETAIL_NULLARY_FUNCTION_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace detail + { + + template + class nullary_function; + template <> + class nullary_function + { + struct impl_base + { + virtual void call()=0; + virtual ~impl_base() + { + } + }; + csbl::shared_ptr impl; + template + struct impl_type: impl_base + { + F f; +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + impl_type(F &f_) + : f(f_) + {} +#endif + impl_type(BOOST_THREAD_RV_REF(F) f_) + : f(boost::move(f_)) + {} + + void call() + { + f(); + } + }; + struct impl_type_ptr: impl_base + { + void (*f)(); + impl_type_ptr(void (*f_)()) + : f(f_) + {} + void call() + { + f(); + } + }; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(nullary_function) + + explicit nullary_function(void (*f)()): + impl(new impl_type_ptr(f)) + {} + +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + template + explicit nullary_function(F& f + , typename disable_if::type, nullary_function>, int* >::type=0 + ): + impl(new impl_type(f)) + {} +#endif + template + nullary_function(BOOST_THREAD_RV_REF(F) f + , typename disable_if::type, nullary_function>, int* >::type=0 + ): + impl(new impl_type::type>(thread_detail::decay_copy(boost::forward(f)))) + {} + + nullary_function() + : impl() + { + } + nullary_function(nullary_function const& other) BOOST_NOEXCEPT : + impl(other.impl) + { + } + nullary_function(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT : +#if defined BOOST_NO_CXX11_SMART_PTR + impl(BOOST_THREAD_RV(other).impl) + { + BOOST_THREAD_RV(other).impl.reset(); + } +#else + impl(boost::move(other.impl)) + { + } +#endif + ~nullary_function() + { + } + + nullary_function& operator=(BOOST_THREAD_COPY_ASSIGN_REF(nullary_function) other) BOOST_NOEXCEPT + { + impl=other.impl; + return *this; + } + nullary_function& operator=(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT + { +#if defined BOOST_NO_CXX11_SMART_PTR + impl=BOOST_THREAD_RV(other).impl; + BOOST_THREAD_RV(other).impl.reset(); +#else + impl = boost::move(other.impl); +#endif + return *this; + } + + + void operator()() + { if (impl) impl->call();} + + }; + + template + class nullary_function + { + struct impl_base + { + virtual R call()=0; + virtual ~impl_base() + { + } + }; + csbl::shared_ptr impl; + template + struct impl_type: impl_base + { + F f; +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + impl_type(F &f_) + : f(f_) + {} +#endif + impl_type(BOOST_THREAD_RV_REF(F) f_) + : f(boost::move(f_)) + {} + + R call() + { + return f(); + } + }; + struct impl_type_ptr: impl_base + { + R (*f)(); + impl_type_ptr(R (*f_)()) + : f(f_) + {} + + R call() + { + return f(); + } + }; + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(nullary_function) + + nullary_function(R (*f)()): + impl(new impl_type_ptr(f)) + {} +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + template + nullary_function(F& f): + impl(new impl_type(f)) + {} +#endif + template + nullary_function(BOOST_THREAD_RV_REF(F) f): + impl(new impl_type::type>(thread_detail::decay_copy(boost::forward(f)))) + {} + + nullary_function(nullary_function const& other) BOOST_NOEXCEPT : + impl(other.impl) + { + } + nullary_function(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT : +#if defined BOOST_NO_CXX11_SMART_PTR + impl(BOOST_THREAD_RV(other).impl) + { + BOOST_THREAD_RV(other).impl.reset(); + } +#else + impl(boost::move(other.impl)) + { + } +#endif + nullary_function() + : impl() + { + } + ~nullary_function() + { + } + + nullary_function& operator=(BOOST_THREAD_COPY_ASSIGN_REF(nullary_function) other) BOOST_NOEXCEPT + { + impl=other.impl; + return *this; + } + nullary_function& operator=(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT + { +#if defined BOOST_NO_CXX11_SMART_PTR + impl=BOOST_THREAD_RV(other).impl; + BOOST_THREAD_RV(other).impl.reset(); +#else + impl = boost::move(other.impl); +#endif + return *this; + } + + R operator()() + { if (impl) return impl->call(); else return R();} + + }; + } + BOOST_THREAD_DCL_MOVABLE_BEG(F) detail::nullary_function BOOST_THREAD_DCL_MOVABLE_END +} + +#endif // header diff --git a/boost/thread/detail/platform.hpp b/boost/thread/detail/platform.hpp new file mode 100644 index 0000000..172a601 --- /dev/null +++ b/boost/thread/detail/platform.hpp @@ -0,0 +1,75 @@ +// Copyright 2006 Roland Schwarz. +// (C) Copyright 2007 Anthony Williams +// 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) +// +// This work is a reimplementation along the design and ideas +// of William E. Kempf. + +#ifndef BOOST_THREAD_RS06040501_HPP +#define BOOST_THREAD_RS06040501_HPP + +// fetch compiler and platform configuration +#include + +// insist on threading support being available: +#include + +// choose platform +#if defined(linux) || defined(__linux) || defined(__linux__) +# define BOOST_THREAD_LINUX +//# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(100000) +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +# define BOOST_THREAD_BSD +#elif defined(sun) || defined(__sun) +# define BOOST_THREAD_SOLARIS +#elif defined(__sgi) +# define BOOST_THREAD_IRIX +#elif defined(__hpux) +# define BOOST_THREAD_HPUX +#elif defined(__CYGWIN__) +# define BOOST_THREAD_CYGWIN +#elif (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && !defined(BOOST_DISABLE_WIN32) +#if ! defined BOOST_THREAD_WIN32 +# define BOOST_THREAD_WIN32 +#endif +#elif defined(__BEOS__) +# define BOOST_THREAD_BEOS +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +# define BOOST_THREAD_MACOS +//# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(1000) +#elif defined(__IBMCPP__) || defined(_AIX) +# define BOOST_THREAD_AIX +#elif defined(__amigaos__) +# define BOOST_THREAD_AMIGAOS +#elif defined(__QNXNTO__) +# define BOOST_THREAD_QNXNTO +#elif defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE) +# if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_THREAD_POSIX) +# define BOOST_THREAD_POSIX +# endif +#endif + +// For every supported platform add a new entry into the dispatch table below. +// BOOST_THREAD_POSIX is tested first, so on platforms where posix and native +// threading is available, the user may choose, by defining BOOST_THREAD_POSIX +// in her source. If a platform is known to support pthreads and no native +// port of boost_thread is available just specify "pthread" in the +// dispatcher table. If there is no entry for a platform but pthreads is +// available on the platform, pthread is choosen as default. If nothing is +// available the preprocessor will fail with a diagnostic message. + +#if defined(BOOST_THREAD_POSIX) +# define BOOST_THREAD_PLATFORM_PTHREAD +#else +# if defined(BOOST_THREAD_WIN32) +# define BOOST_THREAD_PLATFORM_WIN32 +# elif defined(BOOST_HAS_PTHREADS) +# define BOOST_THREAD_PLATFORM_PTHREAD +# else +# error "Sorry, no boost threads are available for this platform." +# endif +#endif + +#endif // BOOST_THREAD_RS06040501_HPP diff --git a/boost/thread/detail/platform_time.hpp b/boost/thread/detail/platform_time.hpp new file mode 100644 index 0000000..2180f13 --- /dev/null +++ b/boost/thread/detail/platform_time.hpp @@ -0,0 +1,478 @@ +#ifndef BOOST_THREAD_DETAIL_PLATFORM_TIME_HPP +#define BOOST_THREAD_DETAIL_PLATFORM_TIME_HPP +// (C) Copyright 2007-8 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#if defined BOOST_THREAD_USES_DATETIME +#include +#endif +#ifndef _WIN32 +#include +#endif +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#include +#endif + +#if defined(BOOST_THREAD_CHRONO_WINDOWS_API) +#include +#include +#include +#elif defined(BOOST_THREAD_CHRONO_MAC_API) +#include //for gettimeofday and timeval +#include // mach_absolute_time, mach_timebase_info_data_t + +#else +#include // for clock_gettime +#endif + +#include + +#include + +namespace boost +{ +//typedef boost::int_least64_t time_max_t; +typedef boost::intmax_t time_max_t; + +#if defined BOOST_THREAD_CHRONO_MAC_API +namespace threads +{ + +namespace chrono_details +{ + +// steady_clock + +// Note, in this implementation steady_clock and high_resolution_clock +// are the same clock. They are both based on mach_absolute_time(). +// mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of +// nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom +// are run time constants supplied by the OS. This clock has no relationship +// to the Gregorian calendar. It's main use is as a high resolution timer. + +// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize +// for that case as an optimization. + +inline time_max_t +steady_simplified() +{ + return mach_absolute_time(); +} + +inline double compute_steady_factor(kern_return_t& err) +{ + mach_timebase_info_data_t MachInfo; + err = mach_timebase_info(&MachInfo); + if ( err != 0 ) { + return 0; + } + return static_cast(MachInfo.numer) / MachInfo.denom; +} + +inline time_max_t steady_full() +{ + kern_return_t err; + const double factor = chrono_details::compute_steady_factor(err); + if (err != 0) + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + return static_cast(mach_absolute_time() * factor); +} + + +typedef time_max_t (*FP)(); + +inline FP init_steady_clock(kern_return_t & err) +{ + mach_timebase_info_data_t MachInfo; + err = mach_timebase_info(&MachInfo); + if ( err != 0 ) + { + return 0; + } + + if (MachInfo.numer == MachInfo.denom) + { + return &chrono_details::steady_simplified; + } + return &chrono_details::steady_full; +} + +} +} +#endif + + namespace detail + { +#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API + inline timespec ns_to_timespec(boost::time_max_t const& ns) + { + boost::time_max_t s = ns / 1000000000l; + timespec ts; + ts.tv_sec = static_cast (s); + ts.tv_nsec = static_cast (ns - s * 1000000000l); + return ts; + } + inline boost::time_max_t timespec_to_ns(timespec const& ts) + { + return static_cast(ts.tv_sec) * 1000000000l + ts.tv_nsec; + } +#endif + + struct platform_duration + { +#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API + explicit platform_duration(timespec const& v) : ts_val(v) {} + timespec const& getTs() const { return ts_val; } + + explicit platform_duration(boost::time_max_t const& ns = 0) : ts_val(ns_to_timespec(ns)) {} + boost::time_max_t getNs() const { return timespec_to_ns(ts_val); } +#else + explicit platform_duration(boost::time_max_t const& ns = 0) : ns_val(ns) {} + boost::time_max_t getNs() const { return ns_val; } +#endif + +#if defined BOOST_THREAD_USES_DATETIME + platform_duration(boost::posix_time::time_duration const& rel_time) + { +#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API + ts_val.tv_sec = rel_time.total_seconds(); + ts_val.tv_nsec = static_cast(rel_time.fractional_seconds() * (1000000000l / rel_time.ticks_per_second())); +#else + ns_val = static_cast(rel_time.total_seconds()) * 1000000000l; + ns_val += rel_time.fractional_seconds() * (1000000000l / rel_time.ticks_per_second()); +#endif + } +#endif + +#if defined BOOST_THREAD_USES_CHRONO + template + platform_duration(chrono::duration const& d) + { +#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API + ts_val = ns_to_timespec(chrono::ceil(d).count()); +#else + ns_val = chrono::ceil(d).count(); +#endif + } +#endif + + boost::time_max_t getMs() const + { + const boost::time_max_t ns = getNs(); + // ceil/floor away from zero + if (ns >= 0) + { + // return ceiling of positive numbers + return (ns + 999999) / 1000000; + } + else + { + // return floor of negative numbers + return (ns - 999999) / 1000000; + } + } + + static platform_duration zero() + { + return platform_duration(0); + } + + private: +#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API + timespec ts_val; +#else + boost::time_max_t ns_val; +#endif + }; + + inline bool operator==(platform_duration const& lhs, platform_duration const& rhs) + { + return lhs.getNs() == rhs.getNs(); + } + inline bool operator!=(platform_duration const& lhs, platform_duration const& rhs) + { + return lhs.getNs() != rhs.getNs(); + } + inline bool operator<(platform_duration const& lhs, platform_duration const& rhs) + { + return lhs.getNs() < rhs.getNs(); + } + inline bool operator<=(platform_duration const& lhs, platform_duration const& rhs) + { + return lhs.getNs() <= rhs.getNs(); + } + inline bool operator>(platform_duration const& lhs, platform_duration const& rhs) + { + return lhs.getNs() > rhs.getNs(); + } + inline bool operator>=(platform_duration const& lhs, platform_duration const& rhs) + { + return lhs.getNs() >= rhs.getNs(); + } + + static inline platform_duration platform_milliseconds(long const& ms) + { + return platform_duration(ms * 1000000l); + } + + struct real_platform_timepoint + { +#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API + explicit real_platform_timepoint(timespec const& v) : dur(v) {} + timespec const& getTs() const { return dur.getTs(); } +#endif + + explicit real_platform_timepoint(boost::time_max_t const& ns) : dur(ns) {} + boost::time_max_t getNs() const { return dur.getNs(); } + +#if defined BOOST_THREAD_USES_DATETIME + real_platform_timepoint(boost::system_time const& abs_time) + : dur(abs_time - boost::posix_time::from_time_t(0)) {} +#endif + +#if defined BOOST_THREAD_USES_CHRONO + template + real_platform_timepoint(chrono::time_point const& abs_time) + : dur(abs_time.time_since_epoch()) {} +#endif + + private: + platform_duration dur; + }; + + inline bool operator==(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs) + { + return lhs.getNs() == rhs.getNs(); + } + inline bool operator!=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs) + { + return lhs.getNs() != rhs.getNs(); + } + inline bool operator<(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs) + { + return lhs.getNs() < rhs.getNs(); + } + inline bool operator<=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs) + { + return lhs.getNs() <= rhs.getNs(); + } + inline bool operator>(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs) + { + return lhs.getNs() > rhs.getNs(); + } + inline bool operator>=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs) + { + return lhs.getNs() >= rhs.getNs(); + } + + inline real_platform_timepoint operator+(real_platform_timepoint const& lhs, platform_duration const& rhs) + { + return real_platform_timepoint(lhs.getNs() + rhs.getNs()); + } + inline real_platform_timepoint operator+(platform_duration const& lhs, real_platform_timepoint const& rhs) + { + return real_platform_timepoint(lhs.getNs() + rhs.getNs()); + } + inline platform_duration operator-(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs) + { + return platform_duration(lhs.getNs() - rhs.getNs()); + } + + struct real_platform_clock + { + static real_platform_timepoint now() + { +#if defined(BOOST_THREAD_CHRONO_WINDOWS_API) + boost::detail::winapi::FILETIME_ ft; + boost::detail::winapi::GetSystemTimeAsFileTime(&ft); // never fails + boost::time_max_t ns = ((((static_cast(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) - 116444736000000000LL) * 100LL); + return real_platform_timepoint(ns); +#elif defined(BOOST_THREAD_CHRONO_MAC_API) + timeval tv; + ::gettimeofday(&tv, 0); + timespec ts; + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; + return real_platform_timepoint(ts); +#else + timespec ts; + if ( ::clock_gettime( CLOCK_REALTIME, &ts ) ) + { + BOOST_ASSERT(0 && "Boost::Thread - clock_gettime(CLOCK_REALTIME) Internal Error"); + return real_platform_timepoint(0); + } + return real_platform_timepoint(ts); +#endif + } + }; + +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) + + struct mono_platform_timepoint + { +#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API + + explicit mono_platform_timepoint(timespec const& v) : dur(v) {} + timespec const& getTs() const { return dur.getTs(); } +#endif + + explicit mono_platform_timepoint(boost::time_max_t const& ns) : dur(ns) {} + boost::time_max_t getNs() const { return dur.getNs(); } + +#if defined BOOST_THREAD_USES_CHRONO + // This conversion assumes that chrono::steady_clock::time_point and mono_platform_timepoint share the same epoch. + template + mono_platform_timepoint(chrono::time_point const& abs_time) + : dur(abs_time.time_since_epoch()) {} +#endif + + // can't name this max() since that is a macro on some Windows systems + static mono_platform_timepoint getMax() + { +#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API + timespec ts; + ts.tv_sec = (std::numeric_limits::max)(); + ts.tv_nsec = 999999999; + return mono_platform_timepoint(ts); +#else + boost::time_max_t ns = (std::numeric_limits::max)(); + return mono_platform_timepoint(ns); +#endif + } + + private: + platform_duration dur; + }; + + inline bool operator==(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs) + { + return lhs.getNs() == rhs.getNs(); + } + inline bool operator!=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs) + { + return lhs.getNs() != rhs.getNs(); + } + inline bool operator<(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs) + { + return lhs.getNs() < rhs.getNs(); + } + inline bool operator<=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs) + { + return lhs.getNs() <= rhs.getNs(); + } + inline bool operator>(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs) + { + return lhs.getNs() > rhs.getNs(); + } + inline bool operator>=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs) + { + return lhs.getNs() >= rhs.getNs(); + } + + inline mono_platform_timepoint operator+(mono_platform_timepoint const& lhs, platform_duration const& rhs) + { + return mono_platform_timepoint(lhs.getNs() + rhs.getNs()); + } + inline mono_platform_timepoint operator+(platform_duration const& lhs, mono_platform_timepoint const& rhs) + { + return mono_platform_timepoint(lhs.getNs() + rhs.getNs()); + } + inline platform_duration operator-(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs) + { + return platform_duration(lhs.getNs() - rhs.getNs()); + } + + struct mono_platform_clock + { + static mono_platform_timepoint now() + { +#if defined(BOOST_THREAD_CHRONO_WINDOWS_API) +#if defined(BOOST_THREAD_USES_CHRONO) + // Use QueryPerformanceCounter() to match the implementation in Boost + // Chrono so that chrono::steady_clock::now() and this function share the + // same epoch and so can be converted between each other. + boost::detail::winapi::LARGE_INTEGER_ freq; + if ( !boost::detail::winapi::QueryPerformanceFrequency( &freq ) ) + { + BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceFrequency Internal Error"); + return mono_platform_timepoint(0); + } + if ( freq.QuadPart <= 0 ) + { + BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceFrequency Internal Error"); + return mono_platform_timepoint(0); + } + + boost::detail::winapi::LARGE_INTEGER_ pcount; + unsigned times=0; + while ( ! boost::detail::winapi::QueryPerformanceCounter( &pcount ) ) + { + if ( ++times > 3 ) + { + BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceCounter Internal Error"); + return mono_platform_timepoint(0); + } + } + + long double ns = 1000000000.0L * pcount.QuadPart / freq.QuadPart; + return mono_platform_timepoint(static_cast(ns)); +#else + // Use GetTickCount64() because it's more reliable on older + // systems like Windows XP and Windows Server 2003. + win32::ticks_type msec = win32::gettickcount64(); + return mono_platform_timepoint(msec * 1000000); +#endif +#elif defined(BOOST_THREAD_CHRONO_MAC_API) + kern_return_t err; + threads::chrono_details::FP fp = threads::chrono_details::init_steady_clock(err); + if ( err != 0 ) + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + return mono_platform_timepoint(fp()); +#else + timespec ts; + if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) ) + { + BOOST_ASSERT(0 && "Boost::Thread - clock_gettime(CLOCK_MONOTONIC) Internal Error"); + return mono_platform_timepoint(0); + } + return mono_platform_timepoint(ts); +#endif + } + }; + +#endif + +#if defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + typedef mono_platform_clock internal_platform_clock; + typedef mono_platform_timepoint internal_platform_timepoint; +#else + typedef real_platform_clock internal_platform_clock; + typedef real_platform_timepoint internal_platform_timepoint; +#endif + +#ifdef BOOST_THREAD_USES_CHRONO +#ifdef BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + typedef chrono::steady_clock internal_chrono_clock; +#else + typedef chrono::system_clock internal_chrono_clock; +#endif +#endif + + } +} + +#include + +#endif diff --git a/boost/thread/detail/thread.hpp b/boost/thread/detail/thread.hpp new file mode 100644 index 0000000..04223ed --- /dev/null +++ b/boost/thread/detail/thread.hpp @@ -0,0 +1,845 @@ +#ifndef BOOST_THREAD_THREAD_COMMON_HPP +#define BOOST_THREAD_THREAD_COMMON_HPP +// 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) +// (C) Copyright 2007-2010 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#include +#include + +#include +#ifndef BOOST_NO_IOSTREAM +#include +#endif +#include +#include +#if defined BOOST_THREAD_USES_DATETIME +#include +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif + +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) +#include +#endif +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +namespace boost +{ + + namespace detail + { + +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + + template + class thread_data: + public detail::thread_data_base + { + public: + BOOST_THREAD_NO_COPYABLE(thread_data) + thread_data(BOOST_THREAD_RV_REF(F) f_, BOOST_THREAD_RV_REF(ArgTypes)... args_): + fp(boost::forward(f_), boost::forward(args_)...) + {} + template + void run2(tuple_indices) + { + + detail::invoke(std::move(std::get<0>(fp)), std::move(std::get(fp))...); + } + void run() + { + typedef typename make_tuple_indices >::value, 1>::type index_type; + + run2(index_type()); + } + + private: + std::tuple::type, typename decay::type...> fp; + }; +#else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + + template + class thread_data: + public detail::thread_data_base + { + public: + BOOST_THREAD_NO_COPYABLE(thread_data) +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + thread_data(BOOST_THREAD_RV_REF(F) f_): + f(boost::forward(f_)) + {} +// This overloading must be removed if we want the packaged_task's tests to pass. +// thread_data(F& f_): +// f(f_) +// {} +#else + + thread_data(BOOST_THREAD_RV_REF(F) f_): + f(f_) + {} + thread_data(F f_): + f(f_) + {} +#endif + //thread_data() {} + + void run() + { + f(); + } + + private: + F f; + }; + + template + class thread_data >: + public detail::thread_data_base + { + private: + F& f; + public: + BOOST_THREAD_NO_COPYABLE(thread_data) + thread_data(boost::reference_wrapper f_): + f(f_) + {} + void run() + { + f(); + } + }; + + template + class thread_data >: + public detail::thread_data_base + { + private: + F& f; + public: + BOOST_THREAD_NO_COPYABLE(thread_data) + thread_data(const boost::reference_wrapper f_): + f(f_) + {} + void run() + { + f(); + } + }; +#endif + } + + class BOOST_THREAD_DECL thread + { + public: + typedef thread_attributes attributes; + + BOOST_THREAD_MOVABLE_ONLY(thread) + private: + + struct dummy; + + void release_handle(); + + detail::thread_data_ptr thread_info; + + private: + bool start_thread_noexcept(); + bool start_thread_noexcept(const attributes& attr); + void start_thread() + { + if (!start_thread_noexcept()) + { + boost::throw_exception(thread_resource_error()); + } + } + void start_thread(const attributes& attr) + { + if (!start_thread_noexcept(attr)) + { + boost::throw_exception(thread_resource_error()); + } + } + + explicit thread(detail::thread_data_ptr data); + + detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const; + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_RV_REF(ArgTypes)... args) + { + return detail::thread_data_ptr(detail::heap_new< + detail::thread_data::type, ArgTypes...> + >( + boost::forward(f), boost::forward(args)... + ) + ); + } +#else + template + static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f) + { + return detail::thread_data_ptr(detail::heap_new::type> >( + boost::forward(f))); + } +#endif + static inline detail::thread_data_ptr make_thread_info(void (*f)()) + { + return detail::thread_data_ptr(detail::heap_new >( + boost::forward(f))); + } +#else + template + static inline detail::thread_data_ptr make_thread_info(F f + , typename disable_if_c< + //boost::thread_detail::is_convertible::value || + is_same::type, thread>::value, + dummy* >::type=0 + ) + { + return detail::thread_data_ptr(detail::heap_new >(f)); + } + template + static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f) + { + return detail::thread_data_ptr(detail::heap_new >(f)); + } + +#endif + public: +#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) + thread(const volatile thread&); +#endif +#endif + thread() BOOST_NOEXCEPT; + ~thread() + { + + #if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE + if (joinable()) { + std::terminate(); + } + #else + detach(); + #endif + } +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template < + class F + > + explicit thread(BOOST_THREAD_RV_REF(F) f + //, typename disable_if::type, thread>, dummy* >::type=0 + ): + thread_info(make_thread_info(thread_detail::decay_copy(boost::forward(f)))) + { + start_thread(); + } + template < + class F + > + thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f): + thread_info(make_thread_info(thread_detail::decay_copy(boost::forward(f)))) + { + start_thread(attrs); + } + +#else +#ifdef BOOST_NO_SFINAE + template + explicit thread(F f): + thread_info(make_thread_info(f)) + { + start_thread(); + } + template + thread(attributes const& attrs, F f): + thread_info(make_thread_info(f)) + { + start_thread(attrs); + } +#else + template + explicit thread(F f + , typename disable_if_c< + boost::thread_detail::is_rv::value // todo as a thread_detail::is_rv + //boost::thread_detail::is_convertible::value + //|| is_same::type, thread>::value + , dummy* >::type=0 + ): + thread_info(make_thread_info(f)) + { + start_thread(); + } + template + thread(attributes const& attrs, F f + , typename disable_if, dummy* >::type=0 + //, typename disable_if, dummy* >::type=0 + ): + thread_info(make_thread_info(f)) + { + start_thread(attrs); + } +#endif + template + explicit thread(BOOST_THREAD_RV_REF(F) f + , typename disable_if::type, thread>, dummy* >::type=0 + ): +#ifdef BOOST_THREAD_USES_MOVE + thread_info(make_thread_info(boost::move(f))) // todo : Add forward +#else + thread_info(make_thread_info(f)) // todo : Add forward +#endif + { + start_thread(); + } + + template + thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f): +#ifdef BOOST_THREAD_USES_MOVE + thread_info(make_thread_info(boost::move(f))) // todo : Add forward +#else + thread_info(make_thread_info(f)) // todo : Add forward +#endif + { + start_thread(attrs); + } +#endif + thread(BOOST_THREAD_RV_REF(thread) x) BOOST_NOEXCEPT + { + thread_info=BOOST_THREAD_RV(x).thread_info; + BOOST_THREAD_RV(x).thread_info.reset(); + } +#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) + thread& operator=(thread x) + { + swap(x); + return *this; + } +#endif +#endif + + thread& operator=(BOOST_THREAD_RV_REF(thread) other) BOOST_NOEXCEPT + { + +#if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE + if (joinable()) std::terminate(); +#else + detach(); +#endif + thread_info=BOOST_THREAD_RV(other).thread_info; + BOOST_THREAD_RV(other).thread_info.reset(); + return *this; + } + +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + thread(F&& f, Arg&& arg, Args&&... args) : + thread_info(make_thread_info( + thread_detail::decay_copy(boost::forward(f)), + thread_detail::decay_copy(boost::forward(arg)), + thread_detail::decay_copy(boost::forward(args))...) + ) + + { + start_thread(); + } + template + thread(attributes const& attrs, F&& f, Arg&& arg, Args&&... args) : + thread_info(make_thread_info( + thread_detail::decay_copy(boost::forward(f)), + thread_detail::decay_copy(boost::forward(arg)), + thread_detail::decay_copy(boost::forward(args))...) + ) + + { + start_thread(attrs); + } +#else + template + thread(F f,A1 a1,typename disable_if, dummy* >::type=0): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1))) + { + start_thread(); + } + template + thread(F f,A1 a1,A2 a2): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6,a7))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6,a7,a8))) + { + start_thread(); + } + + template + thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9): + thread_info(make_thread_info(boost::bind(boost::type(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9))) + { + start_thread(); + } +#endif + void swap(thread& x) BOOST_NOEXCEPT + { + thread_info.swap(x.thread_info); + } + + class id; + id get_id() const BOOST_NOEXCEPT; + + bool joinable() const BOOST_NOEXCEPT; + private: + bool join_noexcept(); + bool do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res); + bool do_try_join_until(detail::internal_platform_timepoint const &timeout); + public: + void join(); + +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_join_until(const chrono::time_point& t) + { + return do_try_join_until(boost::detail::internal_platform_timepoint(t)); + } + + template + bool try_join_until(const chrono::time_point& t) + { + typedef typename common_type::type common_duration; + common_duration d(t - Clock::now()); + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + while ( ! try_join_until(detail::internal_chrono_clock::now() + d) ) + { + d = t - Clock::now(); + if ( d <= common_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + } + return true; + } + + template + bool try_join_for(const chrono::duration& rel_time) + { + return try_join_until(chrono::steady_clock::now() + rel_time); + } +#endif +#if defined BOOST_THREAD_USES_DATETIME + bool timed_join(const system_time& abs_time) + { + const detail::real_platform_timepoint ts(abs_time); +#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + detail::platform_duration d(ts - detail::real_platform_clock::now()); + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + while ( ! do_try_join_until(detail::internal_platform_clock::now() + d) ) + { + d = ts - detail::real_platform_clock::now(); + if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } + return true; +#else + return do_try_join_until(ts); +#endif + } + + template + bool timed_join(TimeDuration const& rel_time) + { + detail::platform_duration d(rel_time); +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + while ( ! do_try_join_until(detail::internal_platform_clock::now() + d) ) + { + d = ts - detail::mono_platform_clock::now(); + if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } + return true; +#else + return do_try_join_until(detail::internal_platform_clock::now() + d); +#endif + } +#endif + void detach(); + + static unsigned hardware_concurrency() BOOST_NOEXCEPT; + static unsigned physical_concurrency() BOOST_NOEXCEPT; + +#define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE + typedef detail::thread_data_base::native_handle_type native_handle_type; + native_handle_type native_handle(); + +#if defined BOOST_THREAD_PROVIDES_THREAD_EQ + // Use thread::id when comparisions are needed + // backwards compatibility + bool operator==(const thread& other) const; + bool operator!=(const thread& other) const; +#endif +#if defined BOOST_THREAD_USES_DATETIME + static inline void yield() BOOST_NOEXCEPT + { + this_thread::yield(); + } + + static inline void sleep(const system_time& xt) + { + this_thread::sleep(xt); + } +#endif + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + // extensions + void interrupt(); + bool interruption_requested() const BOOST_NOEXCEPT; +#endif + }; + + inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT + { + return lhs.swap(rhs); + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + inline thread&& move(thread& t) BOOST_NOEXCEPT + { + return static_cast(t); + } +#endif + + BOOST_THREAD_DCL_MOVABLE(thread) + + namespace this_thread + { +#ifdef BOOST_THREAD_PLATFORM_PTHREAD + thread::id get_id() BOOST_NOEXCEPT; +#else + thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT; +#endif + +#if defined BOOST_THREAD_USES_DATETIME + inline BOOST_SYMBOL_VISIBLE void sleep(::boost::xtime const& abs_time) + { + sleep(system_time(abs_time)); + } +#endif + } + + class BOOST_SYMBOL_VISIBLE thread::id + { + private: + friend inline + std::size_t + hash_value(const thread::id &v) + { +#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID + return hash_value(v.thread_data); +#else + return hash_value(v.thread_data.get()); +#endif + } + +#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID +#if defined(BOOST_THREAD_PLATFORM_WIN32) + typedef unsigned int data; +#else + typedef thread::native_handle_type data; +#endif +#else + typedef detail::thread_data_ptr data; +#endif + data thread_data; + + id(data thread_data_): + thread_data(thread_data_) + {} + friend class thread; + friend id BOOST_THREAD_DECL this_thread::get_id() BOOST_NOEXCEPT; + public: + id() BOOST_NOEXCEPT: +#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID + thread_data(0) +#else + thread_data() +#endif + {} + + id(const id& other) BOOST_NOEXCEPT : + thread_data(other.thread_data) + {} + + bool operator==(const id& y) const BOOST_NOEXCEPT + { + return thread_data==y.thread_data; + } + + bool operator!=(const id& y) const BOOST_NOEXCEPT + { + return thread_data!=y.thread_data; + } + + bool operator<(const id& y) const BOOST_NOEXCEPT + { + return thread_data(const id& y) const BOOST_NOEXCEPT + { + return y.thread_data=(const id& y) const BOOST_NOEXCEPT + { + return !(thread_data + friend BOOST_SYMBOL_VISIBLE + std::basic_ostream& + operator<<(std::basic_ostream& os, const id& x) + { + if(x.thread_data) + { + io::ios_flags_saver ifs( os ); + return os<< std::hex << x.thread_data; + } + else + { + return os<<"{Not-any-thread}"; + } + } +#else + template + BOOST_SYMBOL_VISIBLE + std::basic_ostream& + print(std::basic_ostream& os) const + { + if(thread_data) + { + io::ios_flags_saver ifs( os ); + return os<< std::hex << thread_data; + } + else + { + return os<<"{Not-any-thread}"; + } + } + +#endif +#endif + }; + +#ifdef BOOST_THREAD_PLATFORM_PTHREAD + inline thread::id thread::get_id() const BOOST_NOEXCEPT + { + #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID + return const_cast(this)->native_handle(); + #else + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); + return (local_thread_info? id(local_thread_info) : id()); + #endif + } + + namespace this_thread + { + inline thread::id get_id() BOOST_NOEXCEPT + { + #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID + return pthread_self(); + #else + boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data(); + return (thread_info?thread::id(thread_info->shared_from_this()):thread::id()); + #endif + } + } +#endif + inline void thread::join() { + if (this_thread::get_id() == get_id()) + boost::throw_exception(thread_resource_error(static_cast(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself")); + + BOOST_THREAD_VERIFY_PRECONDITION( join_noexcept(), + thread_resource_error(static_cast(system::errc::invalid_argument), "boost thread: thread not joinable") + ); + } + + inline bool thread::do_try_join_until(detail::internal_platform_timepoint const &timeout) + { + if (this_thread::get_id() == get_id()) + boost::throw_exception(thread_resource_error(static_cast(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself")); + bool res; + if (do_try_join_until_noexcept(timeout, res)) + { + return res; + } + else + { + BOOST_THREAD_THROW_ELSE_RETURN( + (thread_resource_error(static_cast(system::errc::invalid_argument), "boost thread: thread not joinable")), + false + ); + } + } + +#if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + template + BOOST_SYMBOL_VISIBLE + std::basic_ostream& + operator<<(std::basic_ostream& os, const thread::id& x) + { + return x.print(os); + } +#endif + +#if defined BOOST_THREAD_PROVIDES_THREAD_EQ + inline bool thread::operator==(const thread& other) const + { + return get_id()==other.get_id(); + } + + inline bool thread::operator!=(const thread& other) const + { + return get_id()!=other.get_id(); + } +#endif + + namespace detail + { + struct thread_exit_function_base + { + virtual ~thread_exit_function_base() + {} + virtual void operator()()=0; + }; + + template + struct thread_exit_function: + thread_exit_function_base + { + F f; + + thread_exit_function(F f_): + f(f_) + {} + + void operator()() + { + f(); + } + }; + + void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*); +//#ifndef BOOST_NO_EXCEPTIONS + struct shared_state_base; +#if defined(BOOST_THREAD_PLATFORM_WIN32) + inline void make_ready_at_thread_exit(shared_ptr as) + { + detail::thread_data_base* const current_thread_data(detail::get_current_thread_data()); + if(current_thread_data) + { + current_thread_data->make_ready_at_thread_exit(as); + } + } +#else + void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr as); +#endif +//#endif + } + + namespace this_thread + { + template + void at_thread_exit(F f) + { + detail::thread_exit_function_base* const thread_exit_func=detail::heap_new >(f); + detail::add_thread_exit_function(thread_exit_func); + } + } +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#include + +#endif diff --git a/boost/thread/detail/thread_group.hpp b/boost/thread/detail/thread_group.hpp new file mode 100644 index 0000000..4105c73 --- /dev/null +++ b/boost/thread/detail/thread_group.hpp @@ -0,0 +1,155 @@ +#ifndef BOOST_THREAD_DETAIL_THREAD_GROUP_HPP +#define BOOST_THREAD_DETAIL_THREAD_GROUP_HPP +// 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) +// (C) Copyright 2007-9 Anthony Williams + +#include +#include +#include +#include +#include + +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +namespace boost +{ + class thread_group + { + private: + thread_group(thread_group const&); + thread_group& operator=(thread_group const&); + public: + thread_group() {} + ~thread_group() + { + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + delete *it; + } + } + + bool is_this_thread_in() + { + thread::id id = this_thread::get_id(); + boost::shared_lock guard(m); + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + if ((*it)->get_id() == id) + return true; + } + return false; + } + + bool is_thread_in(thread* thrd) + { + if(thrd) + { + thread::id id = thrd->get_id(); + boost::shared_lock guard(m); + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + if ((*it)->get_id() == id) + return true; + } + return false; + } + else + { + return false; + } + } + + template + thread* create_thread(F threadfunc) + { + boost::lock_guard guard(m); + boost::csbl::unique_ptr new_thread(new thread(threadfunc)); + threads.push_back(new_thread.get()); + return new_thread.release(); + } + + void add_thread(thread* thrd) + { + if(thrd) + { + BOOST_THREAD_ASSERT_PRECONDITION( ! is_thread_in(thrd) , + thread_resource_error(static_cast(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying to add a duplicated thread") + ); + + boost::lock_guard guard(m); + threads.push_back(thrd); + } + } + + void remove_thread(thread* thrd) + { + boost::lock_guard guard(m); + std::list::iterator const it=std::find(threads.begin(),threads.end(),thrd); + if(it!=threads.end()) + { + threads.erase(it); + } + } + + void join_all() + { + BOOST_THREAD_ASSERT_PRECONDITION( ! is_this_thread_in() , + thread_resource_error(static_cast(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying joining itself") + ); + boost::shared_lock guard(m); + + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + if ((*it)->joinable()) + (*it)->join(); + } + } + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + void interrupt_all() + { + boost::shared_lock guard(m); + + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + (*it)->interrupt(); + } + } +#endif + + size_t size() const + { + boost::shared_lock guard(m); + return threads.size(); + } + + private: + std::list threads; + mutable shared_mutex m; + }; +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#include + +#endif diff --git a/boost/thread/detail/thread_heap_alloc.hpp b/boost/thread/detail/thread_heap_alloc.hpp new file mode 100644 index 0000000..2f9bfd5 --- /dev/null +++ b/boost/thread/detail/thread_heap_alloc.hpp @@ -0,0 +1,23 @@ +#ifndef BOOST_THREAD_THREAD_HEAP_ALLOC_HPP +#define BOOST_THREAD_THREAD_HEAP_ALLOC_HPP + +// thread_heap_alloc.hpp +// +// (C) Copyright 2008 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + + +#endif diff --git a/boost/thread/detail/thread_interruption.hpp b/boost/thread/detail/thread_interruption.hpp new file mode 100644 index 0000000..5d7d10f --- /dev/null +++ b/boost/thread/detail/thread_interruption.hpp @@ -0,0 +1,39 @@ +#ifndef BOOST_THREAD_DETAIL_THREAD_INTERRUPTION_HPP +#define BOOST_THREAD_DETAIL_THREAD_INTERRUPTION_HPP +// 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) +// (C) Copyright 2007-9 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba + +#include +#include + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + +namespace boost +{ + namespace this_thread + { + class BOOST_THREAD_DECL disable_interruption + { + bool interruption_was_enabled; + friend class restore_interruption; + public: + BOOST_THREAD_NO_COPYABLE(disable_interruption) + disable_interruption() BOOST_NOEXCEPT; + ~disable_interruption() BOOST_NOEXCEPT; + }; + + class BOOST_THREAD_DECL restore_interruption + { + public: + BOOST_THREAD_NO_COPYABLE(restore_interruption) + explicit restore_interruption(disable_interruption& d) BOOST_NOEXCEPT; + ~restore_interruption() BOOST_NOEXCEPT; + }; + } +} + +#endif // BOOST_THREAD_PROVIDES_INTERRUPTIONS +#endif // header diff --git a/boost/thread/detail/thread_safety.hpp b/boost/thread/detail/thread_safety.hpp new file mode 100644 index 0000000..4aa29a8 --- /dev/null +++ b/boost/thread/detail/thread_safety.hpp @@ -0,0 +1,160 @@ +#ifndef BOOST_THREAD_DETAIL_THREAD_SAFETY_HPP +#define BOOST_THREAD_DETAIL_THREAD_SAFETY_HPP + +#if defined(__GNUC__) && !defined(__GXX_EXPERIMENTAL_CXX0X__) +// +// This is horrible, but it seems to be the only we can shut up the +// "anonymous variadic macros were introduced in C99 [-Wvariadic-macros]" +// warning that get spewed out otherwise in non-C++11 mode. +// +#pragma GCC system_header +#endif + +// See https://clang.llvm.org/docs/ThreadSafetyAnalysis.html + +// Un-comment to enable Thread Safety Analysis +//#define BOOST_THREAD_ENABLE_THREAD_SAFETY_ANALYSIS + +// Enable thread safety attributes only with clang. +// The attributes can be safely erased when compiling with other compilers. +#if defined (BOOST_THREAD_ENABLE_THREAD_SAFETY_ANALYSIS) && defined(__clang__) && (!defined(SWIG)) +#define BOOST_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) +#else +#define BOOST_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op +#endif + +#define BOOST_THREAD_CAPABILITY(x) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(capability(x)) + +#define BOOST_THREAD_SCOPED_CAPABILITY \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) + +#define BOOST_THREAD_GUARDED_BY(x) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) + +#define BOOST_THREAD_PT_GUARDED_BY(x) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) + +#define BOOST_THREAD_ACQUIRED_BEFORE(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) + +#define BOOST_THREAD_ACQUIRED_AFTER(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) + +#define BOOST_THREAD_REQUIRES(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__)) + +#define BOOST_THREAD_REQUIRES_SHARED(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) + +#define BOOST_THREAD_ACQUIRE(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) + +#define BOOST_THREAD_ACQUIRE_SHARED(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) + +#define BOOST_THREAD_RELEASE(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__)) + +#define BOOST_THREAD_RELEASE_SHARED(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) + +#define BOOST_THREAD_TRY_ACQUIRE(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) + +#define BOOST_THREAD_TRY_ACQUIRE_SHARED(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) + +#define BOOST_THREAD_EXCLUDES(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) + +#define BOOST_THREAD_ASSERT_CAPABILITY(x) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x)) + +#define BOOST_THREAD_ASSERT_SHARED_CAPABILITY(x) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x)) + +#define BOOST_THREAD_RETURN_CAPABILITY(x) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) + +#define BOOST_THREAD_NO_THREAD_SAFETY_ANALYSIS \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) + +#if defined(__clang__) && (!defined(SWIG)) && defined(__FreeBSD__) +#if __has_attribute(no_thread_safety_analysis) +#define BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis)) +#else +#define BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS +#endif +#else +#define BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS +#endif + +#ifdef USE_LOCK_STYLE_THREAD_SAFETY_ATTRIBUTES +// The original version of thread safety analysis the following attribute +// definitions. These use a lock-based terminology. They are still in use +// by existing thread safety code, and will continue to be supported. + +// Deprecated. +#define BOOST_THREAD_PT_GUARDED_VAR \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_var) + +// Deprecated. +#define BOOST_THREAD_GUARDED_VAR \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(guarded_var) + +// Replaced by REQUIRES +#define BOOST_THREAD_EXCLUSIVE_LOCKS_REQUIRED(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__)) + +// Replaced by REQUIRES_SHARED +#define BOOST_THREAD_SHARED_LOCKS_REQUIRED(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__)) + +// Replaced by CAPABILITY +#define BOOST_THREAD_LOCKABLE \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(lockable) + +// Replaced by SCOPED_CAPABILITY +#define BOOST_THREAD_SCOPED_LOCKABLE \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) + +// Replaced by ACQUIRE +#define BOOST_THREAD_EXCLUSIVE_LOCK_FUNCTION(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__)) + +// Replaced by ACQUIRE_SHARED +#define BOOST_THREAD_SHARED_LOCK_FUNCTION(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__)) + +// Replaced by RELEASE and RELEASE_SHARED +#define BOOST_THREAD_UNLOCK_FUNCTION(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__)) + +// Replaced by TRY_ACQUIRE +#define BOOST_THREAD_EXCLUSIVE_TRYLOCK_FUNCTION(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__)) + +// Replaced by TRY_ACQUIRE_SHARED +#define BOOST_THREAD_SHARED_TRYLOCK_FUNCTION(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__)) + +// Replaced by ASSERT_CAPABILITY +#define BOOST_THREAD_ASSERT_EXCLUSIVE_LOCK(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__)) + +// Replaced by ASSERT_SHARED_CAPABILITY +#define BOOST_THREAD_ASSERT_SHARED_LOCK(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__)) + +// Replaced by EXCLUDE_CAPABILITY. +#define BOOST_THREAD_LOCKS_EXCLUDED(...) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) + +// Replaced by RETURN_CAPABILITY +#define BOOST_THREAD_LOCK_RETURNED(x) \ + BOOST_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) + +#endif // USE_LOCK_STYLE_THREAD_SAFETY_ATTRIBUTES + +#endif // BOOST_THREAD_DETAIL_THREAD_SAFETY_HPP diff --git a/boost/thread/detail/tss_hooks.hpp b/boost/thread/detail/tss_hooks.hpp new file mode 100644 index 0000000..4429821 --- /dev/null +++ b/boost/thread/detail/tss_hooks.hpp @@ -0,0 +1,65 @@ +// (C) Copyright Michael Glassford 2004. +// Use, modification and distribution are subject to 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) + +#if !defined(BOOST_TLS_HOOKS_HPP) +#define BOOST_TLS_HOOKS_HPP + +#include + +#include + +#if defined(BOOST_THREAD_WIN32) + +namespace boost +{ + BOOST_THREAD_DECL void __cdecl on_process_enter(void); + //Function to be called when the exe or dll + //that uses Boost.Threads first starts + //or is first loaded. + //Should be called only before the first call to + //on_thread_enter(). + //Called automatically by Boost.Threads when + //a method for doing so has been discovered. + //May be omitted; may be called multiple times. + + BOOST_THREAD_DECL void __cdecl on_process_exit(void); + //Function to be called when the exe or dll + //that uses Boost.Threads first starts + //or is first loaded. + //Should be called only after the last call to + //on_exit_thread(). + //Called automatically by Boost.Threads when + //a method for doing so has been discovered. + //Must not be omitted; may be called multiple times. + + BOOST_THREAD_DECL void __cdecl on_thread_enter(void); + //Function to be called just after a thread starts + //in an exe or dll that uses Boost.Threads. + //Must be called in the context of the thread + //that is starting. + //Called automatically by Boost.Threads when + //a method for doing so has been discovered. + //May be omitted; may be called multiple times. + + BOOST_THREAD_DECL void __cdecl on_thread_exit(void); + //Function to be called just be fore a thread ends + //in an exe or dll that uses Boost.Threads. + //Must be called in the context of the thread + //that is ending. + //Called automatically by Boost.Threads when + //a method for doing so has been discovered. + //Must not be omitted; may be called multiple times. + + void tss_cleanup_implemented(); + //Dummy function used both to detect whether tss cleanup + //cleanup has been implemented and to force + //it to be linked into the Boost.Threads library. +} + +#endif //defined(BOOST_THREAD_WIN32) + +#include + +#endif //!defined(BOOST_TLS_HOOKS_HPP) diff --git a/boost/thread/detail/variadic_footer.hpp b/boost/thread/detail/variadic_footer.hpp new file mode 100644 index 0000000..9ae25a8 --- /dev/null +++ b/boost/thread/detail/variadic_footer.hpp @@ -0,0 +1,10 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) + + +#if defined BOOST_NO_CXX11_VARIADIC_TEMPLATES + + +#endif diff --git a/boost/thread/detail/variadic_header.hpp b/boost/thread/detail/variadic_header.hpp new file mode 100644 index 0000000..8015ae3 --- /dev/null +++ b/boost/thread/detail/variadic_header.hpp @@ -0,0 +1,19 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +//#if defined BOOST_NO_CXX11_VARIADIC_TEMPLATES + +#include +#include +#include + +#ifndef BOOST_THREAD_MAX_ARGS +#define BOOST_THREAD_MAX_ARGS 9 +#endif + +//#endif + diff --git a/boost/thread/exceptional_ptr.hpp b/boost/thread/exceptional_ptr.hpp new file mode 100644 index 0000000..4954792 --- /dev/null +++ b/boost/thread/exceptional_ptr.hpp @@ -0,0 +1,44 @@ +// 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) +// (C) Copyright 2014 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_EXCEPTIONAL_PTR_HPP +#define BOOST_THREAD_EXCEPTIONAL_PTR_HPP + +#include +#include + +#include + +namespace boost +{ + struct exceptional_ptr { + exception_ptr ptr_; + + exceptional_ptr() : ptr_() {} + explicit exceptional_ptr(exception_ptr ex) : ptr_(ex) {} + template + explicit exceptional_ptr(BOOST_FWD_REF(E) ex) : ptr_(boost::copy_exception(boost::forward(ex))) {} + }; + + template + inline exceptional_ptr make_exceptional(BOOST_FWD_REF(E) ex) { + return exceptional_ptr(boost::forward(ex)); + } + + inline exceptional_ptr make_exceptional(exception_ptr ex) + { + return exceptional_ptr(ex); + } + + inline exceptional_ptr make_exceptional() + { + return exceptional_ptr(); + } + +} // namespace boost + +#include + +#endif diff --git a/boost/thread/exceptions.hpp b/boost/thread/exceptions.hpp new file mode 100644 index 0000000..2a5094b --- /dev/null +++ b/boost/thread/exceptions.hpp @@ -0,0 +1,225 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007-9 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// +// 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_THREAD_EXCEPTIONS_PDM070801_H +#define BOOST_THREAD_EXCEPTIONS_PDM070801_H + +#include + +// pdm: Sorry, but this class is used all over the place & I end up +// with recursive headers if I don't separate it +// wek: Not sure why recursive headers would cause compilation problems +// given the include guards, but regardless it makes sense to +// seperate this out any way. + +#include +#include +#include +#include + + +#include + +namespace boost +{ + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + class BOOST_SYMBOL_VISIBLE thread_interrupted + {}; +#endif + + class BOOST_SYMBOL_VISIBLE thread_exception: + public system::system_error + //public std::exception + { + typedef system::system_error base_type; + public: + thread_exception() + : base_type(0,system::generic_category()) + {} + + thread_exception(int sys_error_code) + : base_type(sys_error_code, system::generic_category()) + {} + + thread_exception( int ev, const char * what_arg ) + : base_type(system::error_code(ev, system::generic_category()), what_arg) + { + } + thread_exception( int ev, const std::string & what_arg ) + : base_type(system::error_code(ev, system::generic_category()), what_arg) + { + } + + ~thread_exception() BOOST_NOEXCEPT_OR_NOTHROW + {} + + + int native_error() const + { + return code().value(); + } + + }; + + class BOOST_SYMBOL_VISIBLE condition_error: + public system::system_error + //public std::exception + { + typedef system::system_error base_type; + public: + condition_error() + : base_type(system::error_code(0, system::generic_category()), "Condition error") + {} + condition_error( int ev ) + : base_type(system::error_code(ev, system::generic_category()), "Condition error") + { + } + condition_error( int ev, const char * what_arg ) + : base_type(system::error_code(ev, system::generic_category()), what_arg) + { + } + condition_error( int ev, const std::string & what_arg ) + : base_type(system::error_code(ev, system::generic_category()), what_arg) + { + } + }; + + + class BOOST_SYMBOL_VISIBLE lock_error: + public thread_exception + { + typedef thread_exception base_type; + public: + lock_error() + : base_type(0, "boost::lock_error") + {} + + lock_error( int ev ) + : base_type(ev, "boost::lock_error") + { + } + lock_error( int ev, const char * what_arg ) + : base_type(ev, what_arg) + { + } + lock_error( int ev, const std::string & what_arg ) + : base_type(ev, what_arg) + { + } + + ~lock_error() BOOST_NOEXCEPT_OR_NOTHROW + {} + + }; + + class BOOST_SYMBOL_VISIBLE thread_resource_error: + public thread_exception + { + typedef thread_exception base_type; + public: + thread_resource_error() + : base_type(static_cast(system::errc::resource_unavailable_try_again), "boost::thread_resource_error") + {} + + thread_resource_error( int ev ) + : base_type(ev, "boost::thread_resource_error") + { + } + thread_resource_error( int ev, const char * what_arg ) + : base_type(ev, what_arg) + { + } + thread_resource_error( int ev, const std::string & what_arg ) + : base_type(ev, what_arg) + { + } + + + ~thread_resource_error() BOOST_NOEXCEPT_OR_NOTHROW + {} + + }; + + class BOOST_SYMBOL_VISIBLE unsupported_thread_option: + public thread_exception + { + typedef thread_exception base_type; + public: + unsupported_thread_option() + : base_type(static_cast(system::errc::invalid_argument), "boost::unsupported_thread_option") + {} + + unsupported_thread_option( int ev ) + : base_type(ev, "boost::unsupported_thread_option") + { + } + unsupported_thread_option( int ev, const char * what_arg ) + : base_type(ev, what_arg) + { + } + unsupported_thread_option( int ev, const std::string & what_arg ) + : base_type(ev, what_arg) + { + } + + }; + + class BOOST_SYMBOL_VISIBLE invalid_thread_argument: + public thread_exception + { + typedef thread_exception base_type; + public: + invalid_thread_argument() + : base_type(static_cast(system::errc::invalid_argument), "boost::invalid_thread_argument") + {} + + invalid_thread_argument( int ev ) + : base_type(ev, "boost::invalid_thread_argument") + { + } + invalid_thread_argument( int ev, const char * what_arg ) + : base_type(ev, what_arg) + { + } + invalid_thread_argument( int ev, const std::string & what_arg ) + : base_type(ev, what_arg) + { + } + + }; + + class BOOST_SYMBOL_VISIBLE thread_permission_error: + public thread_exception + { + typedef thread_exception base_type; + public: + thread_permission_error() + : base_type(static_cast(system::errc::permission_denied), "boost::thread_permission_error") + {} + + thread_permission_error( int ev ) + : base_type(ev, "boost::thread_permission_error") + { + } + thread_permission_error( int ev, const char * what_arg ) + : base_type(ev, what_arg) + { + } + thread_permission_error( int ev, const std::string & what_arg ) + : base_type(ev, what_arg) + { + } + + }; + +} // namespace boost + +#include + +#endif diff --git a/boost/thread/executor.hpp b/boost/thread/executor.hpp new file mode 100644 index 0000000..c2b85a0 --- /dev/null +++ b/boost/thread/executor.hpp @@ -0,0 +1,15 @@ +// Copyright (C) 2013 Vicente J. Botet Escriba +// +// 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) +// +// 2013/09 Vicente J. Botet Escriba +// Adapt to boost from CCIA C++11 implementation + +#ifndef BOOST_THREAD_EXECUTOR_HPP +#define BOOST_THREAD_EXECUTOR_HPP + +#include +#include + +#endif diff --git a/boost/thread/executors/executor.hpp b/boost/thread/executors/executor.hpp new file mode 100644 index 0000000..62824a5 --- /dev/null +++ b/boost/thread/executors/executor.hpp @@ -0,0 +1,150 @@ +// Copyright (C) 2013,2014 Vicente J. Botet Escriba +// +// 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) +// +// 2013/09 Vicente J. Botet Escriba +// Adapt to boost from CCIA C++11 implementation + +#ifndef BOOST_THREAD_EXECUTORS_EXECUTOR_HPP +#define BOOST_THREAD_EXECUTORS_EXECUTOR_HPP + +#include +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE + +#include +#include +#include + +#include + +namespace boost +{ + namespace executors + { + class executor + { + public: + /// type-erasure to store the works to do + typedef executors::work work; + + /// executor is not copyable. + BOOST_THREAD_NO_COPYABLE(executor) + executor() {} + + /** + * \par Effects + * Destroys the executor. + * + * \par Synchronization + * The completion of all the closures happen before the completion of the executor destructor. + */ + virtual ~executor() {} + + /** + * \par Effects + * Close the \c executor for submissions. + * The worker threads will work until there is no more closures to run. + */ + virtual void close() = 0; + + /** + * \par Returns + * Whether the pool is closed for submissions. + */ + virtual bool closed() = 0; + + /** + * \par Effects + * The specified closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the executor will call std::terminate, as is the case with threads. + * + * \par Synchronization + * Ccompletion of closure on a particular thread happens before destruction of thread's thread local variables. + * + * \par Throws + * \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + virtual void submit(BOOST_THREAD_RV_REF(work) closure) = 0; +// virtual void submit(work& closure) = 0; + + /** + * \par Requires + * \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible. + * + * \par Effects + * The specified closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the thread pool will call std::terminate, as is the case with threads. + * + * \par Synchronization + * Completion of closure on a particular thread happens before destruction of thread's thread local variables. + * + * \par Throws + * \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + void submit(Closure & closure) + { + work w ((closure)); + submit(boost::move(w)); + } +#endif + void submit(void (*closure)()) + { + work w ((closure)); + submit(boost::move(w)); + } + + template + void submit(BOOST_THREAD_FWD_REF(Closure) closure) + { + //submit(work(boost::forward(closure))); + work w((boost::forward(closure))); + submit(boost::move(w)); + } + + /** + * \par Effects + * Try to execute one task. + * + * \par Returns + * Whether a task has been executed. + * + * \par Throws + * Whatever the current task constructor throws or the task() throws. + */ + virtual bool try_executing_one() = 0; + + /** + * \par Requires + * This must be called from an scheduled task. + * + * \par Effects + * Reschedule functions until pred() + */ + template + bool reschedule_until(Pred const& pred) + { + do { + //schedule_one_or_yield(); + if ( ! try_executing_one()) + { + return false; + } + } while (! pred()); + return true; + } + }; + + } + using executors::executor; +} + +#include + +#endif +#endif diff --git a/boost/thread/executors/executor_adaptor.hpp b/boost/thread/executors/executor_adaptor.hpp new file mode 100644 index 0000000..b1fd222 --- /dev/null +++ b/boost/thread/executors/executor_adaptor.hpp @@ -0,0 +1,138 @@ +// Copyright (C) 2013,2014 Vicente J. Botet Escriba +// +// 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) +// +// 2013/09 Vicente J. Botet Escriba +// Adapt to boost from CCIA C++11 implementation + +#ifndef BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP +#define BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP + +#include +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE + +#include + +#include + +namespace boost +{ +namespace executors +{ + /** + * Polymorphic adaptor of a model of Executor to an executor. + */ + template + class executor_adaptor : public executor + { + Executor ex; + public: + /// type-erasure to store the works to do + typedef executor::work work; + + /// executor is not copyable. + BOOST_THREAD_NO_COPYABLE(executor_adaptor) + + /** + * executor_adaptor constructor + */ +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + executor_adaptor(BOOST_THREAD_RV_REF(Args) ... args) : ex(boost::forward(args)...) {} +#else + /** + * executor_adaptor constructor + */ + executor_adaptor() : ex() {} + + template + executor_adaptor( + BOOST_THREAD_FWD_REF(A1) a1 + ) : + ex( + boost::forward(a1) + ) {} + template + executor_adaptor( + BOOST_THREAD_FWD_REF(A1) a1, + BOOST_THREAD_FWD_REF(A2) a2 + ) : + ex( + boost::forward(a1), + boost::forward(a2) + ) {} + template + executor_adaptor( + BOOST_THREAD_FWD_REF(A1) a1, + BOOST_THREAD_FWD_REF(A2) a2, + BOOST_THREAD_FWD_REF(A3) a3 + ) : + ex( + boost::forward(a1), + boost::forward(a2), + boost::forward(a3) + ) {} +#endif + Executor& underlying_executor() { return ex; } + + /** + * \b Effects: close the \c executor for submissions. + * The worker threads will work until there is no more closures to run. + */ + void close() { ex.close(); } + + /** + * \b Returns: whether the pool is closed for submissions. + */ + bool closed() { return ex.closed(); } + + /** + * \b Effects: The specified closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the executor will call std::terminate, as is the case with threads. + * + * \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables. + * + * \b Throws: \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + void submit(BOOST_THREAD_RV_REF(work) closure) { + return ex.submit(boost::move(closure)); + } + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + void submit(Closure & closure) + { + submit(work(closure)); + } +#endif + void submit(void (*closure)()) + { + submit(work(closure)); + } + + template + void submit(BOOST_THREAD_FWD_REF(Closure) closure) + { + //submit(work(boost::forward(closure))); + work w((boost::forward(closure))); + submit(boost::move(w)); + } + + /** + * Effects: try to execute one task. + * Returns: whether a task has been executed. + * Throws: whatever the current task constructor throws or the task() throws. + */ + bool try_executing_one() { return ex.try_executing_one(); } + + }; +} +using executors::executor_adaptor; +} + +#include + +#endif +#endif diff --git a/boost/thread/executors/generic_executor_ref.hpp b/boost/thread/executors/generic_executor_ref.hpp new file mode 100644 index 0000000..abe7da4 --- /dev/null +++ b/boost/thread/executors/generic_executor_ref.hpp @@ -0,0 +1,215 @@ +// Copyright (C) 2014 Vicente J. Botet Escriba +// +// 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_THREAD_EXECUTORS_GENERIC_EXECUTOR_REF_HPP +#define BOOST_THREAD_EXECUTORS_GENERIC_EXECUTOR_REF_HPP + +#include +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE + +#include +#include +#include + +#include + +#include + +namespace boost +{ + namespace executors + { + + template + class executor_ref : public executor + { + Executor& ex; + public: + /// type-erasure to store the works to do + typedef executors::work work; + + /// executor is not copyable. + BOOST_THREAD_NO_COPYABLE(executor_ref) + executor_ref(Executor& ex_) : ex(ex_) {} + + /** + * \par Effects + * Destroys the executor. + * + * \par Synchronization + * The completion of all the closures happen before the completion of the executor destructor. + */ + ~executor_ref() {} + + /** + * \par Effects + * Close the \c executor for submissions. + * The worker threads will work until there is no more closures to run. + */ + void close() { ex.close(); } + + /** + * \par Returns + * Whether the pool is closed for submissions. + */ + bool closed() { return ex.closed(); } + + /** + * \par Effects + * The specified closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the executor will call std::terminate, as is the case with threads. + * + * \par Synchronization + * Ccompletion of closure on a particular thread happens before destruction of thread's thread local variables. + * + * \par Throws + * \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + void submit(BOOST_THREAD_RV_REF(work) closure) { + ex.submit(boost::move(closure)); + } +// void submit(work& closure) { +// ex.submit(closure); +// } + + + /** + * \par Effects + * Try to execute one task. + * + * \par Returns + * Whether a task has been executed. + * + * \par Throws + * Whatever the current task constructor throws or the task() throws. + */ + bool try_executing_one() { return ex.try_executing_one(); } + + }; + + class generic_executor_ref + { + shared_ptr ex; + public: + /// type-erasure to store the works to do + typedef executors::work work; + + template + generic_executor_ref(Executor& ex_) + //: ex(make_shared >(ex_)) // todo check why this doesn't works with C++03 + : ex( new executor_ref(ex_) ) + { + } + + //generic_executor_ref(generic_executor_ref const& other) noexcept {} + //generic_executor_ref& operator=(generic_executor_ref const& other) noexcept {} + + + /** + * \par Effects + * Close the \c executor for submissions. + * The worker threads will work until there is no more closures to run. + */ + void close() { ex->close(); } + + /** + * \par Returns + * Whether the pool is closed for submissions. + */ + bool closed() { return ex->closed(); } + + /** + * \par Requires + * \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible. + * + * \par Effects + * The specified closure will be scheduled for execution at some point in the future. + * If invoked closure throws an exception the thread pool will call std::terminate, as is the case with threads. + * + * \par Synchronization + * Completion of closure on a particular thread happens before destruction of thread's thread local variables. + * + * \par Throws + * \c sync_queue_is_closed if the thread pool is closed. + * Whatever exception that can be throw while storing the closure. + */ + + void submit(BOOST_THREAD_RV_REF(work) closure) + { + ex->submit(boost::move(closure)); + } + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + void submit(Closure & closure) + { + //work w ((closure)); + //submit(boost::move(w)); + submit(work(closure)); + } +#endif + void submit(void (*closure)()) + { + work w ((closure)); + submit(boost::move(w)); + //submit(work(closure)); + } + + template + void submit(BOOST_THREAD_FWD_REF(Closure) closure) + { + work w((boost::forward(closure))); + submit(boost::move(w)); + } + +// size_t num_pending_closures() const +// { +// return ex->num_pending_closures(); +// } + + /** + * \par Effects + * Try to execute one task. + * + * \par Returns + * Whether a task has been executed. + * + * \par Throws + * Whatever the current task constructor throws or the task() throws. + */ + bool try_executing_one() { return ex->try_executing_one(); } + + /** + * \par Requires + * This must be called from an scheduled task. + * + * \par Effects + * reschedule functions until pred() + */ + template + bool reschedule_until(Pred const& pred) + { + do { + //schedule_one_or_yield(); + if ( ! try_executing_one()) + { + return false; + } + } while (! pred()); + return true; + } + + }; + } + using executors::executor_ref; + using executors::generic_executor_ref; +} + +#include + +#endif +#endif diff --git a/boost/thread/executors/work.hpp b/boost/thread/executors/work.hpp new file mode 100644 index 0000000..7d98e07 --- /dev/null +++ b/boost/thread/executors/work.hpp @@ -0,0 +1,32 @@ +// (C) Copyright 2013,2014 Vicente J. Botet Escriba +// +// 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_THREAD_EXECUTORS_WORK_HPP +#define BOOST_THREAD_EXECUTORS_WORK_HPP + +#include +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE + +#include +#include + +namespace boost +{ + namespace executors + { + typedef detail::nullary_function work; + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + typedef detail::nullary_function work_pq; + //typedef csbl::function work_pq; +#else + typedef csbl::function work_pq; +#endif + } +} // namespace boost + +#endif +#endif // BOOST_THREAD_EXECUTORS_WORK_HPP diff --git a/boost/thread/future.hpp b/boost/thread/future.hpp new file mode 100644 index 0000000..3d1b29d --- /dev/null +++ b/boost/thread/future.hpp @@ -0,0 +1,5898 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2015 Vicente J. Botet Escriba +// +// 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_THREAD_FUTURE_HPP +#define BOOST_THREAD_FUTURE_HPP + +#include + +// boost::thread::future requires exception handling +// due to boost::exception::exception_ptr dependency + +//#define BOOST_THREAD_CONTINUATION_SYNC + +#ifdef BOOST_NO_EXCEPTIONS +namespace boost +{ +namespace detail { +struct shared_state_base { + void notify_deferred() {} +}; +} +} +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL +#include +#else +#include +#endif + +#include +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS +#include +#include +#if ! defined BOOST_NO_CXX11_ALLOCATOR +#include +#endif +#endif + +#if defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY +#include +#include +#endif + +#include +#include +#include +#include + +#if defined BOOST_THREAD_PROVIDES_FUTURE +#define BOOST_THREAD_FUTURE future +#else +#define BOOST_THREAD_FUTURE unique_future +#endif + +namespace boost +{ + template + shared_ptr static_shared_from_this(T* that) + { + return static_pointer_cast(that->shared_from_this()); + } + template + shared_ptr static_shared_from_this(T const* that) + { + return static_pointer_cast(that->shared_from_this()); + } + +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS +#else + namespace executors { + class executor; + } + using executors::executor; +#endif + typedef shared_ptr executor_ptr_type; + + namespace detail + { + + struct relocker + { + boost::unique_lock& lock_; + + relocker(boost::unique_lock& lk): + lock_(lk) + { + lock_.unlock(); + } + ~relocker() + { + if (! lock_.owns_lock()) { + lock_.lock(); + } + } + void lock() { + if (! lock_.owns_lock()) { + lock_.lock(); + } + } + private: + relocker& operator=(relocker const&); + }; + + struct shared_state_base : enable_shared_from_this + { + typedef std::list waiter_list; + typedef waiter_list::iterator notify_when_ready_handle; + // This type should be only included conditionally if interruptions are allowed, but is included to maintain the same layout. + typedef shared_ptr continuation_ptr_type; + typedef std::vector continuations_type; + + boost::exception_ptr exception; + bool done; + bool is_valid_; + bool is_deferred_; + bool is_constructed; + launch policy_; + mutable boost::mutex mutex; + boost::condition_variable waiters; + waiter_list external_waiters; + boost::function callback; + // This declaration should be only included conditionally, but is included to maintain the same layout. + continuations_type continuations; + executor_ptr_type ex_; + + // This declaration should be only included conditionally, but is included to maintain the same layout. + virtual void launch_continuation() + { + } + + shared_state_base(): + done(false), + is_valid_(true), + is_deferred_(false), + is_constructed(false), + policy_(launch::none), + continuations(), + ex_() + {} + + shared_state_base(exceptional_ptr const& ex): + exception(ex.ptr_), + done(true), + is_valid_(true), + is_deferred_(false), + is_constructed(false), + policy_(launch::none), + continuations(), + ex_() + {} + + + virtual ~shared_state_base() + { + } + + bool is_done() + { + return done; + } + + executor_ptr_type get_executor() + { + return ex_; + } + + void set_executor_policy(executor_ptr_type aex) + { + set_executor(); + ex_ = aex; + } + void set_executor_policy(executor_ptr_type aex, boost::lock_guard&) + { + set_executor(); + ex_ = aex; + } + void set_executor_policy(executor_ptr_type aex, boost::unique_lock&) + { + set_executor(); + ex_ = aex; + } + + bool valid(boost::unique_lock&) { return is_valid_; } + bool valid() { + boost::unique_lock lk(this->mutex); + return valid(lk); + } + void invalidate(boost::unique_lock&) { is_valid_ = false; } + void invalidate() { + boost::unique_lock lk(this->mutex); + invalidate(lk); + } + void validate(boost::unique_lock&) { is_valid_ = true; } + void validate() { + boost::unique_lock lk(this->mutex); + validate(lk); + } + + void set_deferred() + { + is_deferred_ = true; + policy_ = launch::deferred; + } + void set_async() + { + is_deferred_ = false; + policy_ = launch::async; + } +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + void set_executor() + { + is_deferred_ = false; + policy_ = launch::executor; + } +#else + void set_executor() + { + } +#endif + notify_when_ready_handle notify_when_ready(boost::condition_variable_any& cv) + { + boost::unique_lock lock(this->mutex); + do_callback(lock); + return external_waiters.insert(external_waiters.end(),&cv); + } + + void unnotify_when_ready(notify_when_ready_handle it) + { + boost::lock_guard lock(this->mutex); + external_waiters.erase(it); + } + +#if 0 + // this inline definition results in ODR. See https://github.com/boostorg/thread/issues/193 + // to avoid it, we define the function on the derived templates using the macro BOOST_THREAD_DO_CONTINUATION +#define BOOST_THREAD_DO_CONTINUATION +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + void do_continuation(boost::unique_lock& lock) + { + if (! continuations.empty()) { + continuations_type the_continuations = continuations; + continuations.clear(); + relocker rlk(lock); + for (continuations_type::iterator it = the_continuations.begin(); it != the_continuations.end(); ++it) { + (*it)->launch_continuation(); + } + } + } +#else + void do_continuation(boost::unique_lock&) + { + } +#endif + +#else +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION +#define BOOST_THREAD_DO_CONTINUATION \ + void do_continuation(boost::unique_lock& lock) \ + { \ + if (! this->continuations.empty()) { \ + continuations_type the_continuations = this->continuations; \ + this->continuations.clear(); \ + relocker rlk(lock); \ + for (continuations_type::iterator it = the_continuations.begin(); it != the_continuations.end(); ++it) { \ + (*it)->launch_continuation(); \ + } \ + } \ + } +#else +#define BOOST_THREAD_DO_CONTINUATION \ + void do_continuation(boost::unique_lock&) \ + { \ + } +#endif + + virtual void do_continuation(boost::unique_lock&) = 0; +#endif + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + virtual void set_continuation_ptr(continuation_ptr_type continuation, boost::unique_lock& lock) + { + continuations.push_back(continuation); + if (done) { + do_continuation(lock); + } + } +#endif + void mark_finished_internal(boost::unique_lock& lock) + { + done=true; + waiters.notify_all(); + for(waiter_list::const_iterator it=external_waiters.begin(), + end=external_waiters.end();it!=end;++it) + { + (*it)->notify_all(); + } + do_continuation(lock); + } + void notify_deferred() + { + boost::unique_lock lock(this->mutex); + mark_finished_internal(lock); + } + + void do_callback(boost::unique_lock& lock) + { + if(callback && !done) + { + boost::function local_callback=callback; + relocker relock(lock); + local_callback(); + } + } + + virtual bool run_if_is_deferred() + { + boost::unique_lock lk(this->mutex); + if (is_deferred_) + { + is_deferred_=false; + execute(lk); + return true; + } + else + return false; + } + virtual bool run_if_is_deferred_or_ready() + { + boost::unique_lock lk(this->mutex); + if (is_deferred_) + { + is_deferred_=false; + execute(lk); + + return true; + } + else + return done; + } + void wait_internal(boost::unique_lock &lk, bool rethrow=true) + { + do_callback(lk); + if (is_deferred_) + { + is_deferred_=false; + execute(lk); + } + waiters.wait(lk, boost::bind(&shared_state_base::is_done, boost::ref(*this))); + if(rethrow && exception) + { + boost::rethrow_exception(exception); + } + } + + virtual void wait(boost::unique_lock& lock, bool rethrow=true) + { + wait_internal(lock, rethrow); + } + + void wait(bool rethrow=true) + { + boost::unique_lock lock(this->mutex); + wait(lock, rethrow); + } + +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_wait(Duration const& rel_time) + { + boost::unique_lock lock(this->mutex); + if (is_deferred_) + return false; + + do_callback(lock); + return waiters.timed_wait(lock, rel_time, boost::bind(&shared_state_base::is_done, boost::ref(*this))); + } + + bool timed_wait_until(boost::system_time const& target_time) + { + boost::unique_lock lock(this->mutex); + if (is_deferred_) + return false; + + do_callback(lock); + return waiters.timed_wait(lock, target_time, boost::bind(&shared_state_base::is_done, boost::ref(*this))); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + + template + future_status + wait_until(const chrono::time_point& abs_time) + { + boost::unique_lock lock(this->mutex); + if (is_deferred_) + return future_status::deferred; + do_callback(lock); + if(!waiters.wait_until(lock, abs_time, boost::bind(&shared_state_base::is_done, boost::ref(*this)))) + { + return future_status::timeout; + } + return future_status::ready; + } +#endif + void mark_exceptional_finish_internal(boost::exception_ptr const& e, boost::unique_lock& lock) + { + exception=e; + mark_finished_internal(lock); + } + + void mark_exceptional_finish() + { + boost::unique_lock lock(this->mutex); + mark_exceptional_finish_internal(boost::current_exception(), lock); + } + + void set_exception_deferred(exception_ptr e) + { + unique_lock lk(this->mutex); + if (has_value(lk)) + { + throw_exception(promise_already_satisfied()); + } + exception=e; + this->is_constructed = true; + } + void set_exception_at_thread_exit(exception_ptr e) + { + set_exception_deferred(e); +// unique_lock lk(this->mutex); +// if (has_value(lk)) +// { +// throw_exception(promise_already_satisfied()); +// } +// exception=e; +// this->is_constructed = true; + detail::make_ready_at_thread_exit(shared_from_this()); + } + + bool has_value() const + { + boost::lock_guard lock(this->mutex); + return done && ! exception; + } + + bool has_value(unique_lock& ) const + { + return done && ! exception; + } + + bool has_exception() const + { + boost::lock_guard lock(this->mutex); + return done && exception; + } + + launch launch_policy(boost::unique_lock&) const + { + return policy_; + } + + future_state::state get_state(boost::unique_lock&) const + { + if(!done) + { + return future_state::waiting; + } + else + { + return future_state::ready; + } + } + future_state::state get_state() const + { + boost::lock_guard guard(this->mutex); + if(!done) + { + return future_state::waiting; + } + else + { + return future_state::ready; + } + } + + exception_ptr get_exception_ptr() + { + boost::unique_lock lock(this->mutex); + wait_internal(lock, false); + return exception; + } + + template + void set_wait_callback(F f,U* u) + { + boost::lock_guard lock(this->mutex); + callback=boost::bind(f,boost::ref(*u)); + } + + virtual void execute(boost::unique_lock&) {} + + private: + shared_state_base(shared_state_base const&); + shared_state_base& operator=(shared_state_base const&); + }; + + // Used to create stand-alone futures + template + struct shared_state: + detail::shared_state_base + { +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + typedef boost::optional storage_type; +#else + typedef boost::csbl::unique_ptr storage_type; +#endif +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + typedef T const& source_reference_type; + typedef BOOST_THREAD_RV_REF(T) rvalue_source_type; + typedef T move_dest_type; +#elif defined BOOST_THREAD_USES_MOVE + typedef typename conditional::value,T,T const&>::type source_reference_type; + typedef BOOST_THREAD_RV_REF(T) rvalue_source_type; + typedef T move_dest_type; +#else + typedef T& source_reference_type; + typedef typename conditional::value, BOOST_THREAD_RV_REF(T),T const&>::type rvalue_source_type; + typedef typename conditional::value, BOOST_THREAD_RV_REF(T),T>::type move_dest_type; +#endif + + typedef const T& shared_future_get_result_type; + + storage_type result; + + shared_state(): + result() + {} + shared_state(exceptional_ptr const& ex): + detail::shared_state_base(ex), result() + {} + + // locating this definition on the template avoid the ODR issue. See https://github.com/boostorg/thread/issues/193 + BOOST_THREAD_DO_CONTINUATION + + void mark_finished_with_result_internal(source_reference_type result_, boost::unique_lock& lock) + { +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + result = result_; +#else + result.reset(new T(result_)); +#endif + this->mark_finished_internal(lock); + } + + void mark_finished_with_result_internal(rvalue_source_type result_, boost::unique_lock& lock) + { +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + result = boost::move(result_); +#elif ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + result.reset(new T(boost::move(result_))); +#else + result.reset(new T(static_cast(result_))); +#endif + this->mark_finished_internal(lock); + } + + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + void mark_finished_with_result_internal(boost::unique_lock& lock, BOOST_THREAD_FWD_REF(Args)... args) + { +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + result.emplace(boost::forward(args)...); +#else + result.reset(new T(boost::forward(args)...)); +#endif + this->mark_finished_internal(lock); + } +#endif + + void mark_finished_with_result(source_reference_type result_) + { + boost::unique_lock lock(this->mutex); + this->mark_finished_with_result_internal(result_, lock); + } + + void mark_finished_with_result(rvalue_source_type result_) + { + boost::unique_lock lock(this->mutex); + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + mark_finished_with_result_internal(boost::move(result_), lock); +#else + mark_finished_with_result_internal(static_cast(result_), lock); +#endif + } + + storage_type& get_storage(boost::unique_lock& lk) + { + wait_internal(lk); + return result; + } + virtual move_dest_type get(boost::unique_lock& lk) + { + return boost::move(*get_storage(lk)); + } + move_dest_type get() + { + boost::unique_lock lk(this->mutex); + return this->get(lk); + } + + virtual shared_future_get_result_type get_sh(boost::unique_lock& lk) + { + return *get_storage(lk); + } + shared_future_get_result_type get_sh() + { + boost::unique_lock lk(this->mutex); + return this->get_sh(lk); + } + void set_value_deferred(source_reference_type result_) + { + unique_lock lk(this->mutex); + if (this->has_value(lk)) + { + throw_exception(promise_already_satisfied()); + } +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + result = result_; +#else + result.reset(new T(result_)); +#endif + + this->is_constructed = true; + } + void set_value_deferred(rvalue_source_type result_) + { + unique_lock lk(this->mutex); + if (this->has_value(lk)) + { + throw_exception(promise_already_satisfied()); + } + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + result = boost::move(result_); +#else + result.reset(new T(boost::move(result_))); +#endif +#else +#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL + result = boost::move(result_); +#else + result.reset(new T(static_cast(result_))); +#endif +#endif + this->is_constructed = true; + } + + void set_value_at_thread_exit(source_reference_type result_) + { + set_value_deferred(result_); +// unique_lock lk(this->mutex); +// if (this->has_value(lk)) +// { +// throw_exception(promise_already_satisfied()); +// } +//#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL +// result = result_; +//#else +// result.reset(new T(result_)); +//#endif +// +// this->is_constructed = true; + detail::make_ready_at_thread_exit(shared_from_this()); + } + void set_value_at_thread_exit(rvalue_source_type result_) + { + set_value_deferred(boost::move(result_)); +// unique_lock lk(this->mutex); +// if (this->has_value(lk)) +// throw_exception(promise_already_satisfied()); +// +//#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES +//#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL +// result = boost::move(result_); +//#else +// result.reset(new T(boost::move(result_))); +//#endif +//#else +//#if defined BOOST_THREAD_FUTURE_USES_OPTIONAL +// result = boost::move(result_); +//#else +// result.reset(new T(static_cast(result_))); +//#endif +//#endif +// this->is_constructed = true; + detail::make_ready_at_thread_exit(shared_from_this()); + } + + private: + shared_state(shared_state const&); + shared_state& operator=(shared_state const&); + }; + + template + struct shared_state: + detail::shared_state_base + { + typedef T* storage_type; + typedef T& source_reference_type; + typedef T& move_dest_type; + typedef T& shared_future_get_result_type; + + T* result; + + shared_state(): + result(0) + {} + + shared_state(exceptional_ptr const& ex): + detail::shared_state_base(ex), result(0) + {} + + // locating this definition on the template avoid the ODR issue. See https://github.com/boostorg/thread/issues/193 + BOOST_THREAD_DO_CONTINUATION + + void mark_finished_with_result_internal(source_reference_type result_, boost::unique_lock& lock) + { + result= &result_; + mark_finished_internal(lock); + } + + void mark_finished_with_result(source_reference_type result_) + { + boost::unique_lock lock(this->mutex); + mark_finished_with_result_internal(result_, lock); + } + + virtual T& get(boost::unique_lock& lock) + { + wait_internal(lock); + return *result; + } + T& get() + { + boost::unique_lock lk(this->mutex); + return get(lk); + } + + virtual T& get_sh(boost::unique_lock& lock) + { + wait_internal(lock); + return *result; + } + T& get_sh() + { + boost::unique_lock lock(this->mutex); + return get_sh(lock); + } + + void set_value_deferred(T& result_) + { + unique_lock lk(this->mutex); + if (this->has_value(lk)) + { + throw_exception(promise_already_satisfied()); + } + result= &result_; + this->is_constructed = true; + } + + void set_value_at_thread_exit(T& result_) + { + set_value_deferred(result_); +// unique_lock lk(this->mutex); +// if (this->has_value(lk)) +// throw_exception(promise_already_satisfied()); +// result= &result_; +// this->is_constructed = true; + detail::make_ready_at_thread_exit(shared_from_this()); + } + + private: + shared_state(shared_state const&); + shared_state& operator=(shared_state const&); + }; + + template<> + struct shared_state: + detail::shared_state_base + { + typedef void shared_future_get_result_type; + typedef void move_dest_type; + + shared_state() + {} + + shared_state(exceptional_ptr const& ex): + detail::shared_state_base(ex) + {} + + // locating this definition on the template avoid the ODR issue. See https://github.com/boostorg/thread/issues/193 + BOOST_THREAD_DO_CONTINUATION + + void mark_finished_with_result_internal(boost::unique_lock& lock) + { + mark_finished_internal(lock); + } + + void mark_finished_with_result() + { + boost::unique_lock lock(this->mutex); + mark_finished_with_result_internal(lock); + } + + virtual void get(boost::unique_lock& lock) + { + this->wait_internal(lock); + } + void get() + { + boost::unique_lock lock(this->mutex); + this->get(lock); + } + + virtual void get_sh(boost::unique_lock& lock) + { + this->wait_internal(lock); + } + void get_sh() + { + boost::unique_lock lock(this->mutex); + this->get_sh(lock); + } + + void set_value_deferred() + { + unique_lock lk(this->mutex); + if (this->has_value(lk)) + { + throw_exception(promise_already_satisfied()); + } + this->is_constructed = true; + } + void set_value_at_thread_exit() + { + set_value_deferred(); +// unique_lock lk(this->mutex); +// if (this->has_value(lk)) +// { +// throw_exception(promise_already_satisfied()); +// } +// this->is_constructed = true; + detail::make_ready_at_thread_exit(shared_from_this()); + } + private: + shared_state(shared_state const&); + shared_state& operator=(shared_state const&); + }; + + ///////////////////////// + /// future_async_shared_state_base + ///////////////////////// + template + struct future_async_shared_state_base: shared_state + { + typedef shared_state base_type; + protected: +#ifdef BOOST_THREAD_FUTURE_BLOCKING + boost::thread thr_; + void join() + { + if (this_thread::get_id() == thr_.get_id()) + { + thr_.detach(); + return; + } + if (thr_.joinable()) thr_.join(); + } +#endif + public: + future_async_shared_state_base() + { + this->set_async(); + } + + ~future_async_shared_state_base() + { +#ifdef BOOST_THREAD_FUTURE_BLOCKING + join(); +#elif defined BOOST_THREAD_ASYNC_FUTURE_WAITS + unique_lock lk(this->mutex); + this->waiters.wait(lk, boost::bind(&shared_state_base::is_done, boost::ref(*this))); +#endif + } + + virtual void wait(boost::unique_lock& lk, bool rethrow) + { +#ifdef BOOST_THREAD_FUTURE_BLOCKING + { + relocker rlk(lk); + join(); + } +#endif + this->base_type::wait(lk, rethrow); + } + }; + + ///////////////////////// + /// future_async_shared_state + ///////////////////////// + template + struct future_async_shared_state: future_async_shared_state_base + { + future_async_shared_state() + { + } + + void init(BOOST_THREAD_FWD_REF(Fp) f) + { +#ifdef BOOST_THREAD_FUTURE_BLOCKING + this->thr_ = boost::thread(&future_async_shared_state::run, static_shared_from_this(this), boost::forward(f)); +#else + boost::thread(&future_async_shared_state::run, static_shared_from_this(this), boost::forward(f)).detach(); +#endif + } + + static void run(shared_ptr that, BOOST_THREAD_FWD_REF(Fp) f) + { + try + { + that->mark_finished_with_result(f()); + } + catch(...) + { + that->mark_exceptional_finish(); + } + } + }; + + template + struct future_async_shared_state: public future_async_shared_state_base + { + void init(BOOST_THREAD_FWD_REF(Fp) f) + { +#ifdef BOOST_THREAD_FUTURE_BLOCKING + this->thr_ = boost::thread(&future_async_shared_state::run, static_shared_from_this(this), boost::move(f)); +#else + boost::thread(&future_async_shared_state::run, static_shared_from_this(this), boost::move(f)).detach(); +#endif + } + + static void run(shared_ptr that, BOOST_THREAD_FWD_REF(Fp) f) + { + try + { + f(); + that->mark_finished_with_result(); + } + catch(...) + { + that->mark_exceptional_finish(); + } + } + }; + + template + struct future_async_shared_state: future_async_shared_state_base + { + void init(BOOST_THREAD_FWD_REF(Fp) f) + { +#ifdef BOOST_THREAD_FUTURE_BLOCKING + this->thr_ = boost::thread(&future_async_shared_state::run, static_shared_from_this(this), boost::move(f)); +#else + boost::thread(&future_async_shared_state::run, static_shared_from_this(this), boost::move(f)).detach(); +#endif + } + + static void run(shared_ptr that, BOOST_THREAD_FWD_REF(Fp) f) + { + try + { + that->mark_finished_with_result(f()); + } + catch(...) + { + that->mark_exceptional_finish(); + } + } + }; + + ////////////////////////// + /// future_deferred_shared_state + ////////////////////////// + template + struct future_deferred_shared_state: shared_state + { + Fp func_; + + explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f) + : func_(boost::move(f)) + { + this->set_deferred(); + } + + virtual void execute(boost::unique_lock& lck) { + try + { + Fp local_fuct=boost::move(func_); + relocker relock(lck); + Rp res = local_fuct(); + relock.lock(); + this->mark_finished_with_result_internal(boost::move(res), lck); + } + catch (...) + { + this->mark_exceptional_finish_internal(current_exception(), lck); + } + } + }; + template + struct future_deferred_shared_state: shared_state + { + Fp func_; + + explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f) + : func_(boost::move(f)) + { + this->set_deferred(); + } + + virtual void execute(boost::unique_lock& lck) { + try + { + this->mark_finished_with_result_internal(func_(), lck); + } + catch (...) + { + this->mark_exceptional_finish_internal(current_exception(), lck); + } + } + }; + + template + struct future_deferred_shared_state: shared_state + { + Fp func_; + + explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f) + : func_(boost::move(f)) + { + this->set_deferred(); + } + + virtual void execute(boost::unique_lock& lck) { + try + { + Fp local_fuct=boost::move(func_); + relocker relock(lck); + local_fuct(); + relock.lock(); + this->mark_finished_with_result_internal(lck); + } + catch (...) + { + this->mark_exceptional_finish_internal(current_exception(), lck); + } + } + }; + + class future_waiter + { + public: + typedef std::vector::size_type count_type; + private: + struct registered_waiter + { + boost::shared_ptr future_; + detail::shared_state_base::notify_when_ready_handle handle; + count_type index; + + registered_waiter(boost::shared_ptr const& a_future, + detail::shared_state_base::notify_when_ready_handle handle_, + count_type index_): + future_(a_future),handle(handle_),index(index_) + {} + }; + + struct all_futures_lock + { +#ifdef _MANAGED + typedef std::ptrdiff_t count_type_portable; +#else + typedef count_type count_type_portable; +#endif + count_type_portable count; + boost::scoped_array > locks; + + all_futures_lock(std::vector& futures): + count(futures.size()),locks(new boost::unique_lock[count]) + { + for(count_type_portable i=0;i(futures[i].future_->mutex)); + } + } + + void lock() + { + boost::lock(locks.get(),locks.get()+count); + } + + void unlock() + { + for(count_type_portable i=0;i futures_; + count_type future_count; + + public: + future_waiter(): + future_count(0) + {} + + template + void add(F& f) + { + if(f.future_) + { + registered_waiter waiter(f.future_,f.future_->notify_when_ready(cv),future_count); + try { + futures_.push_back(waiter); + } catch(...) { + f.future_->unnotify_when_ready(waiter.handle); + throw; + } + } + ++future_count; + } + +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + template + void add(F1& f1, Fs&... fs) + { + add(f1); add(fs...); + } +#endif + + count_type wait() + { + all_futures_lock lk(futures_); + for(;;) + { + for(count_type i=0;idone) + { + return futures_[i].index; + } + } + cv.wait(lk); + } + } + + ~future_waiter() + { + for(count_type i=0;iunnotify_when_ready(futures_[i].handle); + } + } + }; + + } + + template + class BOOST_THREAD_FUTURE; + + template + class shared_future; + + template + struct is_future_type > : true_type + { + }; + + template + struct is_future_type > : true_type + { + }; + +// template +// typename boost::disable_if,Iterator>::type wait_for_any(Iterator begin,Iterator end) +// { +// if(begin==end) +// return end; +// +// detail::future_waiter waiter; +// for(Iterator current=begin;current!=end;++current) +// { +// waiter.add(*current); +// } +// return boost::next(begin,waiter.wait()); +// } + +#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES + template + typename boost::enable_if,typename detail::future_waiter::count_type>::type wait_for_any(F1& f1,F2& f2) + { + detail::future_waiter waiter; + waiter.add(f1); + waiter.add(f2); + return waiter.wait(); + } + + template + typename detail::future_waiter::count_type wait_for_any(F1& f1,F2& f2,F3& f3) + { + detail::future_waiter waiter; + waiter.add(f1); + waiter.add(f2); + waiter.add(f3); + return waiter.wait(); + } + + template + typename detail::future_waiter::count_type wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4) + { + detail::future_waiter waiter; + waiter.add(f1); + waiter.add(f2); + waiter.add(f3); + waiter.add(f4); + return waiter.wait(); + } + + template + typename detail::future_waiter::count_type wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5) + { + detail::future_waiter waiter; + waiter.add(f1); + waiter.add(f2); + waiter.add(f3); + waiter.add(f4); + waiter.add(f5); + return waiter.wait(); + } +#else + template + typename boost::enable_if, typename detail::future_waiter::count_type>::type + wait_for_any(F1& f1, Fs&... fs) + { + detail::future_waiter waiter; + waiter.add(f1, fs...); + return waiter.wait(); + } +#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + class promise; + + template + class packaged_task; + + namespace detail + { + /// Common implementation for all the futures independently of the return type + class base_future + { + public: + }; + /// Common implementation for future and shared_future. + template + class basic_future : public base_future + { + protected: + public: + + typedef boost::shared_ptr > future_ptr; + typedef typename detail::shared_state::move_dest_type move_dest_type; + + static //BOOST_CONSTEXPR + future_ptr make_exceptional_future_ptr(exceptional_ptr const& ex) { + return future_ptr(new detail::shared_state(ex)); + } + + future_ptr future_; + + basic_future(future_ptr a_future): + future_(a_future) + { + } + + public: + typedef future_state::state state; + + BOOST_THREAD_MOVABLE_ONLY(basic_future) + basic_future(): future_() {} + + + //BOOST_CONSTEXPR + basic_future(exceptional_ptr const& ex) + : future_(make_exceptional_future_ptr(ex)) + { + } + + ~basic_future() { + } + + basic_future(BOOST_THREAD_RV_REF(basic_future) other) BOOST_NOEXCEPT: + future_(BOOST_THREAD_RV(other).future_) + { + BOOST_THREAD_RV(other).future_.reset(); + } + basic_future& operator=(BOOST_THREAD_RV_REF(basic_future) other) BOOST_NOEXCEPT + { + future_=BOOST_THREAD_RV(other).future_; + BOOST_THREAD_RV(other).future_.reset(); + return *this; + } + void swap(basic_future& that) BOOST_NOEXCEPT + { + future_.swap(that.future_); + } + // functions to check state, and wait for ready + state get_state(boost::unique_lock& lk) const + { + if(!future_) + { + return future_state::uninitialized; + } + return future_->get_state(lk); + } + state get_state() const + { + if(!future_) + { + return future_state::uninitialized; + } + return future_->get_state(); + } + + bool is_ready() const + { + return get_state()==future_state::ready; + } + + bool is_ready(boost::unique_lock& lk) const + { + return get_state(lk)==future_state::ready; + } + bool has_exception() const + { + return future_ && future_->has_exception(); + } + + bool has_value() const + { + return future_ && future_->has_value(); + } + + launch launch_policy(boost::unique_lock& lk) const + { + if ( future_ ) return future_->launch_policy(lk); + else return launch(launch::none); + } + + launch launch_policy() const + { + if ( future_ ) { + boost::unique_lock lk(this->future_->mutex); + return future_->launch_policy(lk); + } + else return launch(launch::none); + } + + exception_ptr get_exception_ptr() + { + return future_ + ? future_->get_exception_ptr() + : exception_ptr(); + } + + bool valid() const BOOST_NOEXCEPT + { + return future_.get() != 0 && future_->valid(); + } + + void wait() const + { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + future_->wait(false); + } + + typedef detail::shared_state_base::notify_when_ready_handle notify_when_ready_handle; + + boost::mutex& mutex() { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->mutex; + } + + notify_when_ready_handle notify_when_ready(boost::condition_variable_any& cv) + { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->notify_when_ready(cv); + } + + void unnotify_when_ready(notify_when_ready_handle h) + { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->unnotify_when_ready(h); + } + +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_wait(Duration const& rel_time) const + { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->timed_wait(rel_time); + } + + bool timed_wait_until(boost::system_time const& abs_time) const + { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->timed_wait_until(abs_time); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + future_status + wait_for(const chrono::duration& rel_time) const + { + return wait_until(chrono::steady_clock::now() + rel_time); + + } + template + future_status + wait_until(const chrono::time_point& abs_time) const + { + if(!future_) + { + boost::throw_exception(future_uninitialized()); + } + return future_->wait_until(abs_time); + } +#endif + + }; + + } // detail + BOOST_THREAD_DCL_MOVABLE_BEG(R) detail::basic_future BOOST_THREAD_DCL_MOVABLE_END + + namespace detail + { +#if (!defined _MSC_VER || _MSC_VER >= 1400) // _MSC_VER == 1400 on MSVC 2005 + template + BOOST_THREAD_FUTURE + make_future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f); + + template + BOOST_THREAD_FUTURE + make_future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f); +#endif // #if (!defined _MSC_VER || _MSC_VER >= 1400) +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template + struct future_deferred_continuation_shared_state; + template + struct future_async_continuation_shared_state; + + template + BOOST_THREAD_FUTURE + make_future_async_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + BOOST_THREAD_FUTURE + make_future_sync_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + BOOST_THREAD_FUTURE + make_future_deferred_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + BOOST_THREAD_FUTURE + make_shared_future_deferred_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + BOOST_THREAD_FUTURE + make_shared_future_async_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + BOOST_THREAD_FUTURE + make_shared_future_sync_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + + #ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template + BOOST_THREAD_FUTURE + make_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + BOOST_THREAD_FUTURE + make_shared_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + BOOST_THREAD_FUTURE + make_future_executor_shared_state(Executor& ex, BOOST_THREAD_FWD_REF(Fp) f); + #endif +#endif +#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP + template + struct future_unwrap_shared_state; + template + inline BOOST_THREAD_FUTURE + make_future_unwrap_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f); +#endif + } +#if defined(BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY) + template< typename InputIterator> + typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_all(InputIterator first, InputIterator last); + + inline BOOST_THREAD_FUTURE > when_all(); + + #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_all(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures); + #endif + + template< typename InputIterator> + typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_any(InputIterator first, InputIterator last); + + inline BOOST_THREAD_FUTURE > when_any(); + + #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_any(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures); + #endif +#endif // BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY + + + template + class BOOST_THREAD_FUTURE : public detail::basic_future + { + private: + typedef detail::basic_future base_type; + typedef typename base_type::future_ptr future_ptr; + + friend class shared_future; + friend class promise; +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template + friend struct detail::future_async_continuation_shared_state; + template + friend struct detail::future_deferred_continuation_shared_state; + + template + friend BOOST_THREAD_FUTURE + detail::make_future_async_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_future_sync_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_future_deferred_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_deferred_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_async_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_sync_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + #ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template + friend BOOST_THREAD_FUTURE + detail::make_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_future_executor_shared_state(Executor& ex, BOOST_THREAD_FWD_REF(Fp) f); + #endif +#endif +#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP + template + friend struct detail::future_unwrap_shared_state; + template + friend BOOST_THREAD_FUTURE + detail::make_future_unwrap_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f); +#endif +#if defined(BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY) + template< typename InputIterator> + friend typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_all(InputIterator first, InputIterator last); + + //friend inline BOOST_THREAD_FUTURE > when_all(); + + #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + friend BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_all(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures); + #endif + + template< typename InputIterator> + friend typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_any(InputIterator first, InputIterator last); + + //friend inline BOOST_THREAD_FUTURE > when_any(); + + #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + friend BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_any(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures); + #endif +#endif // BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template friend class packaged_task; // todo check if this works in windows +#else + friend class packaged_task; +#endif + friend class detail::future_waiter; + + template + friend BOOST_THREAD_FUTURE + detail::make_future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f); + + template + friend BOOST_THREAD_FUTURE + detail::make_future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f); + + typedef typename base_type::move_dest_type move_dest_type; + + BOOST_THREAD_FUTURE(future_ptr a_future): + base_type(a_future) + { + } + + public: + BOOST_THREAD_MOVABLE_ONLY(BOOST_THREAD_FUTURE) + typedef future_state::state state; + typedef R value_type; // EXTENSION + + BOOST_CONSTEXPR BOOST_THREAD_FUTURE() {} + //BOOST_CONSTEXPR + BOOST_THREAD_FUTURE(exceptional_ptr const& ex): + base_type(ex) {} + + ~BOOST_THREAD_FUTURE() { + } + + BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT: + base_type(boost::move(static_cast(BOOST_THREAD_RV(other)))) + { + } +#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP + inline explicit BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE >) other); // EXTENSION +#endif + + explicit BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(shared_future) other) : + base_type(boost::move(static_cast(BOOST_THREAD_RV(other)))) + {} + + BOOST_THREAD_FUTURE& operator=(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT + { + this->base_type::operator=(boost::move(static_cast(BOOST_THREAD_RV(other)))); + return *this; + } + + shared_future share() + { + return shared_future(::boost::move(*this)); + } + + void swap(BOOST_THREAD_FUTURE& other) + { + static_cast(this)->swap(other); + } + + // todo this function must be private and friendship provided to the internal users. + void set_async() + { + this->future_->set_async(); + } + // todo this function must be private and friendship provided to the internal users. + void set_deferred() + { + this->future_->set_deferred(); + } + bool run_if_is_deferred() { + return this->future_->run_if_is_deferred(); + } + bool run_if_is_deferred_or_ready() { + return this->future_->run_if_is_deferred_or_ready(); + } + // retrieving the value + move_dest_type get() + { + if (this->future_.get() == 0) + { + boost::throw_exception(future_uninitialized()); + } + unique_lock lk(this->future_->mutex); + if (! this->future_->valid(lk)) + { + boost::throw_exception(future_uninitialized()); + } +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + this->future_->invalidate(lk); +#endif + return this->future_->get(lk); + } + + template + typename boost::disable_if< is_void, move_dest_type>::type + get_or(BOOST_THREAD_RV_REF(R2) v) + { + + if (this->future_.get() == 0) + { + boost::throw_exception(future_uninitialized()); + } + unique_lock lk(this->future_->mutex); + if (! this->future_->valid(lk)) + { + boost::throw_exception(future_uninitialized()); + } + this->future_->wait(lk, false); +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + this->future_->invalidate(lk); +#endif + + if (this->future_->has_value(lk)) { + return this->future_->get(lk); + } + else { + return boost::move(v); + } + } + + template + typename boost::disable_if< is_void, move_dest_type>::type + get_or(R2 const& v) // EXTENSION + { + if (this->future_.get() == 0) + { + boost::throw_exception(future_uninitialized()); + } + unique_lock lk(this->future_->mutex); + if (! this->future_->valid(lk)) + { + boost::throw_exception(future_uninitialized()); + } + this->future_->wait(lk, false); +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + this->future_->invalidate(lk); +#endif + if (this->future_->has_value(lk)) { + return this->future_->get(lk); + } + else { + return v; + } + } + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template + inline BOOST_THREAD_FUTURE::type> + then(BOOST_THREAD_FWD_REF(F) func); // EXTENSION + template + inline BOOST_THREAD_FUTURE::type> + then(launch policy, BOOST_THREAD_FWD_REF(F) func); // EXTENSION + #ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template + inline BOOST_THREAD_FUTURE::type> + then(Ex& ex, BOOST_THREAD_FWD_REF(F) func); // EXTENSION + #endif + + template + inline typename boost::disable_if< is_void, BOOST_THREAD_FUTURE >::type + fallback_to(BOOST_THREAD_RV_REF(R2) v); // EXTENSION + template + inline typename boost::disable_if< is_void, BOOST_THREAD_FUTURE >::type + fallback_to(R2 const& v); // EXTENSION + +#endif + + }; + + BOOST_THREAD_DCL_MOVABLE_BEG(T) BOOST_THREAD_FUTURE BOOST_THREAD_DCL_MOVABLE_END + + template + class BOOST_THREAD_FUTURE > : public detail::basic_future > + { + typedef BOOST_THREAD_FUTURE R; + + private: + typedef detail::basic_future base_type; + typedef typename base_type::future_ptr future_ptr; + + friend class shared_future; + friend class promise; +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template + friend struct detail::future_async_continuation_shared_state; + template + friend struct detail::future_deferred_continuation_shared_state; + + template + friend BOOST_THREAD_FUTURE + detail::make_future_async_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_future_sync_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_future_deferred_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_deferred_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_async_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_sync_continuation_shared_state(boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + #ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template + friend BOOST_THREAD_FUTURE + detail::make_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_shared_future_executor_continuation_shared_state(Ex& ex, boost::unique_lock &lock, F f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_future_executor_shared_state(Executor& ex, BOOST_THREAD_FWD_REF(Fp) f); + #endif + +#endif +#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP + template + friend struct detail::future_unwrap_shared_state; + template + friend BOOST_THREAD_FUTURE + detail::make_future_unwrap_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f); +#endif +#if defined(BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY) + template< typename InputIterator> + friend typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_all(InputIterator first, InputIterator last); + + friend inline BOOST_THREAD_FUTURE > when_all(); + + #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + friend BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_all(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures); + #endif + + template< typename InputIterator> + friend typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_any(InputIterator first, InputIterator last); + + friend inline BOOST_THREAD_FUTURE > when_any(); + + #if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + friend BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_any(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures); + #endif +#endif // BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY + + #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template friend class packaged_task; // todo check if this works in windows + #else + friend class packaged_task; + #endif + friend class detail::future_waiter; + + template + friend BOOST_THREAD_FUTURE + detail::make_future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f); + + template + friend BOOST_THREAD_FUTURE + detail::make_future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f); + + typedef typename base_type::move_dest_type move_dest_type; + + BOOST_THREAD_FUTURE(future_ptr a_future): + base_type(a_future) + { + } + public: + + BOOST_THREAD_MOVABLE_ONLY(BOOST_THREAD_FUTURE) + typedef future_state::state state; + typedef R value_type; // EXTENSION + + BOOST_CONSTEXPR BOOST_THREAD_FUTURE() {} + //BOOST_CONSTEXPR + BOOST_THREAD_FUTURE(exceptional_ptr const& ex): + base_type(ex) {} + + ~BOOST_THREAD_FUTURE() { + } + + BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT: + base_type(boost::move(static_cast(BOOST_THREAD_RV(other)))) + { + } + + BOOST_THREAD_FUTURE& operator=(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT + { + this->base_type::operator=(boost::move(static_cast(BOOST_THREAD_RV(other)))); + return *this; + } + + shared_future share() + { + return shared_future(::boost::move(*this)); + } + + void swap(BOOST_THREAD_FUTURE& other) + { + static_cast(this)->swap(other); + } + + // todo this function must be private and friendship provided to the internal users. + void set_async() + { + this->future_->set_async(); + } + // todo this function must be private and friendship provided to the internal users. + void set_deferred() + { + this->future_->set_deferred(); + } + bool run_if_is_deferred() { + return this->future_->run_if_is_deferred(); + } + bool run_if_is_deferred_or_ready() { + return this->future_->run_if_is_deferred_or_ready(); + } + // retrieving the value + move_dest_type get() + { + if (this->future_.get() == 0) + { + boost::throw_exception(future_uninitialized()); + } + unique_lock lk(this->future_->mutex); + if (! this->future_->valid(lk)) + { + boost::throw_exception(future_uninitialized()); + } + #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + this->future_->invalidate(lk); + #endif + return this->future_->get(lk); + } + move_dest_type get_or(BOOST_THREAD_RV_REF(R) v) // EXTENSION + { + if (this->future_.get() == 0) + { + boost::throw_exception(future_uninitialized()); + } + unique_lock lk(this->future_->mutex); + if (! this->future_->valid(lk)) + { + boost::throw_exception(future_uninitialized()); + } + this->future_->wait(lk, false); + #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + this->future_->invalidate(lk); + #endif + if (this->future_->has_value(lk)) return this->future_->get(lk); + else return boost::move(v); + } + + move_dest_type get_or(R const& v) // EXTENSION + { + if (this->future_.get() == 0) + { + boost::throw_exception(future_uninitialized()); + } + unique_lock lk(this->future_->mutex); + if (! this->future_->valid(lk)) + { + boost::throw_exception(future_uninitialized()); + } + this->future_->wait(lk, false); + #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + this->future_->invalidate(lk); + #endif + if (this->future_->has_value(lk)) return this->future_->get(lk); + else return v; + } + + + #if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template + inline BOOST_THREAD_FUTURE::type> + then(BOOST_THREAD_FWD_REF(F) func); // EXTENSION + template + inline BOOST_THREAD_FUTURE::type> + then(launch policy, BOOST_THREAD_FWD_REF(F) func); // EXTENSION + #ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template + inline BOOST_THREAD_FUTURE::type> + then(Ex &ex, BOOST_THREAD_FWD_REF(F) func); // EXTENSION + #endif + #endif + + #if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP + inline + BOOST_THREAD_FUTURE + unwrap(); // EXTENSION + #endif + + }; + + template + class shared_future : public detail::basic_future + { + typedef detail::basic_future base_type; + typedef typename base_type::future_ptr future_ptr; + + friend class detail::future_waiter; + friend class promise; + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template + friend struct detail::future_async_continuation_shared_state; + template + friend struct detail::future_deferred_continuation_shared_state; + + template + friend BOOST_THREAD_FUTURE + detail::make_future_async_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_future_sync_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); + + template + friend BOOST_THREAD_FUTURE + detail::make_future_deferred_continuation_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c); +#endif +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template friend class packaged_task;// todo check if this works in windows +#else + friend class packaged_task; +#endif + shared_future(future_ptr a_future): + base_type(a_future) + {} + + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(shared_future) + typedef R value_type; // EXTENSION + + shared_future(shared_future const& other): + base_type(other.future_) + {} + + typedef future_state::state state; + + BOOST_CONSTEXPR shared_future() + {} + //BOOST_CONSTEXPR + shared_future(exceptional_ptr const& ex): + base_type(ex) {} + ~shared_future() + {} + + shared_future& operator=(BOOST_THREAD_COPY_ASSIGN_REF(shared_future) other) + { + this->future_ = other.future_; + return *this; + } + + shared_future(BOOST_THREAD_RV_REF(shared_future) other) BOOST_NOEXCEPT : + base_type(boost::move(static_cast(BOOST_THREAD_RV(other)))) + { + } + shared_future(BOOST_THREAD_RV_REF( BOOST_THREAD_FUTURE ) other) BOOST_NOEXCEPT : + base_type(boost::move(static_cast(BOOST_THREAD_RV(other)))) + { + } + + shared_future& operator=(BOOST_THREAD_RV_REF(shared_future) other) BOOST_NOEXCEPT + { + base_type::operator=(boost::move(static_cast(BOOST_THREAD_RV(other)))); + return *this; + } + shared_future& operator=(BOOST_THREAD_RV_REF( BOOST_THREAD_FUTURE ) other) BOOST_NOEXCEPT + { + base_type::operator=(boost::move(static_cast(BOOST_THREAD_RV(other)))); + return *this; + } + + void swap(shared_future& other) BOOST_NOEXCEPT + { + static_cast(this)->swap(other); + } + bool run_if_is_deferred() { + return this->future_->run_if_is_deferred(); + } + bool run_if_is_deferred_or_ready() { + return this->future_->run_if_is_deferred_or_ready(); + } + // retrieving the value + typename detail::shared_state::shared_future_get_result_type get() const + { + if(!this->future_) + { + boost::throw_exception(future_uninitialized()); + } + return this->future_->get_sh(); + } + + template + typename boost::disable_if< is_void, typename detail::shared_state::shared_future_get_result_type>::type + get_or(BOOST_THREAD_RV_REF(R2) v) const // EXTENSION + { + if(!this->future_) + { + boost::throw_exception(future_uninitialized()); + } + this->future_->wait(); + if (this->future_->has_value()) return this->future_->get_sh(); + else return boost::move(v); + } + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template + inline BOOST_THREAD_FUTURE::type> + then(BOOST_THREAD_FWD_REF(F) func) const; // EXTENSION + template + inline BOOST_THREAD_FUTURE::type> + then(launch policy, BOOST_THREAD_FWD_REF(F) func) const; // EXTENSION + #ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template + inline BOOST_THREAD_FUTURE::type> + then(Ex& ex, BOOST_THREAD_FWD_REF(F) func) const; // EXTENSION + #endif +#endif + + }; + + BOOST_THREAD_DCL_MOVABLE_BEG(T) shared_future BOOST_THREAD_DCL_MOVABLE_END + + template + class promise + { + typedef boost::shared_ptr > future_ptr; + + typedef typename detail::shared_state::source_reference_type source_reference_type; + typedef typename detail::shared_state::rvalue_source_type rvalue_source_type; + typedef typename detail::shared_state::move_dest_type move_dest_type; + typedef typename detail::shared_state::shared_future_get_result_type shared_future_get_result_type; + + future_ptr future_; + bool future_obtained; + + void lazy_init() + { +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY +#include + if(!atomic_load(&future_)) + { + future_ptr blank; + atomic_compare_exchange(&future_,&blank,future_ptr(new detail::shared_state)); + } +#include +#endif + } + + public: + BOOST_THREAD_MOVABLE_ONLY(promise) +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + template + promise(boost::allocator_arg_t, Allocator a) + { + typedef typename Allocator::template rebind >::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor D; + + future_ = future_ptr(::new(a2.allocate(1)) detail::shared_state(), D(a2, 1) ); + future_obtained = false; + } +#endif + promise(): +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY + future_(), +#else + future_(new detail::shared_state()), +#endif + future_obtained(false) + {} + + ~promise() + { + if(future_) + { + boost::unique_lock lock(future_->mutex); + + if(!future_->done && !future_->is_constructed) + { + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock); + } + } + } + + // Assignment + promise(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT : + future_(BOOST_THREAD_RV(rhs).future_),future_obtained(BOOST_THREAD_RV(rhs).future_obtained) + { + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; + } + promise & operator=(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT + { + future_=BOOST_THREAD_RV(rhs).future_; + future_obtained=BOOST_THREAD_RV(rhs).future_obtained; + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; + return *this; + } + + void swap(promise& other) + { + future_.swap(other.future_); + std::swap(future_obtained,other.future_obtained); + } + +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + void set_executor(executor_ptr_type aex) + { + lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + boost::lock_guard lk(future_->mutex); + future_->set_executor_policy(aex, lk); + } +#endif + // Result retrieval + BOOST_THREAD_FUTURE get_future() + { + lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + if (future_obtained) + { + boost::throw_exception(future_already_retrieved()); + } + future_obtained=true; + return BOOST_THREAD_FUTURE(future_); + } + +#if defined BOOST_NO_CXX11_RVALUE_REFERENCES + template + typename boost::enable_if_c::value && is_same::value, void>::type + set_value(TR const & r) + { + lazy_init(); + boost::unique_lock lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_finished_with_result_internal(r, lock); + } +#else + void set_value(source_reference_type r) + { + lazy_init(); + boost::unique_lock lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_finished_with_result_internal(r, lock); + } +#endif + + void set_value(rvalue_source_type r) + { + lazy_init(); + boost::unique_lock lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + future_->mark_finished_with_result_internal(boost::move(r), lock); +#else + future_->mark_finished_with_result_internal(static_cast(r), lock); +#endif + } + +#if defined BOOST_NO_CXX11_RVALUE_REFERENCES + template + typename boost::enable_if_c::value && is_same::value, void>::type + set_value_deferred(TR const & r) + { + lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_deferred(r); + } +#else + void set_value_deferred(source_reference_type r) + { + lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_deferred(r); + } +#endif + + void set_value_deferred(rvalue_source_type r) + { + lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + future_->set_value_deferred(boost::move(r)); +#else + future_->set_value_deferred(static_cast(r)); +#endif + } + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + void emplace(BOOST_THREAD_FWD_REF(Args) ...args) + { + lazy_init(); + boost::unique_lock lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_finished_with_result_internal(lock, boost::forward(args)...); + } + +#endif + + void set_exception(boost::exception_ptr p) + { + lazy_init(); + boost::unique_lock lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_exceptional_finish_internal(p, lock); + } + template + void set_exception(E ex) + { + set_exception(boost::copy_exception(ex)); + } + void set_exception_deferred(boost::exception_ptr p) + { + lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_deferred(p); + } + template + void set_exception_deferred(E ex) + { + set_exception_deferred(boost::copy_exception(ex)); + } + + // setting the result with deferred notification +#if defined BOOST_NO_CXX11_RVALUE_REFERENCES + template + typename boost::enable_if_c::value && is_same::value, void>::type set_value_at_thread_exit(TR const& r) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(r); + } +#else + void set_value_at_thread_exit(source_reference_type r) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(r); + } +#endif + void set_value_at_thread_exit(BOOST_THREAD_RV_REF(R) r) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(boost::move(r)); + } + void set_exception_at_thread_exit(exception_ptr e) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_at_thread_exit(e); + } + template + void set_exception_at_thread_exit(E ex) + { + set_exception_at_thread_exit(boost::copy_exception(ex)); + } + + template + void set_wait_callback(F f) + { + lazy_init(); + future_->set_wait_callback(f,this); + } + void notify_deferred() + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->notify_deferred(); + } + + }; + + template + class promise + { + typedef boost::shared_ptr > future_ptr; + + future_ptr future_; + bool future_obtained; + + void lazy_init() + { +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY +#include + if(!atomic_load(&future_)) + { + future_ptr blank; + atomic_compare_exchange(&future_,&blank,future_ptr(new detail::shared_state)); + } +#include +#endif + } + + public: + BOOST_THREAD_MOVABLE_ONLY(promise) +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + template + promise(boost::allocator_arg_t, Allocator a) + { + typedef typename Allocator::template rebind >::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor D; + + future_ = future_ptr(::new(a2.allocate(1)) detail::shared_state(), D(a2, 1) ); + future_obtained = false; + } +#endif + promise(): +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY + future_(), +#else + future_(new detail::shared_state()), +#endif + future_obtained(false) + {} + + ~promise() + { + if(future_) + { + boost::unique_lock lock(future_->mutex); + + if(!future_->done && !future_->is_constructed) + { + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock); + } + } + } + + // Assignment + promise(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT : + future_(BOOST_THREAD_RV(rhs).future_),future_obtained(BOOST_THREAD_RV(rhs).future_obtained) + { + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; + } + promise & operator=(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT + { + future_=BOOST_THREAD_RV(rhs).future_; + future_obtained=BOOST_THREAD_RV(rhs).future_obtained; + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; + return *this; + } + + void swap(promise& other) + { + future_.swap(other.future_); + std::swap(future_obtained,other.future_obtained); + } + + // Result retrieval + BOOST_THREAD_FUTURE get_future() + { + lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + if (future_obtained) + { + boost::throw_exception(future_already_retrieved()); + } + future_obtained=true; + return BOOST_THREAD_FUTURE(future_); + } + + void set_value(R& r) + { + lazy_init(); + boost::unique_lock lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_finished_with_result_internal(r, lock); + } + void set_value_deferred(R& r) + { + lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->set_value_deferred(r); + } + void set_exception(boost::exception_ptr p) + { + lazy_init(); + boost::unique_lock lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_exceptional_finish_internal(p, lock); + } + template + void set_exception(E ex) + { + set_exception(boost::copy_exception(ex)); + } + void set_exception_deferred(boost::exception_ptr p) + { + lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_deferred(p); + } + template + void set_exception_deferred(E ex) + { + set_exception_deferred(boost::copy_exception(ex)); + } + // setting the result with deferred notification + void set_value_at_thread_exit(R& r) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(r); + } + + void set_exception_at_thread_exit(exception_ptr e) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_at_thread_exit(e); + } + template + void set_exception_at_thread_exit(E ex) + { + set_exception_at_thread_exit(boost::copy_exception(ex)); + } + + template + void set_wait_callback(F f) + { + lazy_init(); + future_->set_wait_callback(f,this); + } + void notify_deferred() + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->notify_deferred(); + } + }; + + template <> + class promise + { + typedef boost::shared_ptr > future_ptr; + + future_ptr future_; + bool future_obtained; + + void lazy_init() + { +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY + if(!atomic_load(&future_)) + { + future_ptr blank; + atomic_compare_exchange(&future_,&blank,future_ptr(new detail::shared_state)); + } +#endif + } + public: + BOOST_THREAD_MOVABLE_ONLY(promise) + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + template + promise(boost::allocator_arg_t, Allocator a) + { + typedef typename Allocator::template rebind >::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor D; + + future_ = future_ptr(::new(a2.allocate(1)) detail::shared_state(), D(a2, 1) ); + future_obtained = false; + } +#endif + promise(): +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY + future_(), +#else + future_(new detail::shared_state), +#endif + future_obtained(false) + {} + + ~promise() + { + if(future_) + { + boost::unique_lock lock(future_->mutex); + + if(!future_->done && !future_->is_constructed) + { + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock); + } + } + } + + // Assignment + promise(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT : + future_(BOOST_THREAD_RV(rhs).future_),future_obtained(BOOST_THREAD_RV(rhs).future_obtained) + { + // we need to release the future as shared_ptr doesn't implements move semantics + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; + } + + promise & operator=(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT + { + future_=BOOST_THREAD_RV(rhs).future_; + future_obtained=BOOST_THREAD_RV(rhs).future_obtained; + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; + return *this; + } + + void swap(promise& other) + { + future_.swap(other.future_); + std::swap(future_obtained,other.future_obtained); + } + + // Result retrieval + BOOST_THREAD_FUTURE get_future() + { + lazy_init(); + + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + if(future_obtained) + { + boost::throw_exception(future_already_retrieved()); + } + future_obtained=true; + //return BOOST_THREAD_MAKE_RV_REF(BOOST_THREAD_FUTURE(future_)); + return BOOST_THREAD_FUTURE(future_); + } + + void set_value() + { + lazy_init(); + boost::unique_lock lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_finished_with_result_internal(lock); + } + void set_value_deferred() + { + lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_deferred(); + } + + void set_exception(boost::exception_ptr p) + { + lazy_init(); + boost::unique_lock lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_exceptional_finish_internal(p,lock); + } + template + void set_exception(E ex) + { + set_exception(boost::copy_exception(ex)); + } + void set_exception_deferred(boost::exception_ptr p) + { + lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_deferred(p); + } + template + void set_exception_deferred(E ex) + { + set_exception_deferred(boost::copy_exception(ex)); + } + // setting the result with deferred notification + void set_value_at_thread_exit() + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(); + } + + void set_exception_at_thread_exit(exception_ptr e) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_at_thread_exit(e); + } + template + void set_exception_at_thread_exit(E ex) + { + set_exception_at_thread_exit(boost::copy_exception(ex)); + } + + template + void set_wait_callback(F f) + { + lazy_init(); + future_->set_wait_callback(f,this); + } + void notify_deferred() + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->notify_deferred(); + } + }; +} +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS +namespace boost { namespace container { + template + struct uses_allocator< ::boost::promise , Alloc> : true_type + { + }; +}} +#if ! defined BOOST_NO_CXX11_ALLOCATOR +namespace std { + template + struct uses_allocator< ::boost::promise , Alloc> : true_type + { + }; +} +#endif +#endif + +namespace boost +{ + + BOOST_THREAD_DCL_MOVABLE_BEG(T) promise BOOST_THREAD_DCL_MOVABLE_END + + namespace detail + { +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template + struct task_base_shared_state; +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + struct task_base_shared_state: +#else + template + struct task_base_shared_state: +#endif +#else + template + struct task_base_shared_state: +#endif + detail::shared_state + { + bool started; + + task_base_shared_state(): + started(false) + {} + + void reset() + { + // todo The packaged_task::reset must be as if an assignemnt froma new packaged_task with the same function + // the reset function is an optimization that avoids reallocating a new task. + started=false; + this->validate(); + } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + virtual void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args)=0; + void run(BOOST_THREAD_RV_REF(ArgTypes) ... args) +#else + virtual void do_run()=0; + void run() +#endif + { + { + boost::lock_guard lk(this->mutex); + if(started) + { + boost::throw_exception(task_already_started()); + } + started=true; + } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + do_run(boost::move(args)...); +#else + do_run(); +#endif + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + virtual void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args)=0; + void apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) +#else + virtual void do_apply()=0; + void apply() +#endif + { + { + boost::lock_guard lk(this->mutex); + if(started) + { + boost::throw_exception(task_already_started()); + } + started=true; + } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + do_apply(boost::move(args)...); +#else + do_apply(); +#endif + } + + void owner_destroyed() + { + boost::unique_lock lk(this->mutex); + if(!started) + { + started=true; + this->mark_exceptional_finish_internal(boost::copy_exception(boost::broken_promise()), lk); + } + } + }; + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template + struct task_shared_state; +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + struct task_shared_state: + task_base_shared_state +#else + template + struct task_shared_state: + task_base_shared_state +#endif +#else + template + struct task_shared_state: + task_base_shared_state +#endif + { + private: + task_shared_state(task_shared_state&); + public: + F f; + task_shared_state(F const& f_): + f(f_) + {} + task_shared_state(BOOST_THREAD_RV_REF(F) f_): + f(boost::move(f_)) + {} + + F callable() + { + return boost::move(f); + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->set_value_at_thread_exit(f(boost::move(args)...)); + } +#else + void do_apply() + { + try + { + this->set_value_at_thread_exit(f()); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->mark_finished_with_result(f(boost::move(args)...)); + } +#else + void do_run() + { + try + { +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + R res((f())); + this->mark_finished_with_result(boost::move(res)); +#else + this->mark_finished_with_result(f()); +#endif + } +#endif + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + struct task_shared_state: + task_base_shared_state +#else + template + struct task_shared_state: + task_base_shared_state +#endif +#else + template + struct task_shared_state: + task_base_shared_state +#endif + { + private: + task_shared_state(task_shared_state&); + public: + F f; + task_shared_state(F const& f_): + f(f_) + {} + task_shared_state(BOOST_THREAD_RV_REF(F) f_): + f(boost::move(f_)) + {} + + F callable() + { + return f; + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->set_value_at_thread_exit(f(boost::move(args)...)); + } +#else + void do_apply() + { + try + { + this->set_value_at_thread_exit(f()); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->mark_finished_with_result(f(boost::move(args)...)); + } +#else + void do_run() + { + try + { + R& res((f())); + this->mark_finished_with_result(res); + } +#endif + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; + +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR) + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + struct task_shared_state: + task_base_shared_state +#else + template + struct task_shared_state: + task_base_shared_state +#endif +#else + template + struct task_shared_state : + task_base_shared_state +#endif + { + private: + task_shared_state(task_shared_state&); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef R (*CallableType)(ArgTypes ... ); +#else + typedef R (*CallableType)(); +#endif + public: + CallableType f; + task_shared_state(CallableType f_): + f(f_) + {} + + CallableType callable() + { + return f; + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->set_value_at_thread_exit(f(boost::move(args)...)); + } +#else + void do_apply() + { + try + { + R r((f())); + this->set_value_at_thread_exit(boost::move(r)); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->mark_finished_with_result(f(boost::move(args)...)); + } +#else + void do_run() + { + try + { + R res((f())); + this->mark_finished_with_result(boost::move(res)); + } +#endif + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + struct task_shared_state: + task_base_shared_state +#else + template + struct task_shared_state: + task_base_shared_state +#endif +#else + template + struct task_shared_state : + task_base_shared_state +#endif + { + private: + task_shared_state(task_shared_state&); + public: +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef R& (*CallableType)(BOOST_THREAD_RV_REF(ArgTypes) ... ); +#else + typedef R& (*CallableType)(); +#endif + CallableType f; + task_shared_state(CallableType f_): + f(f_) + {} + + CallableType callable() + { + return boost::move(f); + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->set_value_at_thread_exit(f(boost::move(args)...)); + } +#else + void do_apply() + { + try + { + this->set_value_at_thread_exit(f()); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->mark_finished_with_result(f(boost::move(args)...)); + } +#else + void do_run() + { + try + { + this->mark_finished_with_result(f()); + } +#endif + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; +#endif +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + struct task_shared_state: + task_base_shared_state +#else + template + struct task_shared_state: + task_base_shared_state +#endif +#else + template + struct task_shared_state: + task_base_shared_state +#endif + { + private: + task_shared_state(task_shared_state&); + public: + typedef F CallableType; + F f; + task_shared_state(F const& f_): + f(f_) + {} + task_shared_state(BOOST_THREAD_RV_REF(F) f_): + f(boost::move(f_)) + {} + F callable() + { + return boost::move(f); + } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + f(boost::move(args)...); +#else + void do_apply() + { + try + { + f(); +#endif + this->set_value_at_thread_exit(); + } + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + f(boost::move(args)...); +#else + void do_run() + { + try + { + f(); +#endif + this->mark_finished_with_result(); + } + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + struct task_shared_state: + task_base_shared_state +#else + template<> + struct task_shared_state: + task_base_shared_state +#endif +#else + template<> + struct task_shared_state: + task_base_shared_state +#endif + { + private: + task_shared_state(task_shared_state&); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef void (*CallableType)(ArgTypes...); +#else + typedef void (*CallableType)(); +#endif + public: + CallableType f; + task_shared_state(CallableType f_): + f(f_) + {} + CallableType callable() + { + return f; + } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + f(boost::move(args)...); +#else + void do_apply() + { + try + { + f(); +#endif + this->set_value_at_thread_exit(); + } + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + f(boost::move(args)...); +#else + void do_run() + { + try + { + f(); +#endif + this->mark_finished_with_result(); + } + catch(...) + { + this->mark_exceptional_finish(); + } + } + }; + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + class packaged_task + { + typedef boost::shared_ptr > task_ptr; + boost::shared_ptr > task; + #else + template + class packaged_task + { + typedef boost::shared_ptr > task_ptr; + boost::shared_ptr > task; + #endif +#else + template + class packaged_task + { + typedef boost::shared_ptr > task_ptr; + boost::shared_ptr > task; +#endif + bool future_obtained; + struct dummy; + + public: + typedef R result_type; + BOOST_THREAD_MOVABLE_ONLY(packaged_task) + + packaged_task(): + future_obtained(false) + {} + + // construction and destruction +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR) + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + explicit packaged_task(R(*f)(), BOOST_THREAD_FWD_REF(ArgTypes)... args) + { + typedef R(*FR)(BOOST_THREAD_FWD_REF(ArgTypes)...); + typedef detail::task_shared_state task_shared_state_type; + task= task_ptr(new task_shared_state_type(f, boost::move(args)...)); + future_obtained=false; + } + #else + explicit packaged_task(R(*f)()) + { + typedef R(*FR)(); + typedef detail::task_shared_state task_shared_state_type; + task= task_ptr(new task_shared_state_type(f)); + future_obtained=false; + } + #endif +#else + explicit packaged_task(R(*f)()) + { + typedef R(*FR)(); + typedef detail::task_shared_state task_shared_state_type; + task= task_ptr(new task_shared_state_type(f)); + future_obtained=false; + } +#endif +#endif +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template + explicit packaged_task(BOOST_THREAD_FWD_REF(F) f + , typename boost::disable_if::type, packaged_task>, dummy* >::type=0 + ) + { + typedef typename decay::type FR; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state task_shared_state_type; + #else + typedef detail::task_shared_state task_shared_state_type; + #endif +#else + typedef detail::task_shared_state task_shared_state_type; +#endif + task = task_ptr(new task_shared_state_type(boost::forward(f))); + future_obtained = false; + + } + +#else + template + explicit packaged_task(F const& f + , typename boost::disable_if::type, packaged_task>, dummy* >::type=0 + ) + { +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state task_shared_state_type; + #else + typedef detail::task_shared_state task_shared_state_type; + #endif +#else + typedef detail::task_shared_state task_shared_state_type; +#endif + task = task_ptr(new task_shared_state_type(f)); + future_obtained=false; + } + template + explicit packaged_task(BOOST_THREAD_RV_REF(F) f) + { +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state task_shared_state_type; + task = task_ptr(new task_shared_state_type(boost::move(f))); +#else + typedef detail::task_shared_state task_shared_state_type; + task = task_ptr(new task_shared_state_type(boost::move(f))); +#endif +#else + typedef detail::task_shared_state task_shared_state_type; + task = task_ptr(new task_shared_state_type(boost::move(f))); +#endif + future_obtained=false; + + } +#endif + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR) + template + packaged_task(boost::allocator_arg_t, Allocator a, R(*f)()) + { + typedef R(*FR)(); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state task_shared_state_type; + #else + typedef detail::task_shared_state task_shared_state_type; + #endif +#else + typedef detail::task_shared_state task_shared_state_type; +#endif + typedef typename Allocator::template rebind::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor D; + + task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(f), D(a2, 1) ); + future_obtained = false; + } +#endif // BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + template + packaged_task(boost::allocator_arg_t, Allocator a, BOOST_THREAD_FWD_REF(F) f) + { + typedef typename decay::type FR; + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state task_shared_state_type; + #else + typedef detail::task_shared_state task_shared_state_type; + #endif +#else + typedef detail::task_shared_state task_shared_state_type; +#endif + typedef typename Allocator::template rebind::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor D; + + task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(boost::forward(f)), D(a2, 1) ); + future_obtained = false; + } +#else // ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + template + packaged_task(boost::allocator_arg_t, Allocator a, const F& f) + { +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state task_shared_state_type; + #else + typedef detail::task_shared_state task_shared_state_type; + #endif +#else + typedef detail::task_shared_state task_shared_state_type; +#endif + typedef typename Allocator::template rebind::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor D; + + task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(f), D(a2, 1) ); + future_obtained = false; + } + template + packaged_task(boost::allocator_arg_t, Allocator a, BOOST_THREAD_RV_REF(F) f) + { +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_shared_state task_shared_state_type; + #else + typedef detail::task_shared_state task_shared_state_type; + #endif +#else + typedef detail::task_shared_state task_shared_state_type; +#endif + typedef typename Allocator::template rebind::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor D; + + task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(boost::move(f)), D(a2, 1) ); + future_obtained = false; + } + +#endif //BOOST_NO_CXX11_RVALUE_REFERENCES +#endif // BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + + ~packaged_task() { + if(task) { + task->owner_destroyed(); + } + } + + // assignment + packaged_task(BOOST_THREAD_RV_REF(packaged_task) other) BOOST_NOEXCEPT + : future_obtained(BOOST_THREAD_RV(other).future_obtained) { + task.swap(BOOST_THREAD_RV(other).task); + BOOST_THREAD_RV(other).future_obtained=false; + } + packaged_task& operator=(BOOST_THREAD_RV_REF(packaged_task) other) BOOST_NOEXCEPT { + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + packaged_task temp(boost::move(other)); +#else + packaged_task temp(static_cast(other)); +#endif + swap(temp); + return *this; + } + +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + void set_executor(executor_ptr_type aex) + { + if (!valid()) + boost::throw_exception(task_moved()); + boost::lock_guard lk(task->mutex); + task->set_executor_policy(aex, lk); + } +#endif + void reset() { + if (!valid()) + boost::throw_exception(future_error(system::make_error_code(future_errc::no_state))); + + // As if *this = packaged_task(task->callable()); + + task->reset(); + future_obtained=false; + } + + void swap(packaged_task& other) BOOST_NOEXCEPT { + task.swap(other.task); + std::swap(future_obtained,other.future_obtained); + } + bool valid() const BOOST_NOEXCEPT { + return task.get()!=0; + } + + // result retrieval + BOOST_THREAD_FUTURE get_future() { + if(!task) { + boost::throw_exception(task_moved()); + } else if(!future_obtained) { + future_obtained=true; + return BOOST_THREAD_FUTURE(task); + } else { + boost::throw_exception(future_already_retrieved()); + } + } + + // execution +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void operator()(ArgTypes... args) { + if(!task) { + boost::throw_exception(task_moved()); + } + task->run(boost::move(args)...); + } + void make_ready_at_thread_exit(ArgTypes... args) { + if(!task) { + boost::throw_exception(task_moved()); + } + if (task->has_value()) { + boost::throw_exception(promise_already_satisfied()); + } + task->apply(boost::move(args)...); + } +#else + void operator()() { + if(!task) { + boost::throw_exception(task_moved()); + } + task->run(); + } + void make_ready_at_thread_exit() { + if(!task) { + boost::throw_exception(task_moved()); + } + if (task->has_value()) boost::throw_exception(promise_already_satisfied()); + task->apply(); + } +#endif + template + void set_wait_callback(F f) { + task->set_wait_callback(f,this); + } + }; +} +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS +namespace boost { namespace container { + template + struct uses_allocator< ::boost::packaged_task , Alloc> : true_type + {}; +}} +#if ! defined BOOST_NO_CXX11_ALLOCATOR +namespace std { + template + struct uses_allocator< ::boost::packaged_task , Alloc> : true_type + {}; +} +#endif +#endif + +namespace boost +{ + BOOST_THREAD_DCL_MOVABLE_BEG(T) packaged_task BOOST_THREAD_DCL_MOVABLE_END + +namespace detail +{ + //////////////////////////////// + // make_future_deferred_shared_state + //////////////////////////////// + template + BOOST_THREAD_FUTURE + make_future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f) { + shared_ptr > + h(new future_deferred_shared_state(boost::forward(f))); + return BOOST_THREAD_FUTURE(h); + } + + //////////////////////////////// + // make_future_async_shared_state + //////////////////////////////// + template + BOOST_THREAD_FUTURE + make_future_async_shared_state(BOOST_THREAD_FWD_REF(Fp) f) { + shared_ptr > + h(new future_async_shared_state()); + h->init(boost::forward(f)); + return BOOST_THREAD_FUTURE(h); + } +} + + //////////////////////////////// + // template + // future async(launch policy, F&&, ArgTypes&&...); + //////////////////////////////// + +#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR + +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + BOOST_THREAD_FUTURE + async(launch policy, R(*f)(BOOST_THREAD_FWD_REF(ArgTypes)...), BOOST_THREAD_FWD_REF(ArgTypes)... args) { + typedef R(*F)(BOOST_THREAD_FWD_REF(ArgTypes)...); + typedef detail::invoker::type, typename decay::type...> BF; + typedef typename BF::result_type Rp; + + if (underlying_cast(policy) & int(launch::async)) { + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_async_shared_state( + BF( + f + , thread_detail::decay_copy(boost::forward(args))... + ) + )); + } else if (underlying_cast(policy) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_deferred_shared_state( + BF( + f + , thread_detail::decay_copy(boost::forward(args))... + ) + )); + } else { + std::terminate(); + //BOOST_THREAD_FUTURE ret; + //return ::boost::move(ret); + } + } + +#else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + + template + BOOST_THREAD_FUTURE + async(launch policy, R(*f)()) { + #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + typedef packaged_task packaged_task_type; + #else + typedef packaged_task packaged_task_type; + #endif + + if (underlying_cast(policy) & int(launch::async)) { + packaged_task_type pt( f ); + BOOST_THREAD_FUTURE ret = BOOST_THREAD_MAKE_RV_REF(pt.get_future()); + ret.set_async(); + boost::thread( boost::move(pt) ).detach(); + return ::boost::move(ret); + } else if (underlying_cast(policy) & int(launch::deferred)) { + std::terminate(); + //BOOST_THREAD_FUTURE ret; + //return ::boost::move(ret); + } else { + std::terminate(); + //BOOST_THREAD_FUTURE ret; + //return ::boost::move(ret); + } + } +#endif +#endif // defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR) + +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + + template + BOOST_THREAD_FUTURE::type( + typename decay::type... + )>::type> + async(launch policy, BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(ArgTypes)... args) { + typedef detail::invoker::type, typename decay::type...> BF; + typedef typename BF::result_type Rp; + + if (underlying_cast(policy) & int(launch::async)) { + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_async_shared_state( + BF( + thread_detail::decay_copy(boost::forward(f)) + , thread_detail::decay_copy(boost::forward(args))... + ) + )); + } else if (underlying_cast(policy) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_deferred_shared_state( + BF( + thread_detail::decay_copy(boost::forward(f)) + , thread_detail::decay_copy(boost::forward(args))... + ) + )); + } else { + std::terminate(); + //BOOST_THREAD_FUTURE ret; + //return ::boost::move(ret); + } + } + +#else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + + template + BOOST_THREAD_FUTURE::type()>::type> + async(launch policy, BOOST_THREAD_FWD_REF(F) f) { + typedef typename boost::result_of::type()>::type R; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + typedef packaged_task packaged_task_type; +#else // defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + typedef packaged_task packaged_task_type; +#endif // defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + + if (underlying_cast(policy) & int(launch::async)) { + packaged_task_type pt( boost::forward(f) ); + BOOST_THREAD_FUTURE ret = pt.get_future(); + ret.set_async(); + boost::thread( boost::move(pt) ).detach(); + return ::boost::move(ret); + } else if (underlying_cast(policy) & int(launch::deferred)) { + std::terminate(); + //BOOST_THREAD_FUTURE ret; + //return ::boost::move(ret); + // return boost::detail::make_future_deferred_shared_state( + // BF( + // thread_detail::decay_copy(boost::forward(f)) + // ) + // ); + } else { + std::terminate(); + //BOOST_THREAD_FUTURE ret; + //return ::boost::move(ret); + } + } +#endif // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS +namespace detail { + + ///////////////////////// + /// shared_state_nullary_task + ///////////////////////// + template + struct shared_state_nullary_task + { + + typedef shared_ptr storage_type; + storage_type that; + Fp f_; + public: + + shared_state_nullary_task(storage_type st, BOOST_THREAD_FWD_REF(Fp) f) + : that(st), f_(boost::move(f)) + {}; + +#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_THREAD_COPYABLE_AND_MOVABLE(shared_state_nullary_task) + shared_state_nullary_task(shared_state_nullary_task const& x) //BOOST_NOEXCEPT + : that(x.that), f_(x.f_) + {} + shared_state_nullary_task& operator=(BOOST_THREAD_COPY_ASSIGN_REF(shared_state_nullary_task) x) //BOOST_NOEXCEPT + { + if (this != &x) { + that=x.that; + f_=x.f_; + } + return *this; + } + // move + shared_state_nullary_task(BOOST_THREAD_RV_REF(shared_state_nullary_task) x) //BOOST_NOEXCEPT + : that(x.that), f_(boost::move(x.f_)) + { + x.that.reset(); + } + shared_state_nullary_task& operator=(BOOST_THREAD_RV_REF(shared_state_nullary_task) x) //BOOST_NOEXCEPT + { + if (this != &x) { + that=x.that; + f_=boost::move(x.f_); + x.that.reset(); + } + return *this; + } +#endif + void operator()() { + shared_ptr > that_ = static_pointer_cast >(that); + try { + that_->mark_finished_with_result(f_()); + } catch(...) { + that_->mark_exceptional_finish(); + } + } + ~shared_state_nullary_task() + { + } + }; + + template + struct shared_state_nullary_task + { + typedef shared_ptr storage_type; + storage_type that; + Fp f_; + public: + shared_state_nullary_task(storage_type st, BOOST_THREAD_FWD_REF(Fp) f) + : that(st), f_(boost::move(f)) + {}; + +#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_THREAD_COPYABLE_AND_MOVABLE(shared_state_nullary_task) + shared_state_nullary_task(shared_state_nullary_task const& x) //BOOST_NOEXCEPT + : that(x.that), f_(x.f_) + {} + shared_state_nullary_task& operator=(BOOST_THREAD_COPY_ASSIGN_REF(shared_state_nullary_task) x) //BOOST_NOEXCEPT + { + if (this != &x) { + that=x.that; + f_=x.f_; + } + return *this; + } + // move + shared_state_nullary_task(BOOST_THREAD_RV_REF(shared_state_nullary_task) x) BOOST_NOEXCEPT + : that(x.that), f_(boost::move(x.f_)) + { + x.that.reset(); + } + shared_state_nullary_task& operator=(BOOST_THREAD_RV_REF(shared_state_nullary_task) x) BOOST_NOEXCEPT { + if (this != &x) { + that=x.that; + f_=boost::move(x.f_); + x.that.reset(); + } + return *this; + } +#endif + void operator()() { + shared_ptr > that_ = static_pointer_cast >(that); + try { + f_(); + that_->mark_finished_with_result(); + } catch(...) { + that_->mark_exceptional_finish(); + } + } + }; + +} + BOOST_THREAD_DCL_MOVABLE_BEG2(R,F) detail::shared_state_nullary_task BOOST_THREAD_DCL_MOVABLE_END +namespace detail { + + ///////////////////////// + /// future_executor_shared_state_base + ///////////////////////// + template + struct future_executor_shared_state: shared_state + { + typedef shared_state base_type; + protected: + public: + future_executor_shared_state() { + } + + template + void init(Executor& ex, BOOST_THREAD_FWD_REF(Fp) f) + { + typedef typename decay::type Cont; + this->set_executor_policy(executor_ptr_type(new executor_ref(ex))); + shared_state_nullary_task t(this->shared_from_this(), boost::forward(f)); + ex.submit(boost::move(t)); + } + + ~future_executor_shared_state() {} + }; + + //////////////////////////////// + // make_future_executor_shared_state + //////////////////////////////// + template + BOOST_THREAD_FUTURE + make_future_executor_shared_state(Executor& ex, BOOST_THREAD_FWD_REF(Fp) f) { + shared_ptr > + h(new future_executor_shared_state()); + h->init(ex, boost::forward(f)); + return BOOST_THREAD_FUTURE(h); + } + +} // detail + + //////////////////////////////// + // template + // future async(Executor& ex, F&&, ArgTypes&&...); + //////////////////////////////// + +//#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if defined(BOOST_THREAD_PROVIDES_INVOKE) && ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ! defined(BOOST_NO_CXX11_HDR_TUPLE) + +#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR + + template + BOOST_THREAD_FUTURE + async(Executor& ex, R(*f)(BOOST_THREAD_FWD_REF(ArgTypes)...), BOOST_THREAD_FWD_REF(ArgTypes)... args) { + typedef R(*F)(BOOST_THREAD_FWD_REF(ArgTypes)...); + typedef detail::invoker::type, typename decay::type...> BF; + typedef typename BF::result_type Rp; + + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_executor_shared_state(ex, + BF( + f + , thread_detail::decay_copy(boost::forward(args))... + ) + )); + } +#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR + + template + BOOST_THREAD_FUTURE::type( + typename decay::type... + )>::type> + async(Executor& ex, BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(ArgTypes)... args) { + typedef detail::invoker::type, typename decay::type...> BF; + typedef typename BF::result_type Rp; + + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_executor_shared_state(ex, + BF( + thread_detail::decay_copy(boost::forward(f)) + , thread_detail::decay_copy(boost::forward(args))... + ) + )); + } + +#else // ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR + + template + BOOST_THREAD_FUTURE + async(Executor& ex, R(*f)()) { + typedef R(*F)(); + typedef detail::invoker BF; + typedef typename BF::result_type Rp; + + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_executor_shared_state(ex, + BF( + f + ) + )); + } + + template + BOOST_THREAD_FUTURE + async(Executor& ex, R(*f)(BOOST_THREAD_FWD_REF(A1)), BOOST_THREAD_FWD_REF(A1) a1) { + typedef R(*F)(BOOST_THREAD_FWD_REF(A1)); + typedef detail::invoker::type> BF; + typedef typename BF::result_type Rp; + + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_executor_shared_state(ex, + BF( + f + , thread_detail::decay_copy(boost::forward(a1)) + ) + )); + } +#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR + + template + BOOST_THREAD_FUTURE::type()>::type> + async(Executor& ex, BOOST_THREAD_FWD_REF(F) f) { + typedef detail::invoker::type> BF; + typedef typename BF::result_type Rp; + + return boost::detail::make_future_executor_shared_state(ex, + BF( + thread_detail::decay_copy(boost::forward(f)) + ) + ); + } + + template + BOOST_THREAD_FUTURE::type( + typename decay::type + )>::type> + async(Executor& ex, BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) { + typedef detail::invoker::type, typename decay::type> BF; + typedef typename BF::result_type Rp; + + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_executor_shared_state(ex, + BF( + thread_detail::decay_copy(boost::forward(f)) + , thread_detail::decay_copy(boost::forward(a1)) + ) + )); + } + + template + BOOST_THREAD_FUTURE::type( + typename decay::type, typename decay::type + )>::type> + async(Executor& ex, BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1, BOOST_THREAD_FWD_REF(A2) a2) { + typedef detail::invoker::type, typename decay::type, typename decay::type> BF; + typedef typename BF::result_type Rp; + + return BOOST_THREAD_MAKE_RV_REF(boost::detail::make_future_executor_shared_state(ex, + BF( + thread_detail::decay_copy(boost::forward(f)) + , thread_detail::decay_copy(boost::forward(a1)) + , thread_detail::decay_copy(boost::forward(a2)) + ) + )); + } + +#endif //! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#endif + + //////////////////////////////// + // template + // future async(F&&, ArgTypes&&...); + //////////////////////////////// + +#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + BOOST_THREAD_FUTURE + async(R(*f)(BOOST_THREAD_FWD_REF(ArgTypes)...), BOOST_THREAD_FWD_REF(ArgTypes)... args) { + return BOOST_THREAD_MAKE_RV_REF(async(launch(launch::any), f, boost::forward(args)...)); + } + #else + template + BOOST_THREAD_FUTURE + async(R(*f)()) { + return BOOST_THREAD_MAKE_RV_REF(async(launch(launch::any), f)); + } + #endif +#endif + +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + BOOST_THREAD_FUTURE::type( + typename decay::type... + )>::type> + async(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(ArgTypes)... args) { + return BOOST_THREAD_MAKE_RV_REF(async(launch(launch::any), boost::forward(f), boost::forward(args)...)); + } +#else + template + BOOST_THREAD_FUTURE::type> + async(BOOST_THREAD_FWD_REF(F) f) { + return BOOST_THREAD_MAKE_RV_REF(async(launch(launch::any), boost::forward(f))); + } +#endif + + //////////////////////////////// + // make_future deprecated + //////////////////////////////// + template + BOOST_THREAD_FUTURE::type> make_future(BOOST_THREAD_FWD_REF(T) value) { + typedef typename decay::type future_value_type; + promise p; + p.set_value(boost::forward(value)); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } + +#if defined BOOST_THREAD_USES_MOVE + inline BOOST_THREAD_FUTURE make_future() { + promise p; + p.set_value(); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } +#endif + + //////////////////////////////// + // make_ready_future + //////////////////////////////// + namespace detail { + template + struct deduced_type_impl + { + typedef T type; + }; + + template + struct deduced_type_impl const> + { + typedef T& type; + }; + template + struct deduced_type_impl > + { + typedef T& type; + }; +#if __cplusplus > 201103L + template + struct deduced_type_impl > + { + typedef T& type; + }; +#endif + template + struct deduced_type + { + typedef typename detail::deduced_type_impl::type>::type type; + }; + + } + + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template +#else + template +#endif + BOOST_THREAD_FUTURE::type> make_ready_future(BOOST_THREAD_FWD_REF(T) value) { + typedef typename detail::deduced_type::type future_value_type; + promise p; + p.set_value(boost::forward(value)); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } + + // explicit overloads + template + BOOST_THREAD_FUTURE make_ready_future(typename remove_reference::type & x) + { + promise p; + p.set_value(x); + return p.get_future(); + } + + template + BOOST_THREAD_FUTURE make_ready_future(BOOST_THREAD_FWD_REF(typename remove_reference::type) x) + { + promise p; + p.set_value(forward::type>(x)); + return p.get_future(); + } + + // variadic overload +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + BOOST_THREAD_FUTURE make_ready_future(Args&&... args) + { + promise p; + p.emplace(forward(args)...); + return p.get_future(); + + } +#endif + + template + BOOST_THREAD_FUTURE make_ready_no_decay_future(T1 value) { + typedef T future_value_type; + promise p; + p.set_value(value); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined BOOST_THREAD_USES_MOVE + inline BOOST_THREAD_FUTURE make_ready_future() { + promise p; + p.set_value(); + return p.get_future(); + } +#endif + + + template + BOOST_THREAD_FUTURE make_exceptional_future(exception_ptr ex) { + promise p; + p.set_exception(ex); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } + + template + BOOST_THREAD_FUTURE make_exceptional_future(E ex) { + promise p; + p.set_exception(boost::copy_exception(ex)); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } + + template + BOOST_THREAD_FUTURE make_exceptional_future() { + promise p; + p.set_exception(boost::current_exception()); + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } + template + BOOST_THREAD_FUTURE make_ready_future(exception_ptr ex) { + return make_exceptional_future(ex); + } + +#if 0 + template + make_future(CLOSURE closure) -> BOOST_THREAD_FUTURE { + typedef decltype(closure()) T; + promise p; + try { + p.set_value(closure()); + } catch(...) { + p.set_exception(std::current_exception()); + } + return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + } +#endif + + //////////////////////////////// + // make_shared_future deprecated + //////////////////////////////// + template + shared_future::type> make_shared_future(BOOST_THREAD_FWD_REF(T) value) { + typedef typename decay::type future_type; + promise p; + p.set_value(boost::forward(value)); + return BOOST_THREAD_MAKE_RV_REF(p.get_future().share()); + } + + inline shared_future make_shared_future() { + promise p; + return BOOST_THREAD_MAKE_RV_REF(p.get_future().share()); + } + + //////////////////////////////// + // detail::future_async_continuation_shared_state + //////////////////////////////// +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + +namespace detail +{ + ////////////////////// + // detail::continuation_shared_state + ////////////////////// + template > + struct continuation_shared_state: ShSt + { + F parent; + Fp continuation; + + public: + continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) + : parent(boost::move(f)), + continuation(boost::move(c)) + { + } + + void init(boost::unique_lock &lock) + { + parent.future_->set_continuation_ptr(this->shared_from_this(), lock); + } + + void call() { + try { + this->mark_finished_with_result(this->continuation(boost::move(this->parent))); + } catch(...) { + this->mark_exceptional_finish(); + } + // make sure parent is really cleared to prevent memory "leaks" + this->parent = F(); + } + + void call(boost::unique_lock& lck) { + try { + relocker relock(lck); + + // neither continuation nor parent are protected by the lock - call() must only + // be called once, and no one else must modify it. + Rp res = this->continuation(boost::move(this->parent)); + + // make sure parent is really cleared to prevent memory "leaks" + this->parent = F(); + + relock.lock(); + + this->mark_finished_with_result_internal(boost::move(res), lck); + } catch (...) { + this->mark_exceptional_finish_internal(current_exception(), lck); + + // make sure parent is really cleared to prevent memory "leaks" + relocker relock(lck); + this->parent = F(); + } + } + + static void run(shared_ptr that_) + { + continuation_shared_state* that = static_cast(that_.get()); + that->call(); + } + + ~continuation_shared_state() {} + }; + + template + struct continuation_shared_state: ShSt + { + F parent; + Fp continuation; + + public: + continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) + : parent(boost::move(f)), + continuation(boost::move(c)) + { + } + + void init(boost::unique_lock &lock) + { + parent.future_->set_continuation_ptr(this->shared_from_this(), lock); + } + + void call() + { + try { + this->continuation(boost::move(this->parent)); + this->mark_finished_with_result(); + } catch(...) { + this->mark_exceptional_finish(); + } + // make sure parent is really cleared to prevent memory "leaks" + this->parent = F(); + } + + void call(boost::unique_lock& lck) { + try { + { + relocker relock(lck); + // neither continuation nor parent are protected by the lock - call() must only + // be called once, and no one else must modify it. + this->continuation(boost::move(this->parent)); + + // make sure parent is really cleared to prevent memory "leaks" + this->parent = F(); + } + this->mark_finished_with_result_internal(lck); + } catch (...) { + this->mark_exceptional_finish_internal(current_exception(), lck); + + // make sure parent is really cleared to prevent memory "leaks" + relocker relock(lck); + this->parent = F(); + } + } + + static void run(shared_ptr that_) + { + continuation_shared_state* that = static_cast(that_.get()); + that->call(); + } + + ~continuation_shared_state() {} + }; + ///////////////////////// + /// future_async_continuation_shared_state + ///////////////////////// + + template + struct future_async_continuation_shared_state: continuation_shared_state > + { + typedef continuation_shared_state > base_type; + public: + future_async_continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) + : base_type(boost::move(f), boost::forward(c)) + { } + + void launch_continuation() { +#if defined BOOST_THREAD_FUTURE_BLOCKING + boost::lock_guard lk(this->mutex); + this->thr_ = boost::thread(&future_async_continuation_shared_state::run, static_shared_from_this(this)); +#else + boost::thread(&base_type::run, static_shared_from_this(this)).detach(); +#endif + } + }; + + ///////////////////////// + /// future_sync_continuation_shared_state + ///////////////////////// + + template + struct future_sync_continuation_shared_state: continuation_shared_state > + { + typedef continuation_shared_state > base_type; + public: + future_sync_continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) + : base_type(boost::move(f), boost::forward(c)) + { } + + void launch_continuation() { + this->call(); + } + }; + + + ///////////////////////// + /// future_executor_continuation_shared_state + ///////////////////////// +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + + template + struct run_it { + shared_ptr that_; + +#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + BOOST_THREAD_COPYABLE_AND_MOVABLE(run_it) + run_it(run_it const& x) //BOOST_NOEXCEPT + : that_(x.that_) + {} + run_it& operator=(BOOST_THREAD_COPY_ASSIGN_REF(run_it) x) //BOOST_NOEXCEPT + { + if (this != &x) { + that_=x.that_; + } + return *this; + } + // move + run_it(BOOST_THREAD_RV_REF(run_it) x) BOOST_NOEXCEPT + : that_(x.that_) + { + x.that_.reset(); + } + run_it& operator=(BOOST_THREAD_RV_REF(run_it) x) BOOST_NOEXCEPT { + if (this != &x) { + that_=x.that; + x.that_.reset(); + } + return *this; + } +#endif + run_it(shared_ptr that) : that_ (that) {} + + void operator()() + { + that_->run(that_); + } + }; + +} + BOOST_THREAD_DCL_MOVABLE_BEG(F) detail::run_it BOOST_THREAD_DCL_MOVABLE_END + +namespace detail { + + template + struct future_executor_continuation_shared_state: continuation_shared_state + { + typedef continuation_shared_state base_type; + + public: + future_executor_continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) + : base_type(boost::move(f), boost::forward(c)) + { + } + + template + void init(boost::unique_lock &lk, Ex& ex) + { + this->set_executor_policy(executor_ptr_type(new executor_ref(ex)), lk); + this->base_type::init(lk); + } + + void launch_continuation() { + run_it fct(static_shared_from_this(this)); + this->get_executor()->submit(boost::move(fct)); + } + + ~future_executor_continuation_shared_state() {} + }; +#endif + + ///////////////////////// + /// shared_future_async_continuation_shared_state + ///////////////////////// + + template + struct shared_future_async_continuation_shared_state: continuation_shared_state > + { + typedef continuation_shared_state > base_type; + + public: + shared_future_async_continuation_shared_state(F f, BOOST_THREAD_FWD_REF(Fp) c) + : base_type(boost::move(f), boost::forward(c)) + { + } + + void launch_continuation() { +#if defined BOOST_THREAD_FUTURE_BLOCKING + boost::lock_guard lk(this->mutex); + this->thr_ = boost::thread(&base_type::run, static_shared_from_this(this)); +#else + boost::thread(&base_type::run, static_shared_from_this(this)).detach(); +#endif + } + }; + + ///////////////////////// + /// shared_future_async_continuation_shared_state + ///////////////////////// + + template + struct shared_future_sync_continuation_shared_state: continuation_shared_state > + { + typedef continuation_shared_state > base_type; + + public: + shared_future_sync_continuation_shared_state(F f, BOOST_THREAD_FWD_REF(Fp) c) + : base_type(boost::move(f), boost::forward(c)) + { + } + + void launch_continuation() { + this->call(); + } + }; + + + ///////////////////////// + /// shared_future_executor_continuation_shared_state + ///////////////////////// +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + + template + struct shared_future_executor_continuation_shared_state: continuation_shared_state + { + typedef continuation_shared_state base_type; + + public: + + shared_future_executor_continuation_shared_state(F f, BOOST_THREAD_FWD_REF(Fp) c) + : base_type(boost::move(f), boost::forward(c)) + { + } + + template + void init(boost::unique_lock &lk, Ex& ex) + { + this->set_executor_policy(executor_ptr_type(new executor_ref(ex)), lk); + this->base_type::init(lk); + } + + void launch_continuation() { + run_it fct(static_shared_from_this(this)); + this->get_executor()->submit(boost::move(fct)); + } + + ~shared_future_executor_continuation_shared_state() {} + }; + +#endif + ////////////////////////// + /// future_deferred_continuation_shared_state + ////////////////////////// + template + struct future_deferred_continuation_shared_state: continuation_shared_state + { + typedef continuation_shared_state base_type; + public: + future_deferred_continuation_shared_state(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) + : base_type(boost::move(f), boost::forward(c)) + { + this->set_deferred(); + } + + virtual void execute(boost::unique_lock& lk) { + this->parent.wait(); + this->call(lk); + } + + virtual void launch_continuation() { } + }; + + ////////////////////////// + /// shared_future_deferred_continuation_shared_state + ////////////////////////// + template + struct shared_future_deferred_continuation_shared_state: continuation_shared_state + { + typedef continuation_shared_state base_type; + + public: + shared_future_deferred_continuation_shared_state(F f, BOOST_THREAD_FWD_REF(Fp) c) + : base_type(boost::move(f), boost::forward(c)) + { + this->set_deferred(); + } + + virtual void execute(boost::unique_lock& lk) { + this->parent.wait(); + this->call(lk); + } + + virtual void launch_continuation() { } + }; + + //////////////////////////////// + // make_future_deferred_continuation_shared_state + //////////////////////////////// + template + BOOST_THREAD_FUTURE + make_future_deferred_continuation_shared_state( + boost::unique_lock &lock, + BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_FWD_REF(Fp) c) { + typedef typename decay::type Cont; + shared_ptr > + h(new future_deferred_continuation_shared_state(boost::move(f), boost::forward(c))); + h->init(lock); + return BOOST_THREAD_FUTURE(h); + } + + //////////////////////////////// + // make_future_async_continuation_shared_state + //////////////////////////////// + template + BOOST_THREAD_FUTURE + make_future_async_continuation_shared_state( + boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, + BOOST_THREAD_FWD_REF(Fp) c) { + typedef typename decay::type Cont; + shared_ptr > + h(new future_async_continuation_shared_state(boost::move(f), boost::forward(c))); + h->init(lock); + + return BOOST_THREAD_FUTURE(h); + } + //////////////////////////////// + // make_future_sync_continuation_shared_state + //////////////////////////////// + template + BOOST_THREAD_FUTURE + make_future_sync_continuation_shared_state( + boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, + BOOST_THREAD_FWD_REF(Fp) c) { + typedef typename decay::type Cont; + shared_ptr > + h(new future_sync_continuation_shared_state(boost::move(f), boost::forward(c))); + h->init(lock); + + return BOOST_THREAD_FUTURE(h); + } + + //////////////////////////////// + // make_future_executor_continuation_shared_state + //////////////////////////////// +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + + template + BOOST_THREAD_FUTURE + make_future_executor_continuation_shared_state(Ex& ex, + boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f, + BOOST_THREAD_FWD_REF(Fp) c) { + typedef typename decay::type Cont; + shared_ptr > + h(new future_executor_continuation_shared_state(boost::move(f), boost::forward(c))); + h->init(lock, ex); + + return BOOST_THREAD_FUTURE(h); + } +#endif + + //////////////////////////////// + // make_shared_future_deferred_continuation_shared_state + //////////////////////////////// + template + BOOST_THREAD_FUTURE + make_shared_future_deferred_continuation_shared_state( + boost::unique_lock &lock, + F f, BOOST_THREAD_FWD_REF(Fp) c) { + typedef typename decay::type Cont; + shared_ptr > + h(new shared_future_deferred_continuation_shared_state(f, boost::forward(c))); + h->init(lock); + + return BOOST_THREAD_FUTURE(h); + } + //////////////////////////////// + // make_shared_future_async_continuation_shared_state + //////////////////////////////// + template + BOOST_THREAD_FUTURE + make_shared_future_async_continuation_shared_state( + boost::unique_lock &lock, F f, + BOOST_THREAD_FWD_REF(Fp) c) { + typedef typename decay::type Cont; + shared_ptr > + h(new shared_future_async_continuation_shared_state(f, boost::forward(c))); + h->init(lock); + + return BOOST_THREAD_FUTURE(h); + } + //////////////////////////////// + // make_shared_future_sync_continuation_shared_state + //////////////////////////////// + template + BOOST_THREAD_FUTURE + make_shared_future_sync_continuation_shared_state( + boost::unique_lock &lock, F f, + BOOST_THREAD_FWD_REF(Fp) c) { + typedef typename decay::type Cont; + shared_ptr > + h(new shared_future_sync_continuation_shared_state(f, boost::forward(c))); + h->init(lock); + + return BOOST_THREAD_FUTURE(h); + } + //////////////////////////////// + // make_shared_future_executor_continuation_shared_state + //////////////////////////////// +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + template + BOOST_THREAD_FUTURE + make_shared_future_executor_continuation_shared_state(Ex& ex, + boost::unique_lock &lock, F f, + BOOST_THREAD_FWD_REF(Fp) c) { + typedef typename decay::type Cont; + shared_ptr > + h(new shared_future_executor_continuation_shared_state(f, boost::forward(c))); + h->init(lock, ex); + + return BOOST_THREAD_FUTURE(h); + } +#endif +} + + //////////////////////////////// + // template + // auto future::then(launch policy, F&& func) -> BOOST_THREAD_FUTURE; + //////////////////////////////// + template + template + inline BOOST_THREAD_FUTURE)>::type> + BOOST_THREAD_FUTURE::then(launch policy, BOOST_THREAD_FWD_REF(F) func) { + typedef typename boost::result_of)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized()); + + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + + if (underlying_cast(policy) & int(launch::async)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } else if (underlying_cast(policy) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } else if (underlying_cast(policy) & int(launch::sync)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_sync_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + } else if (underlying_cast(policy) & int(launch::executor)) { + assert(this->future_->get_executor()); + typedef executor Ex; + Ex& ex = *(this->future_->get_executor()); + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state, future_type>(ex, + lock, boost::move(*this), boost::forward(func) + ))); +#endif + } else if (underlying_cast(policy) & int(launch::inherit)) { + + launch policy_ = this->launch_policy(lock); + if (underlying_cast(policy_) & int(launch::async)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } else if (underlying_cast(policy_) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } else if (underlying_cast(policy_) & int(launch::sync)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_sync_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + } else if (underlying_cast(policy_) & int(launch::executor)) { + assert(this->future_->get_executor()); + typedef executor Ex; + Ex& ex = *(this->future_->get_executor()); + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state, future_type>(ex, + lock, boost::move(*this), boost::forward(func) + ))); +#endif + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } + } +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + //////////////////////////////// + // template + // auto future >::then(Ex&, F&& func) -> BOOST_THREAD_FUTURE; + //////////////////////////////// + template + template + inline BOOST_THREAD_FUTURE)>::type> + BOOST_THREAD_FUTURE::then(Ex& ex, BOOST_THREAD_FWD_REF(F) func) { + typedef typename boost::result_of)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized()); + + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state, future_type>(ex, + lock, boost::move(*this), boost::forward(func) + ))); + } +#endif + //////////////////////////////// + // template + // auto future >::then(F&& func) -> BOOST_THREAD_FUTURE; + //////////////////////////////// + template + template + inline BOOST_THREAD_FUTURE)>::type> + BOOST_THREAD_FUTURE::then(BOOST_THREAD_FWD_REF(F) func) { + +#ifndef BOOST_THREAD_CONTINUATION_SYNC + return this->then(this->launch_policy(), boost::forward(func)); +#else + typedef typename boost::result_of)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized()); + + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + + launch policy = this->launch_policy(lock); + if (underlying_cast(policy) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } +#endif + + } + + //////////////////////////////// + // template + // auto future >::then(launch, F&& func) -> BOOST_THREAD_FUTURE; + //////////////////////////////// + template + template + inline BOOST_THREAD_FUTURE >)>::type> + BOOST_THREAD_FUTURE >::then(launch policy, BOOST_THREAD_FWD_REF(F) func) { + typedef BOOST_THREAD_FUTURE R; + typedef typename boost::result_of)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized()); + + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + + if (underlying_cast(policy) & int(launch::async)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } else if (underlying_cast(policy) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } else if (underlying_cast(policy) & int(launch::sync)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_sync_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + } else if (underlying_cast(policy) & int(launch::executor)) { + assert(this->future_->get_executor()); + typedef executor Ex; + Ex& ex = *(this->future_->get_executor()); + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state, future_type>(ex, + lock, boost::move(*this), boost::forward(func) + ))); +#endif + } else if (underlying_cast(policy) & int(launch::inherit)) { + launch policy_ = this->launch_policy(lock); + + if (underlying_cast(policy_) & int(launch::async)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } else if (underlying_cast(policy_) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } else if (underlying_cast(policy_) & int(launch::sync)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_sync_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + } else if (underlying_cast(policy_) & int(launch::executor)) { + assert(this->future_->get_executor()); + typedef executor Ex; + Ex& ex = *(this->future_->get_executor()); + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state, future_type>(ex, + lock, boost::move(*this), boost::forward(func) + ))); +#endif + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } + } + +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + //////////////////////////////// + // template + // auto future >::then(Ex&, F&& func) -> BOOST_THREAD_FUTURE; + //////////////////////////////// + template + template + inline BOOST_THREAD_FUTURE >)>::type> + BOOST_THREAD_FUTURE >::then(Ex& ex, BOOST_THREAD_FWD_REF(F) func) { + typedef BOOST_THREAD_FUTURE R; + typedef typename boost::result_of)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized()); + + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state, future_type>(ex, + lock, boost::move(*this), boost::forward(func) + ))); + } +#endif + + //////////////////////////////// + // template + // auto future >::then(F&& func) -> BOOST_THREAD_FUTURE; + //////////////////////////////// + template + template + inline BOOST_THREAD_FUTURE >)>::type> + BOOST_THREAD_FUTURE >::then(BOOST_THREAD_FWD_REF(F) func) { + +#ifndef BOOST_THREAD_CONTINUATION_SYNC + return this->then(this->launch_policy(), boost::forward(func)); +#else + typedef BOOST_THREAD_FUTURE R; + typedef typename boost::result_of)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized()); + + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + + launch policy = this->launch_policy(lock); + + if (underlying_cast(policy) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_sync_continuation_shared_state, future_type>( + lock, boost::move(*this), boost::forward(func) + ))); + } +#endif + } + + //////////////////////////////// + // template + // auto shared_future::then(launch policy, F&& func) -> BOOST_THREAD_FUTURE; + //////////////////////////////// + template + template + inline BOOST_THREAD_FUTURE)>::type> + shared_future::then(launch policy, BOOST_THREAD_FWD_REF(F) func) const + { + typedef typename boost::result_of)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized()); + + boost::unique_lock lock(this->future_->mutex); + if (underlying_cast(policy) & int(launch::async)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_async_continuation_shared_state, future_type>( + lock, *this, boost::forward(func) + ))); + } else if (underlying_cast(policy) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_deferred_continuation_shared_state, future_type>( + lock, *this, boost::forward(func) + ))); + } else if (underlying_cast(policy) & int(launch::sync)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_sync_continuation_shared_state, future_type>( + lock, *this, boost::forward(func) + ))); +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + } else if (underlying_cast(policy) & int(launch::executor)) { + typedef executor Ex; + Ex& ex = *(this->future_->get_executor()); + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_executor_continuation_shared_state, future_type>(ex, + lock, *this, boost::forward(func) + ))); +#endif + } else if (underlying_cast(policy) & int(launch::inherit)) { + + launch policy_ = this->launch_policy(lock); + if (underlying_cast(policy_) & int(launch::async)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_async_continuation_shared_state, future_type>( + lock, *this, boost::forward(func) + ))); + } else if (underlying_cast(policy_) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_deferred_continuation_shared_state, future_type>( + lock, *this, boost::forward(func) + ))); + } else if (underlying_cast(policy_) & int(launch::sync)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_sync_continuation_shared_state, future_type>( + lock, *this, boost::forward(func) + ))); +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + } else if (underlying_cast(policy_) & int(launch::executor)) { + typedef executor Ex; + Ex& ex = *(this->future_->get_executor()); + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_executor_continuation_shared_state, future_type>(ex, + lock, *this, boost::forward(func) + ))); +#endif + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_async_continuation_shared_state, future_type>( + lock, *this, boost::forward(func) + ))); + } + + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_async_continuation_shared_state, future_type>( + lock, *this, boost::forward(func) + ))); + } + } +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + //////////////////////////////// + // template + // auto shared_future::then(Ex&, F&& func) -> BOOST_THREAD_FUTURE; + //////////////////////////////// + template + template + inline BOOST_THREAD_FUTURE)>::type> + shared_future::then(Ex& ex, BOOST_THREAD_FWD_REF(F) func) const + { + typedef typename boost::result_of)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized()); + + boost::unique_lock lock(this->future_->mutex); + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_executor_continuation_shared_state, future_type>(ex, + lock, *this, boost::forward(func) + ))); + } +#endif + + //////////////////////////////// + // template + // auto shared_future::then(F&& func) -> BOOST_THREAD_FUTURE; + //////////////////////////////// + template + template + inline BOOST_THREAD_FUTURE)>::type> + shared_future::then(BOOST_THREAD_FWD_REF(F) func) const { +#ifndef BOOST_THREAD_CONTINUATION_SYNC + return this->then(this->launch_policy(), boost::forward(func)); +#else + typedef typename boost::result_of)>::type future_type; + BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized()); + + boost::unique_lock lock(this->future_->mutex); + launch policy = this->launch_policy(lock); + if (underlying_cast(policy) & int(launch::deferred)) { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_deferred_continuation_shared_state, future_type>( + lock, *this, boost::forward(func) + ))); + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_sync_continuation_shared_state, future_type>( + lock, *this, boost::forward(func) + ))); + } +#endif + } + +namespace detail +{ + template + struct mfallbacker_to + { + T value_; + typedef T result_type; + mfallbacker_to(BOOST_THREAD_RV_REF(T) v) + : value_(boost::move(v)) + {} + + T operator()(BOOST_THREAD_FUTURE fut) { + return fut.get_or(boost::move(value_)); + } + }; + template + struct cfallbacker_to + { + T value_; + typedef T result_type; + cfallbacker_to(T const& v) + : value_(v) + {} + + T operator()(BOOST_THREAD_FUTURE fut) const { + return fut.get_or(value_); + + } + }; +} + //////////////////////////////// + // future future::fallback_to(R&& v); + //////////////////////////////// + + template + template + inline typename boost::disable_if< is_void, BOOST_THREAD_FUTURE >::type + BOOST_THREAD_FUTURE::fallback_to(BOOST_THREAD_RV_REF(R2) v) { + return then(detail::mfallbacker_to(boost::move(v))); + } + + template + template + inline typename boost::disable_if< is_void, BOOST_THREAD_FUTURE >::type + BOOST_THREAD_FUTURE::fallback_to(R2 const& v) { + return then(detail::cfallbacker_to(v)); + } + +#endif + +#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP +namespace detail +{ + ///////////////////////// + /// future_unwrap_shared_state + ///////////////////////// + + template + struct future_unwrap_shared_state: shared_state + { + F wrapped; + typename F::value_type unwrapped; + public: + explicit future_unwrap_shared_state(BOOST_THREAD_RV_REF(F) f) + : wrapped(boost::move(f)) { + } + + void launch_continuation() + { + boost::unique_lock lk(this->mutex); + // assert(wrapped.is_ready()); + if (! unwrapped.valid() ) + { + if (wrapped.has_exception()) { + this->mark_exceptional_finish_internal(wrapped.get_exception_ptr(), lk); + } else { + unwrapped = wrapped.get(); + if (unwrapped.valid()) + { + lk.unlock(); + boost::unique_lock lk2(unwrapped.future_->mutex); + unwrapped.future_->set_continuation_ptr(this->shared_from_this(), lk2); + } else { + this->mark_exceptional_finish_internal(boost::copy_exception(future_uninitialized()), lk); + } + } + } else { + // assert(unwrapped.is_ready()); + if (unwrapped.has_exception()) { + this->mark_exceptional_finish_internal(unwrapped.get_exception_ptr(), lk); + } else { + this->mark_finished_with_result_internal(unwrapped.get(), lk); + } + } + } + }; + + template + struct future_unwrap_shared_state: shared_state + { + F wrapped; + typename F::value_type unwrapped; + public: + explicit future_unwrap_shared_state(BOOST_THREAD_RV_REF(F) f) + : wrapped(boost::move(f)) { + } + + void launch_continuation() + { + boost::unique_lock lk(this->mutex); + // assert(wrapped.is_ready()); + if (! unwrapped.valid() ) + { + if (wrapped.has_exception()) { + this->mark_exceptional_finish_internal(wrapped.get_exception_ptr(), lk); + } else { + unwrapped = wrapped.get(); + if (unwrapped.valid()) + { + lk.unlock(); + boost::unique_lock lk2(unwrapped.future_->mutex); + unwrapped.future_->set_continuation_ptr(this->shared_from_this(), lk2); + } else { + this->mark_exceptional_finish_internal(boost::copy_exception(future_uninitialized()), lk); + } + } + } else { + // assert(unwrapped.is_ready()); + if (unwrapped.has_exception()) { + this->mark_exceptional_finish_internal(unwrapped.get_exception_ptr(), lk); + } else { + this->mark_finished_with_result_internal(lk); + } + } + } + }; + + template + BOOST_THREAD_FUTURE + make_future_unwrap_shared_state(boost::unique_lock &lock, BOOST_THREAD_RV_REF(F) f) { + shared_ptr > + h(new future_unwrap_shared_state(boost::move(f))); + h->wrapped.future_->set_continuation_ptr(h, lock); + + return BOOST_THREAD_FUTURE(h); + } +} + + template + inline BOOST_THREAD_FUTURE::BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE >) other) + : base_type(other.unwrap()) {} + + template + BOOST_THREAD_FUTURE + BOOST_THREAD_FUTURE >::unwrap() + { + BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized()); + + // keep state alive as we move ourself but hold the lock + shared_ptr sentinel(this->future_); + boost::unique_lock lock(sentinel->mutex); + + return boost::detail::make_future_unwrap_shared_state >, R2>(lock, boost::move(*this)); + } +#endif + +#if defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY +namespace detail +{ + struct input_iterator_tag {}; + struct vector_tag {}; + struct values_tag {}; + template + struct alias_t { typedef T type; }; + + BOOST_CONSTEXPR_OR_CONST input_iterator_tag input_iterator_tag_value = {}; + BOOST_CONSTEXPR_OR_CONST vector_tag vector_tag_value = {}; + BOOST_CONSTEXPR_OR_CONST values_tag values_tag_value = {}; + //////////////////////////////// + // detail::future_async_when_all_shared_state + //////////////////////////////// + template + struct future_when_all_vector_shared_state: future_async_shared_state_base > + { + typedef csbl::vector vector_type; + typedef typename F::value_type value_type; + vector_type vec_; + + static void run(shared_ptr that_) { + future_when_all_vector_shared_state* that = static_cast(that_.get()); + try { + boost::wait_for_all(that->vec_.begin(), that->vec_.end()); + that->mark_finished_with_result(boost::move(that->vec_)); + } catch(...) { + that->mark_exceptional_finish(); + } + } + bool run_deferred() { + + bool res = false; + for (typename csbl::vector::iterator it = vec_.begin(); it != vec_.end(); ++it) { + if (! it->run_if_is_deferred()) + { + res = true; + } + } + return res; + } + void init() { + if (! run_deferred()) + { + future_when_all_vector_shared_state::run(this->shared_from_this()); + return; + } +#ifdef BOOST_THREAD_FUTURE_BLOCKING + this->thr_ = boost::thread(&future_when_all_vector_shared_state::run, this->shared_from_this()); +#else + boost::thread(&future_when_all_vector_shared_state::run, this->shared_from_this()).detach(); +#endif + } + + public: + template< typename InputIterator> + future_when_all_vector_shared_state(input_iterator_tag, InputIterator first, InputIterator last) + : vec_(std::make_move_iterator(first), std::make_move_iterator(last)) + { + } + + future_when_all_vector_shared_state(vector_tag, BOOST_THREAD_RV_REF(csbl::vector) v) + : vec_(boost::move(v)) + { + } + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + future_when_all_vector_shared_state(values_tag, BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures) { + vec_.push_back(boost::forward(f)); + typename alias_t::type{ + ( //first part of magic unpacker + vec_.push_back(boost::forward(futures)),'0' + )..., '0' + }; //second part of magic unpacker + } +#endif + + ~future_when_all_vector_shared_state() {} + }; + + //////////////////////////////// + // detail::future_async_when_any_shared_state + //////////////////////////////// + template + struct future_when_any_vector_shared_state: future_async_shared_state_base > + { + typedef csbl::vector vector_type; + typedef typename F::value_type value_type; + vector_type vec_; + + static void run(shared_ptr that_) + { + future_when_any_vector_shared_state* that = static_cast(that_.get()); + try { + boost::wait_for_any(that->vec_.begin(), that->vec_.end()); + that->mark_finished_with_result(boost::move(that->vec_)); + } catch(...) { + that->mark_exceptional_finish(); + } + } + bool run_deferred() { + + for (typename csbl::vector::iterator it = vec_.begin(); it != vec_.end(); ++it) { + if (it->run_if_is_deferred_or_ready()) + { + return true; + } + } + return false; + } + void init() { + if (run_deferred()) + { + future_when_any_vector_shared_state::run(this->shared_from_this()); + return; + } + +#ifdef BOOST_THREAD_FUTURE_BLOCKING + this->thr_ = boost::thread(&future_when_any_vector_shared_state::run, this->shared_from_this()); +#else + boost::thread(&future_when_any_vector_shared_state::run, this->shared_from_this()).detach(); +#endif + } + + public: + template< typename InputIterator> + future_when_any_vector_shared_state(input_iterator_tag, InputIterator first, InputIterator last) + : vec_(std::make_move_iterator(first), std::make_move_iterator(last)) + { + } + + future_when_any_vector_shared_state(vector_tag, BOOST_THREAD_RV_REF(csbl::vector) v) + : vec_(boost::move(v)) + { + } + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + future_when_any_vector_shared_state(values_tag, + BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures + ) { + vec_.push_back(boost::forward(f)); + typename alias_t::type{ + ( //first part of magic unpacker + vec_.push_back(boost::forward(futures)) + ,'0' + )..., + '0' + }; //second part of magic unpacker + } +#endif + + ~future_when_any_vector_shared_state() {} + }; + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + struct wait_for_all_fctr { + template + void operator()(T&&... v) { + boost::wait_for_all(boost::forward(v)...); + } + }; + + struct wait_for_any_fctr { + template + void operator()(T&&... v) { + boost::wait_for_any(boost::forward(v)...); + } + }; + + + template ::value> + struct accumulate_run_if_is_deferred { + bool operator ()(Tuple& t) + { + return (! csbl::get(t).run_if_is_deferred()) || accumulate_run_if_is_deferred()(t); + } + }; + template + struct accumulate_run_if_is_deferred { + bool operator ()(Tuple& ) + { + return false; + } + }; + + + template< typename Tuple, typename T0, typename ...T> + struct future_when_all_tuple_shared_state: future_async_shared_state_base + { + Tuple tup_; + typedef typename make_tuple_indices<1+sizeof...(T)>::type Index; + + static void run(shared_ptr that_) { + future_when_all_tuple_shared_state* that = static_cast(that_.get()); + try { + // TODO make use of apply(that->tup_, boost::detail::wait_for_all_fctor()); + that->wait_for_all(Index()); + + that->mark_finished_with_result(boost::move(that->tup_)); + } catch(...) { + that->mark_exceptional_finish(); + } + } + + template + void wait_for_all(tuple_indices) { +#if defined BOOST_THREAD_PROVIDES_INVOKE + return invoke(wait_for_all_fctr(), csbl::get(tup_)...); +#else + return wait_for_all_fctr()(csbl::get(tup_)...); +#endif + } + + bool run_deferred() { + + return accumulate_run_if_is_deferred()(tup_); + } + void init() { + if (! run_deferred()) + { + future_when_all_tuple_shared_state::run(this->shared_from_this()); + return; + } +#ifdef BOOST_THREAD_FUTURE_BLOCKING + this->thr_ = boost::thread(&future_when_all_tuple_shared_state::run, this->shared_from_this()); +#else + boost::thread(&future_when_all_tuple_shared_state::run, this->shared_from_this()).detach(); +#endif + + } + public: + template< typename F, typename ...Fs> + future_when_all_tuple_shared_state(values_tag, BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Fs) ... futures) : + tup_(boost::csbl::make_tuple(boost::forward(f), boost::forward(futures)...)) + { + } + + ~future_when_all_tuple_shared_state() {} + + }; + + + template ::value> + struct apply_any_run_if_is_deferred_or_ready { + bool operator ()(Tuple& t) + { + if (csbl::get(t).run_if_is_deferred_or_ready()) return true; + return apply_any_run_if_is_deferred_or_ready()(t); + } + }; + template + struct apply_any_run_if_is_deferred_or_ready { + bool operator ()(Tuple& ) + { + return false; + } + }; + + template< typename Tuple, typename T0, typename ...T > + struct future_when_any_tuple_shared_state: future_async_shared_state_base + { + Tuple tup_; + typedef typename make_tuple_indices<1+sizeof...(T)>::type Index; + + static void run(shared_ptr that_) + { + future_when_any_tuple_shared_state* that = static_cast(that_.get()); + try { + // TODO make use of apply(that->tup_, wait_for_any_fctr); + that->wait_for_any(Index()); + + that->mark_finished_with_result(boost::move(that->tup_)); + } catch(...) { + that->mark_exceptional_finish(); + } + } + template + void wait_for_any(tuple_indices) { +#if defined BOOST_THREAD_PROVIDES_INVOKE + return invoke(wait_for_any_fctr(), csbl::get(tup_)...); +#else + return wait_for_any_fctr()(csbl::get(tup_)...); +#endif + } + bool run_deferred() { + return apply_any_run_if_is_deferred_or_ready()(tup_); + } + void init() { + if (run_deferred()) + { + future_when_any_tuple_shared_state::run(this->shared_from_this()); + return; + } + +#ifdef BOOST_THREAD_FUTURE_BLOCKING + this->thr_ = boost::thread(&future_when_any_tuple_shared_state::run, this->shared_from_this()); +#else + boost::thread(&future_when_any_tuple_shared_state::run, this->shared_from_this()).detach(); +#endif + } + + public: + template< typename F, typename ...Fs> + future_when_any_tuple_shared_state(values_tag, + BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Fs) ... futures + ) : + tup_(boost::csbl::make_tuple(boost::forward(f), boost::forward(futures)...)) + { + } + + ~future_when_any_tuple_shared_state() {} + }; +#endif + +} + + template< typename InputIterator> + typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_all(InputIterator first, InputIterator last) { + typedef typename InputIterator::value_type value_type; + typedef csbl::vector container_type; + typedef detail::future_when_all_vector_shared_state factory_type; + + if (first==last) return make_ready_future(container_type()); + shared_ptr + h(new factory_type(detail::input_iterator_tag_value, first,last)); + h->init(); + return BOOST_THREAD_FUTURE(h); + } + + inline BOOST_THREAD_FUTURE > when_all() { + return make_ready_future(csbl::tuple<>()); + } + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_all(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures) { + typedef csbl::tuple::type, typename decay::type...> container_type; + typedef detail::future_when_all_tuple_shared_state::type, typename decay::type...> factory_type; + + shared_ptr + h(new factory_type(detail::values_tag_value, boost::forward(f), boost::forward(futures)...)); + h->init(); + return BOOST_THREAD_FUTURE(h); + } +#endif + + template< typename InputIterator> + typename boost::disable_if, + BOOST_THREAD_FUTURE > + >::type + when_any(InputIterator first, InputIterator last) { + typedef typename InputIterator::value_type value_type; + typedef csbl::vector container_type; + typedef detail::future_when_any_vector_shared_state factory_type; + + if (first==last) return make_ready_future(container_type()); + shared_ptr + h(new factory_type(detail::input_iterator_tag_value, first,last)); + h->init(); + return BOOST_THREAD_FUTURE(h); + } + + inline BOOST_THREAD_FUTURE > when_any() { + return make_ready_future(csbl::tuple<>()); + } + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template< typename T0, typename ...T> + BOOST_THREAD_FUTURE::type, typename decay::type...> > + when_any(BOOST_THREAD_FWD_REF(T0) f, BOOST_THREAD_FWD_REF(T) ... futures) { + typedef csbl::tuple::type, typename decay::type...> container_type; + typedef detail::future_when_any_tuple_shared_state::type, typename decay::type...> factory_type; + + shared_ptr + h(new factory_type(detail::values_tag_value, boost::forward(f), boost::forward(futures)...)); + h->init(); + return BOOST_THREAD_FUTURE(h); + } +#endif +#endif // BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY +} + +#endif // BOOST_NO_EXCEPTIONS +#endif // header diff --git a/boost/thread/futures/future_error.hpp b/boost/thread/futures/future_error.hpp new file mode 100644 index 0000000..6212dee --- /dev/null +++ b/boost/thread/futures/future_error.hpp @@ -0,0 +1,98 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2015 Vicente J. Botet Escriba +// +// 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_THREAD_FUTURES_FUTURE_ERROR_HPP +#define BOOST_THREAD_FUTURES_FUTURE_ERROR_HPP + +#include + +#include +#include + +#include + +namespace boost +{ + class BOOST_SYMBOL_VISIBLE future_error + : public std::logic_error + { + system::error_code ec_; + public: + future_error(system::error_code ec) + : logic_error(ec.message()), + ec_(ec) + { + } + + const system::error_code& code() const BOOST_NOEXCEPT + { + return ec_; + } + }; + + class BOOST_SYMBOL_VISIBLE future_uninitialized: + public future_error + { + public: + future_uninitialized() : + future_error(system::make_error_code(future_errc::no_state)) + {} + }; + class BOOST_SYMBOL_VISIBLE broken_promise: + public future_error + { + public: + broken_promise(): + future_error(system::make_error_code(future_errc::broken_promise)) + {} + }; + class BOOST_SYMBOL_VISIBLE future_already_retrieved: + public future_error + { + public: + future_already_retrieved(): + future_error(system::make_error_code(future_errc::future_already_retrieved)) + {} + }; + class BOOST_SYMBOL_VISIBLE promise_already_satisfied: + public future_error + { + public: + promise_already_satisfied(): + future_error(system::make_error_code(future_errc::promise_already_satisfied)) + {} + }; + + class BOOST_SYMBOL_VISIBLE task_already_started: + public future_error + { + public: + task_already_started(): + future_error(system::make_error_code(future_errc::promise_already_satisfied)) + {} + }; + + class BOOST_SYMBOL_VISIBLE task_moved: + public future_error + { + public: + task_moved(): + future_error(system::make_error_code(future_errc::no_state)) + {} + }; + + class promise_moved: + public future_error + { + public: + promise_moved(): + future_error(system::make_error_code(future_errc::no_state)) + {} + }; +} + +#endif // header diff --git a/boost/thread/futures/future_error_code.hpp b/boost/thread/futures/future_error_code.hpp new file mode 100644 index 0000000..7c8b6f2 --- /dev/null +++ b/boost/thread/futures/future_error_code.hpp @@ -0,0 +1,61 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2012,2015 Vicente J. Botet Escriba +// +// 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_THREAD_FUTURES_FUTURE_ERROR_CODE_HPP +#define BOOST_THREAD_FUTURES_FUTURE_ERROR_CODE_HPP + +#include +#include +#include +#include + +namespace boost +{ + + //enum class future_errc + BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc) + { + broken_promise = 1, + future_already_retrieved, + promise_already_satisfied, + no_state + } + BOOST_SCOPED_ENUM_DECLARE_END(future_errc) + + namespace system + { + template <> + struct BOOST_SYMBOL_VISIBLE is_error_code_enum< ::boost::future_errc> : public true_type {}; + + #ifdef BOOST_NO_CXX11_SCOPED_ENUMS + template <> + struct BOOST_SYMBOL_VISIBLE is_error_code_enum< ::boost::future_errc::enum_type> : public true_type { }; + #endif + } // system + + BOOST_THREAD_DECL + const system::error_category& future_category() BOOST_NOEXCEPT; + + namespace system + { + inline + error_code + make_error_code(future_errc e) BOOST_NOEXCEPT + { + return error_code(underlying_cast(e), boost::future_category()); + } + + inline + error_condition + make_error_condition(future_errc e) BOOST_NOEXCEPT + { + return error_condition(underlying_cast(e), boost::future_category()); + } + } // system +} // boost + +#endif // header diff --git a/boost/thread/futures/future_status.hpp b/boost/thread/futures/future_status.hpp new file mode 100644 index 0000000..383ac46 --- /dev/null +++ b/boost/thread/futures/future_status.hpp @@ -0,0 +1,30 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2015 Vicente J. Botet Escriba +// +// 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_THREAD_FUTURES_FUTURE_STATUS_HPP +#define BOOST_THREAD_FUTURES_FUTURE_STATUS_HPP + +#include +#include + +namespace boost +{ + //enum class future_status + BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_status) + { + ready, + timeout, + deferred + } + BOOST_SCOPED_ENUM_DECLARE_END(future_status) + namespace future_state + { + enum state { uninitialized, waiting, ready, moved, deferred }; + } +} + +#endif // header diff --git a/boost/thread/futures/is_future_type.hpp b/boost/thread/futures/is_future_type.hpp new file mode 100644 index 0000000..df7a680 --- /dev/null +++ b/boost/thread/futures/is_future_type.hpp @@ -0,0 +1,21 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2015 Vicente J. Botet Escriba +// +// 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_THREAD_FUTURES_IS_FUTURE_TYPE_HPP +#define BOOST_THREAD_FUTURES_IS_FUTURE_TYPE_HPP + +#include + +namespace boost +{ + template + struct is_future_type : false_type + { + }; +} + +#endif // header diff --git a/boost/thread/futures/launch.hpp b/boost/thread/futures/launch.hpp new file mode 100644 index 0000000..329f40d --- /dev/null +++ b/boost/thread/futures/launch.hpp @@ -0,0 +1,32 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2015 Vicente J. Botet Escriba +// +// 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_THREAD_FUTURES_LAUNCH_HPP +#define BOOST_THREAD_FUTURES_LAUNCH_HPP + +#include +#include + +namespace boost +{ + //enum class launch + BOOST_SCOPED_ENUM_DECLARE_BEGIN(launch) + { + none = 0, + async = 1, + deferred = 2, +#ifdef BOOST_THREAD_PROVIDES_EXECUTORS + executor = 4, +#endif + inherit = 8, + sync = 16, + any = async | deferred + } + BOOST_SCOPED_ENUM_DECLARE_END(launch) +} + +#endif // header diff --git a/boost/thread/futures/wait_for_all.hpp b/boost/thread/futures/wait_for_all.hpp new file mode 100644 index 0000000..398eb4a --- /dev/null +++ b/boost/thread/futures/wait_for_all.hpp @@ -0,0 +1,74 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2015 Vicente J. Botet Escriba +// +// 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_THREAD_FUTURES_WAIT_FOR_ALL_HPP +#define BOOST_THREAD_FUTURES_WAIT_FOR_ALL_HPP + +#include +#include + +#include + +namespace boost +{ + template + typename boost::disable_if,void>::type wait_for_all(Iterator begin,Iterator end) + { + for(Iterator current=begin;current!=end;++current) + { + current->wait(); + } + } + +#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES + template + typename boost::enable_if,void>::type wait_for_all(F1& f1,F2& f2) + { + f1.wait(); + f2.wait(); + } + + template + void wait_for_all(F1& f1,F2& f2,F3& f3) + { + f1.wait(); + f2.wait(); + f3.wait(); + } + + template + void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4) + { + f1.wait(); + f2.wait(); + f3.wait(); + f4.wait(); + } + + template + void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5) + { + f1.wait(); + f2.wait(); + f3.wait(); + f4.wait(); + f5.wait(); + } +#else + template + typename boost::enable_if,void>::type wait_for_all(F1& f1, Fs&... fs) + { + bool dummy[] = { (f1.wait(), true), (fs.wait(), true)... }; + + // prevent unused parameter warning + (void) dummy; + } +#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)} + +} + +#endif // header diff --git a/boost/thread/futures/wait_for_any.hpp b/boost/thread/futures/wait_for_any.hpp new file mode 100644 index 0000000..68ec065 --- /dev/null +++ b/boost/thread/futures/wait_for_any.hpp @@ -0,0 +1,162 @@ +// (C) Copyright 2008-10 Anthony Williams +// (C) Copyright 2011-2015 Vicente J. Botet Escriba +// +// 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_THREAD_FUTURES_WAIT_FOR_ANY_HPP +#define BOOST_THREAD_FUTURES_WAIT_FOR_ANY_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +namespace boost +{ + namespace detail + { + template + class waiter_for_any_in_seq + { + struct registered_waiter; + typedef std::vector::size_type count_type; + + struct registered_waiter + { + typedef Future future_type; + future_type* future_; + typedef typename Future::notify_when_ready_handle notify_when_ready_handle; + notify_when_ready_handle handle; + count_type index; + + registered_waiter(future_type & a_future, + notify_when_ready_handle handle_, count_type index_) : + future_(&a_future), handle(handle_), index(index_) + { + } + }; + + struct all_futures_lock + { +#ifdef _MANAGED + typedef std::ptrdiff_t count_type_portable; +#else + typedef count_type count_type_portable; +#endif + count_type_portable count; + boost::scoped_array > locks; + + all_futures_lock(std::vector& waiters) : + count(waiters.size()), locks(new boost::unique_lock[count]) + { + for (count_type_portable i = 0; i < count; ++i) + { + locks[i] = BOOST_THREAD_MAKE_RV_REF(boost::unique_lock(waiters[i].future_->mutex())); + } + } + + void lock() + { + boost::lock(locks.get(), locks.get() + count); + } + + void unlock() + { + for (count_type_portable i = 0; i < count; ++i) + { + locks[i].unlock(); + } + } + }; + + boost::condition_variable_any cv; + std::vector waiters_; + count_type future_count; + + public: + waiter_for_any_in_seq() : + future_count(0) + { + } + + template + void add(F& f) + { + if (f.valid()) + { + registered_waiter waiter(f, f.notify_when_ready(cv), future_count); + try + { + waiters_.push_back(waiter); + } + catch (...) + { + f.future_->unnotify_when_ready(waiter.handle); + throw; + } + ++future_count; + } + } + +#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES + template + void add(F1& f1, Fs&... fs) + { + add(f1); + add(fs...); + } +#endif + + count_type wait() + { + all_futures_lock lk(waiters_); + for (;;) + { + for (count_type i = 0; i < waiters_.size(); ++i) + { + if (waiters_[i].future_->is_ready(lk.locks[i])) + { + return waiters_[i].index; + } + } + cv.wait(lk); + } + } + + ~waiter_for_any_in_seq() + { + for (count_type i = 0; i < waiters_.size(); ++i) + { + waiters_[i].future_->unnotify_when_ready(waiters_[i].handle); + } + } + }; + } + + template + typename boost::disable_if , Iterator>::type wait_for_any(Iterator begin, Iterator end) + { + if (begin == end) return end; + + detail::waiter_for_any_in_seq::value_type> waiter; + for (Iterator current = begin; current != end; ++current) + { + waiter.add(*current); + } + return boost::next(begin, waiter.wait()); + } +} + +#endif // header diff --git a/boost/thread/interruption.hpp b/boost/thread/interruption.hpp new file mode 100644 index 0000000..c91bb28 --- /dev/null +++ b/boost/thread/interruption.hpp @@ -0,0 +1,22 @@ +// (C) Copyright 2013 Vicente J. Botet Escriba +// 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_THREAD_INTERRUPTION_HPP +#define BOOST_THREAD_INTERRUPTION_HPP + +#include + +namespace boost +{ + namespace this_thread + { + void BOOST_THREAD_DECL interruption_point(); + bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT; + bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT; + } +} + +#endif // header diff --git a/boost/thread/is_locked_by_this_thread.hpp b/boost/thread/is_locked_by_this_thread.hpp new file mode 100644 index 0000000..6344c0f --- /dev/null +++ b/boost/thread/is_locked_by_this_thread.hpp @@ -0,0 +1,39 @@ +// (C) Copyright 2012 Vicente J. Botet Escriba +// 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_THREAD_IS_LOCKED_BY_THIS_THREAD_HPP +#define BOOST_THREAD_IS_LOCKED_BY_THIS_THREAD_HPP + +#include + +#include + +namespace boost +{ + template + class testable_mutex; + + /** + * Overloaded function used to check if the mutex is locked when it is testable and do nothing otherwise. + * + * This function is used usually to assert the pre-condition when the function can only be called when the mutex + * must be locked by the current thread. + */ + template + bool is_locked_by_this_thread(testable_mutex const& mtx) + { + return mtx.is_locked_by_this_thread(); + } + template + bool is_locked_by_this_thread(Lockable const&) + { + return true; + } +} + +#include + +#endif // header diff --git a/boost/thread/lock_algorithms.hpp b/boost/thread/lock_algorithms.hpp new file mode 100644 index 0000000..7a55f92 --- /dev/null +++ b/boost/thread/lock_algorithms.hpp @@ -0,0 +1,468 @@ +// 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) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_ALGORITHMS_HPP +#define BOOST_THREAD_LOCK_ALGORITHMS_HPP + +#include +#include +#include + +#include +#include + +#include + +namespace boost +{ + namespace detail + { + template + unsigned try_lock_internal(MutexType1& m1, MutexType2& m2) + { + boost::unique_lock l1(m1, boost::try_to_lock); + if (!l1) + { + return 1; + } + if (!m2.try_lock()) + { + return 2; + } + l1.release(); + return 0; + } + + template + unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3) + { + boost::unique_lock l1(m1, boost::try_to_lock); + if (!l1) + { + return 1; + } + if (unsigned const failed_lock=try_lock_internal(m2,m3)) + { + return failed_lock + 1; + } + l1.release(); + return 0; + } + + template + unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4) + { + boost::unique_lock l1(m1, boost::try_to_lock); + if (!l1) + { + return 1; + } + if (unsigned const failed_lock=try_lock_internal(m2,m3,m4)) + { + return failed_lock + 1; + } + l1.release(); + return 0; + } + + template + unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5) + { + boost::unique_lock l1(m1, boost::try_to_lock); + if (!l1) + { + return 1; + } + if (unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) + { + return failed_lock + 1; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1, MutexType2& m2) + { + boost::unique_lock l1(m1); + if (!m2.try_lock()) + { + return 1; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3) + { + boost::unique_lock l1(m1); + if (unsigned const failed_lock=try_lock_internal(m2,m3)) + { + return failed_lock; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4) + { + boost::unique_lock l1(m1); + if (unsigned const failed_lock=try_lock_internal(m2,m3,m4)) + { + return failed_lock; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5) + { + boost::unique_lock l1(m1); + if (unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) + { + return failed_lock; + } + l1.release(); + return 0; + } + } + + namespace detail + { + template + struct is_mutex_type_wrapper + { + }; + + template + void lock_impl(MutexType1& m1, MutexType2& m2, is_mutex_type_wrapper ) + { + unsigned const lock_count = 2; + unsigned lock_first = 0; + for (;;) + { + switch (lock_first) + { + case 0: + lock_first = detail::lock_helper(m1, m2); + if (!lock_first) return; + break; + case 1: + lock_first = detail::lock_helper(m2, m1); + if (!lock_first) return; + lock_first = (lock_first + 1) % lock_count; + break; + } + } + } + + template + void lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper ); + } + + template + void lock(MutexType1& m1, MutexType2& m2) + { + detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + void lock(const MutexType1& m1, MutexType2& m2) + { + detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + void lock(MutexType1& m1, const MutexType2& m2) + { + detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + void lock(const MutexType1& m1, const MutexType2& m2) + { + detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + void lock(MutexType1& m1, MutexType2& m2, MutexType3& m3) + { + unsigned const lock_count = 3; + unsigned lock_first = 0; + for (;;) + { + switch (lock_first) + { + case 0: + lock_first = detail::lock_helper(m1, m2, m3); + if (!lock_first) return; + break; + case 1: + lock_first = detail::lock_helper(m2, m3, m1); + if (!lock_first) return; + lock_first = (lock_first + 1) % lock_count; + break; + case 2: + lock_first = detail::lock_helper(m3, m1, m2); + if (!lock_first) return; + lock_first = (lock_first + 2) % lock_count; + break; + } + } + } + + template + void lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4) + { + unsigned const lock_count = 4; + unsigned lock_first = 0; + for (;;) + { + switch (lock_first) + { + case 0: + lock_first = detail::lock_helper(m1, m2, m3, m4); + if (!lock_first) return; + break; + case 1: + lock_first = detail::lock_helper(m2, m3, m4, m1); + if (!lock_first) return; + lock_first = (lock_first + 1) % lock_count; + break; + case 2: + lock_first = detail::lock_helper(m3, m4, m1, m2); + if (!lock_first) return; + lock_first = (lock_first + 2) % lock_count; + break; + case 3: + lock_first = detail::lock_helper(m4, m1, m2, m3); + if (!lock_first) return; + lock_first = (lock_first + 3) % lock_count; + break; + } + } + } + + template + void lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5) + { + unsigned const lock_count = 5; + unsigned lock_first = 0; + for (;;) + { + switch (lock_first) + { + case 0: + lock_first = detail::lock_helper(m1, m2, m3, m4, m5); + if (!lock_first) return; + break; + case 1: + lock_first = detail::lock_helper(m2, m3, m4, m5, m1); + if (!lock_first) return; + lock_first = (lock_first + 1) % lock_count; + break; + case 2: + lock_first = detail::lock_helper(m3, m4, m5, m1, m2); + if (!lock_first) return; + lock_first = (lock_first + 2) % lock_count; + break; + case 3: + lock_first = detail::lock_helper(m4, m5, m1, m2, m3); + if (!lock_first) return; + lock_first = (lock_first + 3) % lock_count; + break; + case 4: + lock_first = detail::lock_helper(m5, m1, m2, m3, m4); + if (!lock_first) return; + lock_first = (lock_first + 4) % lock_count; + break; + } + } + } + + namespace detail + { + template ::value> + struct try_lock_impl_return + { + typedef int type; + }; + + template + struct try_lock_impl_return + { + typedef Iterator type; + }; + + template + int try_lock_impl(MutexType1& m1, MutexType2& m2, is_mutex_type_wrapper ) + { + return ((int) detail::try_lock_internal(m1, m2)) - 1; + } + + template + Iterator try_lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper ); + } + + template + typename detail::try_lock_impl_return::type try_lock(MutexType1& m1, MutexType2& m2) + { + return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + typename detail::try_lock_impl_return::type try_lock(const MutexType1& m1, MutexType2& m2) + { + return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + typename detail::try_lock_impl_return::type try_lock(MutexType1& m1, const MutexType2& m2) + { + return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + typename detail::try_lock_impl_return::type try_lock(const MutexType1& m1, const MutexType2& m2) + { + return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3) + { + return ((int) detail::try_lock_internal(m1, m2, m3)) - 1; + } + + template + int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4) + { + return ((int) detail::try_lock_internal(m1, m2, m3, m4)) - 1; + } + + template + int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5) + { + return ((int) detail::try_lock_internal(m1, m2, m3, m4, m5)) - 1; + } + + namespace detail + { + template + struct range_lock_guard + { + Iterator begin; + Iterator end; + + range_lock_guard(Iterator begin_, Iterator end_) : + begin(begin_), end(end_) + { + boost::lock(begin, end); + } + + void release() + { + begin = end; + } + + ~range_lock_guard() + { + for (; begin != end; ++begin) + { + begin->unlock(); + } + } + }; + + template + Iterator try_lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper ) + + { + if (begin == end) + { + return end; + } + typedef typename std::iterator_traits::value_type lock_type; + unique_lock guard(*begin, try_to_lock); + + if (!guard.owns_lock()) + { + return begin; + } + Iterator const failed = boost::try_lock(++begin, end); + if (failed == end) + { + guard.release(); + } + + return failed; + } + } + + namespace detail + { + template + void lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper ) + { + typedef typename std::iterator_traits::value_type lock_type; + + if (begin == end) + { + return; + } + bool start_with_begin = true; + Iterator second = begin; + ++second; + Iterator next = second; + + for (;;) + { + unique_lock begin_lock(*begin, defer_lock); + if (start_with_begin) + { + begin_lock.lock(); + Iterator const failed_lock = boost::try_lock(next, end); + if (failed_lock == end) + { + begin_lock.release(); + return; + } + start_with_begin = false; + next = failed_lock; + } + else + { + detail::range_lock_guard guard(next, end); + if (begin_lock.try_lock()) + { + Iterator const failed_lock = boost::try_lock(second, next); + if (failed_lock == next) + { + begin_lock.release(); + guard.release(); + return; + } + start_with_begin = false; + next = failed_lock; + } + else + { + start_with_begin = true; + next = second; + } + } + } + } + + } + +} +#include + +#endif diff --git a/boost/thread/lock_guard.hpp b/boost/thread/lock_guard.hpp new file mode 100644 index 0000000..3f9ba9b --- /dev/null +++ b/boost/thread/lock_guard.hpp @@ -0,0 +1,88 @@ +// 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) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_GUARD_HPP +#define BOOST_THREAD_LOCK_GUARD_HPP + +#include +#include +#include +#include +#include +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include +#include +#endif + +#include + +namespace boost +{ + + template + class BOOST_THREAD_SCOPED_CAPABILITY lock_guard + { + private: + Mutex& m; + + public: + typedef Mutex mutex_type; + BOOST_THREAD_NO_COPYABLE( lock_guard ) + + explicit lock_guard(Mutex& m_) BOOST_THREAD_ACQUIRE(m_) : + m(m_) + { + m.lock(); + } + + lock_guard(Mutex& m_, adopt_lock_t) BOOST_THREAD_REQUIRES(m_) : + m(m_) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + +#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST + lock_guard(std::initializer_list > l_) : + m(*(const_cast*>(l_.begin())->m)) + { + m.lock(); + } + + lock_guard(std::initializer_list > l_) : + m(*(const_cast*>(l_.begin())->m)) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + +#endif + ~lock_guard() BOOST_THREAD_RELEASE() + { + m.unlock(); + } + }; + + +#if ! defined BOOST_THREAD_NO_MAKE_LOCK_GUARD + template + lock_guard make_lock_guard(Lockable& mtx) + { + return { thread_detail::lockable_wrapper(mtx) }; + } + template + lock_guard make_lock_guard(Lockable& mtx, adopt_lock_t) + { + return { thread_detail::lockable_adopt_wrapper(mtx) }; + } +#endif +} + +#include + +#endif diff --git a/boost/thread/lock_options.hpp b/boost/thread/lock_options.hpp new file mode 100644 index 0000000..68899ca --- /dev/null +++ b/boost/thread/lock_options.hpp @@ -0,0 +1,31 @@ +// 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) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_OPTIONS_HPP +#define BOOST_THREAD_LOCK_OPTIONS_HPP + +#include + +namespace boost +{ + struct defer_lock_t + { + }; + struct try_to_lock_t + { + }; + struct adopt_lock_t + { + }; + + BOOST_CONSTEXPR_OR_CONST defer_lock_t defer_lock = {}; + BOOST_CONSTEXPR_OR_CONST try_to_lock_t try_to_lock = {}; + BOOST_CONSTEXPR_OR_CONST adopt_lock_t adopt_lock = {}; + +} +#include + +#endif diff --git a/boost/thread/lock_types.hpp b/boost/thread/lock_types.hpp new file mode 100644 index 0000000..9b8c57c --- /dev/null +++ b/boost/thread/lock_types.hpp @@ -0,0 +1,1230 @@ +// 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) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_TYPES_HPP +#define BOOST_THREAD_LOCK_TYPES_HPP + +#include +#include +#include +#include +#include +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include +#endif +#include + +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif +#include + +#include + +namespace boost +{ + struct xtime; + + template + class shared_lock; + + template + class upgrade_lock; + + template + class unique_lock; + + namespace detail + { + template + class try_lock_wrapper; + } + +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + namespace sync + { + template + struct is_basic_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template + struct is_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template + struct is_basic_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template + struct is_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template + struct is_basic_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template + struct is_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template + struct is_basic_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template + struct is_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + } +#endif + + + template + class unique_lock + { + private: + Mutex* m; + bool is_locked; + + private: + explicit unique_lock(upgrade_lock&); + unique_lock& operator=(upgrade_lock& other); + public: + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY( unique_lock) + +#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) + unique_lock(const volatile unique_lock&); +#endif +#endif + unique_lock()BOOST_NOEXCEPT : + m(0),is_locked(false) + {} + + explicit unique_lock(Mutex& m_) : + m(&m_), is_locked(false) + { + lock(); + } + unique_lock(Mutex& m_, adopt_lock_t) : + m(&m_), is_locked(true) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + unique_lock(Mutex& m_, defer_lock_t)BOOST_NOEXCEPT: + m(&m_),is_locked(false) + {} + unique_lock(Mutex& m_, try_to_lock_t) : + m(&m_), is_locked(false) + { + try_lock(); + } +#if defined BOOST_THREAD_USES_DATETIME + template + unique_lock(Mutex& m_,TimeDuration const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } + unique_lock(Mutex& m_,system_time const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + unique_lock(Mutex& mtx, const chrono::time_point& t) + : m(&mtx), is_locked(mtx.try_lock_until(t)) + { + } + template + unique_lock(Mutex& mtx, const chrono::duration& d) + : m(&mtx), is_locked(mtx.try_lock_for(d)) + { + } +#endif + + unique_lock(BOOST_THREAD_RV_REF(unique_lock) other) BOOST_NOEXCEPT: + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + BOOST_THREAD_EXPLICIT_LOCK_CONVERSION unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other); + +#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION + //std-2104 unique_lock move-assignment should not be noexcept + unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT + { + unique_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#endif + + //std-2104 unique_lock move-assignment should not be noexcept + unique_lock& operator=(BOOST_THREAD_RV_REF(unique_lock) other) //BOOST_NOEXCEPT + { + unique_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) + unique_lock& operator=(unique_lock other) + { + swap(other); + return *this; + } +#endif // BOOST_WORKAROUND +#endif + + // Conversion from upgrade locking + unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END ul, try_to_lock_t) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(ul).owns_lock()) + { + if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock()) + { + m = BOOST_THREAD_RV(ul).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(ul).release(); + } + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END ul, + const chrono::time_point& abs_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(ul).owns_lock()) + { + if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock_until(abs_time)) + { + m = BOOST_THREAD_RV(ul).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(ul).release(); + } + } + + template + unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END ul, + const chrono::duration& rel_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(ul).owns_lock()) + { + if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock_for(rel_time)) + { + m = BOOST_THREAD_RV(ul).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(ul).release(); + } + } +#endif + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + // Conversion from shared locking + unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, try_to_lock_t) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock()) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, + const chrono::time_point& abs_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_until(abs_time)) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } + + template + unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, + const chrono::duration& rel_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_for(rel_time)) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } +#endif // BOOST_THREAD_USES_CHRONO +#endif // BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + + void swap(unique_lock& other)BOOST_NOEXCEPT + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + + ~unique_lock() + { + if (owns_lock()) + { + m->unlock(); + } + } + void lock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if (owns_lock()) + { + boost::throw_exception( + boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + m->lock(); + is_locked = true; + } + bool try_lock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if (owns_lock()) + { + boost::throw_exception( + boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + is_locked = m->try_lock(); + return is_locked; + } +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_lock(TimeDuration const& relative_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + is_locked=m->timed_lock(relative_time); + return is_locked; + } + + bool timed_lock(::boost::system_time const& absolute_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + is_locked=m->timed_lock(absolute_time); + return is_locked; + } + bool timed_lock(::boost::xtime const& absolute_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + is_locked=m->timed_lock(absolute_time); + return is_locked; + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + + template + bool try_lock_for(const chrono::duration& rel_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + is_locked=m->try_lock_for(rel_time); + return is_locked; + } + template + bool try_lock_until(const chrono::time_point& abs_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex")); + } + is_locked=m->try_lock_until(abs_time); + return is_locked; + } +#endif + + void unlock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost unique_lock has no mutex")); + } + if (!owns_lock()) + { + boost::throw_exception( + boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost unique_lock doesn't own the mutex")); + } + m->unlock(); + is_locked = false; + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef void (unique_lock::*bool_type)(); + operator bool_type() const BOOST_NOEXCEPT + { + return is_locked?&unique_lock::lock:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return !owns_lock(); + } +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + bool owns_lock() const BOOST_NOEXCEPT + { + return is_locked; + } + + Mutex* mutex() const BOOST_NOEXCEPT + { + return m; + } + + Mutex* release()BOOST_NOEXCEPT + { + Mutex* const res=m; + m=0; + is_locked=false; + return res; + } + + friend class shared_lock ; + friend class upgrade_lock ; + }; + + template + void swap(unique_lock& lhs, unique_lock& rhs) + BOOST_NOEXCEPT + { + lhs.swap(rhs); + } + + BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) unique_lock BOOST_THREAD_DCL_MOVABLE_END + + template + class shared_lock + { + protected: + Mutex* m; + bool is_locked; + + public: + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY(shared_lock) + + shared_lock() BOOST_NOEXCEPT: + m(0),is_locked(false) + {} + + explicit shared_lock(Mutex& m_): + m(&m_),is_locked(false) + { + lock(); + } + shared_lock(Mutex& m_,adopt_lock_t): + m(&m_),is_locked(true) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + shared_lock(Mutex& m_,defer_lock_t) BOOST_NOEXCEPT: + m(&m_),is_locked(false) + {} + shared_lock(Mutex& m_,try_to_lock_t): + m(&m_),is_locked(false) + { + try_lock(); + } +#if defined BOOST_THREAD_USES_DATETIME + shared_lock(Mutex& m_,system_time const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + shared_lock(Mutex& mtx, const chrono::time_point& t) + : m(&mtx), is_locked(mtx.try_lock_shared_until(t)) + { + } + template + shared_lock(Mutex& mtx, const chrono::duration& d) + : m(&mtx), is_locked(mtx.try_lock_shared_for(d)) + { + } +#endif + + shared_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + BOOST_THREAD_EXPLICIT_LOCK_CONVERSION shared_lock(BOOST_THREAD_RV_REF_BEG unique_lock BOOST_THREAD_RV_REF_END other): + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + if(is_locked) + { + m->unlock_and_lock_shared(); + } + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + BOOST_THREAD_EXPLICIT_LOCK_CONVERSION shared_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other): + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + if(is_locked) + { + m->unlock_upgrade_and_lock_shared(); + } + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + //std-2104 unique_lock move-assignment should not be noexcept + shared_lock& operator=(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT + { + shared_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION + shared_lock& operator=(BOOST_THREAD_RV_REF_BEG unique_lock BOOST_THREAD_RV_REF_END other) + { + shared_lock temp(::boost::move(other)); + swap(temp); + return *this; + } + + shared_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other) + { + shared_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#endif + + void swap(shared_lock& other) BOOST_NOEXCEPT + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + + Mutex* mutex() const BOOST_NOEXCEPT + { + return m; + } + + Mutex* release() BOOST_NOEXCEPT + { + Mutex* const res=m; + m=0; + is_locked=false; + return res; + } + + ~shared_lock() + { + if(owns_lock()) + { + m->unlock_shared(); + } + } + void lock() + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + m->lock_shared(); + is_locked=true; + } + bool try_lock() + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + is_locked=m->try_lock_shared(); + return is_locked; + } +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(boost::system_time const& target_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + is_locked=m->timed_lock_shared(target_time); + return is_locked; + } + template + bool timed_lock(Duration const& target_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + is_locked=m->timed_lock_shared(target_time); + return is_locked; + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const chrono::duration& rel_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + is_locked=m->try_lock_shared_for(rel_time); + return is_locked; + } + template + bool try_lock_until(const chrono::time_point& abs_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex")); + } + is_locked=m->try_lock_shared_until(abs_time); + return is_locked; + } +#endif + void unlock() + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost shared_lock has no mutex")); + } + if(!owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost shared_lock doesn't own the mutex")); + } + m->unlock_shared(); + is_locked=false; + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef void (shared_lock::*bool_type)(); + operator bool_type() const BOOST_NOEXCEPT + { + return is_locked?&shared_lock::lock:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return !owns_lock(); + } +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + bool owns_lock() const BOOST_NOEXCEPT + { + return is_locked; + } + + }; + + BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) shared_lock BOOST_THREAD_DCL_MOVABLE_END + + template + void swap(shared_lock& lhs,shared_lock& rhs) BOOST_NOEXCEPT + { + lhs.swap(rhs); + } + + template + class upgrade_lock + { + protected: + Mutex* m; + bool is_locked; + + public: + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY( upgrade_lock) + + upgrade_lock()BOOST_NOEXCEPT: + m(0),is_locked(false) + {} + + explicit upgrade_lock(Mutex& m_) : + m(&m_), is_locked(false) + { + lock(); + } + upgrade_lock(Mutex& m_, adopt_lock_t) : + m(&m_), is_locked(true) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + upgrade_lock(Mutex& m_, defer_lock_t)BOOST_NOEXCEPT: + m(&m_),is_locked(false) + {} + upgrade_lock(Mutex& m_, try_to_lock_t) : + m(&m_), is_locked(false) + { + try_lock(); + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + upgrade_lock(Mutex& mtx, const chrono::time_point& t) + : m(&mtx), is_locked(mtx.try_lock_upgrade_until(t)) + { + } + template + upgrade_lock(Mutex& mtx, const chrono::duration& d) + : m(&mtx), is_locked(mtx.try_lock_upgrade_for(d)) + { + } +#endif + + upgrade_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + BOOST_THREAD_EXPLICIT_LOCK_CONVERSION upgrade_lock(BOOST_THREAD_RV_REF_BEG unique_lock BOOST_THREAD_RV_REF_END other): + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + if(is_locked) + { + m->unlock_and_lock_upgrade(); + } + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + //std-2104 unique_lock move-assignment should not be noexcept + upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT + { + upgrade_lock temp(::boost::move(other)); + swap(temp); + return *this; + } + +#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION + upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG unique_lock BOOST_THREAD_RV_REF_END other) + { + upgrade_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#endif + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + // Conversion from shared locking + upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, try_to_lock_t) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade()) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, + const chrono::time_point& abs_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade_until(abs_time)) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } + + template + upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, + const chrono::duration& rel_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade_for(rel_time)) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } +#endif // BOOST_THREAD_USES_CHRONO +#endif // BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + void swap(upgrade_lock& other)BOOST_NOEXCEPT + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + Mutex* mutex() const BOOST_NOEXCEPT + { + return m; + } + + Mutex* release()BOOST_NOEXCEPT + { + Mutex* const res=m; + m=0; + is_locked=false; + return res; + } + ~upgrade_lock() + { + if (owns_lock()) + { + m->unlock_upgrade(); + } + } + void lock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost upgrade_lock has no mutex")); + } + if (owns_lock()) + { + boost::throw_exception( + boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost upgrade_lock owns already the mutex")); + } + m->lock_upgrade(); + is_locked = true; + } + bool try_lock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost upgrade_lock has no mutex")); + } + if (owns_lock()) + { + boost::throw_exception( + boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost upgrade_lock owns already the mutex")); + } + is_locked = m->try_lock_upgrade(); + return is_locked; + } + void unlock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost upgrade_lock has no mutex")); + } + if (!owns_lock()) + { + boost::throw_exception( + boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost upgrade_lock doesn't own the mutex")); + } + m->unlock_upgrade(); + is_locked = false; + } +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const chrono::duration& rel_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost upgrade_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost upgrade_lock owns already the mutex")); + } + is_locked=m->try_lock_upgrade_for(rel_time); + return is_locked; + } + template + bool try_lock_until(const chrono::time_point& abs_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::operation_not_permitted), "boost upgrade_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(static_cast(system::errc::resource_deadlock_would_occur), "boost upgrade_lock owns already the mutex")); + } + is_locked=m->try_lock_upgrade_until(abs_time); + return is_locked; + } +#endif +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef void (upgrade_lock::*bool_type)(); + operator bool_type() const BOOST_NOEXCEPT + { + return is_locked?&upgrade_lock::lock:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return !owns_lock(); + } +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + bool owns_lock() const BOOST_NOEXCEPT + { + return is_locked; + } + friend class shared_lock ; + friend class unique_lock ; + }; + + template + void swap(upgrade_lock& lhs, upgrade_lock& rhs) + BOOST_NOEXCEPT + { + lhs.swap(rhs); + } + + BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_lock BOOST_THREAD_DCL_MOVABLE_END + + template + unique_lock::unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other): + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + if(is_locked) + { + m->unlock_upgrade_and_lock(); + } + BOOST_THREAD_RV(other).release(); + } + + template + class upgrade_to_unique_lock + { + private: + upgrade_lock* source; + unique_lock exclusive; + + public: + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY( upgrade_to_unique_lock) + + explicit upgrade_to_unique_lock(upgrade_lock& m_) : + source(&m_), exclusive(::boost::move(*source)) + { + } + ~upgrade_to_unique_lock() + { + if (source) + { + *source = BOOST_THREAD_MAKE_RV_REF(upgrade_lock (::boost::move(exclusive))); + } + } + + upgrade_to_unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: + source(BOOST_THREAD_RV(other).source),exclusive(::boost::move(BOOST_THREAD_RV(other).exclusive)) + { + BOOST_THREAD_RV(other).source=0; + } + + //std-2104 unique_lock move-assignment should not be noexcept + upgrade_to_unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock BOOST_THREAD_RV_REF_END other) //BOOST_NOEXCEPT + { + upgrade_to_unique_lock temp(::boost::move(other)); + swap(temp); + return *this; + } + + void swap(upgrade_to_unique_lock& other)BOOST_NOEXCEPT + { + std::swap(source,other.source); + exclusive.swap(other.exclusive); + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef void (upgrade_to_unique_lock::*bool_type)(upgrade_to_unique_lock&); + operator bool_type() const BOOST_NOEXCEPT + { + return exclusive.owns_lock()?&upgrade_to_unique_lock::swap:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return !owns_lock(); + } +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + + bool owns_lock() const BOOST_NOEXCEPT + { + return exclusive.owns_lock(); + } + Mutex* mutex() const BOOST_NOEXCEPT + { + return exclusive.mutex(); + } + }; + +BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_to_unique_lock BOOST_THREAD_DCL_MOVABLE_END + +namespace detail +{ + template + class try_lock_wrapper: +private unique_lock + { + typedef unique_lock base; + public: + BOOST_THREAD_MOVABLE_ONLY(try_lock_wrapper) + + try_lock_wrapper() + {} + + explicit try_lock_wrapper(Mutex& m): + base(m,try_to_lock) + {} + + try_lock_wrapper(Mutex& m_,adopt_lock_t): + base(m_,adopt_lock) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m_)); +#endif + } + try_lock_wrapper(Mutex& m_,defer_lock_t): + base(m_,defer_lock) + {} + try_lock_wrapper(Mutex& m_,try_to_lock_t): + base(m_,try_to_lock) + {} +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): + base(::boost::move(other)) + {} + +#elif defined BOOST_THREAD_USES_MOVE + try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): + base(::boost::move(static_cast(other))) + {} + +#else + try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): + base(BOOST_THREAD_RV_REF(base)(*other)) + {} +#endif + try_lock_wrapper& operator=(BOOST_THREAD_RV_REF_BEG try_lock_wrapper BOOST_THREAD_RV_REF_END other) + { + try_lock_wrapper temp(::boost::move(other)); + swap(temp); + return *this; + } + void swap(try_lock_wrapper& other) + { + base::swap(other); + } + void lock() + { + base::lock(); + } + bool try_lock() + { + return base::try_lock(); + } + void unlock() + { + base::unlock(); + } + bool owns_lock() const + { + return base::owns_lock(); + } + Mutex* mutex() const BOOST_NOEXCEPT + { + return base::mutex(); + } + Mutex* release() + { + return base::release(); + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef typename base::bool_type bool_type; + operator bool_type() const + { + return base::operator bool_type(); + } + bool operator!() const + { + return !this->owns_lock(); + } +#else + explicit operator bool() const + { + return owns_lock(); + } +#endif + }; + + template + void swap(try_lock_wrapper& lhs,try_lock_wrapper& rhs) + { + lhs.swap(rhs); + } +} +} +#include + +#endif diff --git a/boost/thread/lockable_traits.hpp b/boost/thread/lockable_traits.hpp new file mode 100644 index 0000000..f46c886 --- /dev/null +++ b/boost/thread/lockable_traits.hpp @@ -0,0 +1,238 @@ +// 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) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCKABLE_TRAITS_HPP +#define BOOST_THREAD_LOCKABLE_TRAITS_HPP + +#include + +#include +#include +#include +#ifdef BOOST_NO_CXX11_SFINAE_EXPR +#include +#else +#include +#endif + +#include + +// todo make use of integral_constant, true_type and false_type + +namespace boost +{ + namespace sync + { + +#if defined(BOOST_NO_SFINAE) || \ + BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \ + BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +#if ! defined BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES +#define BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES +#endif +#endif + +#ifndef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + namespace detail + { +#ifdef BOOST_NO_CXX11_SFINAE_EXPR +#define BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(member_name) \ + template::value> \ + struct has_member_called_##member_name \ + { \ + BOOST_STATIC_CONSTANT(bool, value=false); \ + }; \ + \ + template \ + struct has_member_called_##member_name \ + { \ + typedef char true_type; \ + struct false_type \ + { \ + true_type dummy[2]; \ + }; \ + \ + struct fallback { int member_name; }; \ + struct derived: \ + T, fallback \ + { \ + derived(); \ + }; \ + \ + template struct tester; \ + \ + template \ + static false_type has_member(tester<&U::member_name>*); \ + template \ + static true_type has_member(...); \ + \ + BOOST_STATIC_CONSTANT( \ + bool, value=sizeof(has_member(0))==sizeof(true_type)); \ + } + + BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(lock) +; BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(unlock); + BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(try_lock); + + template::value > + struct has_member_lock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template + struct has_member_lock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(V (U::*)()); + template + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_lock::has_member(&T::lock))==sizeof(true_type)); + }; + + template::value > + struct has_member_unlock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template + struct has_member_unlock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(V (U::*)()); + template + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_unlock::has_member(&T::unlock))==sizeof(true_type)); + }; + + template::value > + struct has_member_try_lock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template + struct has_member_try_lock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(bool (U::*)()); + template + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_try_lock::has_member(&T::try_lock))==sizeof(true_type)); + }; +#else + template + struct has_member_lock : false_type {}; + + template + struct has_member_lock().lock())) + > : true_type {}; + + template + struct has_member_unlock : false_type {}; + + template + struct has_member_unlock().unlock())) + > : true_type {}; + + template + struct has_member_try_lock : false_type {}; + + template + struct has_member_try_lock().try_lock())) + > : true_type {}; +#endif + + } + + template + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock::value && + detail::has_member_unlock::value); + }; + template + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = + is_basic_lockable::value && + detail::has_member_try_lock::value); + }; + +#else + template + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; + template + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; +#endif + + template + struct is_recursive_mutex_sur_parole + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; + template + struct is_recursive_mutex_sur_parolle : is_recursive_mutex_sur_parole + { + }; + + template + struct is_recursive_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = is_basic_lockable::value && + is_recursive_mutex_sur_parolle::value); + }; + template + struct is_recursive_lockable + { + BOOST_STATIC_CONSTANT(bool, value = is_lockable::value && + is_recursive_mutex_sur_parolle::value); + }; + } + template + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = sync::is_lockable::value); + }; + +} +#include + +#endif diff --git a/boost/thread/locks.hpp b/boost/thread/locks.hpp new file mode 100644 index 0000000..0905aec --- /dev/null +++ b/boost/thread/locks.hpp @@ -0,0 +1,17 @@ +// 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) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCKS_HPP +#define BOOST_THREAD_LOCKS_HPP + +#include +#include +#include +#include +#include +#include + +#endif diff --git a/boost/thread/mutex.hpp b/boost/thread/mutex.hpp new file mode 100644 index 0000000..05c6094 --- /dev/null +++ b/boost/thread/mutex.hpp @@ -0,0 +1,53 @@ +#ifndef BOOST_THREAD_MUTEX_HPP +#define BOOST_THREAD_MUTEX_HPP + +// mutex.hpp +// +// (C) Copyright 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + +#include + + +namespace boost +{ + namespace sync + { +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + template<> + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +#endif + } +} + +#endif diff --git a/boost/thread/once.hpp b/boost/thread/once.hpp new file mode 100644 index 0000000..22f9513 --- /dev/null +++ b/boost/thread/once.hpp @@ -0,0 +1,54 @@ +#ifndef BOOST_THREAD_ONCE_HPP +#define BOOST_THREAD_ONCE_HPP + +// once.hpp +// +// (C) Copyright 2006-7 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4702) // unreachable code +#endif + +#include +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#if defined BOOST_THREAD_ONCE_FAST_EPOCH +#include +#elif defined BOOST_THREAD_ONCE_ATOMIC +#include +#else +#error "Once Not Implemented" +#endif +#else +#error "Boost threads unavailable on this platform" +#endif + +#include + +namespace boost +{ + // template void + // call_once(once_flag& flag, Callable&& func, Args&&... args); +template +inline void call_once(Function func,once_flag& flag) +//inline void call_once(void (*func)(),once_flag& flag) + { + call_once(flag,func); + } +} + +#include + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#endif diff --git a/boost/thread/pthread/condition_variable.hpp b/boost/thread/pthread/condition_variable.hpp new file mode 100644 index 0000000..e3c511f --- /dev/null +++ b/boost/thread/pthread/condition_variable.hpp @@ -0,0 +1,496 @@ +#ifndef BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP +#define BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP +// 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) +// (C) Copyright 2007-10 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#include +#include +#include + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS +#include +#include +#endif +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif +#include + +#include + +#include + +namespace boost +{ + namespace thread_cv_detail + { + template + struct lock_on_exit + { + MutexType* m; + + lock_on_exit(): + m(0) + {} + + void activate(MutexType& m_) + { + m_.unlock(); + m=&m_; + } + void deactivate() + { + if (m) + { + m->lock(); + } + m = 0; + } + ~lock_on_exit() BOOST_NOEXCEPT_IF(false) + { + if (m) + { + m->lock(); + } + } + }; + } + + inline void condition_variable::wait(unique_lock& m) + { +#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED + if(! m.owns_lock()) + { + boost::throw_exception(condition_error(-1, "boost::condition_variable::wait() failed precondition mutex not owned")); + } +#endif + int res=0; + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + thread_cv_detail::lock_on_exit > guard; + detail::interruption_checker check_for_interruption(&internal_mutex,&cond); + pthread_mutex_t* the_mutex = &internal_mutex; + guard.activate(m); + res = posix::pthread_cond_wait(&cond,the_mutex); + check_for_interruption.unlock_if_locked(); + guard.deactivate(); +#else + pthread_mutex_t* the_mutex = m.mutex()->native_handle(); + res = posix::pthread_cond_wait(&cond,the_mutex); +#endif + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + this_thread::interruption_point(); +#endif + if(res) + { + boost::throw_exception(condition_error(res, "boost::condition_variable::wait failed in pthread_cond_wait")); + } + } + + // When this function returns true: + // * A notification (or sometimes a spurious OS signal) has been received + // * Do not assume that the timeout has not been reached + // * Do not assume that the predicate has been changed + // + // When this function returns false: + // * The timeout has been reached + // * Do not assume that a notification has not been received + // * Do not assume that the predicate has not been changed + inline bool condition_variable::do_wait_until( + unique_lock& m, + detail::internal_platform_timepoint const &timeout) + { +#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED + if (!m.owns_lock()) + { + boost::throw_exception(condition_error(EPERM, "boost::condition_variable::do_wait_until() failed precondition mutex not owned")); + } +#endif + int cond_res; + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + thread_cv_detail::lock_on_exit > guard; + detail::interruption_checker check_for_interruption(&internal_mutex,&cond); + pthread_mutex_t* the_mutex = &internal_mutex; + guard.activate(m); + cond_res=posix::pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs()); + check_for_interruption.unlock_if_locked(); + guard.deactivate(); +#else + pthread_mutex_t* the_mutex = m.mutex()->native_handle(); + cond_res=posix::pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs()); +#endif + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + this_thread::interruption_point(); +#endif + if(cond_res==ETIMEDOUT) + { + return false; + } + if(cond_res) + { + boost::throw_exception(condition_error(cond_res, "boost::condition_variable::do_wait_until failed in pthread_cond_timedwait")); + } + return true; + } + + inline void condition_variable::notify_one() BOOST_NOEXCEPT + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); +#endif + BOOST_VERIFY(!posix::pthread_cond_signal(&cond)); + } + + inline void condition_variable::notify_all() BOOST_NOEXCEPT + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); +#endif + BOOST_VERIFY(!posix::pthread_cond_broadcast(&cond)); + } + + class condition_variable_any + { + pthread_mutex_t internal_mutex; + pthread_cond_t cond; + + public: + BOOST_THREAD_NO_COPYABLE(condition_variable_any) + condition_variable_any() + { + int const res=posix::pthread_mutex_init(&internal_mutex); + if(res) + { + boost::throw_exception(thread_resource_error(res, "boost::condition_variable_any::condition_variable_any() failed in pthread_mutex_init")); + } + int const res2 = posix::pthread_cond_init(&cond); + if(res2) + { + BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex)); + boost::throw_exception(thread_resource_error(res2, "boost::condition_variable_any::condition_variable_any() failed in pthread_cond_init")); + } + } + ~condition_variable_any() + { + BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex)); + BOOST_VERIFY(!posix::pthread_cond_destroy(&cond)); + } + + template + void wait(lock_type& m) + { + int res=0; + { + thread_cv_detail::lock_on_exit guard; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + detail::interruption_checker check_for_interruption(&internal_mutex,&cond); +#else + boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); +#endif + guard.activate(m); + res=posix::pthread_cond_wait(&cond,&internal_mutex); + check_for_interruption.unlock_if_locked(); + guard.deactivate(); + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + this_thread::interruption_point(); +#endif + if(res) + { + boost::throw_exception(condition_error(res, "boost::condition_variable_any::wait() failed in pthread_cond_wait")); + } + } + + template + void wait(lock_type& m,predicate_type pred) + { + while (!pred()) + { + wait(m); + } + } + +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_wait(lock_type& m,boost::system_time const& abs_time) + { +#if defined BOOST_THREAD_WAIT_BUG + const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG); +#else + const detail::real_platform_timepoint ts(abs_time); +#endif +#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + const detail::platform_duration d(ts - detail::real_platform_clock::now()); + do_wait_until(m, detail::internal_platform_clock::now() + d); + return ts > detail::real_platform_clock::now(); +#else + return do_wait_until(m, ts); +#endif + } + template + bool timed_wait(lock_type& m,::boost::xtime const& abs_time) + { + return timed_wait(m,system_time(abs_time)); + } + + template + bool timed_wait(lock_type& m,duration_type const& wait_duration) + { + if (wait_duration.is_pos_infinity()) + { + wait(m); + return true; + } + if (wait_duration.is_special()) + { + return true; + } + detail::platform_duration d(wait_duration); +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); + do_wait_until(m, detail::internal_platform_clock::now() + d); + return ts > detail::mono_platform_clock::now(); +#else + return do_wait_until(m, detail::internal_platform_clock::now() + d); +#endif + } + + template + bool timed_wait(lock_type& m,boost::system_time const& abs_time, predicate_type pred) + { +#if defined BOOST_THREAD_WAIT_BUG + const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG); +#else + const detail::real_platform_timepoint ts(abs_time); +#endif + while (!pred()) + { +#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + detail::platform_duration d(ts - detail::real_platform_clock::now()); + if (d <= detail::platform_duration::zero()) break; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + do_wait_until(m, detail::internal_platform_clock::now() + d); +#else + if (!do_wait_until(m, ts)) break; // timeout occurred +#endif + } + return pred(); + } + + template + bool timed_wait(lock_type& m,::boost::xtime const& abs_time, predicate_type pred) + { + return timed_wait(m,system_time(abs_time),pred); + } + + template + bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) + { + if (wait_duration.is_pos_infinity()) + { + while (!pred()) + { + wait(m); + } + return true; + } + if (wait_duration.is_special()) + { + return pred(); + } + detail::platform_duration d(wait_duration); +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); + while (!pred()) + { + if (d <= detail::platform_duration::zero()) break; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + do_wait_until(m, detail::internal_platform_clock::now() + d); + d = ts - detail::mono_platform_clock::now(); + } +#else + const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d); + while (!pred()) + { + if (!do_wait_until(m, ts)) break; // timeout occurred + } +#endif + return pred(); + } +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template + cv_status + wait_until( + lock_type& lock, + const chrono::time_point& t) + { + const boost::detail::internal_platform_timepoint ts(t); + if (do_wait_until(lock, ts)) return cv_status::no_timeout; + else return cv_status::timeout; + } + + template + cv_status + wait_until( + lock_type& lock, + const chrono::time_point& t) + { + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + typedef typename common_type::type common_duration; + common_duration d(t - Clock::now()); + do_wait_until(lock, detail::internal_chrono_clock::now() + d); + if (t > Clock::now()) return cv_status::no_timeout; + else return cv_status::timeout; + } + + template + cv_status + wait_for( + lock_type& lock, + const chrono::duration& d) + { + return wait_until(lock, chrono::steady_clock::now() + d); + } + + template + bool + wait_until( + lock_type& lock, + const chrono::time_point& t, + Predicate pred) + { + const detail::internal_platform_timepoint ts(t); + while (!pred()) + { + if (!do_wait_until(lock, ts)) break; // timeout occurred + } + return pred(); + } + + template + bool + wait_until( + lock_type& lock, + const chrono::time_point& t, + Predicate pred) + { + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + typedef typename common_type::type common_duration; + while (!pred()) + { + common_duration d(t - Clock::now()); + if (d <= common_duration::zero()) break; // timeout occurred + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d)); + } + return pred(); + } + + template + bool + wait_for( + lock_type& lock, + const chrono::duration& d, + Predicate pred) + { + return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); + } +#endif + + void notify_one() BOOST_NOEXCEPT + { + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); + BOOST_VERIFY(!posix::pthread_cond_signal(&cond)); + } + + void notify_all() BOOST_NOEXCEPT + { + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); + BOOST_VERIFY(!posix::pthread_cond_broadcast(&cond)); + } + private: + + // When this function returns true: + // * A notification (or sometimes a spurious OS signal) has been received + // * Do not assume that the timeout has not been reached + // * Do not assume that the predicate has been changed + // + // When this function returns false: + // * The timeout has been reached + // * Do not assume that a notification has not been received + // * Do not assume that the predicate has not been changed + template + bool do_wait_until( + lock_type& m, + detail::internal_platform_timepoint const &timeout) + { + int res=0; + { + thread_cv_detail::lock_on_exit guard; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + detail::interruption_checker check_for_interruption(&internal_mutex,&cond); +#else + boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex); +#endif + guard.activate(m); + res=posix::pthread_cond_timedwait(&cond,&internal_mutex,&timeout.getTs()); + check_for_interruption.unlock_if_locked(); + guard.deactivate(); + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + this_thread::interruption_point(); +#endif + if(res==ETIMEDOUT) + { + return false; + } + if(res) + { + boost::throw_exception(condition_error(res, "boost::condition_variable_any::do_wait_until() failed in pthread_cond_timedwait")); + } + return true; + } + }; +} + +#include + +#endif diff --git a/boost/thread/pthread/condition_variable_fwd.hpp b/boost/thread/pthread/condition_variable_fwd.hpp new file mode 100644 index 0000000..f596348 --- /dev/null +++ b/boost/thread/pthread/condition_variable_fwd.hpp @@ -0,0 +1,341 @@ +#ifndef BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP +#define BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP +// 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) +// (C) Copyright 2007-8 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined BOOST_THREAD_USES_DATETIME +#include +#endif + +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif +#include +#include + +#include + +#include + +namespace boost +{ + class condition_variable + { + private: +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + pthread_mutex_t internal_mutex; +//#endif + pthread_cond_t cond; + + public: + //private: // used by boost::thread::try_join_until + + bool do_wait_until( + unique_lock& lock, + detail::internal_platform_timepoint const &timeout); + + public: + BOOST_THREAD_NO_COPYABLE(condition_variable) + condition_variable() + { + int res; +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + // Even if it is not used, the internal_mutex exists (see + // above) and must be initialized (etc) in case some + // compilation units provide interruptions and others + // don't. + res=posix::pthread_mutex_init(&internal_mutex); + if(res) + { + boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_mutex_init")); + } +//#endif + res = posix::pthread_cond_init(&cond); + if (res) + { +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + // ditto + BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex)); +//#endif + boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_cond_init")); + } + } + ~condition_variable() + { +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + // ditto + BOOST_VERIFY(!posix::pthread_mutex_destroy(&internal_mutex)); +//#endif + BOOST_VERIFY(!posix::pthread_cond_destroy(&cond)); + } + + void wait(unique_lock& m); + + template + void wait(unique_lock& m,predicate_type pred) + { + while (!pred()) + { + wait(m); + } + } + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_wait( + unique_lock& m, + boost::system_time const& abs_time) + { +#if defined BOOST_THREAD_WAIT_BUG + const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG); +#else + const detail::real_platform_timepoint ts(abs_time); +#endif +#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + const detail::platform_duration d(ts - detail::real_platform_clock::now()); + do_wait_until(m, detail::internal_platform_clock::now() + d); + return ts > detail::real_platform_clock::now(); +#else + return do_wait_until(m, ts); +#endif + } + bool timed_wait( + unique_lock& m, + ::boost::xtime const& abs_time) + { + return timed_wait(m,system_time(abs_time)); + } + + template + bool timed_wait( + unique_lock& m, + duration_type const& wait_duration) + { + if (wait_duration.is_pos_infinity()) + { + wait(m); + return true; + } + if (wait_duration.is_special()) + { + return true; + } + detail::platform_duration d(wait_duration); +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); + do_wait_until(m, detail::internal_platform_clock::now() + d); + return ts > detail::mono_platform_clock::now(); +#else + return do_wait_until(m, detail::internal_platform_clock::now() + d); +#endif + } + + template + bool timed_wait( + unique_lock& m, + boost::system_time const& abs_time,predicate_type pred) + { +#if defined BOOST_THREAD_WAIT_BUG + const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG); +#else + const detail::real_platform_timepoint ts(abs_time); +#endif + while (!pred()) + { +#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + detail::platform_duration d(ts - detail::real_platform_clock::now()); + if (d <= detail::platform_duration::zero()) break; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + do_wait_until(m, detail::internal_platform_clock::now() + d); +#else + if (!do_wait_until(m, ts)) break; // timeout occurred +#endif + } + return pred(); + } + + template + bool timed_wait( + unique_lock& m, + ::boost::xtime const& abs_time,predicate_type pred) + { + return timed_wait(m,system_time(abs_time),pred); + } + + template + bool timed_wait( + unique_lock& m, + duration_type const& wait_duration,predicate_type pred) + { + if (wait_duration.is_pos_infinity()) + { + while (!pred()) + { + wait(m); + } + return true; + } + if (wait_duration.is_special()) + { + return pred(); + } + detail::platform_duration d(wait_duration); +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); + while (!pred()) + { + if (d <= detail::platform_duration::zero()) break; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + do_wait_until(m, detail::internal_platform_clock::now() + d); + d = ts - detail::mono_platform_clock::now(); + } +#else + const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d); + while (!pred()) + { + if (!do_wait_until(m, ts)) break; // timeout occurred + } +#endif + return pred(); + } +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + + template + cv_status + wait_until( + unique_lock& lock, + const chrono::time_point& t) + { + const detail::internal_platform_timepoint ts(t); + if (do_wait_until(lock, ts)) return cv_status::no_timeout; + else return cv_status::timeout; + } + + template + cv_status + wait_until( + unique_lock& lock, + const chrono::time_point& t) + { + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + typedef typename common_type::type common_duration; + common_duration d(t - Clock::now()); + do_wait_until(lock, detail::internal_chrono_clock::now() + d); + if (t > Clock::now()) return cv_status::no_timeout; + else return cv_status::timeout; + } + + template + cv_status + wait_for( + unique_lock& lock, + const chrono::duration& d) + { + return wait_until(lock, chrono::steady_clock::now() + d); + } + + template + bool + wait_until( + unique_lock& lock, + const chrono::time_point& t, + Predicate pred) + { + const detail::internal_platform_timepoint ts(t); + while (!pred()) + { + if (!do_wait_until(lock, ts)) break; // timeout occurred + } + return pred(); + } + + template + bool + wait_until( + unique_lock& lock, + const chrono::time_point& t, + Predicate pred) + { + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + typedef typename common_type::type common_duration; + while (!pred()) + { + common_duration d(t - Clock::now()); + if (d <= common_duration::zero()) break; // timeout occurred + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d)); + } + return pred(); + } + + template + bool + wait_for( + unique_lock& lock, + const chrono::duration& d, + Predicate pred) + { + return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); + } +#endif + +#define BOOST_THREAD_DEFINES_CONDITION_VARIABLE_NATIVE_HANDLE + typedef pthread_cond_t* native_handle_type; + native_handle_type native_handle() + { + return &cond; + } + + void notify_one() BOOST_NOEXCEPT; + void notify_all() BOOST_NOEXCEPT; + }; + + BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); +} + +#include + +#endif diff --git a/boost/thread/pthread/mutex.hpp b/boost/thread/pthread/mutex.hpp new file mode 100644 index 0000000..94a7388 --- /dev/null +++ b/boost/thread/pthread/mutex.hpp @@ -0,0 +1,320 @@ +#ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP +#define BOOST_THREAD_PTHREAD_MUTEX_HPP +// (C) Copyright 2007-8 Anthony Williams +// (C) Copyright 2011,2012,2015 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include +#endif +#include +#if defined BOOST_THREAD_USES_DATETIME +#include +#endif +#include +#include +#include +#include +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif +#include + + +#include + +namespace boost +{ + + class BOOST_THREAD_CAPABILITY("mutex") mutex + { + private: + pthread_mutex_t m; + public: + BOOST_THREAD_NO_COPYABLE(mutex) + + mutex() + { + int const res=posix::pthread_mutex_init(&m); + if(res) + { + boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init")); + } + } + ~mutex() + { + BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); + } + + void lock() BOOST_THREAD_ACQUIRE() + { + int res = posix::pthread_mutex_lock(&m); + if (res) + { + boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); + } + } + + void unlock() BOOST_THREAD_RELEASE() + { + BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); + } + + bool try_lock() BOOST_THREAD_TRY_ACQUIRE(true) + { + int res = posix::pthread_mutex_trylock(&m); + if (res==EBUSY) + { + return false; + } + + return !res; + } + +#define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + typedef unique_lock scoped_lock; + typedef detail::try_lock_wrapper scoped_try_lock; +#endif + }; + + typedef mutex try_mutex; + + class timed_mutex + { + private: + pthread_mutex_t m; +#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK + pthread_cond_t cond; + bool is_locked; +#endif + public: + BOOST_THREAD_NO_COPYABLE(timed_mutex) + timed_mutex() + { + int const res=posix::pthread_mutex_init(&m); + if(res) + { + boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init")); + } +#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK + int const res2=posix::pthread_cond_init(&cond); + if(res2) + { + BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); + boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init")); + } + is_locked=false; +#endif + } + ~timed_mutex() + { + BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); +#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK + BOOST_VERIFY(!posix::pthread_cond_destroy(&cond)); +#endif + } + +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_lock(TimeDuration const & relative_time) + { + if (relative_time.is_pos_infinity()) + { + lock(); + return true; + } + if (relative_time.is_special()) + { + return true; + } + detail::platform_duration d(relative_time); +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) ) + { + d = ts - detail::mono_platform_clock::now(); + if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } + return true; +#else + return do_try_lock_until(detail::internal_platform_clock::now() + d); +#endif + } + bool timed_lock(boost::xtime const & absolute_time) + { + return timed_lock(system_time(absolute_time)); + } +#endif +#ifdef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK + void lock() + { + int res = posix::pthread_mutex_lock(&m); + if (res) + { + boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); + } + } + + void unlock() + { + BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); + } + + bool try_lock() + { + int res = posix::pthread_mutex_trylock(&m); + if (res==EBUSY) + { + return false; + } + + return !res; + } + + + private: + bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) + { + int const res=pthread_mutex_timedlock(&m,&timeout.getTs()); + BOOST_ASSERT(!res || res==ETIMEDOUT); + return !res; + } + public: + +#else + void lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + while(is_locked) + { + BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m)); + } + is_locked=true; + } + + void unlock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + is_locked=false; + BOOST_VERIFY(!posix::pthread_cond_signal(&cond)); + } + + bool try_lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked) + { + return false; + } + is_locked=true; + return true; + } + + private: + bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + while(is_locked) + { + int const cond_res=posix::pthread_cond_timedwait(&cond,&m,&timeout.getTs()); + if(cond_res==ETIMEDOUT) + { + break; + } + BOOST_ASSERT(!cond_res); + } + if(is_locked) + { + return false; + } + is_locked=true; + return true; + } + public: +#endif + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(system_time const & abs_time) + { + const detail::real_platform_timepoint ts(abs_time); +#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + detail::platform_duration d(ts - detail::real_platform_clock::now()); + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) ) + { + d = ts - detail::real_platform_clock::now(); + if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } + return true; +#else + return do_try_lock_until(ts); +#endif + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const chrono::duration& rel_time) + { + return try_lock_until(chrono::steady_clock::now() + rel_time); + } + template + bool try_lock_until(const chrono::time_point& t) + { + typedef typename common_type::type common_duration; + common_duration d(t - Clock::now()); + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + while ( ! try_lock_until(detail::internal_chrono_clock::now() + d)) + { + d = t - Clock::now(); + if ( d <= common_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + } + return true; + } + template + bool try_lock_until(const chrono::time_point& t) + { + detail::internal_platform_timepoint ts(t); + return do_try_lock_until(ts); + } +#endif + +#define BOOST_THREAD_DEFINES_TIMED_MUTEX_NATIVE_HANDLE + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + typedef unique_lock scoped_timed_lock; + typedef detail::try_lock_wrapper scoped_try_lock; + typedef scoped_timed_lock scoped_lock; +#endif + }; +} + +#include + + +#endif diff --git a/boost/thread/pthread/once.hpp b/boost/thread/pthread/once.hpp new file mode 100644 index 0000000..515b78e --- /dev/null +++ b/boost/thread/pthread/once.hpp @@ -0,0 +1,541 @@ +#ifndef BOOST_THREAD_PTHREAD_ONCE_HPP +#define BOOST_THREAD_PTHREAD_ONCE_HPP + +// once.hpp +// +// (C) Copyright 2007-8 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace boost +{ + + struct once_flag; + + #define BOOST_ONCE_INITIAL_FLAG_VALUE 0 + + namespace thread_detail + { + typedef boost::uint32_t uintmax_atomic_t; + #define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(value) value##u + #define BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_C2(~0) + + } + +#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args); +#else + template + inline void call_once(once_flag& flag, Function f); + template + inline void call_once(once_flag& flag, Function f, T1 p1); + template + inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2); + template + inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3); +#endif + + struct once_flag + { + BOOST_THREAD_NO_COPYABLE(once_flag) + BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT + : epoch(BOOST_ONCE_INITIAL_FLAG_VALUE) + {} + private: + volatile thread_detail::uintmax_atomic_t epoch; + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + template + friend void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args); +#else + template + friend void call_once(once_flag& flag, Function f); + template + friend void call_once(once_flag& flag, Function f, T1 p1); + template + friend void call_once(once_flag& flag, Function f, T1 p1, T2 p2); + template + friend void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3); + +#endif + + }; + +#define BOOST_ONCE_INIT once_flag() + +#else // BOOST_THREAD_PROVIDES_ONCE_CXX11 + + struct once_flag + { + volatile thread_detail::uintmax_atomic_t epoch; + }; + +#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE} +#endif // BOOST_THREAD_PROVIDES_ONCE_CXX11 + + +#if defined BOOST_THREAD_PROVIDES_INVOKE +#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke +#define BOOST_THREAD_INVOKE_RET_VOID_CALL +#elif defined BOOST_THREAD_PROVIDES_INVOKE_RET +#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke +#define BOOST_THREAD_INVOKE_RET_VOID_CALL +#else +#define BOOST_THREAD_INVOKE_RET_VOID boost::bind +#define BOOST_THREAD_INVOKE_RET_VOID_CALL () +#endif + + namespace thread_detail + { + BOOST_THREAD_DECL uintmax_atomic_t& get_once_per_thread_epoch(); + BOOST_THREAD_DECL extern uintmax_atomic_t once_global_epoch; + BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex; + BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv; + } + + // Based on Mike Burrows fast_pthread_once algorithm as described in + // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html + + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + + + template + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch(f)), + thread_detail::decay_copy(boost::forward(args))... + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + BOOST_RETHROW + } + BOOST_CATCH_END + flag.epoch=--thread_detail::once_global_epoch; + BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) + { + BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex)); + } + } + } + this_thread_epoch=thread_detail::once_global_epoch; + + } + } +#else + template + inline void call_once(once_flag& flag, Function f) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch + inline void call_once(once_flag& flag, Function f, T1 p1) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch + inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch + inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch(f)), + thread_detail::decay_copy(boost::forward(p1)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + BOOST_RETHROW + } + BOOST_CATCH_END + flag.epoch=--thread_detail::once_global_epoch; + BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) + { + BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex)); + } + } + } + this_thread_epoch=thread_detail::once_global_epoch; + } + } + template + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch(f)), + thread_detail::decay_copy(boost::forward(p1)), + thread_detail::decay_copy(boost::forward(p2)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + BOOST_RETHROW + } + BOOST_CATCH_END + flag.epoch=--thread_detail::once_global_epoch; + BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) + { + BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex)); + } + } + } + this_thread_epoch=thread_detail::once_global_epoch; + } + } + + template + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3) + { + static thread_detail::uintmax_atomic_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE; + static thread_detail::uintmax_atomic_t const being_initialized=uninitialized_flag+1; + thread_detail::uintmax_atomic_t const epoch=flag.epoch; + thread_detail::uintmax_atomic_t& this_thread_epoch=thread_detail::get_once_per_thread_epoch(); + + if(epoch(f)), + thread_detail::decay_copy(boost::forward(p1)), + thread_detail::decay_copy(boost::forward(p2)), + thread_detail::decay_copy(boost::forward(p3)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + flag.epoch=uninitialized_flag; + BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + BOOST_RETHROW + } + BOOST_CATCH_END + flag.epoch=--thread_detail::once_global_epoch; + BOOST_VERIFY(!posix::pthread_cond_broadcast(&thread_detail::once_epoch_cv)); + } + else + { + while(flag.epoch==being_initialized) + { + BOOST_VERIFY(!posix::pthread_cond_wait(&thread_detail::once_epoch_cv,&thread_detail::once_epoch_mutex)); + } + } + } + this_thread_epoch=thread_detail::once_global_epoch; + } + } + +#endif + +} + +#include + +#endif diff --git a/boost/thread/pthread/once_atomic.hpp b/boost/thread/pthread/once_atomic.hpp new file mode 100644 index 0000000..c54a35c --- /dev/null +++ b/boost/thread/pthread/once_atomic.hpp @@ -0,0 +1,313 @@ +#ifndef BOOST_THREAD_PTHREAD_ONCE_ATOMIC_HPP +#define BOOST_THREAD_PTHREAD_ONCE_ATOMIC_HPP + +// once.hpp +// +// (C) Copyright 2013 Andrey Semashev +// (C) Copyright 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost +{ + + struct once_flag; + + namespace thread_detail + { + +#if BOOST_ATOMIC_INT_LOCK_FREE == 2 + typedef unsigned int atomic_int_type; +#elif BOOST_ATOMIC_SHORT_LOCK_FREE == 2 + typedef unsigned short atomic_int_type; +#elif BOOST_ATOMIC_CHAR_LOCK_FREE == 2 + typedef unsigned char atomic_int_type; +#elif BOOST_ATOMIC_LONG_LOCK_FREE == 2 + typedef unsigned long atomic_int_type; +#elif defined(BOOST_HAS_LONG_LONG) && BOOST_ATOMIC_LLONG_LOCK_FREE == 2 + typedef ulong_long_type atomic_int_type; +#else + // All tested integer types are not atomic, the spinlock pool will be used + typedef unsigned int atomic_int_type; +#endif + + typedef boost::atomic atomic_type; + + BOOST_THREAD_DECL bool enter_once_region(once_flag& flag) BOOST_NOEXCEPT; + BOOST_THREAD_DECL void commit_once_region(once_flag& flag) BOOST_NOEXCEPT; + BOOST_THREAD_DECL void rollback_once_region(once_flag& flag) BOOST_NOEXCEPT; + inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT; + } + +#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 + + struct once_flag + { + BOOST_THREAD_NO_COPYABLE(once_flag) + BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT : storage(0) + { + } + + private: + thread_detail::atomic_type storage; + + friend BOOST_THREAD_DECL bool thread_detail::enter_once_region(once_flag& flag) BOOST_NOEXCEPT; + friend BOOST_THREAD_DECL void thread_detail::commit_once_region(once_flag& flag) BOOST_NOEXCEPT; + friend BOOST_THREAD_DECL void thread_detail::rollback_once_region(once_flag& flag) BOOST_NOEXCEPT; + friend thread_detail::atomic_type& thread_detail::get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT; + }; + +#define BOOST_ONCE_INIT boost::once_flag() + + namespace thread_detail + { + inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT + { + //return reinterpret_cast< atomic_type& >(flag.storage); + return flag.storage; + } + } + +#else // BOOST_THREAD_PROVIDES_ONCE_CXX11 + struct once_flag + { + // The thread_detail::atomic_int_type storage is marked + // with this attribute in order to let the compiler know that it will alias this member + // and silence compilation warnings. + BOOST_THREAD_ATTRIBUTE_MAY_ALIAS thread_detail::atomic_int_type storage; + }; + + #define BOOST_ONCE_INIT {0} + + namespace thread_detail + { + inline atomic_type& get_atomic_storage(once_flag& flag) BOOST_NOEXCEPT + { + return reinterpret_cast< atomic_type& >(flag.storage); + } + + } + +#endif // BOOST_THREAD_PROVIDES_ONCE_CXX11 + +#if defined BOOST_THREAD_PROVIDES_INVOKE +#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke +#define BOOST_THREAD_INVOKE_RET_VOID_CALL +#elif defined BOOST_THREAD_PROVIDES_INVOKE_RET +#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke +#define BOOST_THREAD_INVOKE_RET_VOID_CALL +#else +#define BOOST_THREAD_INVOKE_RET_VOID boost::bind +#define BOOST_THREAD_INVOKE_RET_VOID_CALL () +#endif + + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + + template + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward(f)), + thread_detail::decay_copy(boost::forward(args))... + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } +#else + template + inline void call_once(once_flag& flag, Function f) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + + template + inline void call_once(once_flag& flag, Function f, T1 p1) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f, p1) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + + template + inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f, p1, p2) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + + template + inline void call_once(once_flag& flag, Function f, T1 p1, T2 p2, T3 p3) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f, p1, p2, p3) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } +#if !(defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x5130)) + template + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + + template + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward(f)), + thread_detail::decay_copy(boost::forward(p1)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + template + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward(f)), + thread_detail::decay_copy(boost::forward(p1)), + thread_detail::decay_copy(boost::forward(p2)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + template + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3) + { + if (thread_detail::enter_once_region(flag)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward(f)), + thread_detail::decay_copy(boost::forward(p1)), + thread_detail::decay_copy(boost::forward(p2)), + thread_detail::decay_copy(boost::forward(p3)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + + } + BOOST_CATCH (...) + { + thread_detail::rollback_once_region(flag); + BOOST_RETHROW + } + BOOST_CATCH_END + thread_detail::commit_once_region(flag); + } + } + +#endif // __SUNPRO_CC + +#endif +} + +#include + +#endif + diff --git a/boost/thread/pthread/pthread_helpers.hpp b/boost/thread/pthread/pthread_helpers.hpp new file mode 100644 index 0000000..6809994 --- /dev/null +++ b/boost/thread/pthread/pthread_helpers.hpp @@ -0,0 +1,187 @@ +#ifndef BOOST_THREAD_PTHREAD_PTHREAD_HELPERS_HPP +#define BOOST_THREAD_PTHREAD_PTHREAD_HELPERS_HPP +// Copyright (C) 2017 +// Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include + +#include + +#ifndef BOOST_THREAD_HAS_NO_EINTR_BUG +#define BOOST_THREAD_HAS_EINTR_BUG +#endif + +namespace boost +{ + namespace posix + { + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr = NULL) + { + return ::pthread_mutex_init(m, attr); + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_cond_init(pthread_cond_t* c) + { +#ifdef BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + pthread_condattr_t attr; + int res = pthread_condattr_init(&attr); + if (res) + { + return res; + } + BOOST_VERIFY(!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)); + res = ::pthread_cond_init(c, &attr); + BOOST_VERIFY(!pthread_condattr_destroy(&attr)); + return res; +#else + return ::pthread_cond_init(c, NULL); +#endif + } + +#ifdef BOOST_THREAD_HAS_EINTR_BUG + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_mutex_destroy(pthread_mutex_t* m) + { + int ret; + do + { + ret = ::pthread_mutex_destroy(m); + } while (ret == EINTR); + return ret; + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_cond_destroy(pthread_cond_t* c) + { + int ret; + do + { + ret = ::pthread_cond_destroy(c); + } while (ret == EINTR); + return ret; + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_mutex_lock(pthread_mutex_t* m) + { + int ret; + do + { + ret = ::pthread_mutex_lock(m); + } while (ret == EINTR); + return ret; + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_mutex_trylock(pthread_mutex_t* m) + { + int ret; + do + { + ret = ::pthread_mutex_trylock(m); + } while (ret == EINTR); + return ret; + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_mutex_unlock(pthread_mutex_t* m) + { + int ret; + do + { + ret = ::pthread_mutex_unlock(m); + } while (ret == EINTR); + return ret; + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_cond_wait(pthread_cond_t* c, pthread_mutex_t* m) + { + int ret; + do + { + ret = ::pthread_cond_wait(c, m); + } while (ret == EINTR); + return ret; + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_cond_timedwait(pthread_cond_t* c, pthread_mutex_t* m, const struct timespec* t) + { + int ret; + do + { + ret = ::pthread_cond_timedwait(c, m, t); + } while (ret == EINTR); + return ret; + } +#else + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_mutex_destroy(pthread_mutex_t* m) + { + return ::pthread_mutex_destroy(m); + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_cond_destroy(pthread_cond_t* c) + { + return ::pthread_cond_destroy(c); + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_mutex_lock(pthread_mutex_t* m) + { + return ::pthread_mutex_lock(m); + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_mutex_trylock(pthread_mutex_t* m) + { + return ::pthread_mutex_trylock(m); + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_mutex_unlock(pthread_mutex_t* m) + { + return ::pthread_mutex_unlock(m); + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_cond_wait(pthread_cond_t* c, pthread_mutex_t* m) + { + return ::pthread_cond_wait(c, m); + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_cond_timedwait(pthread_cond_t* c, pthread_mutex_t* m, const struct timespec* t) + { + return ::pthread_cond_timedwait(c, m, t); + } +#endif + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_cond_signal(pthread_cond_t* c) + { + return ::pthread_cond_signal(c); + } + + BOOST_FORCEINLINE BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS + int pthread_cond_broadcast(pthread_cond_t* c) + { + return ::pthread_cond_broadcast(c); + } + } +} + +#include + +#endif diff --git a/boost/thread/pthread/pthread_mutex_scoped_lock.hpp b/boost/thread/pthread/pthread_mutex_scoped_lock.hpp new file mode 100644 index 0000000..4823254 --- /dev/null +++ b/boost/thread/pthread/pthread_mutex_scoped_lock.hpp @@ -0,0 +1,71 @@ +#ifndef BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP +#define BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP +// (C) Copyright 2007-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#include + +namespace boost +{ + namespace pthread + { + class pthread_mutex_scoped_lock + { + pthread_mutex_t* m; + bool locked; + public: + explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_) BOOST_NOEXCEPT: + m(m_),locked(true) + { + BOOST_VERIFY(!posix::pthread_mutex_lock(m)); + } + void unlock() BOOST_NOEXCEPT + { + BOOST_VERIFY(!posix::pthread_mutex_unlock(m)); + locked=false; + } + void unlock_if_locked() BOOST_NOEXCEPT + { + if(locked) + { + unlock(); + } + } + ~pthread_mutex_scoped_lock() BOOST_NOEXCEPT + { + if(locked) + { + unlock(); + } + } + + }; + + class pthread_mutex_scoped_unlock + { + pthread_mutex_t* m; + public: + explicit pthread_mutex_scoped_unlock(pthread_mutex_t* m_) BOOST_NOEXCEPT: + m(m_) + { + BOOST_VERIFY(!posix::pthread_mutex_unlock(m)); + } + ~pthread_mutex_scoped_unlock() BOOST_NOEXCEPT + { + BOOST_VERIFY(!posix::pthread_mutex_lock(m)); + } + + }; + } +} + +#include + +#endif diff --git a/boost/thread/pthread/recursive_mutex.hpp b/boost/thread/pthread/recursive_mutex.hpp new file mode 100644 index 0000000..2aaf425 --- /dev/null +++ b/boost/thread/pthread/recursive_mutex.hpp @@ -0,0 +1,436 @@ +#ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP +#define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP +// (C) Copyright 2007-8 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include +#endif +#include +#include +#ifndef _WIN32 +#include +#endif +#include +#include +#include +#include +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif +#include + + +#if defined BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE \ + || defined __ANDROID__ +#define BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE +#endif + +#if defined BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE && defined BOOST_THREAD_USES_PTHREAD_TIMEDLOCK +#define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK +#endif + +#include + +namespace boost +{ + class recursive_mutex + { + private: + pthread_mutex_t m; +#ifndef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE + pthread_cond_t cond; + bool is_locked; + pthread_t owner; + unsigned count; +#endif + public: + BOOST_THREAD_NO_COPYABLE(recursive_mutex) + recursive_mutex() + { +#ifdef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE + pthread_mutexattr_t attr; + + int const init_attr_res=pthread_mutexattr_init(&attr); + if(init_attr_res) + { + boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_init")); + } + int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); + if(set_attr_res) + { + BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); + boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_settype")); + } + + int const res=posix::pthread_mutex_init(&m,&attr); + if(res) + { + BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); + boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init")); + } + BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); +#else + int const res=posix::pthread_mutex_init(&m); + if(res) + { + boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init")); + } + int const res2=posix::pthread_cond_init(&cond); + if(res2) + { + BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); + boost::throw_exception(thread_resource_error(res2, "boost:: recursive_mutex constructor failed in pthread_cond_init")); + } + is_locked=false; + count=0; +#endif + } + ~recursive_mutex() + { + BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); +#ifndef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE + BOOST_VERIFY(!posix::pthread_cond_destroy(&cond)); +#endif + } + +#ifdef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE + void lock() + { + BOOST_VERIFY(!posix::pthread_mutex_lock(&m)); + } + + void unlock() + { + BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); + } + + bool try_lock() BOOST_NOEXCEPT + { + int const res=posix::pthread_mutex_trylock(&m); + BOOST_ASSERT(!res || res==EBUSY); + return !res; + } +#define BOOST_THREAD_DEFINES_RECURSIVE_MUTEX_NATIVE_HANDLE + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + +#else + void lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && pthread_equal(owner,pthread_self())) + { + ++count; + return; + } + + while(is_locked) + { + BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m)); + } + is_locked=true; + ++count; + owner=pthread_self(); + } + + void unlock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(!--count) + { + is_locked=false; + } + BOOST_VERIFY(!posix::pthread_cond_signal(&cond)); + } + + bool try_lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && !pthread_equal(owner,pthread_self())) + { + return false; + } + is_locked=true; + ++count; + owner=pthread_self(); + return true; + } + +#endif + +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + typedef unique_lock scoped_lock; + typedef detail::try_lock_wrapper scoped_try_lock; +#endif + }; + + typedef recursive_mutex recursive_try_mutex; + + class recursive_timed_mutex + { + private: + pthread_mutex_t m; +#ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK + pthread_cond_t cond; + bool is_locked; + pthread_t owner; + unsigned count; +#endif + public: + BOOST_THREAD_NO_COPYABLE(recursive_timed_mutex) + recursive_timed_mutex() + { +#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK + pthread_mutexattr_t attr; + + int const init_attr_res=pthread_mutexattr_init(&attr); + if(init_attr_res) + { + boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_init")); + } + int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); + if(set_attr_res) + { + boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_settype")); + } + + int const res=posix::pthread_mutex_init(&m,&attr); + if(res) + { + BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); + boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init")); + } + BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); +#else + int const res=posix::pthread_mutex_init(&m); + if(res) + { + boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init")); + } + int const res2=posix::pthread_cond_init(&cond); + if(res2) + { + BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); + boost::throw_exception(thread_resource_error(res2, "boost:: recursive_timed_mutex constructor failed in pthread_cond_init")); + } + is_locked=false; + count=0; +#endif + } + ~recursive_timed_mutex() + { + BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); +#ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK + BOOST_VERIFY(!posix::pthread_cond_destroy(&cond)); +#endif + } + +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_lock(TimeDuration const & relative_time) + { + if (relative_time.is_pos_infinity()) + { + lock(); + return true; + } + if (relative_time.is_special()) + { + return true; + } + detail::platform_duration d(relative_time); +#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) + const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) ) + { + d = ts - detail::mono_platform_clock::now(); + if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } + return true; +#else + return do_try_lock_until(detail::internal_platform_clock::now() + d); +#endif + } +#endif + +#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK + void lock() + { + BOOST_VERIFY(!posix::pthread_mutex_lock(&m)); + } + + void unlock() + { + BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); + } + + bool try_lock() + { + int const res=posix::pthread_mutex_trylock(&m); + BOOST_ASSERT(!res || res==EBUSY); + return !res; + } + private: + bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) + { + int const res=pthread_mutex_timedlock(&m,&timeout.getTs()); + BOOST_ASSERT(!res || res==ETIMEDOUT); + return !res; + } + + public: + +#else + void lock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && pthread_equal(owner,pthread_self())) + { + ++count; + return; + } + + while(is_locked) + { + BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m)); + } + is_locked=true; + ++count; + owner=pthread_self(); + } + + void unlock() + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(!--count) + { + is_locked=false; + } + BOOST_VERIFY(!posix::pthread_cond_signal(&cond)); + } + + bool try_lock() BOOST_NOEXCEPT + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && !pthread_equal(owner,pthread_self())) + { + return false; + } + is_locked=true; + ++count; + owner=pthread_self(); + return true; + } + + private: + bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) + { + boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); + if(is_locked && pthread_equal(owner,pthread_self())) + { + ++count; + return true; + } + while(is_locked) + { + int const cond_res=posix::pthread_cond_timedwait(&cond,&m,&timeout.getTs()); + if(cond_res==ETIMEDOUT) + { + break; + } + BOOST_ASSERT(!cond_res); + } + if(is_locked) + { + return false; + } + is_locked=true; + ++count; + owner=pthread_self(); + return true; + } + public: + +#endif + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(system_time const & abs_time) + { + const detail::real_platform_timepoint ts(abs_time); +#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO + detail::platform_duration d(ts - detail::real_platform_clock::now()); + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) ) + { + d = ts - detail::real_platform_clock::now(); + if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } + return true; +#else + return do_try_lock_until(ts); +#endif + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const chrono::duration& rel_time) + { + return try_lock_until(chrono::steady_clock::now() + rel_time); + } + template + bool try_lock_until(const chrono::time_point& t) + { + typedef typename common_type::type common_duration; + common_duration d(t - Clock::now()); + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + while ( ! try_lock_until(detail::internal_chrono_clock::now() + d)) + { + d = t - Clock::now(); + if ( d <= common_duration::zero() ) return false; // timeout occurred + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + } + return true; + + } + template + bool try_lock_until(const chrono::time_point& t) + { + detail::internal_platform_timepoint ts(t); + return do_try_lock_until(ts); + } +#endif + +#define BOOST_THREAD_DEFINES_RECURSIVE_TIMED_MUTEX_NATIVE_HANDLE + typedef pthread_mutex_t* native_handle_type; + native_handle_type native_handle() + { + return &m; + } + +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + typedef unique_lock scoped_timed_lock; + typedef detail::try_lock_wrapper scoped_try_lock; + typedef scoped_timed_lock scoped_lock; +#endif + }; + +} + +#include + +#endif diff --git a/boost/thread/pthread/shared_mutex.hpp b/boost/thread/pthread/shared_mutex.hpp new file mode 100644 index 0000000..ed9a296 --- /dev/null +++ b/boost/thread/pthread/shared_mutex.hpp @@ -0,0 +1,642 @@ +#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP +#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP + +// (C) Copyright 2006-8 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS +#include +#endif +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif +#include + +#include + +namespace boost +{ + class shared_mutex + { + private: + class state_data + { + public: + state_data () : + shared_count(0), + exclusive(false), + upgrade(false), + exclusive_waiting_blocked(false) + {} + + void assert_free() const + { + BOOST_ASSERT( ! exclusive ); + BOOST_ASSERT( ! upgrade ); + BOOST_ASSERT( shared_count==0 ); + } + + void assert_locked() const + { + BOOST_ASSERT( exclusive ); + BOOST_ASSERT( shared_count==0 ); + BOOST_ASSERT( ! upgrade ); + } + + void assert_lock_shared () const + { + BOOST_ASSERT( ! exclusive ); + BOOST_ASSERT( shared_count>0 ); + //BOOST_ASSERT( (! upgrade) || (shared_count>1)); + // if upgraded there are at least 2 threads sharing the mutex, + // except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership. + } + + void assert_lock_upgraded () const + { + BOOST_ASSERT( ! exclusive ); + BOOST_ASSERT( upgrade ); + BOOST_ASSERT( shared_count>0 ); + } + + void assert_lock_not_upgraded () const + { + BOOST_ASSERT( ! upgrade ); + } + + bool can_lock () const + { + return ! (shared_count || exclusive); + } + + void lock () + { + exclusive = true; + } + + void unlock () + { + exclusive = false; + exclusive_waiting_blocked = false; + } + + bool can_lock_shared () const + { + return ! (exclusive || exclusive_waiting_blocked); + } + + bool no_shared () const + { + return shared_count==0; + } + + bool one_shared () const + { + return shared_count==1; + } + + void lock_shared () + { + ++shared_count; + } + + + void unlock_shared () + { + --shared_count; + } + + void lock_upgrade () + { + ++shared_count; + upgrade=true; + } + bool can_lock_upgrade () const + { + return ! (exclusive || exclusive_waiting_blocked || upgrade); + } + + void unlock_upgrade () + { + upgrade=false; + --shared_count; + } + + //private: + unsigned shared_count; + bool exclusive; + bool upgrade; + bool exclusive_waiting_blocked; + }; + + + + state_data state; + boost::mutex state_change; + boost::condition_variable shared_cond; + boost::condition_variable exclusive_cond; + boost::condition_variable upgrade_cond; + + void release_waiters() + { + exclusive_cond.notify_one(); + shared_cond.notify_all(); + } + + public: + + BOOST_THREAD_NO_COPYABLE(shared_mutex) + + shared_mutex() + { + } + + ~shared_mutex() + { + } + + void lock_shared() + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + shared_cond.wait(lk, boost::bind(&state_data::can_lock_shared, boost::ref(state))); + state.lock_shared(); + } + + bool try_lock_shared() + { + boost::unique_lock lk(state_change); + + if(!state.can_lock_shared()) + { + return false; + } + state.lock_shared(); + return true; + } + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock_shared(system_time const& timeout) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + if(!shared_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock_shared, boost::ref(state)))) + { + return false; + } + state.lock_shared(); + return true; + } + + template + bool timed_lock_shared(TimeDuration const & relative_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + if(!shared_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock_shared, boost::ref(state)))) + { + return false; + } + state.lock_shared(); + return true; + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_shared_for(const chrono::duration& rel_time) + { + return try_lock_shared_until(chrono::steady_clock::now() + rel_time); + } + template + bool try_lock_shared_until(const chrono::time_point& abs_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_shared, boost::ref(state)))) + { + return false; + } + state.lock_shared(); + return true; + } +#endif + void unlock_shared() + { + boost::unique_lock lk(state_change); + state.assert_lock_shared(); + state.unlock_shared(); + if (state.no_shared()) + { + if (state.upgrade) + { + // As there is a thread doing a unlock_upgrade_and_lock that is waiting for state.no_shared() + // avoid other threads to lock, lock_upgrade or lock_shared, so only this thread is notified. + state.upgrade=false; + state.exclusive=true; + //lk.unlock(); + upgrade_cond.notify_one(); + } + else + { + state.exclusive_waiting_blocked=false; + //lk.unlock(); + } + release_waiters(); + } + } + + void lock() + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + state.exclusive_waiting_blocked=true; + exclusive_cond.wait(lk, boost::bind(&state_data::can_lock, boost::ref(state))); + state.exclusive=true; + } + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(system_time const& timeout) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + state.exclusive_waiting_blocked=true; + if(!exclusive_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock, boost::ref(state)))) + { + state.exclusive_waiting_blocked=false; + release_waiters(); + return false; + } + state.exclusive=true; + return true; + } + + template + bool timed_lock(TimeDuration const & relative_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + state.exclusive_waiting_blocked=true; + if(!exclusive_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock, boost::ref(state)))) + { + state.exclusive_waiting_blocked=false; + release_waiters(); + return false; + } + state.exclusive=true; + return true; + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const chrono::duration& rel_time) + { + return try_lock_until(chrono::steady_clock::now() + rel_time); + } + template + bool try_lock_until(const chrono::time_point& abs_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + state.exclusive_waiting_blocked=true; + if(!exclusive_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock, boost::ref(state)))) + { + state.exclusive_waiting_blocked=false; + release_waiters(); + return false; + } + state.exclusive=true; + return true; + } +#endif + + bool try_lock() + { + boost::unique_lock lk(state_change); + if(!state.can_lock()) + { + return false; + } + state.exclusive=true; + return true; + } + + void unlock() + { + boost::unique_lock lk(state_change); + state.assert_locked(); + state.exclusive=false; + state.exclusive_waiting_blocked=false; + state.assert_free(); + release_waiters(); + } + + void lock_upgrade() + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + shared_cond.wait(lk, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))); + state.lock_shared(); + state.upgrade=true; + } + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock_upgrade(system_time const& timeout) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + if(!shared_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock_upgrade, boost::ref(state)))) + { + return false; + } + state.lock_shared(); + state.upgrade=true; + return true; + } + + template + bool timed_lock_upgrade(TimeDuration const & relative_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + if(!shared_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state)))) + { + return false; + } + state.lock_shared(); + state.upgrade=true; + return true; + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_upgrade_for(const chrono::duration& rel_time) + { + return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time); + } + template + bool try_lock_upgrade_until(const chrono::time_point& abs_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state)))) + { + return false; + } + state.lock_shared(); + state.upgrade=true; + return true; + } +#endif + bool try_lock_upgrade() + { + boost::unique_lock lk(state_change); + if(!state.can_lock_upgrade()) + { + return false; + } + state.lock_shared(); + state.upgrade=true; + state.assert_lock_upgraded(); + return true; + } + + void unlock_upgrade() + { + boost::unique_lock lk(state_change); + //state.upgrade=false; + state.unlock_upgrade(); + if(state.no_shared()) + { + state.exclusive_waiting_blocked=false; + release_waiters(); + } else { + shared_cond.notify_all(); + } + } + + // Upgrade <-> Exclusive + void unlock_upgrade_and_lock() + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + state.assert_lock_upgraded(); + state.unlock_shared(); + upgrade_cond.wait(lk, boost::bind(&state_data::no_shared, boost::ref(state))); + state.upgrade=false; + state.exclusive=true; + state.assert_locked(); + } + + void unlock_and_lock_upgrade() + { + boost::unique_lock lk(state_change); + state.assert_locked(); + state.exclusive=false; + state.upgrade=true; + state.lock_shared(); + state.exclusive_waiting_blocked=false; + state.assert_lock_upgraded(); + release_waiters(); + } + + bool try_unlock_upgrade_and_lock() + { + boost::unique_lock lk(state_change); + state.assert_lock_upgraded(); + if( !state.exclusive + && !state.exclusive_waiting_blocked + && state.upgrade + && state.shared_count==1) + { + state.shared_count=0; + state.exclusive=true; + state.upgrade=false; + state.assert_locked(); + return true; + } + return false; + } +#ifdef BOOST_THREAD_USES_CHRONO + template + bool + try_unlock_upgrade_and_lock_for( + const chrono::duration& rel_time) + { + return try_unlock_upgrade_and_lock_until( + chrono::steady_clock::now() + rel_time); + } + template + bool + try_unlock_upgrade_and_lock_until( + const chrono::time_point& abs_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + state.assert_lock_upgraded(); + if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::one_shared, boost::ref(state)))) + { + return false; + } + state.upgrade=false; + state.exclusive=true; + state.exclusive_waiting_blocked=false; + state.shared_count=0; + return true; + } +#endif + + // Shared <-> Exclusive + void unlock_and_lock_shared() + { + boost::unique_lock lk(state_change); + state.assert_locked(); + state.exclusive=false; + state.lock_shared(); + state.exclusive_waiting_blocked=false; + release_waiters(); + } + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + bool try_unlock_shared_and_lock() + { + boost::unique_lock lk(state_change); + state.assert_lock_shared(); + if( !state.exclusive + && !state.exclusive_waiting_blocked + && !state.upgrade + && state.shared_count==1) + { + state.shared_count=0; + state.exclusive=true; + return true; + } + return false; + } +#ifdef BOOST_THREAD_USES_CHRONO + template + bool + try_unlock_shared_and_lock_for( + const chrono::duration& rel_time) + { + return try_unlock_shared_and_lock_until( + chrono::steady_clock::now() + rel_time); + } + template + bool + try_unlock_shared_and_lock_until( + const chrono::time_point& abs_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + state.assert_lock_shared(); + if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::one_shared, boost::ref(state)))) + { + return false; + } + state.upgrade=false; + state.exclusive=true; + state.exclusive_waiting_blocked=false; + state.shared_count=0; + return true; + } +#endif +#endif + + // Shared <-> Upgrade + void unlock_upgrade_and_lock_shared() + { + boost::unique_lock lk(state_change); + state.assert_lock_upgraded(); + state.upgrade=false; + state.exclusive_waiting_blocked=false; + release_waiters(); + } + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + bool try_unlock_shared_and_lock_upgrade() + { + boost::unique_lock lk(state_change); + state.assert_lock_shared(); + if(state.can_lock_upgrade()) + { + state.upgrade=true; + return true; + } + return false; + } +#ifdef BOOST_THREAD_USES_CHRONO + template + bool + try_unlock_shared_and_lock_upgrade_for( + const chrono::duration& rel_time) + { + return try_unlock_shared_and_lock_upgrade_until( + chrono::steady_clock::now() + rel_time); + } + template + bool + try_unlock_shared_and_lock_upgrade_until( + const chrono::time_point& abs_time) + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + boost::this_thread::disable_interruption do_not_disturb; +#endif + boost::unique_lock lk(state_change); + state.assert_lock_shared(); + if(!exclusive_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state)))) + { + return false; + } + state.upgrade=true; + return true; + } +#endif +#endif + }; + + typedef shared_mutex upgrade_mutex; +} + +#include + +#endif diff --git a/boost/thread/pthread/thread_data.hpp b/boost/thread/pthread/thread_data.hpp new file mode 100644 index 0000000..aefbeb4 --- /dev/null +++ b/boost/thread/pthread/thread_data.hpp @@ -0,0 +1,408 @@ +#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP +#define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP +// 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) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#endif + +#include +#include +#include + +#if defined(__ANDROID__) +# ifndef PAGE_SIZE +# define PAGE_SIZE 4096 +# endif +#endif + +#include +#include + +#include + +namespace boost +{ + class thread_attributes { + public: + thread_attributes() BOOST_NOEXCEPT { + int res = pthread_attr_init(&val_); + BOOST_VERIFY(!res && "pthread_attr_init failed"); + } + ~thread_attributes() { + int res = pthread_attr_destroy(&val_); + BOOST_VERIFY(!res && "pthread_attr_destroy failed"); + } + // stack + void set_stack_size(std::size_t size) BOOST_NOEXCEPT { + if (size==0) return; +#ifdef BOOST_THREAD_USES_GETPAGESIZE + std::size_t page_size = getpagesize(); +#else + std::size_t page_size = ::sysconf( _SC_PAGESIZE); +#endif +#if PTHREAD_STACK_MIN > 0 + if (size thread_data_ptr; + + struct BOOST_THREAD_DECL thread_data_base: + enable_shared_from_this + { + thread_data_ptr self; + pthread_t thread_handle; + boost::mutex data_mutex; + boost::condition_variable done_condition; + bool done; + bool join_started; + bool joined; + boost::detail::thread_exit_callback_node* thread_exit_callbacks; + std::map tss_data; + +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + // These data must be at the end so that the access to the other fields doesn't change + // when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined. + // Another option is to have them always + pthread_mutex_t* cond_mutex; + pthread_cond_t* current_cond; +//#endif + typedef std::vector + //, hidden_allocator > + > notify_list_t; + notify_list_t notify; + +//#ifndef BOOST_NO_EXCEPTIONS + typedef std::vector > async_states_t; + async_states_t async_states_; +//#endif +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + // These data must be at the end so that the access to the other fields doesn't change + // when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined. + // Another option is to have them always + bool interrupt_enabled; + bool interrupt_requested; +//#endif + thread_data_base(): + thread_handle(0), + done(false),join_started(false),joined(false), + thread_exit_callbacks(0), +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + cond_mutex(0), + current_cond(0), +//#endif + notify() +//#ifndef BOOST_NO_EXCEPTIONS + , async_states_() +//#endif +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + , interrupt_enabled(true) + , interrupt_requested(false) +//#endif + {} + virtual ~thread_data_base(); + + typedef pthread_t native_handle_type; + + virtual void run()=0; + virtual void notify_all_at_thread_exit(condition_variable* cv, mutex* m) + { + notify.push_back(std::pair(cv, m)); + } + +//#ifndef BOOST_NO_EXCEPTIONS + void make_ready_at_thread_exit(shared_ptr as) + { + async_states_.push_back(as); + } +//#endif + }; + + BOOST_THREAD_DECL thread_data_base* get_current_thread_data(); + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + class interruption_checker + { + thread_data_base* const thread_info; + pthread_mutex_t* m; + bool set; + bool done; + + void check_for_interruption() + { +#ifndef BOOST_NO_EXCEPTIONS + if(thread_info->interrupt_requested) + { + thread_info->interrupt_requested=false; + throw thread_interrupted(); // BOOST_NO_EXCEPTIONS protected + } +#endif + } + + void operator=(interruption_checker&); + public: + explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond): + thread_info(detail::get_current_thread_data()),m(cond_mutex), + set(thread_info && thread_info->interrupt_enabled), done(false) + { + if(set) + { + lock_guard guard(thread_info->data_mutex); + check_for_interruption(); + thread_info->cond_mutex=cond_mutex; + thread_info->current_cond=cond; + BOOST_VERIFY(!posix::pthread_mutex_lock(m)); + } + else + { + BOOST_VERIFY(!posix::pthread_mutex_lock(m)); + } + } + void unlock_if_locked() + { + if ( ! done) { + if (set) + { + BOOST_VERIFY(!posix::pthread_mutex_unlock(m)); + lock_guard guard(thread_info->data_mutex); + thread_info->cond_mutex=NULL; + thread_info->current_cond=NULL; + } + else + { + BOOST_VERIFY(!posix::pthread_mutex_unlock(m)); + } + done = true; + } + } + + ~interruption_checker() BOOST_NOEXCEPT_IF(false) + { + unlock_if_locked(); + } + }; +#endif + } + + namespace this_thread + { + void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; + + namespace hidden + { + inline bool always_false() + { + return false; + } + } + +#if defined BOOST_THREAD_USES_DATETIME +#ifdef __DECXXX + /// Workaround of DECCXX issue of incorrect template substitution + template<> +#endif + inline void sleep(system_time const& abs_time) + { + mutex mx; + unique_lock lock(mx); + condition_variable cond; + cond.timed_wait(lock, abs_time, hidden::always_false); + } + + template + void sleep(TimeDuration const& rel_time) + { + mutex mx; + unique_lock lock(mx); + condition_variable cond; + cond.timed_wait(lock, rel_time, hidden::always_false); + } +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template + void sleep_until(const chrono::time_point& t) + { + mutex mut; + unique_lock lk(mut); + condition_variable cv; + cv.wait_until(lk, t, hidden::always_false); + } + + template + void sleep_for(const chrono::duration& d) + { + mutex mut; + unique_lock lk(mut); + condition_variable cv; + cv.wait_for(lk, d, hidden::always_false); + } +#endif + + namespace no_interruption_point + { +#if defined BOOST_THREAD_SLEEP_FOR_IS_STEADY +// Use pthread_delay_np or nanosleep when available +// because they do not provide an interruption point. + + namespace hidden + { + void BOOST_THREAD_DECL sleep_for_internal(const detail::platform_duration& ts); + } + +#if defined BOOST_THREAD_USES_DATETIME +#ifdef __DECXXX + /// Workaround of DECCXX issue of incorrect template substitution + template<> +#endif + inline void sleep(system_time const& abs_time) + { + const detail::real_platform_timepoint ts(abs_time); + detail::platform_duration d(ts - detail::real_platform_clock::now()); + while (d > detail::platform_duration::zero()) + { + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + hidden::sleep_for_internal(d); + d = ts - detail::real_platform_clock::now(); + } + } + + template + void sleep(TimeDuration const& rel_time) + { + hidden::sleep_for_internal(detail::platform_duration(rel_time)); + } +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template + void sleep_for(const chrono::duration& d) + { + hidden::sleep_for_internal(detail::platform_duration(d)); + } + + template + void sleep_until(const chrono::time_point& t) + { + sleep_for(t - chrono::steady_clock::now()); + } + + template + void sleep_until(const chrono::time_point& t) + { + typedef typename common_type::type common_duration; + common_duration d(t - Clock::now()); + while (d > common_duration::zero()) + { + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + hidden::sleep_for_internal(detail::platform_duration(d)); + d = t - Clock::now(); + } + } +#endif + +#else // BOOST_THREAD_SLEEP_FOR_IS_STEADY +// When pthread_delay_np and nanosleep are not available, +// fall back to using the interruptible sleep functions. + +#if defined BOOST_THREAD_USES_DATETIME +#ifdef __DECXXX + /// Workaround of DECCXX issue of incorrect template substitution + template<> +#endif + inline void sleep(system_time const& abs_time) + { + this_thread::sleep(abs_time); + } + + template + void sleep(TimeDuration const& rel_time) + { + this_thread::sleep(rel_time); + } +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template + void sleep_until(const chrono::time_point& t) + { + this_thread::sleep_until(t); + } + + template + void sleep_for(const chrono::duration& d) + { + this_thread::sleep_for(d); + } +#endif + +#endif // BOOST_THREAD_SLEEP_FOR_IS_STEADY + } // no_interruption_point + } // this_thread +} + +#include + +#endif diff --git a/boost/thread/pthread/thread_heap_alloc.hpp b/boost/thread/pthread/thread_heap_alloc.hpp new file mode 100644 index 0000000..dec7b66 --- /dev/null +++ b/boost/thread/pthread/thread_heap_alloc.hpp @@ -0,0 +1,272 @@ +// 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) +// (C) Copyright 2008 Anthony Williams +#ifndef THREAD_HEAP_ALLOC_PTHREAD_HPP +#define THREAD_HEAP_ALLOC_PTHREAD_HPP + +#include + +namespace boost +{ + namespace detail + { + template + inline T* heap_new() + { + return new T(); + } +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) && ! defined (BOOST_NO_CXX11_RVALUE_REFERENCES) + template + inline T* heap_new(Args&&... args) + { + return new T(static_cast(args)...); + } +#elif ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + template + inline T* heap_new(A1&& a1) + { + return new T(static_cast(a1)); + } + template + inline T* heap_new(A1&& a1,A2&& a2) + { + return new T(static_cast(a1),static_cast(a2)); + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3) + { + return new T(static_cast(a1),static_cast(a2), + static_cast(a3)); + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4) + { + return new T(static_cast(a1),static_cast(a2), + static_cast(a3),static_cast(a4)); + } +#else + template + inline T* heap_new_impl(A1 a1) + { + return new T(a1); + } + template + inline T* heap_new_impl(A1 a1,A2 a2) + { + return new T(a1,a2); + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3) + { + return new T(a1,a2,a3); + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4) + { + return new T(a1,a2,a3,a4); + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4,A5 a5) + { + return new T(a1,a2,a3,a4,a5); + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6) + { + return new T(a1,a2,a3,a4,a5,a6); + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7) + { + return new T(a1,a2,a3,a4,a5,a6,a7); + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8) + { + return new T(a1,a2,a3,a4,a5,a6,a7,a8); + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9) + { + return new T(a1,a2,a3,a4,a5,a6,a7,a8,a9); + } + + template + inline T* heap_new(A1 const& a1) + { + return heap_new_impl(a1); + } + template + inline T* heap_new(A1& a1) + { + return heap_new_impl(a1); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1 const& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + +#endif + template + inline void heap_delete(T* data) + { + delete data; + } + + template + struct do_heap_delete + { + void operator()(T* data) const + { + detail::heap_delete(data); + } + }; + } +} + +#include + +#endif diff --git a/boost/thread/recursive_mutex.hpp b/boost/thread/recursive_mutex.hpp new file mode 100644 index 0000000..e716a19 --- /dev/null +++ b/boost/thread/recursive_mutex.hpp @@ -0,0 +1,64 @@ +#ifndef BOOST_THREAD_RECURSIVE_MUTEX_HPP +#define BOOST_THREAD_RECURSIVE_MUTEX_HPP + +// recursive_mutex.hpp +// +// (C) Copyright 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + +#include + +namespace boost +{ + namespace sync + { + +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + template<> + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +#endif + + template<> + struct is_recursive_mutex_sur_parolle + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_recursive_mutex_sur_parolle + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + } +} +#endif diff --git a/boost/thread/shared_lock_guard.hpp b/boost/thread/shared_lock_guard.hpp new file mode 100644 index 0000000..97a6397 --- /dev/null +++ b/boost/thread/shared_lock_guard.hpp @@ -0,0 +1,53 @@ +// 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) +// (C) Copyright 2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_SHARED_LOCK_GUARD_HPP +#define BOOST_THREAD_SHARED_LOCK_GUARD_HPP +#include +//#include +#include +#include + +namespace boost +{ + + template + class shared_lock_guard + { + private: + SharedMutex& m; + + public: + typedef SharedMutex mutex_type; + BOOST_THREAD_NO_COPYABLE(shared_lock_guard) + explicit shared_lock_guard(SharedMutex& m_): + m(m_) + { + m.lock_shared(); + } + shared_lock_guard(SharedMutex& m_,adopt_lock_t): + m(m_) + {} + ~shared_lock_guard() + { + m.unlock_shared(); + } + }; + +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + + template + struct is_mutex_type > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + +#endif + + +} + +#endif // header diff --git a/boost/thread/shared_mutex.hpp b/boost/thread/shared_mutex.hpp new file mode 100644 index 0000000..20a95d8 --- /dev/null +++ b/boost/thread/shared_mutex.hpp @@ -0,0 +1,57 @@ +#ifndef BOOST_THREAD_SHARED_MUTEX_HPP +#define BOOST_THREAD_SHARED_MUTEX_HPP + +// shared_mutex.hpp +// +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#if defined(BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN) +#if defined(BOOST_THREAD_V2_SHARED_MUTEX) +#include +#else +#include +#endif +#else +#include +#endif +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#if defined(BOOST_THREAD_V2_SHARED_MUTEX) +#include +#else +#include +#endif +#else +#error "Boost threads unavailable on this platform" +#endif + +#include + +namespace boost +{ + typedef shared_mutex shared_timed_mutex; + namespace sync + { +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + template<> + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +#endif + + } +} + +#endif diff --git a/boost/thread/thread.hpp b/boost/thread/thread.hpp new file mode 100644 index 0000000..3e63b42 --- /dev/null +++ b/boost/thread/thread.hpp @@ -0,0 +1,16 @@ +#ifndef BOOST_THREAD_THREAD_HPP +#define BOOST_THREAD_THREAD_HPP + +// thread.hpp +// +// (C) Copyright 2007-8 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + + +#endif diff --git a/boost/thread/thread_only.hpp b/boost/thread/thread_only.hpp new file mode 100644 index 0000000..d408344 --- /dev/null +++ b/boost/thread/thread_only.hpp @@ -0,0 +1,29 @@ +#ifndef BOOST_THREAD_THREAD_ONLY_HPP +#define BOOST_THREAD_THREAD_ONLY_HPP + +// thread.hpp +// +// (C) Copyright 2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#include +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +#include +#else +#error "Boost threads unavailable on this platform" +#endif + +#include +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS +#include +#endif +#include + + +#endif diff --git a/boost/thread/thread_time.hpp b/boost/thread/thread_time.hpp new file mode 100644 index 0000000..ffdcf85 --- /dev/null +++ b/boost/thread/thread_time.hpp @@ -0,0 +1,55 @@ +#ifndef BOOST_THREAD_TIME_HPP +#define BOOST_THREAD_TIME_HPP +// (C) Copyright 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +#include + +namespace boost +{ + typedef boost::posix_time::ptime system_time; + + inline system_time get_system_time() + { +#if defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) + return boost::date_time::microsec_clock::universal_time(); +#else // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) + return boost::date_time::second_clock::universal_time(); +#endif // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) + } + + namespace detail + { + inline system_time get_system_time_sentinel() + { + return system_time(boost::posix_time::pos_infin); + } + + inline unsigned long get_milliseconds_until(system_time const& target_time) + { + if(target_time.is_pos_infinity()) + { + return ~(unsigned long)0; + } + system_time const now=get_system_time(); + if(target_time<=now) + { + return 0; + } + return static_cast((target_time-now).total_milliseconds()+1); + } + + } + +} + +#include + +#endif diff --git a/boost/thread/tss.hpp b/boost/thread/tss.hpp new file mode 100644 index 0000000..bcfbdf0 --- /dev/null +++ b/boost/thread/tss.hpp @@ -0,0 +1,95 @@ +#ifndef BOOST_THREAD_TSS_HPP +#define BOOST_THREAD_TSS_HPP +// 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) +// (C) Copyright 2007-8 Anthony Williams + +#include + +#include + +#include + +namespace boost +{ + namespace detail + { + namespace thread + { + typedef void(*cleanup_func_t)(void*); + typedef void(*cleanup_caller_t)(cleanup_func_t, void*); + } + + BOOST_THREAD_DECL void set_tss_data(void const* key,detail::thread::cleanup_caller_t caller,detail::thread::cleanup_func_t func,void* tss_data,bool cleanup_existing); + BOOST_THREAD_DECL void* get_tss_data(void const* key); + } + + template + class thread_specific_ptr + { + private: + thread_specific_ptr(thread_specific_ptr&); + thread_specific_ptr& operator=(thread_specific_ptr&); + + typedef void(*original_cleanup_func_t)(T*); + + static void default_deleter(T* data) + { + delete data; + } + + static void cleanup_caller(detail::thread::cleanup_func_t cleanup_function,void* data) + { + reinterpret_cast(cleanup_function)(static_cast(data)); + } + + + detail::thread::cleanup_func_t cleanup; + + public: + typedef T element_type; + + thread_specific_ptr(): + cleanup(reinterpret_cast(&default_deleter)) + {} + explicit thread_specific_ptr(void (*func_)(T*)) + : cleanup(reinterpret_cast(func_)) + {} + ~thread_specific_ptr() + { + detail::set_tss_data(this,0,0,0,true); + } + + T* get() const + { + return static_cast(detail::get_tss_data(this)); + } + T* operator->() const + { + return get(); + } + typename add_reference::type operator*() const + { + return *get(); + } + T* release() + { + T* const temp=get(); + detail::set_tss_data(this,0,0,0,false); + return temp; + } + void reset(T* new_value=0) + { + T* const current_value=get(); + if(current_value!=new_value) + { + detail::set_tss_data(this,&cleanup_caller,cleanup,new_value,true); + } + } + }; +} + +#include + +#endif diff --git a/boost/thread/v2/shared_mutex.hpp b/boost/thread/v2/shared_mutex.hpp new file mode 100644 index 0000000..e30a59e --- /dev/null +++ b/boost/thread/v2/shared_mutex.hpp @@ -0,0 +1,1052 @@ +#ifndef BOOST_THREAD_V2_SHARED_MUTEX_HPP +#define BOOST_THREAD_V2_SHARED_MUTEX_HPP + +// shared_mutex.hpp +// +// Copyright Howard Hinnant 2007-2010. +// Copyright Vicente J. Botet Escriba 2012. +// +// 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) + +/* + synopsis + +namespace boost +{ +namespace thread_v2 +{ + +class shared_mutex +{ +public: + + shared_mutex(); + ~shared_mutex(); + + shared_mutex(const shared_mutex&) = delete; + shared_mutex& operator=(const shared_mutex&) = delete; + + // Exclusive ownership + + void lock(); + bool try_lock(); + template + bool try_lock_for(const boost::chrono::duration& rel_time); + template + bool + try_lock_until( + const boost::chrono::time_point& abs_time); + void unlock(); + + // Shared ownership + + void lock_shared(); + bool try_lock_shared(); + template + bool + try_lock_shared_for(const boost::chrono::duration& rel_time); + template + bool + try_lock_shared_until( + const boost::chrono::time_point& abs_time); + void unlock_shared(); +}; + +class upgrade_mutex +{ +public: + + upgrade_mutex(); + ~upgrade_mutex(); + + upgrade_mutex(const upgrade_mutex&) = delete; + upgrade_mutex& operator=(const upgrade_mutex&) = delete; + + // Exclusive ownership + + void lock(); + bool try_lock(); + template + bool try_lock_for(const boost::chrono::duration& rel_time); + template + bool + try_lock_until( + const boost::chrono::time_point& abs_time); + void unlock(); + + // Shared ownership + + void lock_shared(); + bool try_lock_shared(); + template + bool + try_lock_shared_for(const boost::chrono::duration& rel_time); + template + bool + try_lock_shared_until( + const boost::chrono::time_point& abs_time); + void unlock_shared(); + + // Upgrade ownership + + void lock_upgrade(); + bool try_lock_upgrade(); + template + bool + try_lock_upgrade_for( + const boost::chrono::duration& rel_time); + template + bool + try_lock_upgrade_until( + const boost::chrono::time_point& abs_time); + void unlock_upgrade(); + + // Shared <-> Exclusive + + bool try_unlock_shared_and_lock(); + template + bool + try_unlock_shared_and_lock_for( + const boost::chrono::duration& rel_time); + template + bool + try_unlock_shared_and_lock_until( + const boost::chrono::time_point& abs_time); + void unlock_and_lock_shared(); + + // Shared <-> Upgrade + + bool try_unlock_shared_and_lock_upgrade(); + template + bool + try_unlock_shared_and_lock_upgrade_for( + const boost::chrono::duration& rel_time); + template + bool + try_unlock_shared_and_lock_upgrade_until( + const boost::chrono::time_point& abs_time); + void unlock_upgrade_and_lock_shared(); + + // Upgrade <-> Exclusive + + void unlock_upgrade_and_lock(); + bool try_unlock_upgrade_and_lock(); + template + bool + try_unlock_upgrade_and_lock_for( + const boost::chrono::duration& rel_time); + template + bool + try_unlock_upgrade_and_lock_until( + const boost::chrono::time_point& abs_time); + void unlock_and_lock_upgrade(); +}; + +} // thread_v2 +} // boost + + */ + +#include +#include +#include +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#endif +#include +#include +#include + +namespace boost { + namespace thread_v2 { + + class shared_mutex + { + typedef boost::mutex mutex_t; + typedef boost::condition_variable cond_t; + typedef unsigned count_t; + + mutex_t mut_; + cond_t gate1_; + // the gate2_ condition variable is only used by functions that + // have taken write_entered_ but are waiting for no_readers() + cond_t gate2_; + count_t state_; + + static const count_t write_entered_ = 1U << (sizeof(count_t)*CHAR_BIT - 1); + static const count_t n_readers_ = ~write_entered_; + + bool no_writer() const + { + return (state_ & write_entered_) == 0; + } + + bool one_writer() const + { + return (state_ & write_entered_) != 0; + } + + bool no_writer_no_readers() const + { + //return (state_ & write_entered_) == 0 && + // (state_ & n_readers_) == 0; + return state_ == 0; + } + + bool no_writer_no_max_readers() const + { + return (state_ & write_entered_) == 0 && + (state_ & n_readers_) != n_readers_; + } + + bool no_readers() const + { + return (state_ & n_readers_) == 0; + } + + bool one_or_more_readers() const + { + return (state_ & n_readers_) > 0; + } + + shared_mutex(shared_mutex const&); + shared_mutex& operator=(shared_mutex const&); + + public: + shared_mutex(); + ~shared_mutex(); + + // Exclusive ownership + + void lock(); + bool try_lock(); +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const boost::chrono::duration& rel_time) + { + return try_lock_until(chrono::steady_clock::now() + rel_time); + } + template + bool try_lock_until( + const boost::chrono::time_point& abs_time); +#endif +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_lock(T const & abs_or_rel_time); +#endif + void unlock(); + + // Shared ownership + + void lock_shared(); + bool try_lock_shared(); +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_shared_for(const boost::chrono::duration& rel_time) + { + return try_lock_shared_until(chrono::steady_clock::now() + rel_time); + } + template + bool try_lock_shared_until( + const boost::chrono::time_point& abs_time); +#endif +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_lock_shared(T const & abs_or_rel_time); +#endif + void unlock_shared(); + }; + + inline shared_mutex::shared_mutex() + : state_(0) + { + } + + inline shared_mutex::~shared_mutex() + { + boost::lock_guard _(mut_); + } + + // Exclusive ownership + + inline void shared_mutex::lock() + { + boost::unique_lock lk(mut_); + gate1_.wait(lk, boost::bind(&shared_mutex::no_writer, boost::ref(*this))); + state_ |= write_entered_; + gate2_.wait(lk, boost::bind(&shared_mutex::no_readers, boost::ref(*this))); + } + + inline bool shared_mutex::try_lock() + { + boost::unique_lock lk(mut_); + if (!no_writer_no_readers()) + { + return false; + } + state_ = write_entered_; + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + bool shared_mutex::try_lock_until( + const boost::chrono::time_point& abs_time) + { + boost::unique_lock lk(mut_); + if (!gate1_.wait_until(lk, abs_time, boost::bind( + &shared_mutex::no_writer, boost::ref(*this)))) + { + return false; + } + state_ |= write_entered_; + if (!gate2_.wait_until(lk, abs_time, boost::bind( + &shared_mutex::no_readers, boost::ref(*this)))) + { + state_ &= ~write_entered_; + return false; + } + return true; + } +#endif + +#if defined BOOST_THREAD_USES_DATETIME + template + bool shared_mutex::timed_lock(T const & abs_or_rel_time) + { + boost::unique_lock lk(mut_); + if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind( + &shared_mutex::no_writer, boost::ref(*this)))) + { + return false; + } + state_ |= write_entered_; + if (!gate2_.timed_wait(lk, abs_or_rel_time, boost::bind( + &shared_mutex::no_readers, boost::ref(*this)))) + { + state_ &= ~write_entered_; + return false; + } + return true; + } +#endif + + inline void shared_mutex::unlock() + { + boost::lock_guard _(mut_); + BOOST_ASSERT(one_writer()); + BOOST_ASSERT(no_readers()); + state_ = 0; + // notify all since multiple *lock_shared*() calls may be able + // to proceed in response to this notification + gate1_.notify_all(); + } + + // Shared ownership + + inline void shared_mutex::lock_shared() + { + boost::unique_lock lk(mut_); + gate1_.wait(lk, boost::bind(&shared_mutex::no_writer_no_max_readers, boost::ref(*this))); + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= num_readers; + } + + inline bool shared_mutex::try_lock_shared() + { + boost::unique_lock lk(mut_); + if (!no_writer_no_max_readers()) + { + return false; + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= num_readers; + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + bool shared_mutex::try_lock_shared_until( + const boost::chrono::time_point& abs_time) + { + boost::unique_lock lk(mut_); + if (!gate1_.wait_until(lk, abs_time, boost::bind( + &shared_mutex::no_writer_no_max_readers, boost::ref(*this)))) + { + return false; + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= num_readers; + return true; + } +#endif + +#if defined BOOST_THREAD_USES_DATETIME + template + bool shared_mutex::timed_lock_shared(T const & abs_or_rel_time) + { + boost::unique_lock lk(mut_); + if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind( + &shared_mutex::no_writer_no_max_readers, boost::ref(*this)))) + { + return false; + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= num_readers; + return true; + } +#endif + + inline void shared_mutex::unlock_shared() + { + boost::lock_guard _(mut_); + BOOST_ASSERT(one_or_more_readers()); + count_t num_readers = (state_ & n_readers_) - 1; + state_ &= ~n_readers_; + state_ |= num_readers; + if (no_writer()) + { + if (num_readers == n_readers_ - 1) + gate1_.notify_one(); + } + else + { + if (num_readers == 0) + gate2_.notify_one(); + } + } + + } // thread_v2 +} // boost + +namespace boost { + namespace thread_v2 { + + class upgrade_mutex + { + typedef boost::mutex mutex_t; + typedef boost::condition_variable cond_t; + typedef unsigned count_t; + + mutex_t mut_; + cond_t gate1_; + // the gate2_ condition variable is only used by functions that + // have taken write_entered_ but are waiting for no_readers() + cond_t gate2_; + count_t state_; + + static const unsigned write_entered_ = 1U << (sizeof(count_t)*CHAR_BIT - 1); + static const unsigned upgradable_entered_ = write_entered_ >> 1; + static const unsigned n_readers_ = ~(write_entered_ | upgradable_entered_); + + bool no_writer() const + { + return (state_ & write_entered_) == 0; + } + + bool one_writer() const + { + return (state_ & write_entered_) != 0; + } + + bool no_writer_no_max_readers() const + { + return (state_ & write_entered_) == 0 && + (state_ & n_readers_) != n_readers_; + } + + bool no_writer_no_upgrader() const + { + return (state_ & (write_entered_ | upgradable_entered_)) == 0; + } + + bool no_writer_no_upgrader_no_readers() const + { + //return (state_ & (write_entered_ | upgradable_entered_)) == 0 && + // (state_ & n_readers_) == 0; + return state_ == 0; + } + + bool no_writer_no_upgrader_one_reader() const + { + //return (state_ & (write_entered_ | upgradable_entered_)) == 0 && + // (state_ & n_readers_) == 1; + return state_ == 1; + } + + bool no_writer_no_upgrader_no_max_readers() const + { + return (state_ & (write_entered_ | upgradable_entered_)) == 0 && + (state_ & n_readers_) != n_readers_; + } + + bool no_upgrader() const + { + return (state_ & upgradable_entered_) == 0; + } + + bool one_upgrader() const + { + return (state_ & upgradable_entered_) != 0; + } + + bool no_readers() const + { + return (state_ & n_readers_) == 0; + } + + bool one_reader() const + { + return (state_ & n_readers_) == 1; + } + + bool one_or_more_readers() const + { + return (state_ & n_readers_) > 0; + } + + upgrade_mutex(const upgrade_mutex&); + upgrade_mutex& operator=(const upgrade_mutex&); + + public: + upgrade_mutex(); + ~upgrade_mutex(); + + // Exclusive ownership + + void lock(); + bool try_lock(); +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const boost::chrono::duration& rel_time) + { + return try_lock_until(chrono::steady_clock::now() + rel_time); + } + template + bool try_lock_until( + const boost::chrono::time_point& abs_time); +#endif +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_lock(T const & abs_or_rel_time); +#endif + void unlock(); + + // Shared ownership + + void lock_shared(); + bool try_lock_shared(); +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_shared_for(const boost::chrono::duration& rel_time) + { + return try_lock_shared_until(chrono::steady_clock::now() + rel_time); + } + template + bool try_lock_shared_until( + const boost::chrono::time_point& abs_time); +#endif +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_lock_shared(T const & abs_or_rel_time); +#endif + void unlock_shared(); + + // Upgrade ownership + + void lock_upgrade(); + bool try_lock_upgrade(); +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_upgrade_for( + const boost::chrono::duration& rel_time) + { + return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time); + } + template + bool try_lock_upgrade_until( + const boost::chrono::time_point& abs_time); +#endif +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_lock_upgrade(T const & abs_or_rel_time); +#endif + void unlock_upgrade(); + + // Shared <-> Exclusive + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + //bool unlock_shared_and_lock(); // can cause a deadlock if used + bool try_unlock_shared_and_lock(); +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_unlock_shared_and_lock_for( + const boost::chrono::duration& rel_time) + { + return try_unlock_shared_and_lock_until(chrono::steady_clock::now() + rel_time); + } + template + bool try_unlock_shared_and_lock_until( + const boost::chrono::time_point& abs_time); +#endif +#endif + void unlock_and_lock_shared(); + + // Shared <-> Upgrade + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + //bool unlock_shared_and_lock_upgrade(); // can cause a deadlock if used + bool try_unlock_shared_and_lock_upgrade(); +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_unlock_shared_and_lock_upgrade_for( + const boost::chrono::duration& rel_time) + { + return try_unlock_shared_and_lock_upgrade_until(chrono::steady_clock::now() + rel_time); + } + template + bool try_unlock_shared_and_lock_upgrade_until( + const boost::chrono::time_point& abs_time); +#endif +#endif + void unlock_upgrade_and_lock_shared(); + + // Upgrade <-> Exclusive + + void unlock_upgrade_and_lock(); + bool try_unlock_upgrade_and_lock(); +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_unlock_upgrade_and_lock_for( + const boost::chrono::duration& rel_time) + { + return try_unlock_upgrade_and_lock_until(chrono::steady_clock::now() + rel_time); + } + template + bool try_unlock_upgrade_and_lock_until( + const boost::chrono::time_point& abs_time); +#endif + void unlock_and_lock_upgrade(); + }; + + inline upgrade_mutex::upgrade_mutex() + : gate1_(), + gate2_(), + state_(0) + { + } + + inline upgrade_mutex::~upgrade_mutex() + { + boost::lock_guard _(mut_); + } + + // Exclusive ownership + + inline void upgrade_mutex::lock() + { + boost::unique_lock lk(mut_); + gate1_.wait(lk, boost::bind(&upgrade_mutex::no_writer_no_upgrader, boost::ref(*this))); + state_ |= write_entered_; + gate2_.wait(lk, boost::bind(&upgrade_mutex::no_readers, boost::ref(*this))); + } + + inline bool upgrade_mutex::try_lock() + { + boost::unique_lock lk(mut_); + if (!no_writer_no_upgrader_no_readers()) + { + return false; + } + state_ = write_entered_; + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + bool upgrade_mutex::try_lock_until( + const boost::chrono::time_point& abs_time) + { + boost::unique_lock lk(mut_); + if (!gate1_.wait_until(lk, abs_time, boost::bind( + &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this)))) + { + return false; + } + state_ |= write_entered_; + if (!gate2_.wait_until(lk, abs_time, boost::bind( + &upgrade_mutex::no_readers, boost::ref(*this)))) + { + state_ &= ~write_entered_; + return false; + } + return true; + } +#endif + +#if defined BOOST_THREAD_USES_DATETIME + template + bool upgrade_mutex::timed_lock(T const & abs_or_rel_time) + { + boost::unique_lock lk(mut_); + if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind( + &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this)))) + { + return false; + } + state_ |= write_entered_; + if (!gate2_.timed_wait(lk, abs_or_rel_time, boost::bind( + &upgrade_mutex::no_readers, boost::ref(*this)))) + { + state_ &= ~write_entered_; + return false; + } + return true; + } +#endif + + inline void upgrade_mutex::unlock() + { + boost::lock_guard _(mut_); + BOOST_ASSERT(one_writer()); + BOOST_ASSERT(no_upgrader()); + BOOST_ASSERT(no_readers()); + state_ = 0; + // notify all since multiple *lock_shared*() calls and a *lock_upgrade*() + // call may be able to proceed in response to this notification + gate1_.notify_all(); + } + + // Shared ownership + + inline void upgrade_mutex::lock_shared() + { + boost::unique_lock lk(mut_); + gate1_.wait(lk, boost::bind(&upgrade_mutex::no_writer_no_max_readers, boost::ref(*this))); + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= num_readers; + } + + inline bool upgrade_mutex::try_lock_shared() + { + boost::unique_lock lk(mut_); + if (!no_writer_no_max_readers()) + { + return false; + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= num_readers; + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + bool upgrade_mutex::try_lock_shared_until( + const boost::chrono::time_point& abs_time) + { + boost::unique_lock lk(mut_); + if (!gate1_.wait_until(lk, abs_time, boost::bind( + &upgrade_mutex::no_writer_no_max_readers, boost::ref(*this)))) + { + return false; + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= num_readers; + return true; + } +#endif + +#if defined BOOST_THREAD_USES_DATETIME + template + bool upgrade_mutex::timed_lock_shared(T const & abs_or_rel_time) + { + boost::unique_lock lk(mut_); + if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind( + &upgrade_mutex::no_writer_no_max_readers, boost::ref(*this)))) + { + return false; + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= num_readers; + return true; + } +#endif + + inline void upgrade_mutex::unlock_shared() + { + boost::lock_guard _(mut_); + BOOST_ASSERT(one_or_more_readers()); + count_t num_readers = (state_ & n_readers_) - 1; + state_ &= ~n_readers_; + state_ |= num_readers; + if (no_writer()) + { + if (num_readers == n_readers_ - 1) + gate1_.notify_one(); + } + else + { + if (num_readers == 0) + gate2_.notify_one(); + } + } + + // Upgrade ownership + + inline void upgrade_mutex::lock_upgrade() + { + boost::unique_lock lk(mut_); + gate1_.wait(lk, boost::bind(&upgrade_mutex::no_writer_no_upgrader_no_max_readers, boost::ref(*this))); + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= upgradable_entered_ | num_readers; + } + + inline bool upgrade_mutex::try_lock_upgrade() + { + boost::unique_lock lk(mut_); + if (!no_writer_no_upgrader_no_max_readers()) + { + return false; + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= upgradable_entered_ | num_readers; + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + bool upgrade_mutex::try_lock_upgrade_until( + const boost::chrono::time_point& abs_time) + { + boost::unique_lock lk(mut_); + if (!gate1_.wait_until(lk, abs_time, boost::bind( + &upgrade_mutex::no_writer_no_upgrader_no_max_readers, boost::ref(*this)))) + { + return false; + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= upgradable_entered_ | num_readers; + return true; + } +#endif + +#if defined BOOST_THREAD_USES_DATETIME + template + bool upgrade_mutex::timed_lock_upgrade(T const & abs_or_rel_time) + { + boost::unique_lock lk(mut_); + if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind( + &upgrade_mutex::no_writer_no_upgrader_no_max_readers, boost::ref(*this)))) + { + return false; + } + count_t num_readers = (state_ & n_readers_) + 1; + state_ &= ~n_readers_; + state_ |= upgradable_entered_ | num_readers; + return true; + } +#endif + + inline void upgrade_mutex::unlock_upgrade() + { + boost::lock_guard _(mut_); + BOOST_ASSERT(no_writer()); + BOOST_ASSERT(one_upgrader()); + BOOST_ASSERT(one_or_more_readers()); + count_t num_readers = (state_ & n_readers_) - 1; + state_ &= ~(upgradable_entered_ | n_readers_); + state_ |= num_readers; + // notify all since both a *lock*() and a *lock_shared*() call + // may be able to proceed in response to this notification + gate1_.notify_all(); + } + + // Shared <-> Exclusive + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + inline bool upgrade_mutex::try_unlock_shared_and_lock() + { + boost::unique_lock lk(mut_); + BOOST_ASSERT(one_or_more_readers()); + if (!no_writer_no_upgrader_one_reader()) + { + return false; + } + state_ = write_entered_; + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + bool upgrade_mutex::try_unlock_shared_and_lock_until( + const boost::chrono::time_point& abs_time) + { + boost::unique_lock lk(mut_); + BOOST_ASSERT(one_or_more_readers()); + if (!gate1_.wait_until(lk, abs_time, boost::bind( + &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this)))) + { + return false; + } + count_t num_readers = (state_ & n_readers_) - 1; + state_ &= ~n_readers_; + state_ |= (write_entered_ | num_readers); + if (!gate2_.wait_until(lk, abs_time, boost::bind( + &upgrade_mutex::no_readers, boost::ref(*this)))) + { + ++num_readers; + state_ &= ~(write_entered_ | n_readers_); + state_ |= num_readers; + return false; + } + return true; + } +#endif +#endif + + inline void upgrade_mutex::unlock_and_lock_shared() + { + boost::lock_guard _(mut_); + BOOST_ASSERT(one_writer()); + BOOST_ASSERT(no_upgrader()); + BOOST_ASSERT(no_readers()); + state_ = 1; + // notify all since multiple *lock_shared*() calls and a *lock_upgrade*() + // call may be able to proceed in response to this notification + gate1_.notify_all(); + } + + // Shared <-> Upgrade + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + inline bool upgrade_mutex::try_unlock_shared_and_lock_upgrade() + { + boost::unique_lock lk(mut_); + BOOST_ASSERT(one_or_more_readers()); + if (!no_writer_no_upgrader()) + { + return false; + } + state_ |= upgradable_entered_; + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + bool upgrade_mutex::try_unlock_shared_and_lock_upgrade_until( + const boost::chrono::time_point& abs_time) + { + boost::unique_lock lk(mut_); + BOOST_ASSERT(one_or_more_readers()); + if (!gate1_.wait_until(lk, abs_time, boost::bind( + &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this)))) + { + return false; + } + state_ |= upgradable_entered_; + return true; + } +#endif +#endif + + inline void upgrade_mutex::unlock_upgrade_and_lock_shared() + { + boost::lock_guard _(mut_); + BOOST_ASSERT(no_writer()); + BOOST_ASSERT(one_upgrader()); + BOOST_ASSERT(one_or_more_readers()); + state_ &= ~upgradable_entered_; + // notify all since only one *lock*() or *lock_upgrade*() call can win and + // proceed in response to this notification, but a *lock_shared*() call may + // also be waiting and could steal the notification + gate1_.notify_all(); + } + + // Upgrade <-> Exclusive + + inline void upgrade_mutex::unlock_upgrade_and_lock() + { + boost::unique_lock lk(mut_); + BOOST_ASSERT(no_writer()); + BOOST_ASSERT(one_upgrader()); + BOOST_ASSERT(one_or_more_readers()); + count_t num_readers = (state_ & n_readers_) - 1; + state_ &= ~(upgradable_entered_ | n_readers_); + state_ |= write_entered_ | num_readers; + gate2_.wait(lk, boost::bind(&upgrade_mutex::no_readers, boost::ref(*this))); + } + + inline bool upgrade_mutex::try_unlock_upgrade_and_lock() + { + boost::unique_lock lk(mut_); + BOOST_ASSERT(no_writer()); + BOOST_ASSERT(one_upgrader()); + BOOST_ASSERT(one_or_more_readers()); + if (!one_reader()) + { + return false; + } + state_ = write_entered_; + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + bool upgrade_mutex::try_unlock_upgrade_and_lock_until( + const boost::chrono::time_point& abs_time) + { + boost::unique_lock lk(mut_); + BOOST_ASSERT(no_writer()); + BOOST_ASSERT(one_upgrader()); + BOOST_ASSERT(one_or_more_readers()); + count_t num_readers = (state_ & n_readers_) - 1; + state_ &= ~(upgradable_entered_ | n_readers_); + state_ |= (write_entered_ | num_readers); + if (!gate2_.wait_until(lk, abs_time, boost::bind( + &upgrade_mutex::no_readers, boost::ref(*this)))) + { + ++num_readers; + state_ &= ~(write_entered_ | n_readers_); + state_ |= (upgradable_entered_ | num_readers); + return false; + } + return true; + } +#endif + + inline void upgrade_mutex::unlock_and_lock_upgrade() + { + boost::lock_guard _(mut_); + BOOST_ASSERT(one_writer()); + BOOST_ASSERT(no_upgrader()); + BOOST_ASSERT(no_readers()); + state_ = upgradable_entered_ | 1; + // notify all since multiple *lock_shared*() calls may be able + // to proceed in response to this notification + gate1_.notify_all(); + } + + } // thread_v2 +} // boost + +namespace boost { + //using thread_v2::shared_mutex; + using thread_v2::upgrade_mutex; + typedef thread_v2::upgrade_mutex shared_mutex; +} + +#endif diff --git a/boost/thread/win32/basic_recursive_mutex.hpp b/boost/thread/win32/basic_recursive_mutex.hpp new file mode 100644 index 0000000..1fa05ad --- /dev/null +++ b/boost/thread/win32/basic_recursive_mutex.hpp @@ -0,0 +1,176 @@ +#ifndef BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP +#define BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP + +// basic_recursive_mutex.hpp +// +// (C) Copyright 2006-8 Anthony Williams +// (C) Copyright 2011-2012,2017-2018 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif + +#include + +namespace boost +{ + namespace detail + { + template + struct basic_recursive_mutex_impl + { + long recursion_count; + long locking_thread_id; + underlying_mutex_type mutex; + + void initialize() + { + recursion_count=0; + locking_thread_id=0; + mutex.initialize(); + } + + void destroy() + { + mutex.destroy(); + } + + bool try_lock() BOOST_NOEXCEPT + { + long const current_thread_id=boost::winapi::GetCurrentThreadId(); + return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id); + } + + void lock() + { + long const current_thread_id=boost::winapi::GetCurrentThreadId(); + if(!try_recursive_lock(current_thread_id)) + { + mutex.lock(); + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + } + } +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(::boost::system_time const& target) + { + long const current_thread_id=boost::winapi::GetCurrentThreadId(); + return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target); + } + template + bool timed_lock(Duration const& target) + { + long const current_thread_id=boost::winapi::GetCurrentThreadId(); + return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target); + } +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const chrono::duration& rel_time) + { + long const current_thread_id=boost::winapi::GetCurrentThreadId(); + return try_recursive_lock(current_thread_id) || try_timed_lock_for(current_thread_id,rel_time); + } + template + bool try_lock_until(const chrono::time_point& t) + { + long const current_thread_id=boost::winapi::GetCurrentThreadId(); + return try_recursive_lock(current_thread_id) || try_timed_lock_until(current_thread_id,t); + } +#endif + void unlock() + { + if(!--recursion_count) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,0); + mutex.unlock(); + } + } + + private: + bool try_recursive_lock(long current_thread_id) BOOST_NOEXCEPT + { + if(::boost::detail::interlocked_read_acquire(&locking_thread_id)==current_thread_id) + { + ++recursion_count; + return true; + } + return false; + } + + bool try_basic_lock(long current_thread_id) BOOST_NOEXCEPT + { + if(mutex.try_lock()) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + return true; + } + return false; + } + +#if defined BOOST_THREAD_USES_DATETIME + bool try_timed_lock(long current_thread_id,::boost::system_time const& target) + { + if(mutex.timed_lock(target)) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + return true; + } + return false; + } + template + bool try_timed_lock(long current_thread_id,Duration const& target) + { + if(mutex.timed_lock(target)) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + return true; + } + return false; + } +#endif + template + bool try_timed_lock_until(long current_thread_id,TP const& target) + { + if(mutex.try_lock_until(target)) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + return true; + } + return false; + } + template + bool try_timed_lock_for(long current_thread_id,D const& target) + { + if(mutex.try_lock_for(target)) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + return true; + } + return false; + } + }; + + typedef basic_recursive_mutex_impl basic_recursive_mutex; + typedef basic_recursive_mutex_impl basic_recursive_timed_mutex; + } +} + +#define BOOST_BASIC_RECURSIVE_MUTEX_INITIALIZER {0} + +#include + +#endif diff --git a/boost/thread/win32/basic_timed_mutex.hpp b/boost/thread/win32/basic_timed_mutex.hpp new file mode 100644 index 0000000..b332dab --- /dev/null +++ b/boost/thread/win32/basic_timed_mutex.hpp @@ -0,0 +1,297 @@ +#ifndef BOOST_BASIC_TIMED_MUTEX_WIN32_HPP +#define BOOST_BASIC_TIMED_MUTEX_WIN32_HPP + +// basic_timed_mutex_win32.hpp +// +// (C) Copyright 2006-8 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#if defined BOOST_THREAD_USES_DATETIME +#include +#endif +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif +#include + +#include + +namespace boost +{ + namespace detail + { + struct basic_timed_mutex + { + BOOST_STATIC_CONSTANT(unsigned char,lock_flag_bit=31); + BOOST_STATIC_CONSTANT(unsigned char,event_set_flag_bit=30); + BOOST_STATIC_CONSTANT(long,lock_flag_value=1<(d.getMs()); + } + + template + unsigned long getMs(Duration const& d) + { + return static_cast(chrono::ceil(d).count()); + } + + template + bool do_lock_until(Timepoint const& t, Duration const& max) + { + if(try_lock()) + { + return true; + } + + long old_count=active_count; + mark_waiting_and_try_lock(old_count); + + if(old_count&lock_flag_value) + { + void* const sem=get_event(); + + // If the clock is the system clock, it may jump while this function + // is waiting. To compensate for this and time out near the correct + // time, we call WaitForSingleObjectEx() in a loop with a short + // timeout and recheck the time remaining each time through the loop. + do + { + Duration d(t - Clock::now()); + if(d <= Duration::zero()) // timeout occurred + { + BOOST_INTERLOCKED_DECREMENT(&active_count); + return false; + } + if(max != Duration::zero()) + { + d = (std::min)(d, max); + } + if(winapi::WaitForSingleObjectEx(sem,getMs(d),0)==0) + { + clear_waiting_and_try_lock(old_count); + } + } + while(old_count&lock_flag_value); + } + return true; + } + public: + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(::boost::system_time const& wait_until) + { + const detail::real_platform_timepoint t(wait_until); + return do_lock_until(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } + + template + bool timed_lock(Duration const& timeout) + { + const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(timeout)); + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_until(t, detail::platform_duration::zero()); + } + + bool timed_lock(boost::xtime const& timeout) + { + return timed_lock(boost::system_time(timeout)); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const chrono::duration& rel_time) + { + const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time); + typedef typename chrono::duration Duration; + typedef typename common_type::type common_duration; + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_until(t, common_duration::zero()); + } + template + bool try_lock_until(const chrono::time_point& t) + { + typedef typename common_type::type common_duration; + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_until(t, common_duration::zero()); + } + template + bool try_lock_until(const chrono::time_point& t) + { + typedef typename common_type::type common_duration; + return do_lock_until(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + } +#endif + + void unlock() + { + // Clear the lock flag using atomic addition (works since long is always 32 bits on Windows) + long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value); + // If someone is waiting to take the lock, set the event set flag and, if + // the event set flag hadn't already been set, send an event. + if(!(old_count&event_set_flag_value) && (old_count>lock_flag_value)) + { + if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit)) + { + winapi::SetEvent(get_event()); + } + } + } + + private: + // Create an event in a thread-safe way + // The first thread to create the event wins and all other thread will use that event + void* get_event() + { + void* current_event=::boost::detail::interlocked_read_acquire(&event); + + if(!current_event) + { + void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset); +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4311) +#pragma warning(disable:4312) +#endif + void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0); +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + if(old_event!=0) + { + winapi::CloseHandle(new_event); + return old_event; + } + else + { + return new_event; + } + } + return current_event; + } + + }; + + } +} + +#define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0} + +#include + +#endif diff --git a/boost/thread/win32/condition_variable.hpp b/boost/thread/win32/condition_variable.hpp new file mode 100644 index 0000000..5cf975a --- /dev/null +++ b/boost/thread/win32/condition_variable.hpp @@ -0,0 +1,725 @@ +#ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP +#define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP +// 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) +// (C) Copyright 2007-8 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#include +#include +#include +#include +#include +#if defined BOOST_THREAD_USES_DATETIME +#include +#endif +#include +#include +#include +#include +#include + +#include +#include + +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif + +#include +#include +#include + +#include + +namespace boost +{ + namespace detail + { + class basic_cv_list_entry; + void intrusive_ptr_add_ref(basic_cv_list_entry * p); + void intrusive_ptr_release(basic_cv_list_entry * p); + + class basic_cv_list_entry + { + private: + detail::win32::handle_manager semaphore; + detail::win32::handle_manager wake_sem; + long waiters; + bool notified; + long references; + + public: + BOOST_THREAD_NO_COPYABLE(basic_cv_list_entry) + explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_): + semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)), + wake_sem(wake_sem_.duplicate()), + waiters(1),notified(false),references(0) + {} + + static bool no_waiters(boost::intrusive_ptr const& entry) + { + return !detail::interlocked_read_acquire(&entry->waiters); + } + + void add_waiter() + { + BOOST_INTERLOCKED_INCREMENT(&waiters); + } + + void remove_waiter() + { + BOOST_INTERLOCKED_DECREMENT(&waiters); + } + + void release(unsigned count_to_release) + { + notified=true; + winapi::ReleaseSemaphore(semaphore,count_to_release,0); + } + + void release_waiters() + { + release(detail::interlocked_read_acquire(&waiters)); + } + + bool is_notified() const + { + return notified; + } + + bool interruptible_wait(detail::internal_platform_timepoint const &timeout) + { + return this_thread::interruptible_wait(semaphore, timeout); + } + + bool woken() + { + unsigned long const woken_result=winapi::WaitForSingleObjectEx(wake_sem,0,0); + BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0)); + return woken_result==0; + } + + friend void intrusive_ptr_add_ref(basic_cv_list_entry * p); + friend void intrusive_ptr_release(basic_cv_list_entry * p); + }; + + inline void intrusive_ptr_add_ref(basic_cv_list_entry * p) + { + BOOST_INTERLOCKED_INCREMENT(&p->references); + } + + inline void intrusive_ptr_release(basic_cv_list_entry * p) + { + if(!BOOST_INTERLOCKED_DECREMENT(&p->references)) + { + delete p; + } + } + + class basic_condition_variable + { + boost::mutex internal_mutex; + long total_count; + unsigned active_generation_count; + + typedef basic_cv_list_entry list_entry; + + typedef boost::intrusive_ptr entry_ptr; + typedef std::vector generation_list; + + generation_list generations; + detail::win32::handle_manager wake_sem; + + void wake_waiters(long count_to_wake) + { + detail::interlocked_write_release(&total_count,total_count-count_to_wake); + winapi::ReleaseSemaphore(wake_sem,count_to_wake,0); + } + + template + struct relocker + { + BOOST_THREAD_NO_COPYABLE(relocker) + lock_type& _lock; + bool _unlocked; + + relocker(lock_type& lock_): + _lock(lock_), _unlocked(false) + {} + void unlock() + { + if ( ! _unlocked ) + { + _lock.unlock(); + _unlocked=true; + } + } + void lock() + { + if ( _unlocked ) + { + _lock.lock(); + _unlocked=false; + } + } + ~relocker() BOOST_NOEXCEPT_IF(false) + { + lock(); + } + }; + + + entry_ptr get_wait_entry() + { + boost::lock_guard lk(internal_mutex); + if(!wake_sem) + { + wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + BOOST_ASSERT(wake_sem); + } + + detail::interlocked_write_release(&total_count,total_count+1); + if(generations.empty() || generations.back()->is_notified()) + { + entry_ptr new_entry(new list_entry(wake_sem)); + generations.push_back(new_entry); + return new_entry; + } + else + { + generations.back()->add_waiter(); + return generations.back(); + } + } + + struct entry_manager + { + entry_ptr entry; + boost::mutex& internal_mutex; + + + BOOST_THREAD_NO_COPYABLE(entry_manager) +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + entry_manager(entry_ptr&& entry_, boost::mutex& mutex_): + entry(static_cast< entry_ptr&& >(entry_)), internal_mutex(mutex_) + {} +#else + entry_manager(entry_ptr const& entry_, boost::mutex& mutex_): + entry(entry_), internal_mutex(mutex_) + {} +#endif + + void remove_waiter_and_reset() + { + if (entry) { + boost::lock_guard internal_lock(internal_mutex); + entry->remove_waiter(); + entry.reset(); + } + } + ~entry_manager() BOOST_NOEXCEPT_IF(false) + { + remove_waiter_and_reset(); + } + + list_entry* operator->() + { + return entry.get(); + } + }; + + protected: + basic_condition_variable(const basic_condition_variable& other); + basic_condition_variable& operator=(const basic_condition_variable& other); + + public: + basic_condition_variable(): + total_count(0),active_generation_count(0),wake_sem(0) + {} + + ~basic_condition_variable() + {} + + // When this function returns true: + // * A notification (or sometimes a spurious OS signal) has been received + // * Do not assume that the timeout has not been reached + // * Do not assume that the predicate has been changed + // + // When this function returns false: + // * The timeout has been reached + // * Do not assume that a notification has not been received + // * Do not assume that the predicate has not been changed + template + bool do_wait_until(lock_type& lock, detail::internal_platform_timepoint const &timeout) + { + relocker locker(lock); + entry_manager entry(get_wait_entry(), internal_mutex); + locker.unlock(); + + bool woken=false; + while(!woken) + { + if(!entry->interruptible_wait(timeout)) + { + return false; + } + + woken=entry->woken(); + } + // do it here to avoid throwing on the destructor + entry.remove_waiter_and_reset(); + locker.lock(); + return true; + } + + void notify_one() BOOST_NOEXCEPT + { + if(detail::interlocked_read_acquire(&total_count)) + { + boost::lock_guard internal_lock(internal_mutex); + if(!total_count) + { + return; + } + wake_waiters(1); + + for(generation_list::iterator it=generations.begin(), + end=generations.end(); + it!=end;++it) + { + (*it)->release(1); + } + generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end()); + } + } + + void notify_all() BOOST_NOEXCEPT + { + if(detail::interlocked_read_acquire(&total_count)) + { + boost::lock_guard internal_lock(internal_mutex); + if(!total_count) + { + return; + } + wake_waiters(total_count); + for(generation_list::iterator it=generations.begin(), + end=generations.end(); + it!=end;++it) + { + (*it)->release_waiters(); + } + generations.clear(); + wake_sem=detail::win32::handle(0); + } + } + + }; + } + + class condition_variable: + private detail::basic_condition_variable + { + public: + BOOST_THREAD_NO_COPYABLE(condition_variable) + condition_variable() + {} + + using detail::basic_condition_variable::do_wait_until; + using detail::basic_condition_variable::notify_one; + using detail::basic_condition_variable::notify_all; + + void wait(unique_lock& m) + { + do_wait_until(m, detail::internal_platform_timepoint::getMax()); + } + + template + void wait(unique_lock& m,predicate_type pred) + { + while (!pred()) + { + wait(m); + } + } + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_wait(unique_lock& m,boost::system_time const& abs_time) + { + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + const detail::real_platform_timepoint ts(abs_time); + const detail::platform_duration d(ts - detail::real_platform_clock::now()); + do_wait_until(m, detail::internal_platform_clock::now() + d); + return ts > detail::real_platform_clock::now(); + } + bool timed_wait(unique_lock& m,boost::xtime const& abs_time) + { + return timed_wait(m, system_time(abs_time)); + } + template + bool timed_wait(unique_lock& m,duration_type const& wait_duration) + { + if (wait_duration.is_pos_infinity()) + { + wait(m); + return true; + } + if (wait_duration.is_special()) + { + return true; + } + const detail::platform_duration d(wait_duration); + return do_wait_until(m, detail::internal_platform_clock::now() + d); + } + + template + bool timed_wait(unique_lock& m,boost::system_time const& abs_time,predicate_type pred) + { + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + const detail::real_platform_timepoint ts(abs_time); + while (!pred()) + { + detail::platform_duration d(ts - detail::real_platform_clock::now()); + if (d <= detail::platform_duration::zero()) break; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + do_wait_until(m, detail::internal_platform_clock::now() + d); + } + return pred(); + } + template + bool timed_wait(unique_lock& m,boost::xtime const& abs_time,predicate_type pred) + { + return timed_wait(m, system_time(abs_time), pred); + } + template + bool timed_wait(unique_lock& m,duration_type const& wait_duration,predicate_type pred) + { + if (wait_duration.is_pos_infinity()) + { + while (!pred()) + { + wait(m); + } + return true; + } + if (wait_duration.is_special()) + { + return pred(); + } + const detail::platform_duration d(wait_duration); + const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d); + while (!pred()) + { + if (!do_wait_until(m, ts)) break; // timeout occurred + } + return pred(); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + cv_status + wait_until( + unique_lock& lock, + const chrono::time_point& t) + { + const detail::internal_platform_timepoint ts(t); + if (do_wait_until(lock, ts)) return cv_status::no_timeout; + else return cv_status::timeout; + } + + template + cv_status + wait_until( + unique_lock& lock, + const chrono::time_point& t) + { + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + typedef typename common_type::type common_duration; + common_duration d(t - Clock::now()); + do_wait_until(lock, detail::internal_chrono_clock::now() + d); + if (t > Clock::now()) return cv_status::no_timeout; + else return cv_status::timeout; + } + + template + cv_status + wait_for( + unique_lock& lock, + const chrono::duration& d) + { + return wait_until(lock, chrono::steady_clock::now() + d); + } + + template + bool + wait_until( + unique_lock& lock, + const chrono::time_point& t, + Predicate pred) + { + const detail::internal_platform_timepoint ts(t); + while (!pred()) + { + if (!do_wait_until(lock, ts)) break; // timeout occurred + } + return pred(); + } + + template + bool + wait_until( + unique_lock& lock, + const chrono::time_point& t, + Predicate pred) + { + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + typedef typename common_type::type common_duration; + while (!pred()) + { + common_duration d(t - Clock::now()); + if (d <= common_duration::zero()) break; // timeout occurred + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d)); + } + return pred(); + } + + template + bool + wait_for( + unique_lock& lock, + const chrono::duration& d, + Predicate pred) + { + return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); + } +#endif + }; + + class condition_variable_any: + private detail::basic_condition_variable + { + public: + BOOST_THREAD_NO_COPYABLE(condition_variable_any) + condition_variable_any() + {} + + using detail::basic_condition_variable::do_wait_until; + using detail::basic_condition_variable::notify_one; + using detail::basic_condition_variable::notify_all; + + template + void wait(lock_type& m) + { + do_wait_until(m, detail::internal_platform_timepoint::getMax()); + } + + template + void wait(lock_type& m,predicate_type pred) + { + while (!pred()) + { + wait(m); + } + } + +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_wait(lock_type& m,boost::system_time const& abs_time) + { + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + const detail::real_platform_timepoint ts(abs_time); + const detail::platform_duration d(ts - detail::real_platform_clock::now()); + do_wait_until(m, detail::internal_platform_clock::now() + d); + return ts > detail::real_platform_clock::now(); + } + + template + bool timed_wait(lock_type& m,boost::xtime const& abs_time) + { + return timed_wait(m, system_time(abs_time)); + } + + template + bool timed_wait(lock_type& m,duration_type const& wait_duration) + { + if (wait_duration.is_pos_infinity()) + { + wait(m); + return true; + } + if (wait_duration.is_special()) + { + return true; + } + const detail::platform_duration d(wait_duration); + return do_wait_until(m, detail::internal_platform_clock::now() + d); + } + + template + bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred) + { + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + const detail::real_platform_timepoint ts(abs_time); + while (!pred()) + { + detail::platform_duration d(ts - detail::real_platform_clock::now()); + if (d <= detail::platform_duration::zero()) break; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + do_wait_until(m, detail::internal_platform_clock::now() + d); + } + return pred(); + } + + template + bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred) + { + return timed_wait(m, system_time(abs_time), pred); + } + + template + bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) + { + if (wait_duration.is_pos_infinity()) + { + while (!pred()) + { + wait(m); + } + return true; + } + if (wait_duration.is_special()) + { + return pred(); + } + const detail::platform_duration d(wait_duration); + const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d); + while (!pred()) + { + if (!do_wait_until(m, ts)) break; // timeout occurred + } + return pred(); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + cv_status + wait_until( + lock_type& lock, + const chrono::time_point& t) + { + const detail::internal_platform_timepoint ts(t); + if (do_wait_until(lock, ts)) return cv_status::no_timeout; + else return cv_status::timeout; + } + + template + cv_status + wait_until( + lock_type& lock, + const chrono::time_point& t) + { + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + typedef typename common_type::type common_duration; + common_duration d(t - Clock::now()); + do_wait_until(lock, detail::internal_chrono_clock::now() + d); + if (t > Clock::now()) return cv_status::no_timeout; + else return cv_status::timeout; + } + + template + cv_status + wait_for( + lock_type& lock, + const chrono::duration& d) + { + return wait_until(lock, chrono::steady_clock::now() + d); + } + + template + bool + wait_until( + lock_type& lock, + const chrono::time_point& t, + Predicate pred) + { + const detail::internal_platform_timepoint ts(t); + while (!pred()) + { + if (!do_wait_until(lock, ts)) break; // timeout occurred + } + return pred(); + } + + template + bool + wait_until( + lock_type& lock, + const chrono::time_point& t, + Predicate pred) + { + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + typedef typename common_type::type common_duration; + while (!pred()) + { + common_duration d(t - Clock::now()); + if (d <= common_duration::zero()) break; // timeout occurred + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d)); + } + return pred(); + } + + template + bool + wait_for( + lock_type& lock, + const chrono::duration& d, + Predicate pred) + { + return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); + } +#endif + }; + + BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); +} + +#include + +#endif diff --git a/boost/thread/win32/interlocked_read.hpp b/boost/thread/win32/interlocked_read.hpp new file mode 100644 index 0000000..e25c21e --- /dev/null +++ b/boost/thread/win32/interlocked_read.hpp @@ -0,0 +1,214 @@ +#ifndef BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP +#define BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP + +// interlocked_read_win32.hpp +// +// (C) Copyright 2005-8 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba +// (C) Copyright 2017 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +#include + +// Define compiler barriers +#if defined(__INTEL_COMPILER) +#define BOOST_THREAD_DETAIL_COMPILER_BARRIER() __memory_barrier() +#elif defined(_MSC_VER) && !defined(_WIN32_WCE) +extern "C" void _ReadWriteBarrier(void); +#pragma intrinsic(_ReadWriteBarrier) +#define BOOST_THREAD_DETAIL_COMPILER_BARRIER() _ReadWriteBarrier() +#endif + +#ifndef BOOST_THREAD_DETAIL_COMPILER_BARRIER +#define BOOST_THREAD_DETAIL_COMPILER_BARRIER() +#endif + +#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) + +// Since VS2005 and until VS2012 volatile reads always acquire and volatile writes are always release. +// But VS2012 adds a compiler switch that can change behavior to the standard. On x86 though +// the compiler generates a single instruction for the load/store, which is enough synchronization +// as far as uarch is concerned. To prevent compiler reordering code around the load/store we add +// compiler barriers. + +namespace boost +{ + namespace detail + { + inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT + { + long const res=*x; + BOOST_THREAD_DETAIL_COMPILER_BARRIER(); + return res; + } + inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT + { + void* const res=*x; + BOOST_THREAD_DETAIL_COMPILER_BARRIER(); + return res; + } + + inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT + { + BOOST_THREAD_DETAIL_COMPILER_BARRIER(); + *x=value; + } + inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT + { + BOOST_THREAD_DETAIL_COMPILER_BARRIER(); + *x=value; + } + } +} + +#elif defined(_MSC_VER) && _MSC_VER >= 1700 && (defined(_M_ARM) || defined(_M_ARM64)) + +#include + +namespace boost +{ + namespace detail + { + inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT + { + long const res=__iso_volatile_load32((const volatile __int32*)x); + BOOST_THREAD_DETAIL_COMPILER_BARRIER(); + __dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later + BOOST_THREAD_DETAIL_COMPILER_BARRIER(); + return res; + } + inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT + { + void* const res= +#if defined(_M_ARM64) + (void*)__iso_volatile_load64((const volatile __int64*)x); +#else + (void*)__iso_volatile_load32((const volatile __int32*)x); +#endif + BOOST_THREAD_DETAIL_COMPILER_BARRIER(); + __dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later + BOOST_THREAD_DETAIL_COMPILER_BARRIER(); + return res; + } + + inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT + { + BOOST_THREAD_DETAIL_COMPILER_BARRIER(); + __dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later + BOOST_THREAD_DETAIL_COMPILER_BARRIER(); + __iso_volatile_store32((volatile __int32*)x, (__int32)value); + } + inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT + { + BOOST_THREAD_DETAIL_COMPILER_BARRIER(); + __dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later + BOOST_THREAD_DETAIL_COMPILER_BARRIER(); +#if defined(_M_ARM64) + __iso_volatile_store64((volatile __int64*)x, (__int64)value); +#else + __iso_volatile_store32((volatile __int32*)x, (__int32)value); +#endif + } + } +} + +#elif defined(__GNUC__) && (((__GNUC__ * 100 + __GNUC_MINOR__) >= 407) || (defined(__clang__) && (__clang_major__ * 100 + __clang_minor__) >= 302)) + +namespace boost +{ + namespace detail + { + inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT + { + return __atomic_load_n((long*)x, __ATOMIC_ACQUIRE); + } + inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT + { + return __atomic_load_n((void**)x, __ATOMIC_ACQUIRE); + } + + inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT + { + __atomic_store_n((long*)x, value, __ATOMIC_RELEASE); + } + inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT + { + __atomic_store_n((void**)x, value, __ATOMIC_RELEASE); + } + } +} + +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +namespace boost +{ + namespace detail + { + inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT + { + long res; + __asm__ __volatile__ ("movl %1, %0" : "=r" (res) : "m" (*x) : "memory"); + return res; + } + inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT + { + void* res; +#if defined(__x86_64__) + __asm__ __volatile__ ("movq %1, %0" : "=r" (res) : "m" (*x) : "memory"); +#else + __asm__ __volatile__ ("movl %1, %0" : "=r" (res) : "m" (*x) : "memory"); +#endif + return res; + } + + inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT + { + __asm__ __volatile__ ("movl %1, %0" : "=m" (*x) : "r" (value) : "memory"); + } + inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT + { +#if defined(__x86_64__) + __asm__ __volatile__ ("movq %1, %0" : "=m" (*x) : "r" (value) : "memory"); +#else + __asm__ __volatile__ ("movl %1, %0" : "=m" (*x) : "r" (value) : "memory"); +#endif + } + } +} + +#else + +namespace boost +{ + namespace detail + { + inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT + { + return BOOST_INTERLOCKED_COMPARE_EXCHANGE((long*)x,0,0); + } + inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT + { + return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER((void**)x,0,0); + } + inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT + { + BOOST_INTERLOCKED_EXCHANGE((long*)x,value); + } + inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT + { + BOOST_INTERLOCKED_EXCHANGE_POINTER((void**)x,value); + } + } +} + +#endif + +#include + +#endif diff --git a/boost/thread/win32/mutex.hpp b/boost/thread/win32/mutex.hpp new file mode 100644 index 0000000..0154478 --- /dev/null +++ b/boost/thread/win32/mutex.hpp @@ -0,0 +1,72 @@ +#ifndef BOOST_THREAD_WIN32_MUTEX_HPP +#define BOOST_THREAD_WIN32_MUTEX_HPP +// (C) Copyright 2005-7 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include +#endif +#include + +#include + +namespace boost +{ + namespace detail + { + typedef ::boost::detail::basic_timed_mutex underlying_mutex; + } + + class mutex: + public ::boost::detail::underlying_mutex + { + public: + BOOST_THREAD_NO_COPYABLE(mutex) + mutex() + { + initialize(); + } + ~mutex() + { + destroy(); + } + +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + typedef unique_lock scoped_lock; + typedef detail::try_lock_wrapper scoped_try_lock; +#endif + }; + + typedef mutex try_mutex; + + class timed_mutex: + public ::boost::detail::basic_timed_mutex + { + public: + BOOST_THREAD_NO_COPYABLE(timed_mutex) + timed_mutex() + { + initialize(); + } + + ~timed_mutex() + { + destroy(); + } + +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + typedef unique_lock scoped_timed_lock; + typedef detail::try_lock_wrapper scoped_try_lock; + typedef scoped_timed_lock scoped_lock; +#endif + }; +} + +#include + +#endif diff --git a/boost/thread/win32/once.hpp b/boost/thread/win32/once.hpp new file mode 100644 index 0000000..3c515ba --- /dev/null +++ b/boost/thread/win32/once.hpp @@ -0,0 +1,1087 @@ +#ifndef BOOST_THREAD_WIN32_ONCE_HPP +#define BOOST_THREAD_WIN32_ONCE_HPP + +// once.hpp +// +// (C) Copyright 2005-7 Anthony Williams +// (C) Copyright 2005 John Maddock +// (C) Copyright 2011-2013 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std +{ + using ::memcpy; + using ::ptrdiff_t; +} +#endif + +namespace boost +{ + struct once_flag; + namespace detail + { + struct once_context; + + inline bool enter_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT; + inline void commit_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT; + inline void rollback_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT; + } + +#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 + + struct once_flag + { + BOOST_THREAD_NO_COPYABLE(once_flag) + BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT + : status(0), count(0) + {} + long status; + long count; + private: + friend inline bool enter_once_region(once_flag& flag, detail::once_context& ctx) BOOST_NOEXCEPT; + friend inline void commit_once_region(once_flag& flag, detail::once_context& ctx) BOOST_NOEXCEPT; + friend inline void rollback_once_region(once_flag& flag, detail::once_context& ctx) BOOST_NOEXCEPT; + }; + +#define BOOST_ONCE_INIT once_flag() +#else // BOOST_THREAD_PROVIDES_ONCE_CXX11 + + struct once_flag + { + long status; + long count; + }; + +#define BOOST_ONCE_INIT {0,0} +#endif // BOOST_THREAD_PROVIDES_ONCE_CXX11 + +#if defined BOOST_THREAD_PROVIDES_INVOKE +#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke +#define BOOST_THREAD_INVOKE_RET_VOID_CALL +#elif defined BOOST_THREAD_PROVIDES_INVOKE_RET +#define BOOST_THREAD_INVOKE_RET_VOID detail::invoke +#define BOOST_THREAD_INVOKE_RET_VOID_CALL +#else +#define BOOST_THREAD_INVOKE_RET_VOID boost::bind +#define BOOST_THREAD_INVOKE_RET_VOID_CALL () +#endif + + namespace detail + { +#ifdef BOOST_NO_ANSI_APIS + typedef wchar_t once_char_type; +#else + typedef char once_char_type; +#endif + unsigned const once_mutex_name_fixed_length=54; + unsigned const once_mutex_name_length=once_mutex_name_fixed_length+ + sizeof(void*)*2+sizeof(unsigned long)*2+1; + + template + void int_to_string(I p, once_char_type* buf) + { + for(unsigned i=0; i < sizeof(I)*2; ++i,++buf) + { +#ifdef BOOST_NO_ANSI_APIS + once_char_type const a=L'A'; +#else + once_char_type const a='A'; +#endif + *buf = a + static_cast((p >> (i*4)) & 0x0f); + } + *buf = 0; + } + + inline void name_once_mutex(once_char_type* mutex_name,void* flag_address) + { +#ifdef BOOST_NO_ANSI_APIS + static const once_char_type fixed_mutex_name[]=L"Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag"; +#else + static const once_char_type fixed_mutex_name[]="Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag"; +#endif + BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) == + (sizeof(once_char_type)*(once_mutex_name_fixed_length+1))); + + std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name)); + detail::int_to_string(reinterpret_cast(flag_address), + mutex_name + once_mutex_name_fixed_length); + detail::int_to_string(winapi::GetCurrentProcessId(), + mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2); + } + + inline void* open_once_event(once_char_type* mutex_name,void* flag_address) + { + if(!*mutex_name) + { + name_once_mutex(mutex_name,flag_address); + } + +#ifdef BOOST_NO_ANSI_APIS + return ::boost::winapi::OpenEventW( +#else + return ::boost::winapi::OpenEventA( +#endif + ::boost::detail::win32::synchronize | + ::boost::detail::win32::event_modify_state, + false, + mutex_name); + } + + inline void* create_once_event(once_char_type* mutex_name,void* flag_address) + { + if(!*mutex_name) + { + name_once_mutex(mutex_name,flag_address); + } + + return ::boost::detail::win32::create_event( + mutex_name, + ::boost::detail::win32::manual_reset_event, + ::boost::detail::win32::event_initially_reset); + } + + struct once_context { + long const function_complete_flag_value; + long const running_value; + bool counted; + detail::win32::handle_manager event_handle; + detail::once_char_type mutex_name[once_mutex_name_length]; + once_context() : + function_complete_flag_value(0xc15730e2), + running_value(0x7f0725e3), + counted(false) + { + mutex_name[0]=0; + } + }; + enum once_action {try_, break_, continue_}; + + inline bool enter_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT + { + long status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,ctx.running_value,0); + if(!status) + { + if(!ctx.event_handle) + { + ctx.event_handle=detail::open_once_event(ctx.mutex_name,&flag); + } + if(ctx.event_handle) + { + ::boost::winapi::ResetEvent(ctx.event_handle); + } + return true; + } + return false; + } + inline void commit_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT + { + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + } + BOOST_INTERLOCKED_EXCHANGE(&flag.status,ctx.function_complete_flag_value); + if(!ctx.event_handle && + (::boost::detail::interlocked_read_acquire(&flag.count)>1)) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + } + if(ctx.event_handle) + { + ::boost::winapi::SetEvent(ctx.event_handle); + } + } + inline void rollback_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT + { + BOOST_INTERLOCKED_EXCHANGE(&flag.status,0); + if(!ctx.event_handle) + { + ctx.event_handle=detail::open_once_event(ctx.mutex_name,&flag); + } + if(ctx.event_handle) + { + ::boost::winapi::SetEvent(ctx.event_handle); + } + } + } + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +//#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR) + inline void call_once(once_flag& flag, void (*f)()) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite, 0)); + } + } +//#endif + template + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template + inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(A) a, BOOST_THREAD_RV_REF(ArgTypes)... args) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward(f)), + thread_detail::decay_copy(boost::forward(a)), + thread_detail::decay_copy(boost::forward(args))... + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } +#else +#if ! defined(BOOST_MSVC) && ! defined(BOOST_INTEL) + template + void call_once(once_flag& flag,Function f) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template + void call_once(once_flag& flag,Function f, T1 p1) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template + void call_once(once_flag& flag,Function f, T1 p1, T2 p2) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template + void call_once(once_flag& flag,Function f, T1 p1, T2 p2, T3 p3) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2,p3) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } +#elif defined BOOST_NO_CXX11_RVALUE_REFERENCES + + template + void call_once(once_flag& flag,Function const&f) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template + void call_once(once_flag& flag,Function const&f, T1 const&p1) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f,p1) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template + void call_once(once_flag& flag,Function const&f, T1 const&p1, T2 const&p2) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template + void call_once(once_flag& flag,Function const&f, T1 const&p1, T2 const&p2, T3 const&p3) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID(f,p1,p2,p3) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } +#endif +#if 1 +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR) + inline void call_once(once_flag& flag, void (*f)()) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template + void call_once(once_flag& flag,void (*f)(BOOST_THREAD_RV_REF(T1)), BOOST_THREAD_RV_REF(T1) p1) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f( + thread_detail::decay_copy(boost::forward(p1)) + ); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template + void call_once(once_flag& flag,void (*f)(BOOST_THREAD_RV_REF(T1),BOOST_THREAD_RV_REF(T2)), BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f( + thread_detail::decay_copy(boost::forward(p1)), + thread_detail::decay_copy(boost::forward(p2)) + ); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template + void call_once(once_flag& flag,void (*f)(BOOST_THREAD_RV_REF(T1),BOOST_THREAD_RV_REF(T2)), BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f( + thread_detail::decay_copy(boost::forward(p1)), + thread_detail::decay_copy(boost::forward(p2)), + thread_detail::decay_copy(boost::forward(p3)) + ); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } +#endif + template + void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + f(); + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + + template + void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward(f)), + thread_detail::decay_copy(boost::forward(p1)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template + void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward(f)), + thread_detail::decay_copy(boost::forward(p1)), + thread_detail::decay_copy(boost::forward(p2)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + template + void call_once(once_flag& flag,BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(T1) p1, BOOST_THREAD_RV_REF(T2) p2, BOOST_THREAD_RV_REF(T3) p3) + { + // Try for a quick win: if the procedure has already been called + // just skip through: + detail::once_context ctx; + while(::boost::detail::interlocked_read_acquire(&flag.status) + !=ctx.function_complete_flag_value) + { + if(detail::enter_once_region(flag, ctx)) + { + BOOST_TRY + { + BOOST_THREAD_INVOKE_RET_VOID( + thread_detail::decay_copy(boost::forward(f)), + thread_detail::decay_copy(boost::forward(p1)), + thread_detail::decay_copy(boost::forward(p2)), + thread_detail::decay_copy(boost::forward(p3)) + ) BOOST_THREAD_INVOKE_RET_VOID_CALL; + + } + BOOST_CATCH(...) + { + detail::rollback_once_region(flag, ctx); + BOOST_RETHROW + } + BOOST_CATCH_END + detail::commit_once_region(flag, ctx); + break; + } + if(!ctx.counted) + { + BOOST_INTERLOCKED_INCREMENT(&flag.count); + ctx.counted=true; + long status=::boost::detail::interlocked_read_acquire(&flag.status); + if(status==ctx.function_complete_flag_value) + { + break; + } + if(!ctx.event_handle) + { + ctx.event_handle=detail::create_once_event(ctx.mutex_name,&flag); + continue; + } + } + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( + ctx.event_handle,::boost::detail::win32::infinite,0)); + } + } + +#endif +#endif +} + +#include + +#endif diff --git a/boost/thread/win32/recursive_mutex.hpp b/boost/thread/win32/recursive_mutex.hpp new file mode 100644 index 0000000..1f0f7f5 --- /dev/null +++ b/boost/thread/win32/recursive_mutex.hpp @@ -0,0 +1,70 @@ +#ifndef BOOST_RECURSIVE_MUTEX_WIN32_HPP +#define BOOST_RECURSIVE_MUTEX_WIN32_HPP + +// recursive_mutex.hpp +// +// (C) Copyright 2006-7 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#include +#include +#include +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include +#endif + +#include + +namespace boost +{ + class recursive_mutex: + public ::boost::detail::basic_recursive_mutex + { + public: + BOOST_THREAD_NO_COPYABLE(recursive_mutex) + recursive_mutex() + { + ::boost::detail::basic_recursive_mutex::initialize(); + } + ~recursive_mutex() + { + ::boost::detail::basic_recursive_mutex::destroy(); + } + +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + typedef unique_lock scoped_lock; + typedef detail::try_lock_wrapper scoped_try_lock; +#endif + }; + + typedef recursive_mutex recursive_try_mutex; + + class recursive_timed_mutex: + public ::boost::detail::basic_recursive_timed_mutex + { + public: + BOOST_THREAD_NO_COPYABLE(recursive_timed_mutex) + recursive_timed_mutex() + { + ::boost::detail::basic_recursive_timed_mutex::initialize(); + } + ~recursive_timed_mutex() + { + ::boost::detail::basic_recursive_timed_mutex::destroy(); + } + +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + typedef unique_lock scoped_timed_lock; + typedef detail::try_lock_wrapper scoped_try_lock; + typedef scoped_timed_lock scoped_lock; +#endif + }; +} + +#include + +#endif diff --git a/boost/thread/win32/shared_mutex.hpp b/boost/thread/win32/shared_mutex.hpp new file mode 100644 index 0000000..7f8d279 --- /dev/null +++ b/boost/thread/win32/shared_mutex.hpp @@ -0,0 +1,856 @@ +#ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP +#define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP + +// (C) Copyright 2006-8 Anthony Williams +// (C) Copyright 2011-2012,2017-2018 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif +#include +#include + +#include + +namespace boost +{ + class shared_mutex + { + private: + struct state_data + { + unsigned long shared_count:11, + shared_waiting:11, + exclusive:1, + upgrade:1, + exclusive_waiting:7, + exclusive_waiting_blocked:1; + + friend bool operator==(state_data const& lhs,state_data const& rhs) + { + return std::memcmp(&lhs, &rhs, sizeof(lhs)) == 0; + } + }; + + static state_data interlocked_compare_exchange(state_data* target, state_data new_value, state_data comparand) + { + BOOST_STATIC_ASSERT(sizeof(state_data) == sizeof(long)); + long new_val, comp; + std::memcpy(&new_val, &new_value, sizeof(new_value)); + std::memcpy(&comp, &comparand, sizeof(comparand)); + long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast(target), + new_val, + comp); + state_data result; + std::memcpy(&result, &res, sizeof(result)); + return result; + } + + enum + { + unlock_sem = 0, + exclusive_sem = 1 + }; + + state_data state; + detail::win32::handle semaphores[2]; + detail::win32::handle upgrade_sem; + + void release_waiters(state_data old_state) + { + if(old_state.exclusive_waiting) + { + BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0); + } + + if(old_state.shared_waiting || old_state.exclusive_waiting) + { + BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); + } + } + void release_shared_waiters(state_data old_state) + { + if(old_state.shared_waiting || old_state.exclusive_waiting) + { + BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); + } + } + + public: + BOOST_THREAD_NO_COPYABLE(shared_mutex) + shared_mutex() + { + semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX); + semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX); + if (!semaphores[exclusive_sem]) + { + detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX); + boost::throw_exception(thread_resource_error()); + } + upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX); + if (!upgrade_sem) + { + detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX); + detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX); + boost::throw_exception(thread_resource_error()); + } + state_data state_={0,0,0,0,0,0}; + state=state_; + } + + ~shared_mutex() + { + winapi::CloseHandle(upgrade_sem); + winapi::CloseHandle(semaphores[unlock_sem]); + winapi::CloseHandle(semaphores[exclusive_sem]); + } + + bool try_lock_shared() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(!new_state.exclusive && !new_state.exclusive_waiting_blocked) + { + ++new_state.shared_count; + if(!new_state.shared_count) + { + return false; + } + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + return !(old_state.exclusive| old_state.exclusive_waiting_blocked); + } + + void lock_shared() + { + for(;;) + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked) + { + ++new_state.shared_waiting; + if(!new_state.shared_waiting) + { + boost::throw_exception(boost::lock_error()); + } + } + else + { + ++new_state.shared_count; + if(!new_state.shared_count) + { + boost::throw_exception(boost::lock_error()); + } + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) + { + return; + } + + BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::win32::infinite,0)==0); + } + } + + private: + unsigned long getMs(detail::platform_duration const& d) + { + return static_cast(d.getMs()); + } + + template + unsigned long getMs(Duration const& d) + { + return static_cast(chrono::ceil(d).count()); + } + + template + bool do_lock_shared_until(Timepoint const& t, Duration const& max) + { + for(;;) + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked) + { + ++new_state.shared_waiting; + if(!new_state.shared_waiting) + { + boost::throw_exception(boost::lock_error()); + } + } + else + { + ++new_state.shared_count; + if(!new_state.shared_count) + { + boost::throw_exception(boost::lock_error()); + } + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) + { + return true; + } + + // If the clock is the system clock, it may jump while this function + // is waiting. To compensate for this and time out near the correct + // time, we call WaitForSingleObjectEx() in a loop with a short + // timeout and recheck the time remaining each time through the loop. + unsigned long res=0; + for(;;) + { + Duration d(t - Clock::now()); + if(d <= Duration::zero()) // timeout occurred + { + res=detail::win32::timeout; + break; + } + if(max != Duration::zero()) + { + d = (std::min)(d, max); + } + res=winapi::WaitForSingleObjectEx(semaphores[unlock_sem],getMs(d),0); + if(res!=detail::win32::timeout) // semaphore released + { + break; + } + } + + if(res==detail::win32::timeout) + { + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked) + { + if(new_state.shared_waiting) + { + --new_state.shared_waiting; + } + } + else + { + ++new_state.shared_count; + if(!new_state.shared_count) + { + return false; + } + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) + { + return true; + } + return false; + } + + BOOST_ASSERT(res==0); + } + } + public: + +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_lock_shared(TimeDuration const & relative_time) + { + const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time)); + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_shared_until(t, detail::platform_duration::zero()); + } + bool timed_lock_shared(boost::system_time const& wait_until) + { + const detail::real_platform_timepoint t(wait_until); + return do_lock_shared_until(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_shared_for(const chrono::duration& rel_time) + { + const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time); + typedef typename chrono::duration Duration; + typedef typename common_type::type common_duration; + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_shared_until(t, common_duration::zero()); + } + template + bool try_lock_shared_until(const chrono::time_point& t) + { + typedef typename common_type::type common_duration; + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_shared_until(t, common_duration::zero()); + } + template + bool try_lock_shared_until(const chrono::time_point& t) + { + typedef typename common_type::type common_duration; + return do_lock_shared_until(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + } +#endif + + void unlock_shared() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + bool const last_reader=!--new_state.shared_count; + + if(last_reader) + { + if(new_state.upgrade) + { + new_state.upgrade=false; + new_state.exclusive=true; + } + else + { + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + } + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + if(last_reader) + { + if(old_state.upgrade) + { + BOOST_VERIFY(winapi::ReleaseSemaphore(upgrade_sem,1,0)!=0); + } + else + { + release_waiters(old_state); + } + } + break; + } + old_state=current_state; + } + } + + bool try_lock() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.shared_count || new_state.exclusive) + { + return false; + } + else + { + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + return true; + } + + void lock() + { + for(;;) + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.shared_count || new_state.exclusive) + { + ++new_state.exclusive_waiting; + if(!new_state.exclusive_waiting) + { + boost::throw_exception(boost::lock_error()); + } + + new_state.exclusive_waiting_blocked=true; + } + else + { + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!old_state.shared_count && !old_state.exclusive) + { + return; + } + + #ifndef UNDER_CE + const bool wait_all = true; + #else + const bool wait_all = false; + #endif + BOOST_VERIFY(winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::win32::infinite,0)<2); + } + } + + private: + template + bool do_lock_until(Timepoint const& t, Duration const& max) + { + for(;;) + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.shared_count || new_state.exclusive) + { + ++new_state.exclusive_waiting; + if(!new_state.exclusive_waiting) + { + boost::throw_exception(boost::lock_error()); + } + + new_state.exclusive_waiting_blocked=true; + } + else + { + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!old_state.shared_count && !old_state.exclusive) + { + return true; + } + + // If the clock is the system clock, it may jump while this function + // is waiting. To compensate for this and time out near the correct + // time, we call WaitForMultipleObjectsEx() in a loop with a short + // timeout and recheck the time remaining each time through the loop. + unsigned long wait_res=0; + for(;;) + { + Duration d(t - Clock::now()); + if(d <= Duration::zero()) // timeout occurred + { + wait_res=detail::win32::timeout; + break; + } + if(max != Duration::zero()) + { + d = (std::min)(d, max); + } + #ifndef UNDER_CE + wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,true,getMs(d),0); + #else + wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,false,getMs(d),0); + #endif + //wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,getMs(d), 0); + + if(wait_res!=detail::win32::timeout) // semaphore released + { + break; + } + } + + if(wait_res==detail::win32::timeout) + { + for(;;) + { + bool must_notify = false; + state_data new_state=old_state; + if(new_state.shared_count || new_state.exclusive) + { + if(new_state.exclusive_waiting) + { + if(!--new_state.exclusive_waiting) + { + new_state.exclusive_waiting_blocked=false; + must_notify = true; + } + } + } + else + { + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if (must_notify) + { + BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0); + } + + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + if(!old_state.shared_count && !old_state.exclusive) + { + return true; + } + return false; + } + + BOOST_ASSERT(wait_res<2); + } + } + public: + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(boost::system_time const& wait_until) + { + const detail::real_platform_timepoint t(wait_until); + return do_lock_until(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } + template + bool timed_lock(TimeDuration const & relative_time) + { + const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time)); + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_until(t, detail::platform_duration::zero()); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const chrono::duration& rel_time) + { + const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time); + typedef typename chrono::duration Duration; + typedef typename common_type::type common_duration; + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_until(t, common_duration::zero()); + } + template + bool try_lock_until(const chrono::time_point& t) + { + typedef typename common_type::type common_duration; + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_until(t, common_duration::zero()); + } + template + bool try_lock_until(const chrono::time_point& t) + { + typedef typename common_type::type common_duration; + return do_lock_until(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + } +#endif + + void unlock() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.exclusive=false; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + release_waiters(old_state); + } + + void lock_upgrade() + { + for(;;) + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) + { + ++new_state.shared_waiting; + if(!new_state.shared_waiting) + { + boost::throw_exception(boost::lock_error()); + } + } + else + { + ++new_state.shared_count; + if(!new_state.shared_count) + { + boost::throw_exception(boost::lock_error()); + } + new_state.upgrade=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade)) + { + return; + } + + BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],winapi::infinite,0)==0); + } + } + + bool try_lock_upgrade() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade) + { + return false; + } + else + { + ++new_state.shared_count; + if(!new_state.shared_count) + { + return false; + } + new_state.upgrade=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + return true; + } + + void unlock_upgrade() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.upgrade=false; + bool const last_reader=!--new_state.shared_count; + + new_state.shared_waiting=0; + if(last_reader) + { + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + if(last_reader) + { + release_waiters(old_state); + } + else { + release_shared_waiters(old_state); + } + // #7720 + //else { + // release_waiters(old_state); + //} + break; + } + old_state=current_state; + } + } + + void unlock_upgrade_and_lock() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + bool const last_reader=!--new_state.shared_count; + + if(last_reader) + { + new_state.upgrade=false; + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + if(!last_reader) + { + BOOST_VERIFY(winapi::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite,0)==0); + } + break; + } + old_state=current_state; + } + } + + void unlock_and_lock_upgrade() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.exclusive=false; + new_state.upgrade=true; + ++new_state.shared_count; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + release_waiters(old_state); + } + + void unlock_and_lock_shared() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.exclusive=false; + ++new_state.shared_count; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + release_waiters(old_state); + } + void unlock_upgrade_and_lock_shared() + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + new_state.upgrade=false; + if(new_state.exclusive_waiting) + { + --new_state.exclusive_waiting; + new_state.exclusive_waiting_blocked=false; + } + new_state.shared_waiting=0; + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + release_waiters(old_state); + } + + }; + typedef shared_mutex upgrade_mutex; + +} + +#include + +#endif diff --git a/boost/thread/win32/thread_data.hpp b/boost/thread/win32/thread_data.hpp new file mode 100644 index 0000000..b1a550a --- /dev/null +++ b/boost/thread/win32/thread_data.hpp @@ -0,0 +1,302 @@ +#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP +#define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP +// 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) +// (C) Copyright 2008 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#include +#include +#include +#include +#include + +#include + +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#endif + +#include +#include +#include + +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +namespace boost +{ + class condition_variable; + class mutex; + + class thread_attributes { + public: + thread_attributes() BOOST_NOEXCEPT { + val_.stack_size = 0; + //val_.lpThreadAttributes=0; + } + ~thread_attributes() { + } + // stack size + void set_stack_size(std::size_t size) BOOST_NOEXCEPT { + val_.stack_size = size; + } + + std::size_t get_stack_size() const BOOST_NOEXCEPT { + return val_.stack_size; + } + + //void set_security(LPSECURITY_ATTRIBUTES lpThreadAttributes) + //{ + // val_.lpThreadAttributes=lpThreadAttributes; + //} + //LPSECURITY_ATTRIBUTES get_security() + //{ + // return val_.lpThreadAttributes; + //} + + struct win_attrs { + std::size_t stack_size; + //LPSECURITY_ATTRIBUTES lpThreadAttributes; + }; + typedef win_attrs native_handle_type; + native_handle_type* native_handle() {return &val_;} + const native_handle_type* native_handle() const {return &val_;} + + private: + win_attrs val_; + }; + + namespace detail + { + struct shared_state_base; + struct tss_cleanup_function; + struct thread_exit_callback_node; + struct tss_data_node + { + typedef void(*cleanup_func_t)(void*); + typedef void(*cleanup_caller_t)(cleanup_func_t, void*); + + cleanup_caller_t caller; + cleanup_func_t func; + void* value; + + tss_data_node(cleanup_caller_t caller_,cleanup_func_t func_,void* value_): + caller(caller_),func(func_),value(value_) + {} + }; + + struct thread_data_base; + void intrusive_ptr_add_ref(thread_data_base * p); + void intrusive_ptr_release(thread_data_base * p); + + struct BOOST_THREAD_DECL thread_data_base + { + long count; + + // Win32 threading APIs are not available in store apps so + // use abstraction on top of Windows::System::Threading. +#if BOOST_PLAT_WINDOWS_RUNTIME + detail::win32::scoped_winrt_thread thread_handle; +#else + detail::win32::handle_manager thread_handle; +#endif + + boost::detail::thread_exit_callback_node* thread_exit_callbacks; + unsigned id; + std::map tss_data; + typedef std::vector + //, hidden_allocator > + > notify_list_t; + notify_list_t notify; + +//#ifndef BOOST_NO_EXCEPTIONS + typedef std::vector > async_states_t; + async_states_t async_states_; +//#endif +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + // These data must be at the end so that the access to the other fields doesn't change + // when BOOST_THREAD_PROVIDES_INTERRUPTIONS is defined + // Another option is to have them always + detail::win32::handle_manager interruption_handle; + bool interruption_enabled; +//#endif + + thread_data_base(): + count(0), + thread_handle(), + thread_exit_callbacks(0), + id(0), + tss_data(), + notify() +//#ifndef BOOST_NO_EXCEPTIONS + , async_states_() +//#endif +//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + , interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)) + , interruption_enabled(true) +//#endif + {} + virtual ~thread_data_base(); + + friend void intrusive_ptr_add_ref(thread_data_base * p) + { + BOOST_INTERLOCKED_INCREMENT(&p->count); + } + + friend void intrusive_ptr_release(thread_data_base * p) + { + if(!BOOST_INTERLOCKED_DECREMENT(&p->count)) + { + detail::heap_delete(p); + } + } + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + void interrupt() + { + BOOST_VERIFY(winapi::SetEvent(interruption_handle)!=0); + } +#endif + typedef detail::win32::handle native_handle_type; + + virtual void run()=0; + + virtual void notify_all_at_thread_exit(condition_variable* cv, mutex* m) + { + notify.push_back(std::pair(cv, m)); + } + +//#ifndef BOOST_NO_EXCEPTIONS + void make_ready_at_thread_exit(shared_ptr as) + { + async_states_.push_back(as); + } +//#endif + }; + BOOST_THREAD_DECL thread_data_base* get_current_thread_data(); + + typedef boost::intrusive_ptr thread_data_ptr; + } + + namespace this_thread + { + void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; + + bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout); + +#if defined BOOST_THREAD_USES_DATETIME + template + BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) + { + interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(rel_time)); + } + + inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time) + { + const detail::real_platform_timepoint ts(abs_time); + detail::platform_duration d(ts - detail::real_platform_clock::now()); + while (d > detail::platform_duration::zero()) + { + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + d); + d = ts - detail::real_platform_clock::now(); + } + } +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template + void sleep_for(const chrono::duration& d) + { + interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(d)); + } + + template + void sleep_until(const chrono::time_point& t) + { + sleep_for(t - chrono::steady_clock::now()); + } + + template + void sleep_until(const chrono::time_point& t) + { + typedef typename common_type::type common_duration; + common_duration d(t - Clock::now()); + while (d > common_duration::zero()) + { + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + sleep_for(d); + d = t - Clock::now(); + } + } +#endif + + namespace no_interruption_point + { + bool BOOST_THREAD_DECL non_interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout); + +#if defined BOOST_THREAD_USES_DATETIME + template + BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) + { + non_interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(rel_time)); + } + + inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time) + { + const detail::real_platform_timepoint ts(abs_time); + detail::platform_duration d(ts - detail::real_platform_clock::now()); + while (d > detail::platform_duration::zero()) + { + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + non_interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + d); + d = ts - detail::real_platform_clock::now(); + } + } +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template + void sleep_for(const chrono::duration& d) + { + non_interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(d)); + } + + template + void sleep_until(const chrono::time_point& t) + { + sleep_for(t - chrono::steady_clock::now()); + } + + template + void sleep_until(const chrono::time_point& t) + { + typedef typename common_type::type common_duration; + common_duration d(t - Clock::now()); + while (d > common_duration::zero()) + { + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + sleep_for(d); + d = t - Clock::now(); + } + } +#endif + } + } + +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#include + +#endif diff --git a/boost/thread/win32/thread_heap_alloc.hpp b/boost/thread/win32/thread_heap_alloc.hpp new file mode 100644 index 0000000..176d269 --- /dev/null +++ b/boost/thread/win32/thread_heap_alloc.hpp @@ -0,0 +1,469 @@ +// 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) +// (C) Copyright 2007 Anthony Williams +#ifndef THREAD_HEAP_ALLOC_HPP +#define THREAD_HEAP_ALLOC_HPP +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace boost +{ + namespace detail + { + inline void* allocate_raw_heap_memory(unsigned size) + { + void* const heap_memory=winapi::HeapAlloc(winapi::GetProcessHeap(),0,size); + if(!heap_memory) + { + boost::throw_exception(std::bad_alloc()); + } + return heap_memory; + } + + inline void free_raw_heap_memory(void* heap_memory) + { + BOOST_VERIFY(winapi::HeapFree(winapi::GetProcessHeap(),0,heap_memory)!=0); + } +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) && ! defined (BOOST_NO_CXX11_RVALUE_REFERENCES) + template + inline T* heap_new(Args&&... args) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(static_cast(args)...); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } +#else + template + inline T* heap_new() + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template + inline T* heap_new(A1&& a1) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(static_cast(a1)); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } + template + inline T* heap_new(A1&& a1,A2&& a2) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2)); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2), + static_cast(a3)); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } + template + inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2), + static_cast(a3),static_cast(a4)); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } +#else + template + inline T* heap_new_impl(A1 a1) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(a1); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + inline T* heap_new_impl(A1 a1,A2 a2) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(a1,a2); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(a1,a2,a3); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(a1,a2,a3,a4); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4,A5 a5) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(a1,a2,a3,a4,a5); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(a1,a2,a3,a4,a5,a6); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(a1,a2,a3,a4,a5,a6,a7); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(a1,a2,a3,a4,a5,a6,a7,a8); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } + template + inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9) + { + void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); + BOOST_TRY + { + T* const data=new (heap_memory) T(a1,a2,a3,a4,a5,a6,a7,a8,a9); + return data; + } + BOOST_CATCH(...) + { + free_raw_heap_memory(heap_memory); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + + template + inline T* heap_new(A1 const& a1) + { + return heap_new_impl(a1); + } + template + inline T* heap_new(A1& a1) + { + return heap_new_impl(a1); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2 const& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1 const& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + template + inline T* heap_new(A1& a1,A2& a2) + { + return heap_new_impl(a1,a2); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3) + { + return heap_new_impl(a1,a2,a3); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + + template + inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + template + inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4) + { + return heap_new_impl(a1,a2,a3,a4); + } + +#endif +#endif + template + inline void heap_delete(T* data) + { + data->~T(); + free_raw_heap_memory(data); + } + + template + struct do_heap_delete + { + void operator()(T* data) const + { + detail::heap_delete(data); + } + }; + } +} + +#include + + +#endif diff --git a/boost/thread/win32/thread_primitives.hpp b/boost/thread/win32/thread_primitives.hpp new file mode 100644 index 0000000..391d737 --- /dev/null +++ b/boost/thread/win32/thread_primitives.hpp @@ -0,0 +1,426 @@ +#ifndef BOOST_WIN32_THREAD_PRIMITIVES_HPP +#define BOOST_WIN32_THREAD_PRIMITIVES_HPP + +// win32_thread_primitives.hpp +// +// (C) Copyright 2005-7 Anthony Williams +// (C) Copyright 2007 David Deakins +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include +#include +#include + +#if BOOST_PLAT_WINDOWS_RUNTIME +#include +#endif + +namespace boost +{ + namespace detail + { + namespace win32 + { + typedef ::boost::winapi::HANDLE_ handle; + typedef ::boost::winapi::SYSTEM_INFO_ system_info; + typedef ::boost::winapi::ULONGLONG_ ticks_type; + unsigned const infinite=::boost::winapi::INFINITE_; + unsigned const timeout=::boost::winapi::WAIT_TIMEOUT_; + handle const invalid_handle_value=::boost::winapi::INVALID_HANDLE_VALUE_; + unsigned const event_modify_state=::boost::winapi::EVENT_MODIFY_STATE_; + unsigned const synchronize=::boost::winapi::SYNCHRONIZE_; + unsigned const wait_abandoned=::boost::winapi::WAIT_ABANDONED_; + unsigned const create_event_initial_set = 0x00000002; + unsigned const create_event_manual_reset = 0x00000001; + unsigned const event_all_access = ::boost::winapi::EVENT_ALL_ACCESS_; + unsigned const semaphore_all_access = boost::winapi::SEMAPHORE_ALL_ACCESS_; + } + } +} + +#include + +namespace boost +{ + namespace detail + { + namespace win32 + { + namespace detail { typedef ticks_type (BOOST_WINAPI_WINAPI_CC *gettickcount64_t)(); } + extern BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64; + + enum event_type + { + auto_reset_event=false, + manual_reset_event=true + }; + + enum initial_event_state + { + event_initially_reset=false, + event_initially_set=true + }; + + inline handle create_event( +#if !defined(BOOST_NO_ANSI_APIS) + const char *mutex_name, +#else + const wchar_t *mutex_name, +#endif + event_type type, + initial_event_state state) + { +#if !defined(BOOST_NO_ANSI_APIS) + handle const res = ::boost::winapi::CreateEventA(0, type, state, mutex_name); +#elif BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA + handle const res = ::boost::winapi::CreateEventW(0, type, state, mutex_name); +#else + handle const res = ::boost::winapi::CreateEventExW( + 0, + mutex_name, + (type ? create_event_manual_reset : 0) | (state ? create_event_initial_set : 0), + event_all_access); +#endif + return res; + } + + inline handle create_anonymous_event(event_type type,initial_event_state state) + { + handle const res = create_event(0, type, state); + if(!res) + { + boost::throw_exception(thread_resource_error()); + } + return res; + } + + inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count) + { +#if !defined(BOOST_NO_ANSI_APIS) + handle const res=::boost::winapi::CreateSemaphoreA(0,initial_count,max_count,0); +#else +#if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA + handle const res=::boost::winapi::CreateSemaphoreEx(0,initial_count,max_count,0,0); +#else + handle const res=::boost::winapi::CreateSemaphoreExW(0,initial_count,max_count,0,0,semaphore_all_access); +#endif +#endif + return res; + } + + inline handle create_anonymous_semaphore(long initial_count,long max_count) + { + handle const res=create_anonymous_semaphore_nothrow(initial_count,max_count); + if(!res) + { + boost::throw_exception(thread_resource_error()); + } + return res; + } + + inline handle duplicate_handle(handle source) + { + handle const current_process=::boost::winapi::GetCurrentProcess(); + long const same_access_flag=2; + handle new_handle=0; + bool const success=::boost::winapi::DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0; + if(!success) + { + boost::throw_exception(thread_resource_error()); + } + return new_handle; + } + + inline void release_semaphore(handle semaphore,long count) + { + BOOST_VERIFY(::boost::winapi::ReleaseSemaphore(semaphore,count,0)!=0); + } + + inline void get_system_info(system_info *info) + { +#if BOOST_PLAT_WINDOWS_RUNTIME + ::boost::winapi::GetNativeSystemInfo(info); +#else + ::boost::winapi::GetSystemInfo(info); +#endif + } + + inline void sleep(unsigned long milliseconds) + { + if(milliseconds == 0) + { +#if BOOST_PLAT_WINDOWS_RUNTIME + std::this_thread::yield(); +#else + ::boost::winapi::Sleep(0); +#endif + } + else + { +#if BOOST_PLAT_WINDOWS_RUNTIME + ::boost::winapi::WaitForSingleObjectEx(::boost::winapi::GetCurrentThread(), milliseconds, 0); +#else + ::boost::winapi::Sleep(milliseconds); +#endif + } + } + +#if BOOST_PLAT_WINDOWS_RUNTIME + class BOOST_THREAD_DECL scoped_winrt_thread + { + public: + scoped_winrt_thread() : m_completionHandle(invalid_handle_value) + {} + + ~scoped_winrt_thread() + { + if (m_completionHandle != ::boost::detail::win32::invalid_handle_value) + { + ::boost::winapi::CloseHandle(m_completionHandle); + } + } + + typedef unsigned(__stdcall * thread_func)(void *); + bool start(thread_func address, void *parameter, unsigned int *thrdId); + + handle waitable_handle() const + { + BOOST_ASSERT(m_completionHandle != ::boost::detail::win32::invalid_handle_value); + return m_completionHandle; + } + + private: + handle m_completionHandle; + }; +#endif + class BOOST_THREAD_DECL handle_manager + { + private: + handle handle_to_manage; + handle_manager(handle_manager&); + handle_manager& operator=(handle_manager&); + + void cleanup() + { + if(handle_to_manage && handle_to_manage!=invalid_handle_value) + { + BOOST_VERIFY(::boost::winapi::CloseHandle(handle_to_manage)); + } + } + + public: + explicit handle_manager(handle handle_to_manage_): + handle_to_manage(handle_to_manage_) + {} + handle_manager(): + handle_to_manage(0) + {} + + handle_manager& operator=(handle new_handle) + { + cleanup(); + handle_to_manage=new_handle; + return *this; + } + + operator handle() const + { + return handle_to_manage; + } + + handle duplicate() const + { + return duplicate_handle(handle_to_manage); + } + + void swap(handle_manager& other) + { + std::swap(handle_to_manage,other.handle_to_manage); + } + + handle release() + { + handle const res=handle_to_manage; + handle_to_manage=0; + return res; + } + + bool operator!() const + { + return !handle_to_manage; + } + + ~handle_manager() + { + cleanup(); + } + }; + } + } +} + +#if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE) + +namespace boost +{ + namespace detail + { + namespace win32 + { +#if _MSC_VER==1400 + extern "C" unsigned char _interlockedbittestandset(long *a,long b); + extern "C" unsigned char _interlockedbittestandreset(long *a,long b); +#else + extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b); + extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b); +#endif + +#pragma intrinsic(_interlockedbittestandset) +#pragma intrinsic(_interlockedbittestandreset) + + inline bool interlocked_bit_test_and_set(long* x,long bit) + { + return _interlockedbittestandset(x,bit)!=0; + } + + inline bool interlocked_bit_test_and_reset(long* x,long bit) + { + return _interlockedbittestandreset(x,bit)!=0; + } + + } + } +} +#define BOOST_THREAD_BTS_DEFINED +#elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86) +namespace boost +{ + namespace detail + { + namespace win32 + { + inline bool interlocked_bit_test_and_set(long* x,long bit) + { +#ifndef BOOST_INTEL_CXX_VERSION + __asm { + mov eax,bit; + mov edx,x; + lock bts [edx],eax; + setc al; + }; +#else + bool ret; + __asm { + mov eax,bit + mov edx,x + lock bts [edx],eax + setc al + mov ret, al + }; + return ret; + +#endif + } + + inline bool interlocked_bit_test_and_reset(long* x,long bit) + { +#ifndef BOOST_INTEL_CXX_VERSION + __asm { + mov eax,bit; + mov edx,x; + lock btr [edx],eax; + setc al; + }; +#else + bool ret; + __asm { + mov eax,bit + mov edx,x + lock btr [edx],eax + setc al + mov ret, al + }; + return ret; + +#endif + } + + } + } +} +#define BOOST_THREAD_BTS_DEFINED +#endif + +#ifndef BOOST_THREAD_BTS_DEFINED + +namespace boost +{ + namespace detail + { + namespace win32 + { + inline bool interlocked_bit_test_and_set(long* x,long bit) + { + long const value=1< + +#endif diff --git a/boost/thread/xtime.hpp b/boost/thread/xtime.hpp new file mode 100644 index 0000000..d04a0d9 --- /dev/null +++ b/boost/thread/xtime.hpp @@ -0,0 +1,93 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007-8 Anthony Williams +// +// 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_XTIME_WEK070601_HPP +#define BOOST_XTIME_WEK070601_HPP + +#include +#if defined BOOST_THREAD_USES_DATETIME + +#include +#include +#include + +#include + +namespace boost { + +enum xtime_clock_types +{ + TIME_UTC_=1 +// TIME_TAI, +// TIME_MONOTONIC, +// TIME_PROCESS, +// TIME_THREAD, +// TIME_LOCAL, +// TIME_SYNC, +// TIME_RESOLUTION +}; + +struct xtime +{ +#if defined(BOOST_NO_INT64_T) + typedef int_fast32_t xtime_sec_t; //INT_FAST32_MIN <= sec <= INT_FAST32_MAX +#else + typedef int_fast64_t xtime_sec_t; //INT_FAST64_MIN <= sec <= INT_FAST64_MAX +#endif + + typedef int_fast32_t xtime_nsec_t; //0 <= xtime.nsec < NANOSECONDS_PER_SECOND + + xtime_sec_t sec; + xtime_nsec_t nsec; + + operator system_time() const + { + return boost::posix_time::from_time_t(0)+ + boost::posix_time::seconds(static_cast(sec))+ +#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS + boost::posix_time::nanoseconds(nsec); +#else + boost::posix_time::microseconds((nsec+500)/1000); +#endif + } + +}; + +inline ::boost::xtime get_xtime(boost::system_time const& abs_time) +{ + ::boost::xtime res; + boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0); + + res.sec=static_cast< ::boost::xtime::xtime_sec_t>(time_since_epoch.total_seconds()); + res.nsec=static_cast< ::boost::xtime::xtime_nsec_t>(time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second())); + return res; +} + +inline int xtime_get(struct ::boost::xtime* xtp, int clock_type) +{ + if (clock_type == TIME_UTC_) + { + *xtp=get_xtime(get_system_time()); + return clock_type; + } + return 0; +} + + +inline int xtime_cmp(const ::boost::xtime& xt1, const ::boost::xtime& xt2) +{ + if (xt1.sec == xt2.sec) + return (int)(xt1.nsec - xt2.nsec); + else + return (xt1.sec > xt2.sec) ? 1 : -1; +} + +} // namespace boost + +#include +#endif +#endif //BOOST_XTIME_WEK070601_HPP diff --git a/boost/tuple/detail/tuple_basic.hpp b/boost/tuple/detail/tuple_basic.hpp new file mode 100644 index 0000000..879f0e9 --- /dev/null +++ b/boost/tuple/detail/tuple_basic.hpp @@ -0,0 +1,987 @@ +// tuple_basic.hpp ----------------------------------------------------- + +// Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// +// 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) + +// For more information, see http://www.boost.org + +// Outside help: +// This and that, Gary Powell. +// Fixed return types for get_head/get_tail +// ( and other bugs ) per suggestion of Jens Maurer +// simplified element type accessors + bug fix (Jeremy Siek) +// Several changes/additions according to suggestions by Douglas Gregor, +// William Kempf, Vesa Karvonen, John Max Skaller, Ed Brey, Beman Dawes, +// David Abrahams. + +// Revision history: +// 2002 05 01 Hugo Duncan: Fix for Borland after Jaakko's previous changes +// 2002 04 18 Jaakko: tuple element types can be void or plain function +// types, as long as no object is created. +// Tuple objects can no hold even noncopyable types +// such as arrays. +// 2001 10 22 John Maddock +// Fixes for Borland C++ +// 2001 08 30 David Abrahams +// Added default constructor for cons<>. +// ----------------------------------------------------------------- + +#ifndef BOOST_TUPLE_BASIC_HPP +#define BOOST_TUPLE_BASIC_HPP + + +#include // needed for the assignment from pair to tuple + +#include +#include +#include + +#include // needed for BOOST_WORKAROUND + +#if defined(BOOST_GCC) && (BOOST_GCC >= 40700) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-local-typedefs" +#endif + +namespace boost { +namespace tuples { + +// -- null_type -------------------------------------------------------- +struct null_type {}; + +// a helper function to provide a const null_type type temporary +namespace detail { + inline const null_type cnull() { return null_type(); } + + +// -- if construct ------------------------------------------------ +// Proposed by Krzysztof Czarnecki and Ulrich Eisenecker + +template struct IF { typedef Then RET; }; + +template struct IF { + typedef Else RET; +}; + +} // end detail + +// - cons forward declaration ----------------------------------------------- +template struct cons; + + +// - tuple forward declaration ----------------------------------------------- +template < + class T0 = null_type, class T1 = null_type, class T2 = null_type, + class T3 = null_type, class T4 = null_type, class T5 = null_type, + class T6 = null_type, class T7 = null_type, class T8 = null_type, + class T9 = null_type> +class tuple; + +// tuple_length forward declaration +template struct length; + + + +namespace detail { + +// -- generate error template, referencing to non-existing members of this +// template is used to produce compilation errors intentionally +template +class generate_error; + +template +struct drop_front { + template + struct apply { + typedef BOOST_DEDUCED_TYPENAME drop_front::BOOST_NESTED_TEMPLATE + apply next; + typedef BOOST_DEDUCED_TYPENAME next::type::tail_type type; + static const type& call(const Tuple& tup) { + return next::call(tup).tail; + } + }; +}; + +template<> +struct drop_front<0> { + template + struct apply { + typedef Tuple type; + static const type& call(const Tuple& tup) { + return tup; + } + }; +}; + +} // end of namespace detail + + +// -cons type accessors ---------------------------------------- +// typename tuples::element::type gets the type of the +// Nth element ot T, first element is at index 0 +// ------------------------------------------------------- + +#ifndef BOOST_NO_CV_SPECIALIZATIONS + +template +struct element +{ + typedef BOOST_DEDUCED_TYPENAME detail::drop_front::BOOST_NESTED_TEMPLATE + apply::type::head_type type; +}; + +template +struct element +{ +private: + typedef BOOST_DEDUCED_TYPENAME detail::drop_front::BOOST_NESTED_TEMPLATE + apply::type::head_type unqualified_type; +public: +#if BOOST_WORKAROUND(__BORLANDC__,<0x600) + typedef const unqualified_type type; +#else + typedef BOOST_DEDUCED_TYPENAME boost::add_const::type type; +#endif +}; +#else // def BOOST_NO_CV_SPECIALIZATIONS + +namespace detail { + +template +struct element_impl +{ + typedef BOOST_DEDUCED_TYPENAME detail::drop_front::BOOST_NESTED_TEMPLATE + apply::type::head_type type; +}; + +template +struct element_impl +{ + typedef BOOST_DEDUCED_TYPENAME detail::drop_front::BOOST_NESTED_TEMPLATE + apply::type::head_type unqualified_type; + typedef const unqualified_type type; +}; + +} // end of namespace detail + + +template +struct element: + public detail::element_impl::value> +{ +}; + +#endif + + +// -get function templates ----------------------------------------------- +// Usage: get(aTuple) + +// -- some traits classes for get functions + +// access traits lifted from detail namespace to be part of the interface, +// (Joel de Guzman's suggestion). Rationale: get functions are part of the +// interface, so should the way to express their return types be. + +template struct access_traits { + typedef const T& const_type; + typedef T& non_const_type; + + typedef const typename boost::remove_cv::type& parameter_type; + +// used as the tuple constructors parameter types +// Rationale: non-reference tuple element types can be cv-qualified. +// It should be possible to initialize such types with temporaries, +// and when binding temporaries to references, the reference must +// be non-volatile and const. 8.5.3. (5) +}; + +template struct access_traits { + + typedef T& const_type; + typedef T& non_const_type; + + typedef T& parameter_type; +}; + +// get function for non-const cons-lists, returns a reference to the element + +template +inline typename access_traits< + typename element >::type + >::non_const_type +get(cons& c) { + typedef BOOST_DEDUCED_TYPENAME detail::drop_front::BOOST_NESTED_TEMPLATE + apply > impl; + typedef BOOST_DEDUCED_TYPENAME impl::type cons_element; + return const_cast(impl::call(c)).head; +} + +// get function for const cons-lists, returns a const reference to +// the element. If the element is a reference, returns the reference +// as such (that is, can return a non-const reference) +template +inline typename access_traits< + typename element >::type + >::const_type +get(const cons& c) { + typedef BOOST_DEDUCED_TYPENAME detail::drop_front::BOOST_NESTED_TEMPLATE + apply > impl; + return impl::call(c).head; +} + +// -- the cons template -------------------------------------------------- +namespace detail { + +// These helper templates wrap void types and plain function types. +// The reationale is to allow one to write tuple types with those types +// as elements, even though it is not possible to instantiate such object. +// E.g: typedef tuple some_type; // ok +// but: some_type x; // fails + +template class non_storeable_type { + non_storeable_type(); +}; + +template struct wrap_non_storeable_type { + typedef typename IF< + ::boost::is_function::value, non_storeable_type, T + >::RET type; +}; +template <> struct wrap_non_storeable_type { + typedef non_storeable_type type; +}; + +} // detail + +template +struct cons { + + typedef HT head_type; + typedef TT tail_type; + + typedef typename + detail::wrap_non_storeable_type::type stored_head_type; + + stored_head_type head; + tail_type tail; + + typename access_traits::non_const_type + get_head() { return head; } + + typename access_traits::non_const_type + get_tail() { return tail; } + + typename access_traits::const_type + get_head() const { return head; } + + typename access_traits::const_type + get_tail() const { return tail; } + + cons() : head(), tail() {} + // cons() : head(detail::default_arg::f()), tail() {} + + // the argument for head is not strictly needed, but it prevents + // array type elements. This is good, since array type elements + // cannot be supported properly in any case (no assignment, + // copy works only if the tails are exactly the same type, ...) + + cons(typename access_traits::parameter_type h, + const tail_type& t) + : head (h), tail(t) {} + + template + cons( T1& t1, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6, T7& t7, T8& t8, T9& t9, T10& t10 ) + : head (t1), + tail (t2, t3, t4, t5, t6, t7, t8, t9, t10, detail::cnull()) + {} + + template + cons( const null_type& /*t1*/, T2& t2, T3& t3, T4& t4, T5& t5, + T6& t6, T7& t7, T8& t8, T9& t9, T10& t10 ) + : head (), + tail (t2, t3, t4, t5, t6, t7, t8, t9, t10, detail::cnull()) + {} + + + template + cons( const cons& u ) : head(u.head), tail(u.tail) {} + + template + cons& operator=( const cons& u ) { + head=u.head; tail=u.tail; return *this; + } + + // must define assignment operator explicitly, implicit version is + // illformed if HT is a reference (12.8. (12)) + cons& operator=(const cons& u) { + head = u.head; tail = u.tail; return *this; + } + + template + cons& operator=( const std::pair& u ) { + BOOST_STATIC_ASSERT(length::value == 2); // check length = 2 + head = u.first; tail.head = u.second; return *this; + } + + // get member functions (non-const and const) + template + typename access_traits< + typename element >::type + >::non_const_type + get() { + return boost::tuples::get(*this); // delegate to non-member get + } + + template + typename access_traits< + typename element >::type + >::const_type + get() const { + return boost::tuples::get(*this); // delegate to non-member get + } +}; + +template +struct cons { + + typedef HT head_type; + typedef null_type tail_type; + typedef cons self_type; + + typedef typename + detail::wrap_non_storeable_type::type stored_head_type; + stored_head_type head; + + typename access_traits::non_const_type + get_head() { return head; } + + null_type get_tail() { return null_type(); } + + typename access_traits::const_type + get_head() const { return head; } + + const null_type get_tail() const { return null_type(); } + + // cons() : head(detail::default_arg::f()) {} + cons() : head() {} + + cons(typename access_traits::parameter_type h, + const null_type& = null_type()) + : head (h) {} + + template + cons(T1& t1, const null_type&, const null_type&, const null_type&, + const null_type&, const null_type&, const null_type&, + const null_type&, const null_type&, const null_type&) + : head (t1) {} + + cons(const null_type&, + const null_type&, const null_type&, const null_type&, + const null_type&, const null_type&, const null_type&, + const null_type&, const null_type&, const null_type&) + : head () {} + + template + cons( const cons& u ) : head(u.head) {} + + template + cons& operator=(const cons& u ) + { head = u.head; return *this; } + + // must define assignment operator explicitely, implicit version + // is illformed if HT is a reference + cons& operator=(const cons& u) { head = u.head; return *this; } + + template + typename access_traits< + typename element::type + >::non_const_type + get() { + return boost::tuples::get(*this); + } + + template + typename access_traits< + typename element::type + >::const_type + get() const { + return boost::tuples::get(*this); + } + +}; + +// templates for finding out the length of the tuple ------------------- + +template +struct length { + BOOST_STATIC_CONSTANT(int, value = 1 + length::value); +}; + +template<> +struct length > { + BOOST_STATIC_CONSTANT(int, value = 0); +}; + +template<> +struct length const> { + BOOST_STATIC_CONSTANT(int, value = 0); +}; + +template<> +struct length { + BOOST_STATIC_CONSTANT(int, value = 0); +}; + +template<> +struct length { + BOOST_STATIC_CONSTANT(int, value = 0); +}; + +namespace detail { + +// Tuple to cons mapper -------------------------------------------------- +template +struct map_tuple_to_cons +{ + typedef cons::type + > type; +}; + +// The empty tuple is a null_type +template <> +struct map_tuple_to_cons +{ + typedef null_type type; +}; + +} // end detail + +// ------------------------------------------------------------------- +// -- tuple ------------------------------------------------------ +template + +class tuple : + public detail::map_tuple_to_cons::type +{ +public: + typedef typename + detail::map_tuple_to_cons::type inherited; + typedef typename inherited::head_type head_type; + typedef typename inherited::tail_type tail_type; + + +// access_traits::parameter_type takes non-reference types as const T& + tuple() {} + + explicit tuple(typename access_traits::parameter_type t0) + : inherited(t0, detail::cnull(), detail::cnull(), detail::cnull(), + detail::cnull(), detail::cnull(), detail::cnull(), + detail::cnull(), detail::cnull(), detail::cnull()) {} + + tuple(typename access_traits::parameter_type t0, + typename access_traits::parameter_type t1) + : inherited(t0, t1, detail::cnull(), detail::cnull(), + detail::cnull(), detail::cnull(), detail::cnull(), + detail::cnull(), detail::cnull(), detail::cnull()) {} + + tuple(typename access_traits::parameter_type t0, + typename access_traits::parameter_type t1, + typename access_traits::parameter_type t2) + : inherited(t0, t1, t2, detail::cnull(), detail::cnull(), + detail::cnull(), detail::cnull(), detail::cnull(), + detail::cnull(), detail::cnull()) {} + + tuple(typename access_traits::parameter_type t0, + typename access_traits::parameter_type t1, + typename access_traits::parameter_type t2, + typename access_traits::parameter_type t3) + : inherited(t0, t1, t2, t3, detail::cnull(), detail::cnull(), + detail::cnull(), detail::cnull(), detail::cnull(), + detail::cnull()) {} + + tuple(typename access_traits::parameter_type t0, + typename access_traits::parameter_type t1, + typename access_traits::parameter_type t2, + typename access_traits::parameter_type t3, + typename access_traits::parameter_type t4) + : inherited(t0, t1, t2, t3, t4, detail::cnull(), detail::cnull(), + detail::cnull(), detail::cnull(), detail::cnull()) {} + + tuple(typename access_traits::parameter_type t0, + typename access_traits::parameter_type t1, + typename access_traits::parameter_type t2, + typename access_traits::parameter_type t3, + typename access_traits::parameter_type t4, + typename access_traits::parameter_type t5) + : inherited(t0, t1, t2, t3, t4, t5, detail::cnull(), detail::cnull(), + detail::cnull(), detail::cnull()) {} + + tuple(typename access_traits::parameter_type t0, + typename access_traits::parameter_type t1, + typename access_traits::parameter_type t2, + typename access_traits::parameter_type t3, + typename access_traits::parameter_type t4, + typename access_traits::parameter_type t5, + typename access_traits::parameter_type t6) + : inherited(t0, t1, t2, t3, t4, t5, t6, detail::cnull(), + detail::cnull(), detail::cnull()) {} + + tuple(typename access_traits::parameter_type t0, + typename access_traits::parameter_type t1, + typename access_traits::parameter_type t2, + typename access_traits::parameter_type t3, + typename access_traits::parameter_type t4, + typename access_traits::parameter_type t5, + typename access_traits::parameter_type t6, + typename access_traits::parameter_type t7) + : inherited(t0, t1, t2, t3, t4, t5, t6, t7, detail::cnull(), + detail::cnull()) {} + + tuple(typename access_traits::parameter_type t0, + typename access_traits::parameter_type t1, + typename access_traits::parameter_type t2, + typename access_traits::parameter_type t3, + typename access_traits::parameter_type t4, + typename access_traits::parameter_type t5, + typename access_traits::parameter_type t6, + typename access_traits::parameter_type t7, + typename access_traits::parameter_type t8) + : inherited(t0, t1, t2, t3, t4, t5, t6, t7, t8, detail::cnull()) {} + + tuple(typename access_traits::parameter_type t0, + typename access_traits::parameter_type t1, + typename access_traits::parameter_type t2, + typename access_traits::parameter_type t3, + typename access_traits::parameter_type t4, + typename access_traits::parameter_type t5, + typename access_traits::parameter_type t6, + typename access_traits::parameter_type t7, + typename access_traits::parameter_type t8, + typename access_traits::parameter_type t9) + : inherited(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9) {} + + + template + tuple(const cons& p) : inherited(p) {} + + template + tuple& operator=(const cons& k) { + inherited::operator=(k); + return *this; + } + + template + tuple& operator=(const std::pair& k) { + BOOST_STATIC_ASSERT(length::value == 2);// check_length = 2 + this->head = k.first; + this->tail.head = k.second; + return *this; + } + +}; + +// The empty tuple +template <> +class tuple : + public null_type +{ +public: + typedef null_type inherited; +}; + + +// Swallows any assignment (by Doug Gregor) +namespace detail { + +struct swallow_assign; +typedef void (detail::swallow_assign::*ignore_t)(); +struct swallow_assign { + swallow_assign(ignore_t(*)(ignore_t)) {} + template + swallow_assign const& operator=(const T&) const { + return *this; + } +}; + + +} // namespace detail + +// "ignore" allows tuple positions to be ignored when using "tie". +inline detail::ignore_t ignore(detail::ignore_t) { return 0; } + +// --------------------------------------------------------------------------- +// The call_traits for make_tuple +// Honours the reference_wrapper class. + +// Must be instantiated with plain or const plain types (not with references) + +// from template foo(const T& t) : make_tuple_traits::type +// from template foo(T& t) : make_tuple_traits::type + +// Conversions: +// T -> T, +// references -> compile_time_error +// reference_wrapper -> T& +// const reference_wrapper -> T& +// array -> const ref array + + +template +struct make_tuple_traits { + typedef T type; + + // commented away, see below (JJ) + // typedef typename IF< + // boost::is_function::value, + // T&, + // T>::RET type; + +}; + +// The is_function test was there originally for plain function types, +// which can't be stored as such (we must either store them as references or +// pointers). Such a type could be formed if make_tuple was called with a +// reference to a function. +// But this would mean that a const qualified function type was formed in +// the make_tuple function and hence make_tuple can't take a function +// reference as a parameter, and thus T can't be a function type. +// So is_function test was removed. +// (14.8.3. says that type deduction fails if a cv-qualified function type +// is created. (It only applies for the case of explicitly specifying template +// args, though?)) (JJ) + +template +struct make_tuple_traits { + typedef typename + detail::generate_error:: + do_not_use_with_reference_type error; +}; + +// Arrays can't be stored as plain types; convert them to references. +// All arrays are converted to const. This is because make_tuple takes its +// parameters as const T& and thus the knowledge of the potential +// non-constness of actual argument is lost. +template struct make_tuple_traits { + typedef const T (&type)[n]; +}; + +template +struct make_tuple_traits { + typedef const T (&type)[n]; +}; + +template struct make_tuple_traits { + typedef const volatile T (&type)[n]; +}; + +template +struct make_tuple_traits { + typedef const volatile T (&type)[n]; +}; + +template +struct make_tuple_traits >{ + typedef T& type; +}; + +template +struct make_tuple_traits >{ + typedef T& type; +}; + +template<> +struct make_tuple_traits { + typedef detail::swallow_assign type; +}; + + + +namespace detail { + +// a helper traits to make the make_tuple functions shorter (Vesa Karvonen's +// suggestion) +template < + class T0 = null_type, class T1 = null_type, class T2 = null_type, + class T3 = null_type, class T4 = null_type, class T5 = null_type, + class T6 = null_type, class T7 = null_type, class T8 = null_type, + class T9 = null_type +> +struct make_tuple_mapper { + typedef + tuple::type, + typename make_tuple_traits::type, + typename make_tuple_traits::type, + typename make_tuple_traits::type, + typename make_tuple_traits::type, + typename make_tuple_traits::type, + typename make_tuple_traits::type, + typename make_tuple_traits::type, + typename make_tuple_traits::type, + typename make_tuple_traits::type> type; +}; + +} // end detail + +// -make_tuple function templates ----------------------------------- +inline tuple<> make_tuple() { + return tuple<>(); +} + +template +inline typename detail::make_tuple_mapper::type +make_tuple(const T0& t0) { + typedef typename detail::make_tuple_mapper::type t; + return t(t0); +} + +template +inline typename detail::make_tuple_mapper::type +make_tuple(const T0& t0, const T1& t1) { + typedef typename detail::make_tuple_mapper::type t; + return t(t0, t1); +} + +template +inline typename detail::make_tuple_mapper::type +make_tuple(const T0& t0, const T1& t1, const T2& t2) { + typedef typename detail::make_tuple_mapper::type t; + return t(t0, t1, t2); +} + +template +inline typename detail::make_tuple_mapper::type +make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3) { + typedef typename detail::make_tuple_mapper::type t; + return t(t0, t1, t2, t3); +} + +template +inline typename detail::make_tuple_mapper::type +make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3, + const T4& t4) { + typedef typename detail::make_tuple_mapper::type t; + return t(t0, t1, t2, t3, t4); +} + +template +inline typename detail::make_tuple_mapper::type +make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5) { + typedef typename detail::make_tuple_mapper::type t; + return t(t0, t1, t2, t3, t4, t5); +} + +template +inline typename detail::make_tuple_mapper::type +make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5, const T6& t6) { + typedef typename detail::make_tuple_mapper + ::type t; + return t(t0, t1, t2, t3, t4, t5, t6); +} + +template +inline typename detail::make_tuple_mapper::type +make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5, const T6& t6, const T7& t7) { + typedef typename detail::make_tuple_mapper + ::type t; + return t(t0, t1, t2, t3, t4, t5, t6, t7); +} + +template +inline typename detail::make_tuple_mapper + ::type +make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5, const T6& t6, const T7& t7, + const T8& t8) { + typedef typename detail::make_tuple_mapper + ::type t; + return t(t0, t1, t2, t3, t4, t5, t6, t7, t8); +} + +template +inline typename detail::make_tuple_mapper + ::type +make_tuple(const T0& t0, const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5, const T6& t6, const T7& t7, + const T8& t8, const T9& t9) { + typedef typename detail::make_tuple_mapper + ::type t; + return t(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9); +} + +namespace detail { + +template +struct tie_traits { + typedef T& type; +}; + +template<> +struct tie_traits { + typedef swallow_assign type; +}; + +template<> +struct tie_traits { + typedef null_type type; +}; + +template < + class T0 = void, class T1 = void, class T2 = void, + class T3 = void, class T4 = void, class T5 = void, + class T6 = void, class T7 = void, class T8 = void, + class T9 = void +> +struct tie_mapper { + typedef + tuple::type, + typename tie_traits::type, + typename tie_traits::type, + typename tie_traits::type, + typename tie_traits::type, + typename tie_traits::type, + typename tie_traits::type, + typename tie_traits::type, + typename tie_traits::type, + typename tie_traits::type> type; +}; + +} + +// Tie function templates ------------------------------------------------- +template +inline typename detail::tie_mapper::type +tie(T0& t0) { + typedef typename detail::tie_mapper::type t; + return t(t0); +} + +template +inline typename detail::tie_mapper::type +tie(T0& t0, T1& t1) { + typedef typename detail::tie_mapper::type t; + return t(t0, t1); +} + +template +inline typename detail::tie_mapper::type +tie(T0& t0, T1& t1, T2& t2) { + typedef typename detail::tie_mapper::type t; + return t(t0, t1, t2); +} + +template +inline typename detail::tie_mapper::type +tie(T0& t0, T1& t1, T2& t2, T3& t3) { + typedef typename detail::tie_mapper::type t; + return t(t0, t1, t2, t3); +} + +template +inline typename detail::tie_mapper::type +tie(T0& t0, T1& t1, T2& t2, T3& t3, + T4& t4) { + typedef typename detail::tie_mapper::type t; + return t(t0, t1, t2, t3, t4); +} + +template +inline typename detail::tie_mapper::type +tie(T0& t0, T1& t1, T2& t2, T3& t3, + T4& t4, T5& t5) { + typedef typename detail::tie_mapper::type t; + return t(t0, t1, t2, t3, t4, t5); +} + +template +inline typename detail::tie_mapper::type +tie(T0& t0, T1& t1, T2& t2, T3& t3, + T4& t4, T5& t5, T6& t6) { + typedef typename detail::tie_mapper + ::type t; + return t(t0, t1, t2, t3, t4, t5, t6); +} + +template +inline typename detail::tie_mapper::type +tie(T0& t0, T1& t1, T2& t2, T3& t3, + T4& t4, T5& t5, T6& t6, T7& t7) { + typedef typename detail::tie_mapper + ::type t; + return t(t0, t1, t2, t3, t4, t5, t6, t7); +} + +template +inline typename detail::tie_mapper + ::type +tie(T0& t0, T1& t1, T2& t2, T3& t3, + T4& t4, T5& t5, T6& t6, T7& t7, + T8& t8) { + typedef typename detail::tie_mapper + ::type t; + return t(t0, t1, t2, t3, t4, t5, t6, t7, t8); +} + +template +inline typename detail::tie_mapper + ::type +tie(T0& t0, T1& t1, T2& t2, T3& t3, + T4& t4, T5& t5, T6& t6, T7& t7, + T8& t8, T9& t9) { + typedef typename detail::tie_mapper + ::type t; + return t(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9); +} + +template +void swap(tuple& lhs, + tuple& rhs); +inline void swap(null_type&, null_type&) {} +template +inline void swap(cons& lhs, cons& rhs) { + ::boost::swap(lhs.head, rhs.head); +} +template +inline void swap(cons& lhs, cons& rhs) { + ::boost::swap(lhs.head, rhs.head); + ::boost::tuples::swap(lhs.tail, rhs.tail); +} +template +inline void swap(tuple& lhs, + tuple& rhs) { + typedef tuple tuple_type; + typedef typename tuple_type::inherited base; + ::boost::tuples::swap(static_cast(lhs), static_cast(rhs)); +} + +} // end of namespace tuples +} // end of namespace boost + + +#if defined(BOOST_GCC) && (BOOST_GCC >= 40700) +#pragma GCC diagnostic pop +#endif + + +#endif // BOOST_TUPLE_BASIC_HPP diff --git a/boost/tuple/tuple.hpp b/boost/tuple/tuple.hpp new file mode 100644 index 0000000..d71e7df --- /dev/null +++ b/boost/tuple/tuple.hpp @@ -0,0 +1,67 @@ +// tuple.hpp - Boost Tuple Library -------------------------------------- + +// Copyright (C) 1999, 2000 Jaakko Jarvi (jaakko.jarvi@cs.utu.fi) +// +// 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) + +// For more information, see http://www.boost.org + +// ----------------------------------------------------------------- + +#ifndef BOOST_TUPLE_HPP +#define BOOST_TUPLE_HPP + +#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 +// Work around a compiler bug. +// boost::python::tuple has to be seen by the compiler before the +// boost::tuple class template. +namespace boost { namespace python { class tuple; }} +#endif + +#include +#include + +// other compilers +#include +#include + + +namespace boost { + +using tuples::tuple; +using tuples::make_tuple; +using tuples::tie; +#if !defined(BOOST_NO_USING_TEMPLATE) +using tuples::get; +#else +// +// The "using tuples::get" statement causes the +// Borland compiler to ICE, use forwarding +// functions instead: +// +template +inline typename tuples::access_traits< + typename tuples::element >::type + >::non_const_type +get(tuples::cons& c) { + return tuples::get(c); +} +// get function for const cons-lists, returns a const reference to +// the element. If the element is a reference, returns the reference +// as such (that is, can return a non-const reference) +template +inline typename tuples::access_traits< + typename tuples::element >::type + >::const_type +get(const tuples::cons& c) { + return tuples::get(c); +} + +#endif // BOOST_NO_USING_TEMPLATE + +} // end namespace boost + + +#endif // BOOST_TUPLE_HPP diff --git a/boost/type_traits/cv_traits.hpp b/boost/type_traits/cv_traits.hpp new file mode 100644 index 0000000..5bd6c4f --- /dev/null +++ b/boost/type_traits/cv_traits.hpp @@ -0,0 +1,24 @@ +// (C) Copyright Dave Abrahams, Steve Cleary, Beman Dawes, Howard +// Hinnant & John Maddock 2000. +// Use, modification and distribution are subject to 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/libs/type_traits for most recent version including documentation. +// +// defines traits classes for cv-qualified types: +// is_const, is_volatile, remove_const, remove_volatile, remove_cv. + +#ifndef BOOST_TT_CV_TRAITS_HPP_INCLUDED +#define BOOST_TT_CV_TRAITS_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // BOOST_TT_CV_TRAITS_HPP_INCLUDED diff --git a/boost/type_traits/is_bounded_array.hpp b/boost/type_traits/is_bounded_array.hpp new file mode 100644 index 0000000..5aeca6f --- /dev/null +++ b/boost/type_traits/is_bounded_array.hpp @@ -0,0 +1,42 @@ +/* +Copyright 2018 Glen Joseph Fernandes +(glenjofe@gmail.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_TT_IS_BOUNDED_ARRAY_HPP_INCLUDED +#define BOOST_TT_IS_BOUNDED_ARRAY_HPP_INCLUDED + +#include +#include + +namespace boost { + +template +struct is_bounded_array + : false_type { }; + +#if !defined(BOOST_NO_ARRAY_TYPE_SPECIALIZATIONS) +template +struct is_bounded_array + : true_type { }; + +template +struct is_bounded_array + : true_type { }; + +template +struct is_bounded_array + : true_type { }; + +template +struct is_bounded_array + : true_type { }; +#endif + +} /* boost */ + +#endif diff --git a/boost/type_traits/is_unbounded_array.hpp b/boost/type_traits/is_unbounded_array.hpp new file mode 100644 index 0000000..1bacfdc --- /dev/null +++ b/boost/type_traits/is_unbounded_array.hpp @@ -0,0 +1,41 @@ +/* +Copyright 2018 Glen Joseph Fernandes +(glenjofe@gmail.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_TT_IS_UNBOUNDED_ARRAY_HPP_INCLUDED +#define BOOST_TT_IS_UNBOUNDED_ARRAY_HPP_INCLUDED + +#include + +namespace boost { + +template +struct is_unbounded_array + : false_type { }; + +#if !defined(BOOST_NO_ARRAY_TYPE_SPECIALIZATIONS) +template +struct is_unbounded_array + : true_type { }; + +template +struct is_unbounded_array + : true_type { }; + +template +struct is_unbounded_array + : true_type { }; + +template +struct is_unbounded_array + : true_type { }; +#endif + +} /* boost */ + +#endif diff --git a/boost/utility/swap.hpp b/boost/utility/swap.hpp new file mode 100644 index 0000000..dd9ecd9 --- /dev/null +++ b/boost/utility/swap.hpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2014 Glen Fernandes + * + * 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_UTILITY_SWAP_HPP +#define BOOST_UTILITY_SWAP_HPP + +// The header file at this path is deprecated; +// use boost/core/swap.hpp instead. + +#include + +#endif diff --git a/boost/variant/detail/generic_result_type.hpp b/boost/variant/detail/generic_result_type.hpp deleted file mode 100644 index 8b1289c..0000000 --- a/boost/variant/detail/generic_result_type.hpp +++ /dev/null @@ -1,88 +0,0 @@ -//----------------------------------------------------------------------------- -// boost variant/detail/generic_result_type.hpp header file -// See http://www.boost.org for updates, documentation, and revision history. -//----------------------------------------------------------------------------- -// -// Copyright (c) 2003 -// Eric Friedman -// -// 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_VARIANT_DETAIL_GENERIC_RESULT_TYPE_HPP -#define BOOST_VARIANT_DETAIL_GENERIC_RESULT_TYPE_HPP - -#include - -////////////////////////////////////////////////////////////////////////// -// (workaround) macro BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE -// -// On compilers with BOOST_NO_VOID_RETURNS, this macro provides a route -// to a single syntax for dealing with template functions that may (but -// not necessarily) return nothing (i.e. void). -// -// BOOST_VARIANT_AUX_RETURN_VOID provided for compilers w/ (erroneous?) -// warnings about non-void functions not returning a value. -// - -#if !defined(BOOST_NO_VOID_RETURNS) - -#define BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(T) \ - T \ - /**/ - -#define BOOST_VARIANT_AUX_RETURN_VOID \ - /**/ - -#define BOOST_VARIANT_AUX_RETURN_VOID_TYPE \ - void \ - /**/ - -#else // defined(BOOST_NO_VOID_RETURNS) - -namespace boost { -namespace detail { namespace variant { - -struct fake_return_void -{ - fake_return_void() - { - } - - template - fake_return_void(const T&) - { - } -}; - -template -struct no_void_returns_helper -{ - typedef T type; -}; - -template <> -struct no_void_returns_helper -{ - typedef fake_return_void type; -}; - -}} // namespace detail::variant -} // namespace boost - -#define BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(T) \ - BOOST_DEDUCED_TYPENAME \ - ::boost::detail::variant::no_void_returns_helper< T >::type \ - /**/ - -#define BOOST_VARIANT_AUX_RETURN_VOID \ - return ::boost::detail::variant::fake_return_void() \ - /**/ - -#define BOOST_VARIANT_AUX_RETURN_VOID_TYPE \ - ::boost::detail::variant::fake_return_void - -#endif // BOOST_NO_VOID_RETURNS workaround - -#endif // BOOST_VARIANT_DETAIL_GENERIC_RESULT_TYPE_HPP diff --git a/boost/version.hpp b/boost/version.hpp index 912a59c..2adc0df 100644 --- a/boost/version.hpp +++ b/boost/version.hpp @@ -19,7 +19,7 @@ // BOOST_VERSION / 100 % 1000 is the minor version // BOOST_VERSION / 100000 is the major version -#define BOOST_VERSION 107100 +#define BOOST_VERSION 107200 // // BOOST_LIB_VERSION must be defined to be the same as BOOST_VERSION @@ -27,6 +27,6 @@ // number, y is the minor version number, and z is the patch level if not 0. // This is used by to select which library version to link to. -#define BOOST_LIB_VERSION "1_71" +#define BOOST_LIB_VERSION "1_72" #endif diff --git a/boost/winapi/access_rights.hpp b/boost/winapi/access_rights.hpp new file mode 100644 index 0000000..bf8d287 --- /dev/null +++ b/boost/winapi/access_rights.hpp @@ -0,0 +1,81 @@ +/* + * Copyright 2016 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_ACCESS_RIGHTS_HPP_INCLUDED_ +#define BOOST_WINAPI_ACCESS_RIGHTS_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace winapi { + +#if defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ DELETE_ = DELETE; +BOOST_CONSTEXPR_OR_CONST DWORD_ READ_CONTROL_ = READ_CONTROL; +BOOST_CONSTEXPR_OR_CONST DWORD_ WRITE_DAC_ = WRITE_DAC; +BOOST_CONSTEXPR_OR_CONST DWORD_ WRITE_OWNER_ = WRITE_OWNER; +BOOST_CONSTEXPR_OR_CONST DWORD_ SYNCHRONIZE_ = SYNCHRONIZE; + +BOOST_CONSTEXPR_OR_CONST DWORD_ STANDARD_RIGHTS_ALL_ = STANDARD_RIGHTS_ALL; +BOOST_CONSTEXPR_OR_CONST DWORD_ STANDARD_RIGHTS_EXECUTE_ = STANDARD_RIGHTS_EXECUTE; +BOOST_CONSTEXPR_OR_CONST DWORD_ STANDARD_RIGHTS_READ_ = STANDARD_RIGHTS_READ; +BOOST_CONSTEXPR_OR_CONST DWORD_ STANDARD_RIGHTS_REQUIRED_ = STANDARD_RIGHTS_REQUIRED; +BOOST_CONSTEXPR_OR_CONST DWORD_ STANDARD_RIGHTS_WRITE_ = STANDARD_RIGHTS_WRITE; + +BOOST_CONSTEXPR_OR_CONST DWORD_ SPECIFIC_RIGHTS_ALL_ = SPECIFIC_RIGHTS_ALL; + +BOOST_CONSTEXPR_OR_CONST DWORD_ ACCESS_SYSTEM_SECURITY_ = ACCESS_SYSTEM_SECURITY; + +BOOST_CONSTEXPR_OR_CONST DWORD_ MAXIMUM_ALLOWED_ = MAXIMUM_ALLOWED; + +BOOST_CONSTEXPR_OR_CONST DWORD_ GENERIC_ALL_ = GENERIC_ALL; +BOOST_CONSTEXPR_OR_CONST DWORD_ GENERIC_EXECUTE_ = GENERIC_EXECUTE; +BOOST_CONSTEXPR_OR_CONST DWORD_ GENERIC_WRITE_ = GENERIC_WRITE; +BOOST_CONSTEXPR_OR_CONST DWORD_ GENERIC_READ_ = GENERIC_READ; + +typedef ::ACCESS_MASK ACCESS_MASK_; +typedef ::PACCESS_MASK PACCESS_MASK_; + +#else // defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ DELETE_ = 0x00010000; +BOOST_CONSTEXPR_OR_CONST DWORD_ READ_CONTROL_ = 0x00020000; +BOOST_CONSTEXPR_OR_CONST DWORD_ WRITE_DAC_ = 0x00040000; +BOOST_CONSTEXPR_OR_CONST DWORD_ WRITE_OWNER_ = 0x00080000; +BOOST_CONSTEXPR_OR_CONST DWORD_ SYNCHRONIZE_ = 0x00100000; + +BOOST_CONSTEXPR_OR_CONST DWORD_ STANDARD_RIGHTS_ALL_ = 0x001F0000; +BOOST_CONSTEXPR_OR_CONST DWORD_ STANDARD_RIGHTS_EXECUTE_ = READ_CONTROL_; +BOOST_CONSTEXPR_OR_CONST DWORD_ STANDARD_RIGHTS_READ_ = READ_CONTROL_; +BOOST_CONSTEXPR_OR_CONST DWORD_ STANDARD_RIGHTS_REQUIRED_ = 0x000F0000; +BOOST_CONSTEXPR_OR_CONST DWORD_ STANDARD_RIGHTS_WRITE_ = READ_CONTROL_; + +BOOST_CONSTEXPR_OR_CONST DWORD_ SPECIFIC_RIGHTS_ALL_ = 0x0000FFFF; + +BOOST_CONSTEXPR_OR_CONST DWORD_ ACCESS_SYSTEM_SECURITY_ = 0x01000000; + +BOOST_CONSTEXPR_OR_CONST DWORD_ MAXIMUM_ALLOWED_ = 0x02000000; + +BOOST_CONSTEXPR_OR_CONST DWORD_ GENERIC_ALL_ = 0x10000000; +BOOST_CONSTEXPR_OR_CONST DWORD_ GENERIC_EXECUTE_ = 0x20000000; +BOOST_CONSTEXPR_OR_CONST DWORD_ GENERIC_WRITE_ = 0x40000000; +BOOST_CONSTEXPR_OR_CONST DWORD_ GENERIC_READ_ = 0x80000000; + +typedef DWORD_ ACCESS_MASK_; +typedef ACCESS_MASK_* PACCESS_MASK_; + +#endif // defined( BOOST_USE_WINDOWS_H ) + +} +} + +#endif // BOOST_WINAPI_ACCESS_RIGHTS_HPP_INCLUDED_ diff --git a/boost/winapi/critical_section.hpp b/boost/winapi/critical_section.hpp new file mode 100644 index 0000000..caed26b --- /dev/null +++ b/boost/winapi/critical_section.hpp @@ -0,0 +1,189 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright 2015 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_CRITICAL_SECTION_HPP_INCLUDED_ +#define BOOST_WINAPI_CRITICAL_SECTION_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if !defined( BOOST_USE_WINDOWS_H ) + +extern "C" { +#if !defined( BOOST_WINAPI_IS_MINGW ) +struct _RTL_CRITICAL_SECTION; + +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +BOOST_SYMBOL_IMPORT boost::winapi::VOID_ BOOST_WINAPI_WINAPI_CC +InitializeCriticalSection(::_RTL_CRITICAL_SECTION* lpCriticalSection); +#endif + +BOOST_SYMBOL_IMPORT boost::winapi::VOID_ BOOST_WINAPI_WINAPI_CC +EnterCriticalSection(::_RTL_CRITICAL_SECTION* lpCriticalSection); + +BOOST_SYMBOL_IMPORT boost::winapi::VOID_ BOOST_WINAPI_WINAPI_CC +LeaveCriticalSection(::_RTL_CRITICAL_SECTION* lpCriticalSection); + +#if BOOST_USE_WINAPI_VERSION >= 0x0403 +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +InitializeCriticalSectionAndSpinCount( + ::_RTL_CRITICAL_SECTION* lpCriticalSection, + boost::winapi::DWORD_ dwSpinCount); + +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC +SetCriticalSectionSpinCount( + ::_RTL_CRITICAL_SECTION* lpCriticalSection, + boost::winapi::DWORD_ dwSpinCount); +#endif + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +InitializeCriticalSectionEx( + ::_RTL_CRITICAL_SECTION* lpCriticalSection, + boost::winapi::DWORD_ dwSpinCount, + boost::winapi::DWORD_ Flags); +#endif +#endif + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_NT4 +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +TryEnterCriticalSection(::_RTL_CRITICAL_SECTION* lpCriticalSection); +#endif + +BOOST_SYMBOL_IMPORT boost::winapi::VOID_ BOOST_WINAPI_WINAPI_CC +DeleteCriticalSection(::_RTL_CRITICAL_SECTION* lpCriticalSection); + +#else // defined( BOOST_WINAPI_IS_MINGW ) + +// MinGW uses a different name for the structure +struct _CRITICAL_SECTION; + +BOOST_SYMBOL_IMPORT boost::winapi::VOID_ BOOST_WINAPI_WINAPI_CC +InitializeCriticalSection(::_CRITICAL_SECTION* lpCriticalSection); + +BOOST_SYMBOL_IMPORT boost::winapi::VOID_ BOOST_WINAPI_WINAPI_CC +EnterCriticalSection(::_CRITICAL_SECTION* lpCriticalSection); + +BOOST_SYMBOL_IMPORT boost::winapi::VOID_ BOOST_WINAPI_WINAPI_CC +LeaveCriticalSection(::_CRITICAL_SECTION* lpCriticalSection); + +#if BOOST_USE_WINAPI_VERSION >= 0x0403 +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +InitializeCriticalSectionAndSpinCount( + ::_CRITICAL_SECTION* lpCriticalSection, + boost::winapi::DWORD_ dwSpinCount); + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +InitializeCriticalSectionEx( + ::_CRITICAL_SECTION* lpCriticalSection, + boost::winapi::DWORD_ dwSpinCount, + boost::winapi::DWORD_ Flags); +#endif + +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC +SetCriticalSectionSpinCount( + ::_CRITICAL_SECTION* lpCriticalSection, + boost::winapi::DWORD_ dwSpinCount); +#endif + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_NT4 +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +TryEnterCriticalSection(::_CRITICAL_SECTION* lpCriticalSection); +#endif + +BOOST_SYMBOL_IMPORT boost::winapi::VOID_ BOOST_WINAPI_WINAPI_CC +DeleteCriticalSection(::_CRITICAL_SECTION* lpCriticalSection); + +#endif // defined( BOOST_WINAPI_IS_MINGW ) +} // extern "C" +#endif + +namespace boost { +namespace winapi { + +struct _RTL_CRITICAL_SECTION_DEBUG; + +#pragma pack(push, 8) + +typedef struct BOOST_MAY_ALIAS _RTL_CRITICAL_SECTION { + _RTL_CRITICAL_SECTION_DEBUG* DebugInfo; + LONG_ LockCount; + LONG_ RecursionCount; + HANDLE_ OwningThread; + HANDLE_ LockSemaphore; + ULONG_PTR_ SpinCount; +} CRITICAL_SECTION_, *PCRITICAL_SECTION_; + +#pragma pack(pop) + +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +BOOST_FORCEINLINE VOID_ InitializeCriticalSection(CRITICAL_SECTION_* lpCriticalSection) +{ + ::InitializeCriticalSection(winapi::detail::cast_ptr(lpCriticalSection)); +} +#endif + +BOOST_FORCEINLINE VOID_ EnterCriticalSection(CRITICAL_SECTION_* lpCriticalSection) +{ + ::EnterCriticalSection(winapi::detail::cast_ptr(lpCriticalSection)); +} + +BOOST_FORCEINLINE VOID_ LeaveCriticalSection(CRITICAL_SECTION_* lpCriticalSection) +{ + ::LeaveCriticalSection(winapi::detail::cast_ptr(lpCriticalSection)); +} + +#if BOOST_USE_WINAPI_VERSION >= 0x0403 +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +BOOST_FORCEINLINE BOOL_ InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION_* lpCriticalSection, DWORD_ dwSpinCount) +{ + return ::InitializeCriticalSectionAndSpinCount(winapi::detail::cast_ptr(lpCriticalSection), dwSpinCount); +} + +BOOST_FORCEINLINE DWORD_ SetCriticalSectionSpinCount(CRITICAL_SECTION_* lpCriticalSection, DWORD_ dwSpinCount) +{ + return ::SetCriticalSectionSpinCount(winapi::detail::cast_ptr(lpCriticalSection), dwSpinCount); +} +#endif + +// CRITICAL_SECTION_NO_DEBUG_INFO is defined for WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +BOOST_CONSTEXPR_OR_CONST DWORD_ CRITICAL_SECTION_NO_DEBUG_INFO_ = 0x01000000; +BOOST_CONSTEXPR_OR_CONST DWORD_ CRITICAL_SECTION_FLAG_NO_DEBUG_INFO_ = CRITICAL_SECTION_NO_DEBUG_INFO_; +BOOST_CONSTEXPR_OR_CONST DWORD_ CRITICAL_SECTION_FLAG_DYNAMIC_SPIN_ = 0x02000000; // undocumented +BOOST_CONSTEXPR_OR_CONST DWORD_ CRITICAL_SECTION_FLAG_STATIC_INIT_ = 0x04000000; // undocumented + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_FORCEINLINE BOOL_ InitializeCriticalSectionEx(CRITICAL_SECTION_* lpCriticalSection, DWORD_ dwSpinCount, DWORD_ Flags) +{ + return ::InitializeCriticalSectionEx(winapi::detail::cast_ptr(lpCriticalSection), dwSpinCount, Flags); +} +#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +#endif // BOOST_USE_WINAPI_VERSION >= 0x0403 + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_NT4 +BOOST_FORCEINLINE BOOL_ TryEnterCriticalSection(CRITICAL_SECTION_* lpCriticalSection) +{ + return ::TryEnterCriticalSection(winapi::detail::cast_ptr(lpCriticalSection)); +} +#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_NT4 + +BOOST_FORCEINLINE VOID_ DeleteCriticalSection(CRITICAL_SECTION_* lpCriticalSection) +{ + ::DeleteCriticalSection(winapi::detail::cast_ptr(lpCriticalSection)); +} + +} +} + +#endif // BOOST_WINAPI_CRITICAL_SECTION_HPP_INCLUDED_ diff --git a/boost/winapi/detail/cast_ptr.hpp b/boost/winapi/detail/cast_ptr.hpp new file mode 100644 index 0000000..0d991d5 --- /dev/null +++ b/boost/winapi/detail/cast_ptr.hpp @@ -0,0 +1,37 @@ +/* + * Copyright 2015 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_DETAIL_CAST_PTR_HPP_INCLUDED_ +#define BOOST_WINAPI_DETAIL_CAST_PTR_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace winapi { +namespace detail { + +//! This class is used to automatically cast pointers to the type used in the current Windows SDK function declarations +class cast_ptr +{ +private: + const void* m_p; + +public: + explicit BOOST_FORCEINLINE cast_ptr(const void* p) BOOST_NOEXCEPT : m_p(p) {} + template< typename T > + BOOST_FORCEINLINE operator T* () const BOOST_NOEXCEPT { return (T*)m_p; } +}; + +} +} +} + +#endif // BOOST_WINAPI_DETAIL_CAST_PTR_HPP_INCLUDED_ diff --git a/boost/winapi/dll.hpp b/boost/winapi/dll.hpp new file mode 100644 index 0000000..b42301e --- /dev/null +++ b/boost/winapi/dll.hpp @@ -0,0 +1,238 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright 2014 Renato Tegon Forti, Antony Polukhin + * Copyright 2015 Andrey Semashev + * Copyright 2015 Antony Polukhin + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_DLL_HPP_INCLUDED_ +#define BOOST_WINAPI_DLL_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM + +#if !defined( BOOST_USE_WINDOWS_H ) +extern "C" { +namespace boost { namespace winapi { +#ifdef _WIN64 +typedef INT_PTR_ (BOOST_WINAPI_WINAPI_CC *FARPROC_)(); +typedef INT_PTR_ (BOOST_WINAPI_WINAPI_CC *NEARPROC_)(); +typedef INT_PTR_ (BOOST_WINAPI_WINAPI_CC *PROC_)(); +#else +typedef int (BOOST_WINAPI_WINAPI_CC *FARPROC_)(); +typedef int (BOOST_WINAPI_WINAPI_CC *NEARPROC_)(); +typedef int (BOOST_WINAPI_WINAPI_CC *PROC_)(); +#endif // _WIN64 +}} // namespace boost::winapi + +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_SYMBOL_IMPORT boost::winapi::HMODULE_ BOOST_WINAPI_WINAPI_CC +LoadLibraryA(boost::winapi::LPCSTR_ lpFileName); + +BOOST_SYMBOL_IMPORT boost::winapi::HMODULE_ BOOST_WINAPI_WINAPI_CC +LoadLibraryExA( + boost::winapi::LPCSTR_ lpFileName, + boost::winapi::HANDLE_ hFile, + boost::winapi::DWORD_ dwFlags +); + +BOOST_SYMBOL_IMPORT boost::winapi::HMODULE_ BOOST_WINAPI_WINAPI_CC +GetModuleHandleA(boost::winapi::LPCSTR_ lpFileName); + +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC +GetModuleFileNameA( + boost::winapi::HMODULE_ hModule, + boost::winapi::LPSTR_ lpFilename, + boost::winapi::DWORD_ nSize +); +#endif + +BOOST_SYMBOL_IMPORT boost::winapi::HMODULE_ BOOST_WINAPI_WINAPI_CC +LoadLibraryW(boost::winapi::LPCWSTR_ lpFileName); + +BOOST_SYMBOL_IMPORT boost::winapi::HMODULE_ BOOST_WINAPI_WINAPI_CC +LoadLibraryExW( + boost::winapi::LPCWSTR_ lpFileName, + boost::winapi::HANDLE_ hFile, + boost::winapi::DWORD_ dwFlags +); + +BOOST_SYMBOL_IMPORT boost::winapi::HMODULE_ BOOST_WINAPI_WINAPI_CC +GetModuleHandleW(boost::winapi::LPCWSTR_ lpFileName); + +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC +GetModuleFileNameW( + boost::winapi::HMODULE_ hModule, + boost::winapi::LPWSTR_ lpFilename, + boost::winapi::DWORD_ nSize +); + +#if !defined( UNDER_CE ) +BOOST_SYMBOL_IMPORT boost::winapi::FARPROC_ BOOST_WINAPI_WINAPI_CC +GetProcAddress(boost::winapi::HMODULE_ hModule, boost::winapi::LPCSTR_ lpProcName); +#else +// On Windows CE there are two functions: GetProcAddressA (since Windows CE 3.0) and GetProcAddressW. +// GetProcAddress is a macro that is _always_ defined to GetProcAddressW. +BOOST_SYMBOL_IMPORT boost::winapi::FARPROC_ BOOST_WINAPI_WINAPI_CC +GetProcAddressA(boost::winapi::HMODULE_ hModule, boost::winapi::LPCSTR_ lpProcName); +BOOST_SYMBOL_IMPORT boost::winapi::FARPROC_ BOOST_WINAPI_WINAPI_CC +GetProcAddressW(boost::winapi::HMODULE_ hModule, boost::winapi::LPCWSTR_ lpProcName); +#endif + +struct _MEMORY_BASIC_INFORMATION; + +#if !defined( BOOST_WINAPI_IS_MINGW ) +BOOST_SYMBOL_IMPORT boost::winapi::SIZE_T_ BOOST_WINAPI_WINAPI_CC +VirtualQuery( + boost::winapi::LPCVOID_ lpAddress, + ::_MEMORY_BASIC_INFORMATION* lpBuffer, + boost::winapi::SIZE_T_ dwLength +); +#else // !defined( BOOST_WINAPI_IS_MINGW ) +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC +VirtualQuery( + boost::winapi::LPCVOID_ lpAddress, + ::_MEMORY_BASIC_INFORMATION* lpBuffer, + boost::winapi::DWORD_ dwLength +); +#endif // !defined( BOOST_WINAPI_IS_MINGW ) +} // extern "C" +#endif // #if !defined( BOOST_USE_WINDOWS_H ) + +namespace boost { +namespace winapi { + +typedef struct BOOST_MAY_ALIAS MEMORY_BASIC_INFORMATION_ { + PVOID_ BaseAddress; + PVOID_ AllocationBase; + DWORD_ AllocationProtect; + SIZE_T_ RegionSize; + DWORD_ State; + DWORD_ Protect; + DWORD_ Type; +} *PMEMORY_BASIC_INFORMATION_; + +#if defined( BOOST_USE_WINDOWS_H ) +typedef ::FARPROC FARPROC_; +typedef ::NEARPROC NEARPROC_; +typedef ::PROC PROC_; + +BOOST_CONSTEXPR_OR_CONST DWORD_ DONT_RESOLVE_DLL_REFERENCES_ = DONT_RESOLVE_DLL_REFERENCES; +BOOST_CONSTEXPR_OR_CONST DWORD_ LOAD_WITH_ALTERED_SEARCH_PATH_ = LOAD_WITH_ALTERED_SEARCH_PATH; +#else // defined( BOOST_USE_WINDOWS_H ) +BOOST_CONSTEXPR_OR_CONST DWORD_ DONT_RESOLVE_DLL_REFERENCES_ = 0x00000001; +BOOST_CONSTEXPR_OR_CONST DWORD_ LOAD_WITH_ALTERED_SEARCH_PATH_ = 0x00000008; +#endif // defined( BOOST_USE_WINDOWS_H ) + +// This one is not defined by MinGW +BOOST_CONSTEXPR_OR_CONST DWORD_ LOAD_IGNORE_CODE_AUTHZ_LEVEL_ = 0x00000010; + +#if !defined( BOOST_NO_ANSI_APIS ) +using ::LoadLibraryA; +using ::LoadLibraryExA; +using ::GetModuleHandleA; +using ::GetModuleFileNameA; +#endif // !defined( BOOST_NO_ANSI_APIS ) +using ::LoadLibraryW; +using ::LoadLibraryExW; +using ::GetModuleHandleW; +using ::GetModuleFileNameW; + +#if !defined( UNDER_CE ) +// For backward compatibility, don't use directly. Use get_proc_address instead. +using ::GetProcAddress; +#else +using ::GetProcAddressA; +using ::GetProcAddressW; +#endif + +BOOST_FORCEINLINE FARPROC_ get_proc_address(HMODULE_ hModule, LPCSTR_ lpProcName) +{ +#if !defined( UNDER_CE ) + return ::GetProcAddress(hModule, lpProcName); +#else + return ::GetProcAddressA(hModule, lpProcName); +#endif +} + +BOOST_FORCEINLINE SIZE_T_ VirtualQuery(LPCVOID_ lpAddress, MEMORY_BASIC_INFORMATION_* lpBuffer, SIZE_T_ dwLength) +{ + return ::VirtualQuery(lpAddress, reinterpret_cast< ::_MEMORY_BASIC_INFORMATION* >(lpBuffer), dwLength); +} + +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_FORCEINLINE HMODULE_ load_library(LPCSTR_ lpFileName) +{ + return ::LoadLibraryA(lpFileName); +} + +BOOST_FORCEINLINE HMODULE_ load_library_ex(LPCSTR_ lpFileName, HANDLE_ hFile, DWORD_ dwFlags) +{ + return ::LoadLibraryExA(lpFileName, hFile, dwFlags); +} + +BOOST_FORCEINLINE HMODULE_ get_module_handle(LPCSTR_ lpFileName) +{ + return ::GetModuleHandleA(lpFileName); +} + +BOOST_FORCEINLINE DWORD_ get_module_file_name(HMODULE_ hModule, LPSTR_ lpFilename, DWORD_ nSize) +{ + return ::GetModuleFileNameA(hModule, lpFilename, nSize); +} +#endif // #if !defined( BOOST_NO_ANSI_APIS ) + +BOOST_FORCEINLINE HMODULE_ load_library(LPCWSTR_ lpFileName) +{ + return ::LoadLibraryW(lpFileName); +} + +BOOST_FORCEINLINE HMODULE_ load_library_ex(LPCWSTR_ lpFileName, HANDLE_ hFile, DWORD_ dwFlags) +{ + return ::LoadLibraryExW(lpFileName, hFile, dwFlags); +} + +BOOST_FORCEINLINE HMODULE_ get_module_handle(LPCWSTR_ lpFileName) +{ + return ::GetModuleHandleW(lpFileName); +} + +BOOST_FORCEINLINE DWORD_ get_module_file_name(HMODULE_ hModule, LPWSTR_ lpFilename, DWORD_ nSize) +{ + return ::GetModuleFileNameW(hModule, lpFilename, nSize); +} + +} // namespace winapi +} // namespace boost + +#endif // BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM + +// +// FreeLibrary is in a different partition set (slightly) +// + +#if BOOST_WINAPI_PARTITION_APP || BOOST_WINAPI_PARTITION_SYSTEM + +#if !defined(BOOST_USE_WINDOWS_H) +extern "C" { +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +FreeLibrary(boost::winapi::HMODULE_ hModule); +} +#endif + +namespace boost { +namespace winapi { +using ::FreeLibrary; +} +} + +#endif // BOOST_WINAPI_PARTITION_APP || BOOST_WINAPI_PARTITION_SYSTEM +#endif // BOOST_WINAPI_DLL_HPP_INCLUDED_ diff --git a/boost/winapi/event.hpp b/boost/winapi/event.hpp new file mode 100644 index 0000000..1ec611f --- /dev/null +++ b/boost/winapi/event.hpp @@ -0,0 +1,190 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright 2015, 2017 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_EVENT_HPP_INCLUDED_ +#define BOOST_WINAPI_EVENT_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if !defined( BOOST_USE_WINDOWS_H ) && BOOST_WINAPI_PARTITION_APP_SYSTEM +extern "C" { +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateEventA( + ::_SECURITY_ATTRIBUTES* lpEventAttributes, + boost::winapi::BOOL_ bManualReset, + boost::winapi::BOOL_ bInitialState, + boost::winapi::LPCSTR_ lpName); +#endif + +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateEventW( + ::_SECURITY_ATTRIBUTES* lpEventAttributes, + boost::winapi::BOOL_ bManualReset, + boost::winapi::BOOL_ bInitialState, + boost::winapi::LPCWSTR_ lpName); +} // extern "C" +#endif // !defined( BOOST_USE_WINDOWS_H ) && BOOST_WINAPI_PARTITION_APP_SYSTEM + +#if !defined( BOOST_USE_WINDOWS_H ) +extern "C" { +#if !defined( BOOST_NO_ANSI_APIS ) +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateEventExA( + ::_SECURITY_ATTRIBUTES *lpEventAttributes, + boost::winapi::LPCSTR_ lpName, + boost::winapi::DWORD_ dwFlags, + boost::winapi::DWORD_ dwDesiredAccess); +#endif + +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +OpenEventA( + boost::winapi::DWORD_ dwDesiredAccess, + boost::winapi::BOOL_ bInheritHandle, + boost::winapi::LPCSTR_ lpName); +#endif // !defined( BOOST_NO_ANSI_APIS ) + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateEventExW( + ::_SECURITY_ATTRIBUTES *lpEventAttributes, + boost::winapi::LPCWSTR_ lpName, + boost::winapi::DWORD_ dwFlags, + boost::winapi::DWORD_ dwDesiredAccess); +#endif + +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +OpenEventW( + boost::winapi::DWORD_ dwDesiredAccess, + boost::winapi::BOOL_ bInheritHandle, + boost::winapi::LPCWSTR_ lpName); + +// Windows CE define SetEvent/ResetEvent as inline functions in kfuncs.h +#if !defined( UNDER_CE ) +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +SetEvent(boost::winapi::HANDLE_ hEvent); + +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +ResetEvent(boost::winapi::HANDLE_ hEvent); +#endif +} // extern "C" +#endif + +namespace boost { +namespace winapi { + +#if !defined( BOOST_NO_ANSI_APIS ) +using ::OpenEventA; +#endif +using ::OpenEventW; +using ::SetEvent; +using ::ResetEvent; + +#if defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ EVENT_ALL_ACCESS_ = EVENT_ALL_ACCESS; +BOOST_CONSTEXPR_OR_CONST DWORD_ EVENT_MODIFY_STATE_ = EVENT_MODIFY_STATE; +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_CONSTEXPR_OR_CONST DWORD_ CREATE_EVENT_INITIAL_SET_ = CREATE_EVENT_INITIAL_SET; +BOOST_CONSTEXPR_OR_CONST DWORD_ CREATE_EVENT_MANUAL_RESET_ = CREATE_EVENT_MANUAL_RESET; +#endif + +#else // defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ EVENT_ALL_ACCESS_ = 0x001F0003; +BOOST_CONSTEXPR_OR_CONST DWORD_ EVENT_MODIFY_STATE_ = 0x00000002; +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_CONSTEXPR_OR_CONST DWORD_ CREATE_EVENT_INITIAL_SET_ = 0x00000002; +BOOST_CONSTEXPR_OR_CONST DWORD_ CREATE_EVENT_MANUAL_RESET_ = 0x00000001; +#endif + +#endif // defined( BOOST_USE_WINDOWS_H ) + +// Undocumented and not present in Windows SDK. Enables NtQueryEvent. +// http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FEvent%2FNtQueryEvent.html +BOOST_CONSTEXPR_OR_CONST DWORD_ EVENT_QUERY_STATE_ = 0x00000001; + +BOOST_CONSTEXPR_OR_CONST DWORD_ event_all_access = EVENT_ALL_ACCESS_; +BOOST_CONSTEXPR_OR_CONST DWORD_ event_modify_state = EVENT_MODIFY_STATE_; +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_CONSTEXPR_OR_CONST DWORD_ create_event_initial_set = CREATE_EVENT_INITIAL_SET_; +BOOST_CONSTEXPR_OR_CONST DWORD_ create_event_manual_reset = CREATE_EVENT_MANUAL_RESET_; +#endif + +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_FORCEINLINE HANDLE_ CreateEventA(SECURITY_ATTRIBUTES_* lpEventAttributes, BOOL_ bManualReset, BOOL_ bInitialState, LPCSTR_ lpName) +{ +#if !BOOST_WINAPI_PARTITION_APP_SYSTEM && BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 + const DWORD_ flags = (bManualReset ? create_event_manual_reset : 0u) | (bInitialState ? create_event_initial_set : 0u); + return ::CreateEventExA(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpEventAttributes), lpName, flags, event_all_access); +#else + return ::CreateEventA(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpEventAttributes), bManualReset, bInitialState, lpName); +#endif +} + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_FORCEINLINE HANDLE_ CreateEventExA(SECURITY_ATTRIBUTES_* lpEventAttributes, LPCSTR_ lpName, DWORD_ dwFlags, DWORD_ dwDesiredAccess) +{ + return ::CreateEventExA(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpEventAttributes), lpName, dwFlags, dwDesiredAccess); +} +#endif +#endif + +BOOST_FORCEINLINE HANDLE_ CreateEventW(SECURITY_ATTRIBUTES_* lpEventAttributes, BOOL_ bManualReset, BOOL_ bInitialState, LPCWSTR_ lpName) +{ +#if !BOOST_WINAPI_PARTITION_APP_SYSTEM && BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 + const DWORD_ flags = (bManualReset ? create_event_manual_reset : 0u) | (bInitialState ? create_event_initial_set : 0u); + return ::CreateEventExW(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpEventAttributes), lpName, flags, event_all_access); +#else + return ::CreateEventW(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpEventAttributes), bManualReset, bInitialState, lpName); +#endif +} + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_FORCEINLINE HANDLE_ CreateEventExW(SECURITY_ATTRIBUTES_* lpEventAttributes, LPCWSTR_ lpName, DWORD_ dwFlags, DWORD_ dwDesiredAccess) +{ + return ::CreateEventExW(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpEventAttributes), lpName, dwFlags, dwDesiredAccess); +} +#endif + +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_FORCEINLINE HANDLE_ create_event(SECURITY_ATTRIBUTES_* lpEventAttributes, BOOL_ bManualReset, BOOL_ bInitialState, LPCSTR_ lpName) +{ + return winapi::CreateEventA(lpEventAttributes, bManualReset, bInitialState, lpName); +} + +BOOST_FORCEINLINE HANDLE_ open_event(DWORD_ dwDesiredAccess, BOOL_ bInheritHandle, LPCSTR_ lpName) +{ + return ::OpenEventA(dwDesiredAccess, bInheritHandle, lpName); +} +#endif + +BOOST_FORCEINLINE HANDLE_ create_event(SECURITY_ATTRIBUTES_* lpEventAttributes, BOOL_ bManualReset, BOOL_ bInitialState, LPCWSTR_ lpName) +{ + return winapi::CreateEventW(lpEventAttributes, bManualReset, bInitialState, lpName); +} + +BOOST_FORCEINLINE HANDLE_ open_event(DWORD_ dwDesiredAccess, BOOL_ bInheritHandle, LPCWSTR_ lpName) +{ + return ::OpenEventW(dwDesiredAccess, bInheritHandle, lpName); +} + +BOOST_FORCEINLINE HANDLE_ create_anonymous_event(SECURITY_ATTRIBUTES_* lpEventAttributes, BOOL_ bManualReset, BOOL_ bInitialState) +{ + return winapi::CreateEventW(lpEventAttributes, bManualReset, bInitialState, 0); +} + +} +} + +#endif // BOOST_WINAPI_EVENT_HPP_INCLUDED_ diff --git a/boost/winapi/get_current_process_id.hpp b/boost/winapi/get_current_process_id.hpp new file mode 100644 index 0000000..4883180 --- /dev/null +++ b/boost/winapi/get_current_process_id.hpp @@ -0,0 +1,30 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_GET_CURRENT_PROCESS_ID_HPP_INCLUDED_ +#define BOOST_WINAPI_GET_CURRENT_PROCESS_ID_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// Windows CE define GetCurrentProcessId as an inline function in kfuncs.h +#if !defined( BOOST_USE_WINDOWS_H ) && !defined( UNDER_CE ) +extern "C" { +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC GetCurrentProcessId(BOOST_WINAPI_DETAIL_VOID); +} +#endif + +namespace boost { +namespace winapi { +using ::GetCurrentProcessId; +} +} + +#endif // BOOST_WINAPI_GET_CURRENT_PROCESS_ID_HPP_INCLUDED_ diff --git a/boost/winapi/get_current_thread_id.hpp b/boost/winapi/get_current_thread_id.hpp new file mode 100644 index 0000000..c488e4b --- /dev/null +++ b/boost/winapi/get_current_thread_id.hpp @@ -0,0 +1,31 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright 2015 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_GET_CURRENT_THREAD_ID_HPP_INCLUDED_ +#define BOOST_WINAPI_GET_CURRENT_THREAD_ID_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// Windows CE define GetCurrentThreadId as an inline function in kfuncs.h +#if !defined( BOOST_USE_WINDOWS_H ) && !defined( UNDER_CE ) +extern "C" { +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC GetCurrentThreadId(BOOST_WINAPI_DETAIL_VOID); +} +#endif + +namespace boost { +namespace winapi { +using ::GetCurrentThreadId; +} +} + +#endif // BOOST_WINAPI_GET_CURRENT_THREAD_ID_HPP_INCLUDED_ diff --git a/boost/winapi/handles.hpp b/boost/winapi/handles.hpp new file mode 100644 index 0000000..91054ee --- /dev/null +++ b/boost/winapi/handles.hpp @@ -0,0 +1,72 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright 2015 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_HANDLES_HPP_INCLUDED_ +#define BOOST_WINAPI_HANDLES_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if !defined( BOOST_USE_WINDOWS_H ) +extern "C" { +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +CloseHandle(boost::winapi::HANDLE_ handle); + +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +DuplicateHandle( + boost::winapi::HANDLE_ hSourceProcessHandle, + boost::winapi::HANDLE_ hSourceHandle, + boost::winapi::HANDLE_ hTargetProcessHandle, + boost::winapi::HANDLE_* lpTargetHandle, + boost::winapi::DWORD_ dwDesiredAccess, + boost::winapi::BOOL_ bInheritHandle, + boost::winapi::DWORD_ dwOptions); + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN10 +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +CompareObjectHandles( + boost::winapi::HANDLE_ hFirstObjectHandle, + boost::winapi::HANDLE_ hSecondObjectHandle); +#endif +} // extern "C" +#endif + +namespace boost { +namespace winapi { + +using ::CloseHandle; +using ::DuplicateHandle; + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN10 +using ::CompareObjectHandles; +#endif + +// Note: MSVC-14.1 does not interpret INVALID_HANDLE_VALUE_ initializer as a constant expression +#if defined( BOOST_USE_WINDOWS_H ) +BOOST_CONSTEXPR_OR_CONST DWORD_ DUPLICATE_CLOSE_SOURCE_ = DUPLICATE_CLOSE_SOURCE; +BOOST_CONSTEXPR_OR_CONST DWORD_ DUPLICATE_SAME_ACCESS_ = DUPLICATE_SAME_ACCESS; +const HANDLE_ INVALID_HANDLE_VALUE_ = INVALID_HANDLE_VALUE; +#else +BOOST_CONSTEXPR_OR_CONST DWORD_ DUPLICATE_CLOSE_SOURCE_ = 1; +BOOST_CONSTEXPR_OR_CONST DWORD_ DUPLICATE_SAME_ACCESS_ = 2; +const HANDLE_ INVALID_HANDLE_VALUE_ = (HANDLE_)(-1); +#endif + +BOOST_CONSTEXPR_OR_CONST DWORD_ duplicate_close_source = DUPLICATE_CLOSE_SOURCE_; +BOOST_CONSTEXPR_OR_CONST DWORD_ duplicate_same_access = DUPLICATE_SAME_ACCESS_; +// Note: The "unused" attribute here should not be necessary because the variable is a constant. +// However, MinGW gcc 5.3 spams warnings about this particular constant. +const HANDLE_ invalid_handle_value BOOST_ATTRIBUTE_UNUSED = INVALID_HANDLE_VALUE_; + +} +} + +#endif // BOOST_WINAPI_HANDLES_HPP_INCLUDED_ diff --git a/boost/winapi/heap_memory.hpp b/boost/winapi/heap_memory.hpp new file mode 100644 index 0000000..fcc6153 --- /dev/null +++ b/boost/winapi/heap_memory.hpp @@ -0,0 +1,83 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright 2015, 2017 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_HEAP_MEMORY_HPP_INCLUDED_ +#define BOOST_WINAPI_HEAP_MEMORY_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if !defined( BOOST_USE_WINDOWS_H ) +#undef HeapAlloc +extern "C" { + +#if BOOST_WINAPI_PARTITION_DESKTOP_SYSTEM +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC +GetProcessHeaps(boost::winapi::DWORD_ NumberOfHeaps, boost::winapi::PHANDLE_ ProcessHeaps); +#endif // BOOST_WINAPI_PARTITION_DESKTOP_SYSTEM + +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +GetProcessHeap(BOOST_WINAPI_DETAIL_VOID); + +BOOST_SYMBOL_IMPORT boost::winapi::LPVOID_ BOOST_WINAPI_WINAPI_CC +HeapAlloc( + boost::winapi::HANDLE_ hHeap, + boost::winapi::DWORD_ dwFlags, + boost::winapi::SIZE_T_ dwBytes); + +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +HeapFree( + boost::winapi::HANDLE_ hHeap, + boost::winapi::DWORD_ dwFlags, + boost::winapi::LPVOID_ lpMem); + +BOOST_SYMBOL_IMPORT boost::winapi::LPVOID_ BOOST_WINAPI_WINAPI_CC +HeapReAlloc( + boost::winapi::HANDLE_ hHeap, + boost::winapi::DWORD_ dwFlags, + boost::winapi::LPVOID_ lpMem, + boost::winapi::SIZE_T_ dwBytes); + +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +HeapCreate( + boost::winapi::DWORD_ flOptions, + boost::winapi::SIZE_T_ dwInitialSize, + boost::winapi::SIZE_T_ dwMaximumSize); + +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +HeapDestroy(boost::winapi::HANDLE_ hHeap); +#endif // BOOST_WINAPI_PARTITION_APP_SYSTEM + +} // extern "C" +#endif // !defined( BOOST_USE_WINDOWS_H ) + +namespace boost { +namespace winapi { + +#if BOOST_WINAPI_PARTITION_DESKTOP_SYSTEM +using ::GetProcessHeaps; +#endif + +using ::GetProcessHeap; +using ::HeapAlloc; +using ::HeapFree; +using ::HeapReAlloc; + +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +using ::HeapCreate; +using ::HeapDestroy; +#endif + +} +} + +#endif // BOOST_WINAPI_HEAP_MEMORY_HPP_INCLUDED_ diff --git a/boost/winapi/semaphore.hpp b/boost/winapi/semaphore.hpp new file mode 100644 index 0000000..44a2981 --- /dev/null +++ b/boost/winapi/semaphore.hpp @@ -0,0 +1,186 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright 2015 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_SEMAPHORE_HPP_INCLUDED_ +#define BOOST_WINAPI_SEMAPHORE_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if !defined( BOOST_USE_WINDOWS_H ) +extern "C" { + +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +#if !defined( BOOST_NO_ANSI_APIS ) + +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateSemaphoreA( + ::_SECURITY_ATTRIBUTES* lpSemaphoreAttributes, + boost::winapi::LONG_ lInitialCount, + boost::winapi::LONG_ lMaximumCount, + boost::winapi::LPCSTR_ lpName); + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateSemaphoreExA( + ::_SECURITY_ATTRIBUTES* lpSemaphoreAttributes, + boost::winapi::LONG_ lInitialCount, + boost::winapi::LONG_ lMaximumCount, + boost::winapi::LPCSTR_ lpName, + boost::winapi::DWORD_ dwFlags, + boost::winapi::DWORD_ dwDesiredAccess); +#endif + +#endif // !defined( BOOST_NO_ANSI_APIS ) + +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateSemaphoreW( + ::_SECURITY_ATTRIBUTES* lpSemaphoreAttributes, + boost::winapi::LONG_ lInitialCount, + boost::winapi::LONG_ lMaximumCount, + boost::winapi::LPCWSTR_ lpName); + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +CreateSemaphoreExW( + ::_SECURITY_ATTRIBUTES* lpSemaphoreAttributes, + boost::winapi::LONG_ lInitialCount, + boost::winapi::LONG_ lMaximumCount, + boost::winapi::LPCWSTR_ lpName, + boost::winapi::DWORD_ dwFlags, + boost::winapi::DWORD_ dwDesiredAccess); +#endif + +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +ReleaseSemaphore( + boost::winapi::HANDLE_ hSemaphore, + boost::winapi::LONG_ lReleaseCount, + boost::winapi::LPLONG_ lpPreviousCount); + +#endif // BOOST_WINAPI_PARTITION_APP_SYSTEM + +#if BOOST_WINAPI_PARTITION_DESKTOP_SYSTEM + +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +OpenSemaphoreA( + boost::winapi::DWORD_ dwDesiredAccess, + boost::winapi::BOOL_ bInheritHandle, + boost::winapi::LPCSTR_ lpName); +#endif // !defined( BOOST_NO_ANSI_APIS ) + +BOOST_SYMBOL_IMPORT boost::winapi::HANDLE_ BOOST_WINAPI_WINAPI_CC +OpenSemaphoreW( + boost::winapi::DWORD_ dwDesiredAccess, + boost::winapi::BOOL_ bInheritHandle, + boost::winapi::LPCWSTR_ lpName); + +#endif // BOOST_WINAPI_PARTITION_DESKTOP_SYSTEM + +} // extern "C" +#endif // !defined( BOOST_USE_WINDOWS_H ) + +namespace boost { +namespace winapi { + +#if BOOST_WINAPI_PARTITION_APP_SYSTEM + +using ::ReleaseSemaphore; + +#if defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ SEMAPHORE_ALL_ACCESS_ = SEMAPHORE_ALL_ACCESS; +BOOST_CONSTEXPR_OR_CONST DWORD_ SEMAPHORE_MODIFY_STATE_ = SEMAPHORE_MODIFY_STATE; + +#else // defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ SEMAPHORE_ALL_ACCESS_ = 0x001F0003; +BOOST_CONSTEXPR_OR_CONST DWORD_ SEMAPHORE_MODIFY_STATE_ = 0x00000002; + +#endif // defined( BOOST_USE_WINDOWS_H ) + +// Undocumented and not present in Windows SDK. Enables NtQuerySemaphore. +// http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FEvent%2FNtQueryEvent.html +BOOST_CONSTEXPR_OR_CONST DWORD_ SEMAPHORE_QUERY_STATE_ = 0x00000001; + +BOOST_CONSTEXPR_OR_CONST DWORD_ semaphore_all_access = SEMAPHORE_ALL_ACCESS_; +BOOST_CONSTEXPR_OR_CONST DWORD_ semaphore_modify_state = SEMAPHORE_MODIFY_STATE_; + + +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_FORCEINLINE HANDLE_ CreateSemaphoreA(SECURITY_ATTRIBUTES_* lpSemaphoreAttributes, LONG_ lInitialCount, LONG_ lMaximumCount, LPCSTR_ lpName) +{ + return ::CreateSemaphoreA(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpSemaphoreAttributes), lInitialCount, lMaximumCount, lpName); +} + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_FORCEINLINE HANDLE_ CreateSemaphoreExA(SECURITY_ATTRIBUTES_* lpSemaphoreAttributes, LONG_ lInitialCount, LONG_ lMaximumCount, LPCSTR_ lpName, DWORD_ dwFlags, DWORD_ dwDesiredAccess) +{ + return ::CreateSemaphoreExA(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpSemaphoreAttributes), lInitialCount, lMaximumCount, lpName, dwFlags, dwDesiredAccess); +} +#endif +#endif // !defined( BOOST_NO_ANSI_APIS ) + +BOOST_FORCEINLINE HANDLE_ CreateSemaphoreW(SECURITY_ATTRIBUTES_* lpSemaphoreAttributes, LONG_ lInitialCount, LONG_ lMaximumCount, LPCWSTR_ lpName) +{ + return ::CreateSemaphoreW(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpSemaphoreAttributes), lInitialCount, lMaximumCount, lpName); +} + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +BOOST_FORCEINLINE HANDLE_ CreateSemaphoreExW(SECURITY_ATTRIBUTES_* lpSemaphoreAttributes, LONG_ lInitialCount, LONG_ lMaximumCount, LPCWSTR_ lpName, DWORD_ dwFlags, DWORD_ dwDesiredAccess) +{ + return ::CreateSemaphoreExW(reinterpret_cast< ::_SECURITY_ATTRIBUTES* >(lpSemaphoreAttributes), lInitialCount, lMaximumCount, lpName, dwFlags, dwDesiredAccess); +} +#endif + +#if !defined( BOOST_NO_ANSI_APIS ) +BOOST_FORCEINLINE HANDLE_ create_semaphore(SECURITY_ATTRIBUTES_* lpSemaphoreAttributes, LONG_ lInitialCount, LONG_ lMaximumCount, LPCSTR_ lpName) +{ + return winapi::CreateSemaphoreA(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName); +} +#endif + +BOOST_FORCEINLINE HANDLE_ create_semaphore(SECURITY_ATTRIBUTES_* lpSemaphoreAttributes, LONG_ lInitialCount, LONG_ lMaximumCount, LPCWSTR_ lpName) +{ + return winapi::CreateSemaphoreW(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName); +} + +BOOST_FORCEINLINE HANDLE_ create_anonymous_semaphore(SECURITY_ATTRIBUTES_* lpSemaphoreAttributes, LONG_ lInitialCount, LONG_ lMaximumCount) +{ + return winapi::CreateSemaphoreW(lpSemaphoreAttributes, lInitialCount, lMaximumCount, 0); +} + +#endif // BOOST_WINAPI_PARTITION_APP_SYSTEM + +#if BOOST_WINAPI_PARTITION_DESKTOP_SYSTEM + +#if !defined( BOOST_NO_ANSI_APIS ) +using ::OpenSemaphoreA; + +BOOST_FORCEINLINE HANDLE_ open_semaphore(DWORD_ dwDesiredAccess, BOOL_ bInheritHandle, LPCSTR_ lpName) +{ + return ::OpenSemaphoreA(dwDesiredAccess, bInheritHandle, lpName); +} +#endif // !defined( BOOST_NO_ANSI_APIS ) + +using ::OpenSemaphoreW; + +BOOST_FORCEINLINE HANDLE_ open_semaphore(DWORD_ dwDesiredAccess, BOOL_ bInheritHandle, LPCWSTR_ lpName) +{ + return ::OpenSemaphoreW(dwDesiredAccess, bInheritHandle, lpName); +} + +#endif // BOOST_WINAPI_PARTITION_DESKTOP_SYSTEM + +} +} + +#endif // BOOST_WINAPI_SEMAPHORE_HPP_INCLUDED_ diff --git a/boost/winapi/system.hpp b/boost/winapi/system.hpp new file mode 100644 index 0000000..118e0c9 --- /dev/null +++ b/boost/winapi/system.hpp @@ -0,0 +1,87 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright (c) Microsoft Corporation 2014 + * Copyright 2015 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_SYSTEM_HPP_INCLUDED_ +#define BOOST_WINAPI_SYSTEM_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// nonstandard extension used : nameless struct/union +#pragma warning(disable: 4201) +#endif + +#if !defined( BOOST_USE_WINDOWS_H ) +extern "C" { +struct _SYSTEM_INFO; + +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +BOOST_SYMBOL_IMPORT boost::winapi::VOID_ BOOST_WINAPI_WINAPI_CC +GetSystemInfo(::_SYSTEM_INFO* lpSystemInfo); +#endif + +#if BOOST_WINAPI_PARTITION_APP || BOOST_WINAPI_PARTITION_SYSTEM +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WINXP +BOOST_SYMBOL_IMPORT boost::winapi::VOID_ BOOST_WINAPI_WINAPI_CC +GetNativeSystemInfo(::_SYSTEM_INFO* lpSystemInfo); +#endif +#endif +} +#endif + +namespace boost { +namespace winapi { + +typedef struct BOOST_MAY_ALIAS _SYSTEM_INFO { + BOOST_WINAPI_DETAIL_EXTENSION union { + DWORD_ dwOemId; + BOOST_WINAPI_DETAIL_EXTENSION struct { + WORD_ wProcessorArchitecture; + WORD_ wReserved; + }; + }; + DWORD_ dwPageSize; + LPVOID_ lpMinimumApplicationAddress; + LPVOID_ lpMaximumApplicationAddress; + DWORD_PTR_ dwActiveProcessorMask; + DWORD_ dwNumberOfProcessors; + DWORD_ dwProcessorType; + DWORD_ dwAllocationGranularity; + WORD_ wProcessorLevel; + WORD_ wProcessorRevision; +} SYSTEM_INFO_, *LPSYSTEM_INFO_; + +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +BOOST_FORCEINLINE VOID_ GetSystemInfo(LPSYSTEM_INFO_ lpSystemInfo) +{ + ::GetSystemInfo(reinterpret_cast< ::_SYSTEM_INFO* >(lpSystemInfo)); +} +#endif + +#if BOOST_WINAPI_PARTITION_APP || BOOST_WINAPI_PARTITION_SYSTEM +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WINXP +BOOST_FORCEINLINE VOID_ GetNativeSystemInfo(LPSYSTEM_INFO_ lpSystemInfo) +{ + ::GetNativeSystemInfo(reinterpret_cast< ::_SYSTEM_INFO* >(lpSystemInfo)); +} +#endif +#endif +} +} + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_WINAPI_SYSTEM_HPP_INCLUDED_ diff --git a/boost/winapi/thread.hpp b/boost/winapi/thread.hpp new file mode 100644 index 0000000..c326aab --- /dev/null +++ b/boost/winapi/thread.hpp @@ -0,0 +1,42 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright 2015 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_THREAD_HPP_INCLUDED_ +#define BOOST_WINAPI_THREAD_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if BOOST_WINAPI_PARTITION_APP_SYSTEM + +#if !defined( BOOST_USE_WINDOWS_H ) +extern "C" { +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC +SleepEx( + boost::winapi::DWORD_ dwMilliseconds, + boost::winapi::BOOL_ bAlertable); +BOOST_SYMBOL_IMPORT boost::winapi::VOID_ BOOST_WINAPI_WINAPI_CC Sleep(boost::winapi::DWORD_ dwMilliseconds); +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC SwitchToThread(BOOST_WINAPI_DETAIL_VOID); +} // extern "C" +#endif + +namespace boost { +namespace winapi { +using ::SleepEx; +using ::Sleep; +using ::SwitchToThread; +} +} + +#endif // BOOST_WINAPI_PARTITION_APP_SYSTEM +#endif // BOOST_WINAPI_THREAD_HPP_INCLUDED_ diff --git a/boost/winapi/thread_pool.hpp b/boost/winapi/thread_pool.hpp new file mode 100644 index 0000000..eebf298 --- /dev/null +++ b/boost/winapi/thread_pool.hpp @@ -0,0 +1,129 @@ +/* + * Copyright 2013 Andrey Semashev + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_THREAD_POOL_HPP_INCLUDED_ +#define BOOST_WINAPI_THREAD_POOL_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN2K + +#include + +#if !defined( BOOST_USE_WINDOWS_H ) +extern "C" { +#if BOOST_WINAPI_PARTITION_DESKTOP +typedef boost::winapi::VOID_ (BOOST_WINAPI_NTAPI_CC *WAITORTIMERCALLBACKFUNC) + (boost::winapi::PVOID_, boost::winapi::BOOLEAN_); +typedef WAITORTIMERCALLBACKFUNC WAITORTIMERCALLBACK; + +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +RegisterWaitForSingleObject( + boost::winapi::PHANDLE_ phNewWaitObject, + boost::winapi::HANDLE_ hObject, + WAITORTIMERCALLBACK Callback, + boost::winapi::PVOID_ Context, + boost::winapi::ULONG_ dwMilliseconds, + boost::winapi::ULONG_ dwFlags); +#endif +} // extern "C" +#endif + +// MinGW is buggy - it is missing these function declarations for Win2000 +#if !defined( BOOST_USE_WINDOWS_H ) || (defined(BOOST_WINAPI_IS_MINGW) && BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_WINXP) +extern "C" { +#if BOOST_WINAPI_PARTITION_DESKTOP +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +UnregisterWait(boost::winapi::HANDLE_ WaitHandle); +#endif + +#if BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM +BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ BOOST_WINAPI_WINAPI_CC +UnregisterWaitEx( + boost::winapi::HANDLE_ WaitHandle, + boost::winapi::HANDLE_ CompletionEvent); +#endif +} // extern "C" +#endif + +namespace boost { +namespace winapi { + +#if BOOST_WINAPI_PARTITION_DESKTOP +typedef ::WAITORTIMERCALLBACKFUNC WAITORTIMERCALLBACKFUNC_; +typedef ::WAITORTIMERCALLBACK WAITORTIMERCALLBACK_; + +using ::RegisterWaitForSingleObject; +using ::UnregisterWait; +#endif + +#if BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM +using ::UnregisterWaitEx; +#endif +#if defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEDEFAULT_ = WT_EXECUTEDEFAULT; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINIOTHREAD_ = WT_EXECUTEINIOTHREAD; +#if defined( BOOST_WINAPI_IS_MINGW ) +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINUITHREAD_ = 0x00000002; +#else +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINUITHREAD_ = WT_EXECUTEINUITHREAD; +#endif +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINWAITTHREAD_ = WT_EXECUTEINWAITTHREAD; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEONLYONCE_ = WT_EXECUTEONLYONCE; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINTIMERTHREAD_ = WT_EXECUTEINTIMERTHREAD; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTELONGFUNCTION_ = WT_EXECUTELONGFUNCTION; +#if defined( BOOST_WINAPI_IS_MINGW ) +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINPERSISTENTIOTHREAD_ = 0x00000040; +#else +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINPERSISTENTIOTHREAD_ = WT_EXECUTEINPERSISTENTIOTHREAD; +#endif +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINPERSISTENTTHREAD_ = WT_EXECUTEINPERSISTENTTHREAD; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_TRANSFER_IMPERSONATION_ = WT_TRANSFER_IMPERSONATION; + +#else // defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEDEFAULT_ = 0x00000000; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINIOTHREAD_ = 0x00000001; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINUITHREAD_ = 0x00000002; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINWAITTHREAD_ = 0x00000004; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEONLYONCE_ = 0x00000008; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINTIMERTHREAD_ = 0x00000020; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTELONGFUNCTION_ = 0x00000010; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINPERSISTENTIOTHREAD_ = 0x00000040; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_EXECUTEINPERSISTENTTHREAD_ = 0x00000080; +BOOST_CONSTEXPR_OR_CONST ULONG_ WT_TRANSFER_IMPERSONATION_ = 0x00000100; + +#endif // defined( BOOST_USE_WINDOWS_H ) + +BOOST_FORCEINLINE BOOST_CONSTEXPR ULONG_ wt_set_max_threadpool_threads(ULONG_ flags, ULONG_ limit) BOOST_NOEXCEPT +{ + // Note: We don't use WT_SET_MAX_THREADPOOL_THREADS here because the way it's defined + // the function no longer meets C++11 constexpr requirements. + return flags | (limit << 16); +} + +BOOST_CONSTEXPR_OR_CONST ULONG_ wt_execute_default = WT_EXECUTEDEFAULT_; +BOOST_CONSTEXPR_OR_CONST ULONG_ wt_execute_in_io_thread = WT_EXECUTEINIOTHREAD_; +BOOST_CONSTEXPR_OR_CONST ULONG_ wt_execute_in_ui_thread = WT_EXECUTEINUITHREAD_; +BOOST_CONSTEXPR_OR_CONST ULONG_ wt_execute_in_wait_thread = WT_EXECUTEINWAITTHREAD_; +BOOST_CONSTEXPR_OR_CONST ULONG_ wt_execute_only_once = WT_EXECUTEONLYONCE_; +BOOST_CONSTEXPR_OR_CONST ULONG_ wt_execute_in_timer_thread = WT_EXECUTEINTIMERTHREAD_; +BOOST_CONSTEXPR_OR_CONST ULONG_ wt_execute_long_function = WT_EXECUTELONGFUNCTION_; +BOOST_CONSTEXPR_OR_CONST ULONG_ wt_execute_in_persistent_io_thread = WT_EXECUTEINPERSISTENTIOTHREAD_; +BOOST_CONSTEXPR_OR_CONST ULONG_ wt_execute_in_persistent_thread = WT_EXECUTEINPERSISTENTTHREAD_; +BOOST_CONSTEXPR_OR_CONST ULONG_ wt_transfer_impersonation = WT_TRANSFER_IMPERSONATION_; + +} +} + +#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN2K +#endif // BOOST_WINAPI_THREAD_POOL_HPP_INCLUDED_ diff --git a/boost/winapi/wait.hpp b/boost/winapi/wait.hpp new file mode 100644 index 0000000..15b4094 --- /dev/null +++ b/boost/winapi/wait.hpp @@ -0,0 +1,113 @@ +/* + * Copyright 2010 Vicente J. Botet Escriba + * Copyright 2015 Andrey Semashev + * Copyright 2017 James E. King, III + * + * Distributed under the Boost Software License, Version 1.0. + * See http://www.boost.org/LICENSE_1_0.txt + */ + +#ifndef BOOST_WINAPI_WAIT_HPP_INCLUDED_ +#define BOOST_WINAPI_WAIT_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if !defined( BOOST_USE_WINDOWS_H ) +extern "C" { + +#if BOOST_WINAPI_PARTITION_APP || BOOST_WINAPI_PARTITION_SYSTEM +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC +WaitForSingleObjectEx( + boost::winapi::HANDLE_ hHandle, + boost::winapi::DWORD_ dwMilliseconds, + boost::winapi::BOOL_ bAlertable); +#endif + +#if BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_NT4 +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC +SignalObjectAndWait( + boost::winapi::HANDLE_ hObjectToSignal, + boost::winapi::HANDLE_ hObjectToWaitOn, + boost::winapi::DWORD_ dwMilliseconds, + boost::winapi::BOOL_ bAlertable); +#endif +#endif + +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC +WaitForSingleObject( + boost::winapi::HANDLE_ hHandle, + boost::winapi::DWORD_ dwMilliseconds); + +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC +WaitForMultipleObjects( + boost::winapi::DWORD_ nCount, + boost::winapi::HANDLE_ const* lpHandles, + boost::winapi::BOOL_ bWaitAll, + boost::winapi::DWORD_ dwMilliseconds); + +BOOST_SYMBOL_IMPORT boost::winapi::DWORD_ BOOST_WINAPI_WINAPI_CC +WaitForMultipleObjectsEx( + boost::winapi::DWORD_ nCount, + boost::winapi::HANDLE_ const* lpHandles, + boost::winapi::BOOL_ bWaitAll, + boost::winapi::DWORD_ dwMilliseconds, + boost::winapi::BOOL_ bAlertable); +#endif // BOOST_WINAPI_PARTITION_APP_SYSTEM + +} // extern "C" +#endif + +namespace boost { +namespace winapi { + +#if BOOST_WINAPI_PARTITION_APP || BOOST_WINAPI_PARTITION_SYSTEM +using ::WaitForSingleObjectEx; +#endif +#if BOOST_WINAPI_PARTITION_DESKTOP || BOOST_WINAPI_PARTITION_SYSTEM +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_NT4 +using ::SignalObjectAndWait; +#endif +#endif + +#if BOOST_WINAPI_PARTITION_APP_SYSTEM +using ::WaitForMultipleObjects; +using ::WaitForMultipleObjectsEx; +using ::WaitForSingleObject; +#endif + +#if defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ INFINITE_ = INFINITE; +BOOST_CONSTEXPR_OR_CONST DWORD_ WAIT_ABANDONED_ = WAIT_ABANDONED; +BOOST_CONSTEXPR_OR_CONST DWORD_ WAIT_OBJECT_0_ = WAIT_OBJECT_0; +BOOST_CONSTEXPR_OR_CONST DWORD_ WAIT_TIMEOUT_ = WAIT_TIMEOUT; +BOOST_CONSTEXPR_OR_CONST DWORD_ WAIT_FAILED_ = WAIT_FAILED; + +#else // defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ INFINITE_ = (DWORD_)0xFFFFFFFF; +BOOST_CONSTEXPR_OR_CONST DWORD_ WAIT_ABANDONED_ = 0x00000080L; +BOOST_CONSTEXPR_OR_CONST DWORD_ WAIT_OBJECT_0_ = 0x00000000L; +BOOST_CONSTEXPR_OR_CONST DWORD_ WAIT_TIMEOUT_ = 0x00000102L; +BOOST_CONSTEXPR_OR_CONST DWORD_ WAIT_FAILED_ = (DWORD_)0xFFFFFFFF; + +#endif // defined( BOOST_USE_WINDOWS_H ) + +BOOST_CONSTEXPR_OR_CONST DWORD_ infinite = INFINITE_; +BOOST_CONSTEXPR_OR_CONST DWORD_ wait_abandoned = WAIT_ABANDONED_; +BOOST_CONSTEXPR_OR_CONST DWORD_ wait_object_0 = WAIT_OBJECT_0_; +BOOST_CONSTEXPR_OR_CONST DWORD_ wait_timeout = WAIT_TIMEOUT_; +BOOST_CONSTEXPR_OR_CONST DWORD_ wait_failed = WAIT_FAILED_; + +BOOST_CONSTEXPR_OR_CONST DWORD_ max_non_infinite_wait = (DWORD_)0xFFFFFFFE; + +} +} + +#endif // BOOST_WINAPI_WAIT_HPP_INCLUDED_ diff --git a/build.cmd b/build.cmd index 4e9b3f8..b07beda 100644 --- a/build.cmd +++ b/build.cmd @@ -4,6 +4,7 @@ bcp ^ boost/container/flat_set.hpp ^ boost/container/small_vector.hpp ^ boost/container/static_vector.hpp ^ + boost/context/ ^ boost/crc.hpp ^ boost/date_time/posix_time/posix_time.hpp ^ boost/functional/hash.hpp ^ diff --git a/libs/atomic/build/Jamfile.v2 b/libs/atomic/build/Jamfile.v2 new file mode 100644 index 0000000..433ebc8 --- /dev/null +++ b/libs/atomic/build/Jamfile.v2 @@ -0,0 +1,38 @@ +# Boost.Atomic Library Jamfile +# +# Copyright Helge Bahmann 2011. +# Copyright Andrey Semashev 2018. +# +# 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) + +import common ; + +project boost/atomic + : requirements + multi + shared:BOOST_ATOMIC_DYN_LINK=1 + static:BOOST_ATOMIC_STATIC_LINK=1 + BOOST_ATOMIC_SOURCE + windows:BOOST_USE_WINDOWS_H + windows:_WIN32_WINNT=0x0500 + gcc,windows:"-lkernel32" + : usage-requirements + shared:BOOST_ATOMIC_DYN_LINK=1 + static:BOOST_ATOMIC_STATIC_LINK=1 + : source-location ../src + ; + +alias atomic_sources + : lockpool.cpp + ; + +explicit atomic_sources ; + + +lib boost_atomic + : atomic_sources + ; + +boost-install boost_atomic ; diff --git a/libs/atomic/src/lockpool.cpp b/libs/atomic/src/lockpool.cpp new file mode 100644 index 0000000..a1292fa --- /dev/null +++ b/libs/atomic/src/lockpool.cpp @@ -0,0 +1,167 @@ +/* + * 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) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013-2014 Andrey Semashev + */ +/*! + * \file lockpool.cpp + * + * This file contains implementation of the lockpool used to emulate atomic ops. + */ + +#include +#include +#include +#include +#include + +#if BOOST_ATOMIC_FLAG_LOCK_FREE == 2 +#include +#elif !defined(BOOST_HAS_PTHREADS) +#error Boost.Atomic: Unsupported target platform, POSIX threads are required when native atomic operations are not available +#else +#include +#define BOOST_ATOMIC_USE_PTHREAD +#endif + +#include +#include + +#if defined(BOOST_MSVC) +#pragma warning(push) +// 'struct_name' : structure was padded due to __declspec(align()) +#pragma warning(disable: 4324) +#endif + +namespace boost { +namespace atomics { +namespace detail { + +namespace { + +// Cache line size, in bytes +// NOTE: This constant is made as a macro because some compilers (gcc 4.4 for one) don't allow enums or namespace scope constants in alignment attributes +#if defined(__s390__) || defined(__s390x__) +#define BOOST_ATOMIC_CACHE_LINE_SIZE 256 +#elif defined(powerpc) || defined(__powerpc__) || defined(__ppc__) +#define BOOST_ATOMIC_CACHE_LINE_SIZE 128 +#else +#define BOOST_ATOMIC_CACHE_LINE_SIZE 64 +#endif + +#if defined(BOOST_ATOMIC_USE_PTHREAD) +typedef pthread_mutex_t lock_type; +#else +typedef atomics::detail::operations< 1u, false > lock_operations; +typedef lock_operations::storage_type lock_type; +#endif + +enum +{ + padding_size = (sizeof(lock_type) <= BOOST_ATOMIC_CACHE_LINE_SIZE ? + (BOOST_ATOMIC_CACHE_LINE_SIZE - sizeof(lock_type)) : + (BOOST_ATOMIC_CACHE_LINE_SIZE - sizeof(lock_type) % BOOST_ATOMIC_CACHE_LINE_SIZE)) +}; + +template< unsigned int PaddingSize > +struct BOOST_ALIGNMENT(BOOST_ATOMIC_CACHE_LINE_SIZE) padded_lock +{ + lock_type lock; + // The additional padding is needed to avoid false sharing between locks + char padding[PaddingSize]; +}; + +template< > +struct BOOST_ALIGNMENT(BOOST_ATOMIC_CACHE_LINE_SIZE) padded_lock< 0u > +{ + lock_type lock; +}; + +typedef padded_lock< padding_size > padded_lock_t; + +static padded_lock_t g_lock_pool[41] +#if defined(BOOST_ATOMIC_USE_PTHREAD) += +{ + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, { PTHREAD_MUTEX_INITIALIZER }, + { PTHREAD_MUTEX_INITIALIZER } +} +#endif +; + +} // namespace + + +#if !defined(BOOST_ATOMIC_USE_PTHREAD) + +// NOTE: This function must NOT be inline. Otherwise MSVC 9 will sometimes generate broken code for modulus operation which result in crashes. +BOOST_ATOMIC_DECL lockpool::scoped_lock::scoped_lock(const volatile void* addr) BOOST_NOEXCEPT : + m_lock(&g_lock_pool[reinterpret_cast< std::size_t >(addr) % (sizeof(g_lock_pool) / sizeof(*g_lock_pool))].lock) +{ + while (lock_operations::test_and_set(*static_cast< lock_type* >(m_lock), memory_order_acquire)) + { + do + { + atomics::detail::pause(); + } + while (!!lock_operations::load(*static_cast< lock_type* >(m_lock), memory_order_relaxed)); + } +} + +BOOST_ATOMIC_DECL lockpool::scoped_lock::~scoped_lock() BOOST_NOEXCEPT +{ + lock_operations::clear(*static_cast< lock_type* >(m_lock), memory_order_release); +} + +BOOST_ATOMIC_DECL void signal_fence() BOOST_NOEXCEPT; + +#else // !defined(BOOST_ATOMIC_USE_PTHREAD) + +BOOST_ATOMIC_DECL lockpool::scoped_lock::scoped_lock(const volatile void* addr) BOOST_NOEXCEPT : + m_lock(&g_lock_pool[reinterpret_cast< std::size_t >(addr) % (sizeof(g_lock_pool) / sizeof(*g_lock_pool))].lock) +{ + BOOST_VERIFY(pthread_mutex_lock(static_cast< pthread_mutex_t* >(m_lock)) == 0); +} + +BOOST_ATOMIC_DECL lockpool::scoped_lock::~scoped_lock() BOOST_NOEXCEPT +{ + BOOST_VERIFY(pthread_mutex_unlock(static_cast< pthread_mutex_t* >(m_lock)) == 0); +} + +#endif // !defined(BOOST_ATOMIC_USE_PTHREAD) + +BOOST_ATOMIC_DECL void lockpool::thread_fence() BOOST_NOEXCEPT +{ +#if BOOST_ATOMIC_THREAD_FENCE > 0 + atomics::detail::thread_fence(memory_order_seq_cst); +#else + // Emulate full fence by locking/unlocking a mutex + scoped_lock lock(0); +#endif +} + +BOOST_ATOMIC_DECL void lockpool::signal_fence() BOOST_NOEXCEPT +{ + // This function is intentionally non-inline, even if empty. This forces the compiler to treat its call as a compiler barrier. +#if BOOST_ATOMIC_SIGNAL_FENCE > 0 + atomics::detail::signal_fence(memory_order_seq_cst); +#endif +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif diff --git a/libs/chrono/build/Jamfile.v2 b/libs/chrono/build/Jamfile.v2 new file mode 100644 index 0000000..1d887e2 --- /dev/null +++ b/libs/chrono/build/Jamfile.v2 @@ -0,0 +1,113 @@ +# Boost Chrono Library Build Jamfile + +# Copyright Beman Dawes 2002, 2006, 2008 +# Copyright 2009-2012 Vicente J.Botet Escriba. + +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or www.boost.org/LICENSE_1_0.txt) + +# See library home page at http://www.boost.org/libs/chrono + +project boost/chrono + : source-location ../src + : requirements + freebsd:"-lrt" + linux:"-lrt -lpthread" + pgi:"-lrt" + #single:BOOST_CHRONO_THREAD_DISABLED + #BOOST_ERROR_CODE_HEADER_ONLY + #BOOST_COMMON_TYPE_USES_STATIC_ASSERT + #BOOST_RATIO_USES_STATIC_ASSERT + #BOOST_CHRONO_USES_STATIC_ASSERT + #BOOST_COMMON_TYPE_USES_MPL_ASSERT + #BOOST_RATIO_USES_MPL_ASSERT + #BOOST_CHRONO_USES_MPL_ASSERT + #BOOST_COMMON_TYPE_USES_ARRAY_ASSERT + #BOOST_RATIO_USES_ARRAY_ASSERT + #BOOST_CHRONO_USES_ARRAY_ASSERT + sun:__typeof__=__typeof__ + #gcc-3.4.4:--enable-auto-import + #gcc-4.3.4:--enable-auto-import + #gcc-mingw-4.4.0:--enable-auto-import + #gcc-mingw-4.5.0:--enable-auto-import + all + gcc:-Wextra + #gcc:-pedantic + clang:on + gcc:-Wno-long-long + #gcc:-Wno-variadic-macros + gcc-4:-Wno-variadic-macros + gcc-5:-Wno-variadic-macros + darwin:-Wextra + darwin:-pedantic + darwin:-Wno-long-long + #darwin:-Wno-variadic-macros + darwin-4:-Wno-variadic-macros + darwin-5:-Wno-variadic-macros + #pathscale:-Wextra + pathscale:-Wno-long-long + pathscale:-pedantic + clang:-Wextra + clang:-pedantic + clang:-Wno-long-long + clang:-Wno-variadic-macros + gcc-4.4.0,windows:-fdiagnostics-show-option + gcc-4.5.0,windows:-fdiagnostics-show-option + gcc-4.6.0,windows:-fdiagnostics-show-option + gcc-4.6.3,windows:-fdiagnostics-show-option + gcc-4.7.0,windows:-fdiagnostics-show-option + gcc-4.8.0,windows:-fdiagnostics-show-option + msvc:/wd4512 + +# Note: Some of the remarks from the Intel compiler are disabled +# remark #193: zero used for undefined preprocessing identifier "XXX" +# remark #304: access control not specified ("public" by default) +# remark #383: value copied to temporary, reference to temporary used +# remark #444: destructor for base class "XXX" (declared at line YYY") is not virtual +# remark #593: variable "XXX" was set but never used +# remark #981: operands are evaluated in unspecified order +# remark #1418: external function definition with no prior declaration +# remark #2415: variable "XXX" of static storage duration was declared but never referenced + + intel:-wd193,304,383,444 + intel:-wd593,981 + intel:-wd1418 + intel:-wd2415 + + + + : usage-requirements # pass these requirement to dependents (i.e. users) + single:BOOST_CHRONO_THREAD_DISABLED + #BOOST_ERROR_CODE_HEADER_ONLY + #BOOST_COMMON_TYPE_USES_STATIC_ASSERT + #BOOST_RATIO_USES_STATIC_ASSERT + #BOOST_CHRONO_USES_STATIC_ASSERT + #BOOST_COMMON_TYPE_USES_MPL_ASSERT + #BOOST_RATIO_USES_MPL_ASSERT + #BOOST_CHRONO_USES_MPL_ASSERT + #BOOST_COMMON_TYPE_USES_ARRAY_ASSERT + #BOOST_RATIO_USES_ARRAY_ASSERT + #BOOST_CHRONO_USES_ARRAY_ASSERT + #vacpp:BOOST_COMMON_TYPE_DONT_USE_TYPEOF + vacpp:BOOST_TYPEOF_EMULATION + sun:__typeof__=__typeof__ + + shared:BOOST_CHRONO_DYN_LINK=1 + static:BOOST_CHRONO_STATIC_LINK=1 + gcc-3.4.4:--enable-auto-import + gcc-4.3.4:--enable-auto-import + gcc-4.4.0,windows:--enable-auto-import + gcc-4.5.0,windows:--enable-auto-import + ; + +SOURCES = chrono thread_clock process_cpu_clocks ; + + +lib boost_chrono + : $(SOURCES).cpp + : + shared:BOOST_ALL_DYN_LINK=1 # tell source we're building dll's + static:BOOST_All_STATIC_LINK=1 # tell source we're building static lib's + ; + +boost-install boost_chrono ; diff --git a/libs/chrono/src/chrono.cpp b/libs/chrono/src/chrono.cpp new file mode 100644 index 0000000..f500a79 --- /dev/null +++ b/libs/chrono/src/chrono.cpp @@ -0,0 +1,15 @@ +// chrono.cpp --------------------------------------------------------------// + +// Copyright Beman Dawes 2008 +// Copyright Vicente J. Botet Escriba 2009-2010 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// define BOOST_CHRONO_SOURCE so that knows +// the library is being built (possibly exporting rather than importing code) + +#define BOOST_CHRONO_SOURCE + +#include + diff --git a/libs/chrono/src/process_cpu_clocks.cpp b/libs/chrono/src/process_cpu_clocks.cpp new file mode 100644 index 0000000..c21cab3 --- /dev/null +++ b/libs/chrono/src/process_cpu_clocks.cpp @@ -0,0 +1,18 @@ +// boost process_cpu_clocks.cpp -----------------------------------------------------------// + +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// + +// define BOOST_CHRONO_SOURCE so that knows +// the library is being built (possibly exporting rather than importing code) + +#define BOOST_CHRONO_SOURCE + +#include + diff --git a/libs/chrono/src/thread_clock.cpp b/libs/chrono/src/thread_clock.cpp new file mode 100644 index 0000000..c21b114 --- /dev/null +++ b/libs/chrono/src/thread_clock.cpp @@ -0,0 +1,19 @@ +// boost thread_clock.cpp -----------------------------------------------------------// + +// Copyright 2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// + + +// define BOOST_CHRONO_SOURCE so that knows +// the library is being built (possibly exporting rather than importing code) + +#define BOOST_CHRONO_SOURCE + +#include + diff --git a/libs/config/test/config_info.cpp b/libs/config/test/config_info.cpp new file mode 100644 index 0000000..d59c613 --- /dev/null +++ b/libs/config/test/config_info.cpp @@ -0,0 +1,1349 @@ +// Boost config.hpp configuration test program file -----------------------// + +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Jens Maurer 2001. +// (C) Copyright Peter Dimov 2001. +// (C) Copyright Darin Adler 2001. +// (C) Copyright Beman Dawes 2002. +// Use, modification and distribution are subject to 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/libs/config for most recent version. +// +// Revision $Id$ +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_UNISTD_H +#include +#endif + +#if defined(__MINGW32__) +# include <_mingw.h> +#endif + +static unsigned int indent = 4; +static unsigned int width = 40; + +using std::cout; +using std::istream; + +void print_macro(const char* name, const char* value) +{ + // if name == value+1 then then macro is not defined, + // in which case we don't print anything: + if(0 != strcmp(name, value+1)) + { + for(unsigned i = 0; i < indent; ++i) std::cout.put(' '); + std::cout << std::setw(width); + cout.setf(istream::left, istream::adjustfield); + std::cout << name; + if(value[1]) + { + // macro has a value: + std::cout << value << "\n"; + } + else + { + // macro is defined but has no value: + std::cout << " [no value]\n"; + } + } +} + +#define PRINT_MACRO(X) print_macro(#X, BOOST_STRINGIZE(=X)) + +template +void print_expression(const char* expression, T val) +{ + for(unsigned i = 0; i < indent; ++i) std::cout.put(' '); + std::cout << std::setw(width); + std::cout.setf(istream::left, istream::adjustfield); + std::cout << expression << "=" << val << std::endl; +} + +#define PRINT_EXPRESSION(E) print_expression(#E, E); + +template +void print_byte_order(const char* what, T /* t */ ) +{ + T val = 0; + unsigned i; + for(i = 1; i < sizeof(T); ++i) + { + val |= (CHAR_BIT * static_cast(i)) << (CHAR_BIT * static_cast(i)); + } + const char* p = reinterpret_cast(&val); + + for(i = 0; i < indent; ++i) std::cout.put(' '); + std::cout << std::setw(width); + std::cout.setf(istream::left, istream::adjustfield); + std::cout << what << "="; + for(i = 0; i < sizeof(T); ++i) + { + std::cout << (int)p[i] << " "; + } + std::cout << std::endl; +} + +#define PRINT_ORDER(T) print_byte_order(BOOST_STRINGIZE(byte order for type T), T()) + +template +void print_sign(const char* what, T t) +{ + t = static_cast(-1); // cast suppresses warnings + for(unsigned i = 0; i < indent; ++i) std::cout.put(' '); + std::cout << "Type " << what << " is " << ((t > 0) ? "unsigned" : "signed") << std::endl; +} + +#define PRINT_SIGN(T) print_sign(#T, T()) + + +void print_compiler_macros() +{ + std::cout << BOOST_COMPILER << "\n"; + // Borland options: + PRINT_MACRO(__BORLANDC__); + PRINT_MACRO(__CDECL__); + PRINT_MACRO(_CHAR_UNSIGNED); + PRINT_MACRO(__CODEGUARD__); + PRINT_MACRO(__CONSOLE__); + PRINT_MACRO(_CPPUNWIND); + PRINT_MACRO(__cplusplus); + PRINT_MACRO(__FLAT__); + PRINT_MACRO(__FUNC__); + PRINT_MACRO(_M_IX86); + PRINT_MACRO(__MSDOS__); + PRINT_MACRO(__MT__ ); + PRINT_MACRO(__PASCAL__); + PRINT_MACRO(__STDC__); + PRINT_MACRO(__TLS__); + PRINT_MACRO(_WCHAR_T); + PRINT_MACRO(_Windows); + PRINT_MACRO(__WIN32__); + PRINT_MACRO(_WIN32); + PRINT_MACRO(_WIN64); + PRINT_MACRO(_WIN32_WCE); + PRINT_MACRO(WIN32); + PRINT_MACRO(_RTLDLL); + PRINT_MACRO(__DEBUG); + +// Internal MSVC 7 error workaround (Peter Dimov) + +#ifndef _NATIVE_WCHAR_T_DEFINED + PRINT_MACRO(_WCHAR_T_DEFINED); +#endif + // MSVC macros: + PRINT_MACRO(_ALIGNED_NEW_SUPPORTED); + PRINT_MACRO(__ATOM__); + PRINT_MACRO(__AVX__); + PRINT_MACRO(__AVX2__); + PRINT_MACRO(_CHAR_UNSIGNED); + PRINT_MACRO(_CLR_VER); + PRINT_MACRO(_CONTROL_FLOW_GUARD); + PRINT_MACRO(__cplusplus_cli); + PRINT_MACRO(__cplusplus_winrt); + PRINT_MACRO(_CPPRTTI); + PRINT_MACRO(_CPPUNWIND); + PRINT_MACRO(_DLL); + PRINT_MACRO(_INLINE_VARIABLES_SUPPORTED); + PRINT_MACRO(_ISO_VOLATILE); + PRINT_MACRO(_M_AMD64); + PRINT_MACRO(_M_ARM); + PRINT_MACRO(_M_ARM_ARMV7VE); + PRINT_MACRO(_M_ARM_FP); + PRINT_MACRO(_M_ARM64); + PRINT_MACRO(_M_CEE); + PRINT_MACRO(_M_CEE_PURE); + PRINT_MACRO(_M_CEE_SAFE); + PRINT_MACRO(_M_FP_EXCEPT); + PRINT_MACRO(_M_FP_FAST); + PRINT_MACRO(_M_FP_PRECISE); + PRINT_MACRO(_M_FP_STRICT); + PRINT_MACRO(_M_IX86); + PRINT_MACRO(_M_IX86_FP); + PRINT_MACRO(_M_X64); + PRINT_MACRO(_M_ALPHA); + PRINT_MACRO(_M_MPPC); + PRINT_MACRO(_M_MRX000); + PRINT_MACRO(_M_PPC); + PRINT_MACRO(_MANAGED); + PRINT_MACRO(_MSC_BUILD); + PRINT_MACRO(_MFC_VER); + PRINT_MACRO(_MSC_EXTENSIONS); + PRINT_MACRO(_MSC_VER); + PRINT_MACRO(_MSC_FULL_VER); + PRINT_MACRO(_MSVC_LANG); + PRINT_MACRO(_MSVC_WARNING_LEVEL); + PRINT_MACRO(__MSVC_RUNTIME_CHECKS); + PRINT_MACRO(_MT); + PRINT_MACRO(_NATIVE_WCHAR_T_DEFINED); + PRINT_MACRO(_NOEXCEPT_TYPES_SUPPORTED); + PRINT_MACRO(_OPENMP); + PRINT_MACRO(_PREFAST_); + // GNUC options: + PRINT_MACRO(__GNUC__); + PRINT_MACRO(__GNUC_MINOR__); + PRINT_MACRO(__GNUC_PATCHLEVEL__); + PRINT_MACRO(__STDC_VERSION__); + PRINT_MACRO(__GNUG__); + PRINT_MACRO(__STRICT_ANSI__); + PRINT_MACRO(__GXX_EXPERIMENTAL_CXX0X__); + PRINT_MACRO(__VERSION__); + PRINT_MACRO(__OPTIMIZE__); + PRINT_MACRO(__CHAR_UNSIGNED__); + PRINT_MACRO(__REGISTER_PREFIX__); + PRINT_MACRO(__USER_LABEL_PREFIX__); + PRINT_MACRO(__GNUPRO__); + PRINT_MACRO(__EXCEPTIONS); + PRINT_MACRO(__FreeBSD__); + PRINT_MACRO(__FreeBSD_cc_version); + PRINT_MACRO(__ELF__); + PRINT_MACRO(__GNUPRO__); + PRINT_MACRO(unix); + PRINT_MACRO(bsd); + PRINT_MACRO(vax); + PRINT_MACRO(mc68000); + PRINT_MACRO(m68k); + PRINT_MACRO(M68020); + PRINT_MACRO(_AM29K); + PRINT_MACRO(ns32000); + PRINT_MACRO(sun); + PRINT_MACRO(pyr); + PRINT_MACRO(sequent); + PRINT_MACRO(__i386__); + PRINT_MACRO(__sparc); + PRINT_MACRO(__sparc__); + PRINT_MACRO(__powerpc__); + PRINT_MACRO(__hppa); + PRINT_MACRO(__CYGWIN__); + PRINT_MACRO(__MINGW32__); + PRINT_MACRO(__GXX_RTTI); + PRINT_MACRO(__alpha__); + PRINT_MACRO(__amd64__); + PRINT_MACRO(__arm__); + PRINT_MACRO(__aarch64__); + PRINT_MACRO(__bfin); + PRINT_MACRO(__convex__); + PRINT_MACRO(__epiphany__); + PRINT_MACRO(__hppa__); + PRINT_MACRO(__ia64__); + PRINT_MACRO(__IA64); + PRINT_MACRO(__IA64__); + PRINT_MACRO(__m68k__); + PRINT_MACRO(__mips__); + PRINT_MACRO(__powerpc); + PRINT_MACRO(__powerpc__); + PRINT_MACRO(__powerpc64__); + PRINT_MACRO(__POWERPC__); + PRINT_MACRO(__ppc__); + PRINT_MACRO(__ppc64__); + PRINT_MACRO(__PPC__); + PRINT_MACRO(__PPC64__); + PRINT_MACRO(_ARCH_PPC); + PRINT_MACRO(_ARCH_PPC64); + PRINT_MACRO(__sh__); + PRINT_MACRO(__370__); + PRINT_MACRO(__THW_370__); + // HP aCC: + PRINT_MACRO(__HP_aCC); + PRINT_MACRO(_HPACC_); + PRINT_MACRO(__LP64__); + PRINT_MACRO(__RISC2_0__); + PRINT_MACRO(__STDCPP__); + PRINT_MACRO(__hppa); + PRINT_MACRO(__hpux); + PRINT_MACRO(__hp9000s800); + PRINT_MACRO(__hp9000s700); + PRINT_MACRO(_PA_RISC1_1); + PRINT_MACRO(__HPUX_SOURCE); + PRINT_MACRO(_INCLUDE__STDC_A1_SOURCE); + // SGI IRIX: + PRINT_MACRO(__sgi); + PRINT_MACRO(_COMPILER_VERSION); + // Sunpro: + PRINT_MACRO(__SUNPRO_CC); + PRINT_MACRO(__SUNPRO_CC_COMPAT); + PRINT_MACRO(__BUILTIN_VA_ARG_INCR); + PRINT_MACRO(__sun); + PRINT_MACRO(__SVR4); + PRINT_MACRO(__unix); + PRINT_MACRO(__sparcv9); + PRINT_MACRO(__i386); + PRINT_MACRO(i386); + // Metrowerks + PRINT_MACRO(__MWERKS__); + PRINT_MACRO(__MSL__); + PRINT_MACRO(__MSL_CPP__); + PRINT_MACRO(__A5__); + PRINT_MACRO(__embedded_cplusplus); + PRINT_MACRO(__fourbyteints__); + PRINT_MACRO(__IEEEdoubles__); + PRINT_MACRO(__MC68K__); + PRINT_MACRO(__MC68020__); + PRINT_MACRO(__MC68881__); + PRINT_MACRO(__MIPS__); + PRINT_MACRO(__MIPS_ISA2__); + PRINT_MACRO(__MIPS_ISA3__); + PRINT_MACRO(__MIPS_ISA4__); + PRINT_MACRO(__MWBROWSER__); + PRINT_MACRO(__profile__); + PRINT_MACRO(__powerc); + PRINT_MACRO(_powerc); + PRINT_MACRO(__POWERPC__); + PRINT_MACRO(macintosh); + PRINT_MACRO(__MACH__); + PRINT_MACRO(__APPLE__); + PRINT_MACRO(__APPLE_CC__); + // MPW (MrCpp and SCpp) + PRINT_MACRO(__MRC__); + PRINT_MACRO(__SC__); + PRINT_MACRO(__FPCE__); + PRINT_MACRO(__FPCE_IEEE__); + PRINT_MACRO(MPW_CPLUS); + PRINT_MACRO(MPW_C); + PRINT_MACRO(__MC601); + PRINT_MACRO(__POWERPC); + PRINT_MACRO(__useAppleExts__); + PRINT_MACRO(powerc); + PRINT_MACRO(MC68000); + PRINT_MACRO(THINK_PLUS); + PRINT_MACRO(mc68881); + PRINT_MACRO(__FAR_CODE__); + PRINT_MACRO(__FAR_DATA__); + PRINT_MACRO(__CFM68K__); + // EDG + PRINT_MACRO(__EDG__); + PRINT_MACRO(__EDG_VERSION__); + PRINT_MACRO(c_plusplus); // indication for strict mode + PRINT_MACRO(_BOOL); + PRINT_MACRO(_EXPLICIT); + PRINT_MACRO(__SIGNED_CHARS__); + PRINT_MACRO(_TYPENAME); + PRINT_MACRO(_WCHAR_T); + PRINT_MACRO(__ARRAY_OPERATORS); + PRINT_MACRO(__EDG_ABI_COMPATIBILITY_VERSION); + PRINT_MACRO(__EDG_IMPLICIT_USING_STD); + PRINT_MACRO(__EDG_RUNTIME_USES_NAMESPACES); + PRINT_MACRO(__BOOL_DEFINED); + PRINT_MACRO(__RTTI); + PRINT_MACRO(__PLACEMENT_DELETE); + PRINT_MACRO(__NO_LONG_LONG); + + // Intel options: + PRINT_MACRO(__INTEL__); + PRINT_MACRO(__ICC); + PRINT_MACRO(__ICL); + PRINT_MACRO(__ECC); + PRINT_MACRO(__INTEL_COMPILER); + PRINT_MACRO(__INITIAL_POINTER_SIZE); + PRINT_MACRO(_INTEGRAL_MAX_BITS); + PRINT_MACRO(__INTEL_COMPILER_BUILD_DATE); + PRINT_MACRO(__INTEL_MS_COMPAT_LEVEL); + PRINT_MACRO(__LONG_DOUBLE_SIZE__); + PRINT_MACRO(_M_X64); + PRINT_MACRO(_OPENMP); + PRINT_MACRO(_OPENMPT); + PRINT_MACRO(_PGO_INSTRUMENT); + PRINT_MACRO(__QMSPP_); + PRINT_MACRO(__INTEL_RTTI__); + PRINT_MACRO(__INTEL_CXX11_MODE__); + + // Cray options: + PRINT_MACRO(_CRAYC); + PRINT_MACRO(_RELEASE); + PRINT_MACRO(cray); + PRINT_MACRO(CRAY); + PRINT_MACRO(CRAY1); + PRINT_MACRO(_CRAY1); + PRINT_MACRO(_CRAYMPP); + PRINT_MACRO(_CRAYT3E); + PRINT_MACRO(_CRAYIEEE); + PRINT_MACRO(_ADDR32); + PRINT_MACRO(_ADDR64); + PRINT_MACRO(_LD64); + PRINT_MACRO(_FASTMD); + PRINT_MACRO(_MAXVL); + + // clang options: + PRINT_MACRO(__clang__); + PRINT_MACRO(__clang_major__); + PRINT_MACRO(__clang_minor__); + PRINT_MACRO(__clang_version__); + PRINT_MACRO(__clang_patchlevel__); + + // misc compilers not covered so far: + PRINT_MACRO(__USLC__); + PRINT_MACRO(__DECCXX); + PRINT_MACRO(__IBMCPP__); + PRINT_MACRO(_REENTRANT); + PRINT_MACRO(_PTHREADS); + PRINT_MACRO(__STDC_HOSTED__); + PRINT_MACRO(__COMO__); + PRINT_MACRO(__COMO_VERSION__); + PRINT_MACRO(__DM__); + PRINT_MACRO(__osf__); + PRINT_MACRO(__OSF__); + PRINT_MACRO(__QNXNTO__); + PRINT_MACRO(__QNX__); + PRINT_MACRO(_NTO_VERSION); + PRINT_MACRO(__OPEN64__); + PRINT_MACRO(__open64); + PRINT_MACRO(__NVCC__); + PRINT_MACRO(__CUDACC__); + PRINT_MACRO(__CUDACC_RDC__); + PRINT_MACRO(__CUDACC_VER_MAJOR__); + PRINT_MACRO(__CUDACC_VER_MINOR__); + PRINT_MACRO(__CUDACC_VER_BUILD__); + PRINT_MACRO(__CUDACC_VER__); + + // Android: + PRINT_MACRO(ANDROID); + PRINT_MACRO(__ANDROID__); +} + +void print_stdlib_macros() +{ + std::cout << BOOST_STDLIB << std::endl; + #ifdef _RWSTD_VER + // Rogue Wave 2.x config options: + PRINT_MACRO(__NO_EDG_EXCEPTION_CLASSES); + PRINT_MACRO(_RWSTD_ALLOCATOR); + PRINT_MACRO(_RWSTD_BAD_ALLOC_DEFINED); + PRINT_MACRO(_RWSTD_BAD_EXCEPTION_DEFINED); + PRINT_MACRO(_RWSTD_BOUNDS_CHECKING); + PRINT_MACRO(_RWSTD_COMPILE_INSTANTIATE); + PRINT_MACRO(_RWSTD_DEFAULT_PRECISION); + PRINT_MACRO(_RWSTD_EXCEPTION_DEFINED); + PRINT_MACRO(_RWSTD_EXCEPTION_HANDLER_IN_STD); + PRINT_MACRO(_RWSTD_EXCEPTION_PREDEFINED); + PRINT_MACRO(_RWSTD_FLT_ROUNDS_IS_CONSTANT); + PRINT_MACRO(_RWSTD_LOCALIZED_ERRORS); + PRINT_MACRO(_RWSTD_MESSAGE); + PRINT_MACRO(_RWSTD_MUTEXATTR_DEFAULT); + PRINT_MACRO(_RWSTD_NO_ANSI_SPRINTF); + PRINT_MACRO(_RWSTD_NO_ARG_MATCH); + PRINT_MACRO(_RWSTD_NO_BAD_CAST); + PRINT_MACRO(_RWSTD_NO_BASE_CLASS_MATCH); + PRINT_MACRO(_RWSTD_NO_BOOL); + PRINT_MACRO(_RWSTD_NO_BUILTIN_CTOR); + PRINT_MACRO(_RWSTD_NO_CATOPEN_CATGETS); + PRINT_MACRO(_RWSTD_NO_CLASS_PARTIAL_SPEC); + PRINT_MACRO(_RWSTD_NO_COMPLEX_DEFAULT_TEMPLATES); + PRINT_MACRO(_RWSTD_NO_COMPLICATED_EXCEPTIONS); + PRINT_MACRO(_RWSTD_NO_COMPLICATED_TYPEDEF); + PRINT_MACRO(_RWSTD_NO_CONST_INST); + PRINT_MACRO(_RWSTD_NO_CTOR_RETURN); + PRINT_MACRO(_RWSTD_NO_DEFAULT_FOR_TPARAM); + PRINT_MACRO(_RWSTD_NO_DEFAULT_TEMPLATE_ARGS); + PRINT_MACRO(_RWSTD_NO_DESTROY_BUILTIN); + PRINT_MACRO(_RWSTD_NO_DESTROY_NONBUILTIN); + PRINT_MACRO(_RWSTD_NO_EMBEDDED_TYPEDEF); + PRINT_MACRO(_RWSTD_NO_EX_SPEC); + PRINT_MACRO(_RWSTD_NO_EXCEPTIONS); + PRINT_MACRO(_RWSTD_NO_EXPLICIT); + PRINT_MACRO(_RWSTD_NO_EXPLICIT_ARG); + PRINT_MACRO(_RWSTD_NO_EXPLICIT_FUNC_INSTANTIATION); + PRINT_MACRO(_RWSTD_NO_EXPLICIT_INSTANTIATION); + PRINT_MACRO(_RWSTD_NO_EXTENSION); + PRINT_MACRO(_RWSTD_NO_FORWARD_SPECIALIZATIONS); + PRINT_MACRO(_RWSTD_NO_FPOS_T); + PRINT_MACRO(_RWSTD_NO_FRIEND_TEMPLATES); + PRINT_MACRO(_RWSTD_NO_FUNC_PARTIAL_SPEC); + PRINT_MACRO(_RWSTD_NO_GETTIMEOFDAY); + PRINT_MACRO(_RWSTD_NO_GLOBAL_TZ); + PRINT_MACRO(_RWSTD_NO_INHERITED_TYPEDEFS); + PRINT_MACRO(_RWSTD_NO_INIT_CONST_TEMPLATE_REF_ARG); + PRINT_MACRO(_RWSTD_NO_INT_TYPEDEF); + PRINT_MACRO(_RWSTD_NO_LDIV); + PRINT_MACRO(_RWSTD_NO_LEADING_UNDERSCORE); + PRINT_MACRO(_RWSTD_NO_LOCALE); + PRINT_MACRO(_RWSTD_NO_LONG_NAME); + PRINT_MACRO(_RWSTD_NO_LONGDOUBLE); + PRINT_MACRO(_RWSTD_NO_MBSTATE_T); + PRINT_MACRO(_RWSTD_NO_MEM_CLASS_TEMPLATES); + PRINT_MACRO(_RWSTD_NO_MEMBER_TEMPLATES); + PRINT_MACRO(_RWSTD_NO_MEMBER_TYPE_TPARAM); + PRINT_MACRO(_RWSTD_NO_MEMBER_WO_DEF_CTOR); + PRINT_MACRO(_RWSTD_NO_MEMMOVE); + PRINT_MACRO(_RWSTD_NO_MULTI_DIM_ARRAY); + PRINT_MACRO(_RWSTD_NO_MUTABLE); + PRINT_MACRO(_RWSTD_NO_NAME_INJECTION); + PRINT_MACRO(_RWSTD_NO_NAMESPACE); + PRINT_MACRO(_RWSTD_NO_NESTING_TEMPLATES); + PRINT_MACRO(_RWSTD_NO_NEW_BRACKETS); + PRINT_MACRO(_RWSTD_NO_NEW_DECL); + PRINT_MACRO(_RWSTD_NO_NEW_HEADER); + PRINT_MACRO(_RWSTD_NO_NEW_TEMPLATE_SYNTAX); + PRINT_MACRO(_RWSTD_NO_NONCLASS_ARROW_RETURN); + PRINT_MACRO(_RWSTD_NO_NONTYPE_ARGS); + PRINT_MACRO(_RWSTD_NO_ONLY_NEEDED_INSTANTIATION); + PRINT_MACRO(_RWSTD_NO_OVERLOAD_C_POW); + PRINT_MACRO(_RWSTD_NO_OVERLOAD_OF_TEMPLATE_FUNCTION); + PRINT_MACRO(_RWSTD_NO_OVERLOAD_WCHAR); + PRINT_MACRO(_RWSTD_NO_PART_SPEC_OVERLOAD); + PRINT_MACRO(_RWSTD_NO_RET_TEMPLATE); + PRINT_MACRO(_RWSTD_NO_SIMPLE_DEFAULT_TEMPLATES); + PRINT_MACRO(_RWSTD_NO_STATIC_CAST); + PRINT_MACRO(_RWSTD_NO_STATIC_DEF); + PRINT_MACRO(_RWSTD_NO_STATIC_DEF2); + PRINT_MACRO(_RWSTD_NO_STATIC_DEF3); + PRINT_MACRO(_RWSTD_NO_STATIC_MEM_DEF); + PRINT_MACRO(_RWSTD_NO_STI_SIMPLE); + PRINT_MACRO(_RWSTD_NO_STI_TEMPLATE); + PRINT_MACRO(_RWSTD_NO_STREAM_LONG_DOUBLE); + PRINT_MACRO(_RWSTD_NO_STRFTIME_CAPC); + PRINT_MACRO(_RWSTD_NO_STRICT_TEMPLATE_INSTANTIATE); + PRINT_MACRO(_RWSTD_NO_SWPRINTF); + PRINT_MACRO(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE); + PRINT_MACRO(_RWSTD_NO_TEMPLATE_TEMPLATE); + PRINT_MACRO(_RWSTD_NO_THREADS); + PRINT_MACRO(_RWSTD_NO_THROW_SPEC_ON_NEW); + PRINT_MACRO(_RWSTD_NO_THROW_WITH_SHARED); + PRINT_MACRO(_RWSTD_NO_TYPEDEF_INST); + PRINT_MACRO(_RWSTD_NO_TYPEDEF_OVERLOAD); + PRINT_MACRO(_RWSTD_NO_TYPENAME); + PRINT_MACRO(_RWSTD_NO_UNDEFINED_FRIEND); + PRINT_MACRO(_RWSTD_NO_UNINITIALIZED_STATIC_DEF); + PRINT_MACRO(_RWSTD_NO_WCHAR_H); + PRINT_MACRO(_RWSTD_NO_WCTYPE_H); + PRINT_MACRO(_RWSTD_NO_WIDE_CHAR); + PRINT_MACRO(_RWSTD_NO_WINT_TYPE); + PRINT_MACRO(_RWSTD_NO_WSTR); + PRINT_MACRO(_RWSTD_NOT_ALL_WSTR_CFUNCTIONS); + PRINT_MACRO(_RWSTD_POSIX_D10_THREADS); + PRINT_MACRO(_RWSTD_POSIX_THREADS); + PRINT_MACRO(_RWSTD_REQUIRES_IEEEFP); + PRINT_MACRO(_RWSTD_SOLARIS_THREADS); + PRINT_MACRO(_RWSTD_STRUCT_TM_TZ); + PRINT_MACRO(_RWSTD_WIDE_STRING_NULL_PROBLEM); + #elif defined(__STD_RWCOMPILER_H__) + // Rogue Wave 1.x std lib: + PRINT_MACRO(__NO_EDG_EXCEPTION_CLASSES); + PRINT_MACRO(RWSTD_ALLOCATOR); + PRINT_MACRO(RWSTD_BAD_ALLOC_DEFINED); + PRINT_MACRO(RWSTD_BAD_EXCEPTION_DEFINED); + PRINT_MACRO(RWSTD_BOUNDS_CHECKING); + PRINT_MACRO(RWSTD_COMPILE_INSTANTIATE); + PRINT_MACRO(RWSTD_DEFAULT_PRECISION); + PRINT_MACRO(RWSTD_EXCEPTION_DEFINED); + PRINT_MACRO(RWSTD_EXCEPTION_HANDLER_IN_STD); + PRINT_MACRO(RWSTD_EXCEPTION_PREDEFINED); + PRINT_MACRO(RWSTD_FLT_ROUNDS_IS_CONSTANT); + PRINT_MACRO(RWSTD_LOCALIZED_ERRORS); + PRINT_MACRO(RWSTD_MESSAGE); + PRINT_MACRO(RWSTD_MUTEXATTR_DEFAULT); + PRINT_MACRO(RWSTD_NO_ANSI_SPRINTF); + PRINT_MACRO(RWSTD_NO_ARG_MATCH); + PRINT_MACRO(RWSTD_NO_BAD_CAST); + PRINT_MACRO(RWSTD_NO_BASE_CLASS_MATCH); + PRINT_MACRO(RWSTD_NO_BOOL); + PRINT_MACRO(RWSTD_NO_BUILTIN_CTOR); + PRINT_MACRO(RWSTD_NO_CATOPEN_CATGETS); + PRINT_MACRO(RWSTD_NO_CLASS_PARTIAL_SPEC); + PRINT_MACRO(RWSTD_NO_COMPLEX_DEFAULT_TEMPLATES); + PRINT_MACRO(RWSTD_NO_COMPLICATED_EXCEPTIONS); + PRINT_MACRO(RWSTD_NO_COMPLICATED_TYPEDEF); + PRINT_MACRO(RWSTD_NO_CONST_INST); + PRINT_MACRO(RWSTD_NO_CTOR_RETURN); + PRINT_MACRO(RWSTD_NO_DEFAULT_FOR_TPARAM); + PRINT_MACRO(RWSTD_NO_DEFAULT_TEMPLATE_ARGS); + PRINT_MACRO(RWSTD_NO_DESTROY_BUILTIN); + PRINT_MACRO(RWSTD_NO_DESTROY_NONBUILTIN); + PRINT_MACRO(RWSTD_NO_EMBEDDED_TYPEDEF); + PRINT_MACRO(RWSTD_NO_EX_SPEC); + PRINT_MACRO(RWSTD_NO_EXCEPTIONS); + PRINT_MACRO(RWSTD_NO_EXPLICIT); + PRINT_MACRO(RWSTD_NO_EXPLICIT_ARG); + PRINT_MACRO(RWSTD_NO_EXPLICIT_FUNC_INSTANTIATION); + PRINT_MACRO(RWSTD_NO_EXPLICIT_INSTANTIATION); + PRINT_MACRO(RWSTD_NO_EXTENSION); + PRINT_MACRO(RWSTD_NO_FORWARD_SPECIALIZATIONS); + PRINT_MACRO(RWSTD_NO_FPOS_T); + PRINT_MACRO(RWSTD_NO_FRIEND_TEMPLATES); + PRINT_MACRO(RWSTD_NO_FUNC_PARTIAL_SPEC); + PRINT_MACRO(RWSTD_NO_GETTIMEOFDAY); + PRINT_MACRO(RWSTD_NO_GLOBAL_TZ); + PRINT_MACRO(RWSTD_NO_INHERITED_TYPEDEFS); + PRINT_MACRO(RWSTD_NO_INIT_CONST_TEMPLATE_REF_ARG); + PRINT_MACRO(RWSTD_NO_INT_TYPEDEF); + PRINT_MACRO(RWSTD_NO_LDIV); + PRINT_MACRO(RWSTD_NO_LEADING_UNDERSCORE); + PRINT_MACRO(RWSTD_NO_LOCALE); + PRINT_MACRO(RWSTD_NO_LONG_NAME); + PRINT_MACRO(RWSTD_NO_LONGDOUBLE); + PRINT_MACRO(RWSTD_NO_MBSTATE_T); + PRINT_MACRO(RWSTD_NO_MEM_CLASS_TEMPLATES); + PRINT_MACRO(RWSTD_NO_MEMBER_TEMPLATES); + PRINT_MACRO(RWSTD_NO_MEMBER_TYPE_TPARAM); + PRINT_MACRO(RWSTD_NO_MEMBER_WO_DEF_CTOR); + PRINT_MACRO(RWSTD_NO_MEMMOVE); + PRINT_MACRO(RWSTD_NO_MULTI_DIM_ARRAY); + PRINT_MACRO(RWSTD_NO_MUTABLE); + PRINT_MACRO(RWSTD_NO_NAME_INJECTION); + PRINT_MACRO(RWSTD_NO_NAMESPACE); + PRINT_MACRO(RWSTD_NO_NESTING_TEMPLATES); + PRINT_MACRO(RWSTD_NO_NEW_BRACKETS); + PRINT_MACRO(RWSTD_NO_NEW_DECL); + PRINT_MACRO(RWSTD_NO_NEW_HEADER); + PRINT_MACRO(RWSTD_NO_NEW_TEMPLATE_SYNTAX); + PRINT_MACRO(RWSTD_NO_NONCLASS_ARROW_RETURN); + PRINT_MACRO(RWSTD_NO_NONTYPE_ARGS); + PRINT_MACRO(RWSTD_NO_ONLY_NEEDED_INSTANTIATION); + PRINT_MACRO(RWSTD_NO_OVERLOAD_C_POW); + PRINT_MACRO(RWSTD_NO_OVERLOAD_OF_TEMPLATE_FUNCTION); + PRINT_MACRO(RWSTD_NO_OVERLOAD_WCHAR); + PRINT_MACRO(RWSTD_NO_PART_SPEC_OVERLOAD); + PRINT_MACRO(RWSTD_NO_RET_TEMPLATE); + PRINT_MACRO(RWSTD_NO_SIMPLE_DEFAULT_TEMPLATES); + PRINT_MACRO(RWSTD_NO_STATIC_CAST); + PRINT_MACRO(RWSTD_NO_STATIC_DEF); + PRINT_MACRO(RWSTD_NO_STATIC_DEF2); + PRINT_MACRO(RWSTD_NO_STATIC_DEF3); + PRINT_MACRO(RWSTD_NO_STATIC_MEM_DEF); + PRINT_MACRO(RWSTD_NO_STI_SIMPLE); + PRINT_MACRO(RWSTD_NO_STI_TEMPLATE); + PRINT_MACRO(RWSTD_NO_STREAM_LONG_DOUBLE); + PRINT_MACRO(RWSTD_NO_STRFTIME_CAPC); + PRINT_MACRO(RWSTD_NO_STRICT_TEMPLATE_INSTANTIATE); + PRINT_MACRO(RWSTD_NO_SWPRINTF); + PRINT_MACRO(RWSTD_NO_TEMPLATE_ON_RETURN_TYPE); + PRINT_MACRO(RWSTD_NO_TEMPLATE_TEMPLATE); + PRINT_MACRO(RWSTD_NO_THREADS); + PRINT_MACRO(RWSTD_NO_THROW_SPEC_ON_NEW); + PRINT_MACRO(RWSTD_NO_THROW_WITH_SHARED); + PRINT_MACRO(RWSTD_NO_TYPEDEF_INST); + PRINT_MACRO(RWSTD_NO_TYPEDEF_OVERLOAD); + PRINT_MACRO(RWSTD_NO_TYPENAME); + PRINT_MACRO(RWSTD_NO_UNDEFINED_FRIEND); + PRINT_MACRO(RWSTD_NO_UNINITIALIZED_STATIC_DEF); + PRINT_MACRO(RWSTD_NO_WCHAR_H); + PRINT_MACRO(RWSTD_NO_WCTYPE_H); + PRINT_MACRO(RWSTD_NO_WIDE_CHAR); + PRINT_MACRO(RWSTD_NO_WINT_TYPE); + PRINT_MACRO(RWSTD_NO_WSTR); + PRINT_MACRO(RWSTD_NOT_ALL_WSTR_CFUNCTIONS); + PRINT_MACRO(RWSTD_POSIX_D10_THREADS); + PRINT_MACRO(RWSTD_POSIX_THREADS); + PRINT_MACRO(RWSTD_REQUIRES_IEEEFP); + PRINT_MACRO(RWSTD_SOLARIS_THREADS); + PRINT_MACRO(RWSTD_STRUCT_TM_TZ); + PRINT_MACRO(RWSTD_WIDE_STRING_NULL_PROBLEM); + #endif + // Dinkumware options: + PRINT_MACRO(_CPPLIB_VER); + PRINT_MACRO(_MSVC_STL_VERSION); // VS2017 15.5+ + PRINT_MACRO(_MSVC_STL_UPDATE); // VS2017 15.5+ + PRINT_MACRO(_GLOBAL_USING); + PRINT_MACRO(_HAS_EXCEPTIONS); + PRINT_MACRO(_HAS_MEMBER_TEMPLATES_REBIND); + PRINT_MACRO(_HAS_TEMPLATE_PARTIAL_ORDERING); + // https://blogs.msdn.microsoft.com/vcblog/2016/08/12/stl-fixes-in-vs-2015-update-3/ + PRINT_MACRO(_HAS_CXX17); + PRINT_MACRO(_HAS_AUTO_PTR_ETC); + PRINT_MACRO(_HAS_OLD_IOSTREAMS_MEMBERS); + PRINT_MACRO(_HAS_FUNCTION_ASSIGN); + PRINT_MACRO(_HAS_TR1_NAMESPACE); + PRINT_MACRO(_HAS_IDENTITY_STRUCT); + // VS2017 15.5+ + PRINT_MACRO(_HAS_STATIC_RTTI); + PRINT_MACRO(_HAS_UNEXPECTED); + PRINT_MACRO(_HAS_STD_BYTE); + PRINT_MACRO(_HAS_FUNCTION_ALLOCATOR_SUPPORT); + PRINT_MACRO(_HAS_TR2_SYS_NAMESPACE); + PRINT_MACRO(_ENFORCE_MATCHING_ALLOCATORS); + PRINT_MACRO(_HAS_HAS_UNIQUE_OBJECT_REPRESENTATIONS); + PRINT_MACRO(_HAS_INLINE_VARIABLES); + PRINT_MACRO(_HAS_ALIGNED_NEW); + PRINT_MACRO(_HAS_NOEXCEPT_FUNCTION_TYPES); + PRINT_MACRO(_ITERATOR_DEBUG_LEVEL); + PRINT_MACRO(_HAS_ITERATOR_DEBUGGING); + PRINT_MACRO(_ITERATOR_DEBUG_ARRAY_OVERLOADS); + // Libc++: + PRINT_MACRO(_LIBCPP_VERSION); + // STLPort and generic SGI STL options: + PRINT_MACRO(__SGI_STL_NO_ARROW_OPERATOR); + PRINT_MACRO(__SGI_STL_OWN_IOSTREAMS); + PRINT_MACRO(__SGI_STL_PORT); + PRINT_MACRO(__STL_AUTOMATIC_TYPE_TRAITS); + PRINT_MACRO(__STL_BASE_MATCH_BUG); + PRINT_MACRO(__STL_BASE_TYPEDEF_BUG); + PRINT_MACRO(__STL_BASE_TYPEDEF_OUTSIDE_BUG); + PRINT_MACRO(__STL_BROKEN_USING_DIRECTIVE); + PRINT_MACRO(__STL_CONST_CONSTRUCTOR_BUG); + PRINT_MACRO(__STL_DEBUG); + PRINT_MACRO(__STL_DEBUG_ALLOC); + PRINT_MACRO(__STL_DEFAULT_CONSTRUCTOR_BUG); + PRINT_MACRO(__STL_DEFAULT_TYPE_PARAM); + PRINT_MACRO(__STL_DONT_REDEFINE_STD); + PRINT_MACRO(__STL_DONT_USE_BOOL_TYPEDEF); + PRINT_MACRO(__STL_HAS_NO_EXCEPTIONS); + PRINT_MACRO(__STL_HAS_NO_NAMESPACES); + PRINT_MACRO(__STL_HAS_NO_NEW_C_HEADERS); + PRINT_MACRO(__STL_HAS_NO_NEW_IOSTREAMS); + PRINT_MACRO(__STL_IMPORT_VENDOR_CSTD); + PRINT_MACRO(__STL_LIMITED_DEFAULT_TEMPLATES); + PRINT_MACRO(__STL_LINK_TIME_INSTANTIATION); + PRINT_MACRO(__STL_LONG_LONG); + PRINT_MACRO(__STL_LOOP_INLINE_PROBLEMS); + PRINT_MACRO(__STL_MEMBER_POINTER_PARAM_BUG); + PRINT_MACRO(__STL_NEED_EXPLICIT); + PRINT_MACRO(__STL_NEED_MUTABLE); + PRINT_MACRO(__STL_NEED_TYPENAME); + PRINT_MACRO(__STL_NESTED_TYPE_PARAM_BUG); + PRINT_MACRO(__STL_NO_BAD_ALLOC); + PRINT_MACRO(__STL_NO_BOOL); + PRINT_MACRO(__STL_NO_CLASS_PARTIAL_SPECIALIZATION); + PRINT_MACRO(__STL_NO_CSTD_FUNCTION_IMPORTS); + PRINT_MACRO(__STL_NO_DEFAULT_NON_TYPE_PARAM); + PRINT_MACRO(__STL_NO_EXCEPTION_HEADER); + PRINT_MACRO(__STL_NO_EXCEPTION_SPEC); + PRINT_MACRO(__STL_NO_EXCEPTIONS); + PRINT_MACRO(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS); + PRINT_MACRO(__STL_NO_FRIEND_TEMPLATES); + PRINT_MACRO(__STL_NO_FUNCTION_TMPL_PARTIAL_ORDER); + PRINT_MACRO(__STL_NO_IOSTREAMS); + PRINT_MACRO(__STL_NO_LONG_DOUBLE); + PRINT_MACRO(__STL_NO_MEMBER_TEMPLATE_CLASSES); + PRINT_MACRO(__STL_NO_MEMBER_TEMPLATE_KEYWORD); + PRINT_MACRO(__STL_NO_MEMBER_TEMPLATES); + PRINT_MACRO(__STL_NO_METHOD_SPECIALIZATION); + PRINT_MACRO(__STL_NO_NAMESPACES); + PRINT_MACRO(__STL_NO_NEW_IOSTREAMS); + PRINT_MACRO(__STL_NO_NEW_NEW_HEADER); + PRINT_MACRO(__STL_NO_NEW_STYLE_CASTS); + PRINT_MACRO(__STL_NO_PARTIAL_SPECIALIZATION_SYNTAX); + PRINT_MACRO(__STL_NO_QUALIFIED_FRIENDS); + PRINT_MACRO(__STL_NO_RELOPS_NAMESPACE); + PRINT_MACRO(__STL_NO_SGI_IOSTREAMS); + PRINT_MACRO(__STL_NO_STATIC_TEMPLATE_DATA); + PRINT_MACRO(__STL_NO_TEMPLATE_CONVERSIONS); + PRINT_MACRO(__STL_NO_WCHAR_T); + PRINT_MACRO(__STL_NON_TYPE_TMPL_PARAM_BUG); + PRINT_MACRO(__STL_NONTEMPL_BASE_MATCH_BUG); + PRINT_MACRO(__STL_PARTIAL_SPEC_NEEDS_TEMPLATE_ARGS); + PRINT_MACRO(__STL_RAND48); + PRINT_MACRO(__STL_STATIC_ARRAY_BUG); + PRINT_MACRO(__STL_STATIC_CONST_INIT_BUG); + PRINT_MACRO(__STL_STATIC_CONST_INIT_BUG); + PRINT_MACRO(__STL_THROW_RETURN_BUG); + PRINT_MACRO(__STL_TRIVIAL_CONSTRUCTOR_BUG); + PRINT_MACRO(__STL_TRIVIAL_DESTRUCTOR_BUG); + PRINT_MACRO(__STL_UNINITIALIZABLE_PRIVATE); + PRINT_MACRO(__STL_USE_ABBREVS); + PRINT_MACRO(__STL_USE_DEFALLOC); + PRINT_MACRO(__STL_USE_MALLOC); + PRINT_MACRO(__STL_USE_NEW_C_HEADERS); + PRINT_MACRO(__STL_USE_NEW_IOSTREAMS); + PRINT_MACRO(__STL_USE_NEWALLOC); + PRINT_MACRO(__STL_USE_OWN_NAMESPACE); + PRINT_MACRO(__STL_USE_SGI_ALLOCATORS); + PRINT_MACRO(__STL_WCHAR_T_IS_USHORT); + PRINT_MACRO(__STL_WEAK_ATTRIBUTE); + PRINT_MACRO(__STL_YVALS_H); + PRINT_MACRO(_NOTHREADS); + PRINT_MACRO(_PTHREADS); +#if defined(__SGI_STL_PORT) && (__SGI_STL_PORT > 0x0400) + PRINT_MACRO(_STLP_AUTOMATIC_TYPE_TRAITS); + PRINT_MACRO(_STLP_BASE_MATCH_BUG); + PRINT_MACRO(_STLP_BASE_TYPEDEF_BUG); + PRINT_MACRO(_STLP_BASE_TYPEDEF_OUTSIDE_BUG); + PRINT_MACRO(_STLP_BROKEN_USING_DIRECTIVE); + PRINT_MACRO(_STLP_CONST_CONSTRUCTOR_BUG); + PRINT_MACRO(_STLP_DEBUG); + PRINT_MACRO(_STLP_DEBUG_ALLOC); + PRINT_MACRO(_STLP_DEFAULT_CONSTRUCTOR_BUG); + PRINT_MACRO(_STLP_DEFAULT_TYPE_PARAM); + PRINT_MACRO(_STLP_DONT_REDEFINE_STD); + PRINT_MACRO(_STLP_DONT_USE_BOOL_TYPEDEF); + PRINT_MACRO(_STLP_HAS_NO_EXCEPTIONS); + PRINT_MACRO(_STLP_HAS_NO_NAMESPACES); + PRINT_MACRO(_STLP_HAS_NO_NEW_C_HEADERS); + PRINT_MACRO(_STLP_HAS_NO_NEW_IOSTREAMS); + PRINT_MACRO(_STLP_IMPORT_VENDOR_CSTD); + PRINT_MACRO(_STLP_LIMITED_DEFAULT_TEMPLATES); + PRINT_MACRO(_STLP_LINK_TIME_INSTANTIATION); + PRINT_MACRO(_STLP_LONG_LONG); + PRINT_MACRO(_STLP_LOOP_INLINE_PROBLEMS); + PRINT_MACRO(_STLP_MEMBER_POINTER_PARAM_BUG); + PRINT_MACRO(_STLP_NEED_EXPLICIT); + PRINT_MACRO(_STLP_NEED_MUTABLE); + PRINT_MACRO(_STLP_NEED_TYPENAME); + PRINT_MACRO(_STLP_NESTED_TYPE_PARAM_BUG); + PRINT_MACRO(_STLP_NO_ARROW_OPERATOR); + PRINT_MACRO(_STLP_NO_BAD_ALLOC); + PRINT_MACRO(_STLP_NO_BOOL); + PRINT_MACRO(_STLP_NO_CLASS_PARTIAL_SPECIALIZATION); + PRINT_MACRO(_STLP_NO_CSTD_FUNCTION_IMPORTS); + PRINT_MACRO(_STLP_NO_DEFAULT_NON_TYPE_PARAM); + PRINT_MACRO(_STLP_NO_EXCEPTION_HEADER); + PRINT_MACRO(_STLP_NO_EXCEPTION_SPEC); + PRINT_MACRO(_STLP_NO_EXCEPTIONS); + PRINT_MACRO(_STLP_NO_EXPLICIT_FUNCTION_TMPL_ARGS); + PRINT_MACRO(_STLP_NO_FRIEND_TEMPLATES); + PRINT_MACRO(_STLP_NO_FUNCTION_TMPL_PARTIAL_ORDER); + PRINT_MACRO(_STLP_NO_IOSTREAMS); + PRINT_MACRO(_STLP_NO_LONG_DOUBLE); + PRINT_MACRO(_STLP_NO_MEMBER_TEMPLATE_CLASSES); + PRINT_MACRO(_STLP_NO_MEMBER_TEMPLATE_KEYWORD); + PRINT_MACRO(_STLP_NO_MEMBER_TEMPLATES); + PRINT_MACRO(_STLP_NO_METHOD_SPECIALIZATION); + PRINT_MACRO(_STLP_NO_NAMESPACES); + PRINT_MACRO(_STLP_NO_NEW_IOSTREAMS); + PRINT_MACRO(_STLP_NO_NEW_NEW_HEADER); + PRINT_MACRO(_STLP_NO_NEW_STYLE_CASTS); + PRINT_MACRO(_STLP_NO_PARTIAL_SPECIALIZATION_SYNTAX); + PRINT_MACRO(_STLP_NO_QUALIFIED_FRIENDS); + PRINT_MACRO(_STLP_NO_RELOPS_NAMESPACE); + PRINT_MACRO(_STLP_NO_SGI_IOSTREAMS); + PRINT_MACRO(_STLP_NO_STATIC_TEMPLATE_DATA); + PRINT_MACRO(_STLP_NO_TEMPLATE_CONVERSIONS); + PRINT_MACRO(_STLP_NO_WCHAR_T); + PRINT_MACRO(_STLP_NON_TYPE_TMPL_PARAM_BUG); + PRINT_MACRO(_STLP_NONTEMPL_BASE_MATCH_BUG); + PRINT_MACRO(_STLP_OWN_IOSTREAMS); + PRINT_MACRO(_STLP_PARTIAL_SPEC_NEEDS_TEMPLATE_ARGS); + PRINT_MACRO(_STLP_RAND48); + PRINT_MACRO(_STLP_STATIC_ARRAY_BUG); + PRINT_MACRO(_STLP_STATIC_CONST_INIT_BUG); + PRINT_MACRO(_STLP_STATIC_CONST_INIT_BUG); + PRINT_MACRO(_STLP_THROW_RETURN_BUG); + PRINT_MACRO(_STLP_TRIVIAL_CONSTRUCTOR_BUG); + PRINT_MACRO(_STLP_TRIVIAL_DESTRUCTOR_BUG); + PRINT_MACRO(_STLP_UNINITIALIZABLE_PRIVATE); + PRINT_MACRO(_STLP_USE_ABBREVS); + PRINT_MACRO(_STLP_USE_DEFALLOC); + PRINT_MACRO(_STLP_USE_MALLOC); + PRINT_MACRO(_STLP_USE_NEW_C_HEADERS); + PRINT_MACRO(_STLP_USE_NEWALLOC); + PRINT_MACRO(_STLP_USE_OWN_NAMESPACE); + PRINT_MACRO(_STLP_USE_SGI_ALLOCATORS); + PRINT_MACRO(_STLP_WCHAR_T_IS_USHORT); + PRINT_MACRO(_STLP_WEAK_ATTRIBUTE); + PRINT_MACRO(_STLP_YVALS_H); +#endif + PRINT_MACRO(__GLIBCPP__); + PRINT_MACRO(_GLIBCPP_USE_WCHAR_T); + PRINT_MACRO(_GLIBCPP_VERSION); + PRINT_MACRO(__GLIBCXX__); + PRINT_MACRO(_GLIBCXX_USE_WCHAR_T); + PRINT_MACRO(_GLIBCXX_VERSION); + PRINT_MACRO(_GLIBCXX_USE_LONG_LONG); + PRINT_MACRO(_GLIBCXX_USE_NLS); + PRINT_MACRO(_GLIBCXX_USE_C99_MATH); + PRINT_MACRO(_GLIBCXX_USE_C99); + PRINT_MACRO(_GLIBCXX_CONCEPT_CHECKS); + PRINT_MACRO(_GLIBCXX_USE_LFS); + PRINT_MACRO(_GLIBCXX_SYMVER); + PRINT_MACRO(_GLIBCXX_MEM_LIMITS); + PRINT_MACRO(_GLIBCXX_HOSTED); + PRINT_MACRO(_GLIBCXX_SJLJ_EXCEPTIONS); + PRINT_MACRO(_GLIBCXX_RELEASE); + + // Modena C++ standard library + PRINT_MACRO(MSIPL_ANSI_HEADER); + PRINT_MACRO(MSIPL_BOOL_BUILTIN); + PRINT_MACRO(MSIPL_DEF_EXPLICIT); + PRINT_MACRO(MSIPL_DEF_TEMPARG); + PRINT_MACRO(MSIPL_EXPINST_ALLOWED); + PRINT_MACRO(MSIPL_EXPLICIT_FUNC_TEMPLATE_ARG); + PRINT_MACRO(MISPL_EXPLICIT_TEMPLATE_ARGUMENT); + PRINT_MACRO(MSIPL_FUNC_TEMPLATE_DEFARG); + PRINT_MACRO(MSIPL_MEMBER_TEMPLATE); + PRINT_MACRO(MSIPL_MULTITHREAD); + PRINT_MACRO(MSIPL_NON_TYPE_TEMPARG); + PRINT_MACRO(MSIPL_PARTIAL_TEMPL); + PRINT_MACRO(MSIPL_STATIC_CONST_INIT); + PRINT_MACRO(MSIPL_TEMPL_NEWSPEC); + PRINT_MACRO(MSIPL_TYPENAME); + PRINT_MACRO(MSIPL_USING_NAMESPACE); + PRINT_MACRO(MSIPL_WCHART); +} + +void print_platform_macros() +{ + std::cout << "Detected Platform: " << BOOST_PLATFORM << std::endl; + // signedness: + PRINT_SIGN(char); + PRINT_SIGN(wchar_t); + // byte ordering: + PRINT_ORDER(short); + PRINT_ORDER(int); + PRINT_ORDER(long); + // sizes: + PRINT_EXPRESSION(sizeof(wchar_t)); + PRINT_EXPRESSION(sizeof(short)); + PRINT_EXPRESSION(sizeof(int)); + PRINT_EXPRESSION(sizeof(long)); + PRINT_EXPRESSION(sizeof(size_t)); + PRINT_EXPRESSION(sizeof(ptrdiff_t)); + PRINT_EXPRESSION(sizeof(void*)); + PRINT_EXPRESSION(sizeof(void(*)(void))); + PRINT_EXPRESSION(sizeof(float)); + PRINT_EXPRESSION(sizeof(double)); + PRINT_EXPRESSION(sizeof(long double)); + // limits: + PRINT_MACRO(CHAR_BIT); + PRINT_MACRO(CHAR_MAX); + PRINT_MACRO(WCHAR_MAX); + PRINT_MACRO(SHRT_MAX); + PRINT_MACRO(INT_MAX); + PRINT_MACRO(LONG_MAX); + PRINT_MACRO(LLONG_MAX); + PRINT_MACRO(LONG_LONG_MAX); + PRINT_MACRO(LONGLONG_MAX); + PRINT_MACRO(ULLONG_MAX); // uses these, so we need to know them + PRINT_MACRO(ULONG_LONG_MAX); + PRINT_MACRO(ULONGLONG_MAX); + // general C99: + PRINT_MACRO(__STDC_IEC_559__); + PRINT_MACRO(__STDC_IEC_559_COMPLEX__); + PRINT_MACRO(__STDC_ISO_10646__); + // GNU: + PRINT_MACRO(__GLIBC__); + PRINT_MACRO(__GLIBC_MINOR__); + PRINT_MACRO(__GNU_LIBRARY__); + PRINT_MACRO(_BSD_SOURCE); + PRINT_MACRO(_GNU_SOURCE); + PRINT_MACRO(_ISOC99_SOURCE); + PRINT_MACRO(_ISOC9X_SOURCE); + PRINT_MACRO(_LARGEFILE_SOURCE); + PRINT_MACRO(_LARGEFILE64_SOURCE); + PRINT_MACRO(_SVID_SOURCE); + PRINT_MACRO(_THREAD_SAFE); + PRINT_MACRO(_XOPEN_SOURCE_EXTENDED); + PRINT_MACRO(XPG); + PRINT_MACRO(__MINGW32_MAJOR_VERSION); + PRINT_MACRO(__MINGW32_MINOR_VERSION); + // POSIX: + PRINT_MACRO(_POSIX_ADVISORY_INFO); + PRINT_MACRO(_POSIX_ASYNCHRONOUS_IO); + PRINT_MACRO(_POSIX_BARRIERS); + PRINT_MACRO(_POSIX_C_SOURCE); + PRINT_MACRO(_POSIX_CHOWN_RESTRICTED); + PRINT_MACRO(_POSIX_CLOCK_SELECTION); + PRINT_MACRO(_POSIX_CPUTIME); + PRINT_MACRO(_POSIX_FSYNC); + PRINT_MACRO(_POSIX_JOB_CONTROL); + PRINT_MACRO(_POSIX_MAPPED_FILES); + PRINT_MACRO(_POSIX_MEMLOCK); + PRINT_MACRO(_POSIX_MEMLOCK_RANGE); + PRINT_MACRO(_POSIX_MEMORY_PROTECTION); + PRINT_MACRO(_POSIX_MESSAGE_PASSING); + PRINT_MACRO(_POSIX_MONOTONIC_CLOCK); + PRINT_MACRO(_POSIX_NO_TRUNC); + PRINT_MACRO(_POSIX_PRIORITIZED_IO); + PRINT_MACRO(_POSIX_PRIORITY_SCHEDULING); + PRINT_MACRO(_POSIX_RAW_SOCKETS); + PRINT_MACRO(_POSIX_READER_WRITER_LOCKS); + PRINT_MACRO(_POSIX_REALTIME_SIGNALS); + PRINT_MACRO(_POSIX_REGEXP); + PRINT_MACRO(_POSIX_SAVED_IDS); + PRINT_MACRO(_POSIX_SEMAPHORES); + PRINT_MACRO(_POSIX_SHARED_MEMORY_OBJECTS); + PRINT_MACRO(_POSIX_SHELL); + PRINT_MACRO(_POSIX_SOURCE); + PRINT_MACRO(_POSIX_SPAWN); + PRINT_MACRO(_POSIX_SPIN_LOCKS); + PRINT_MACRO(_POSIX_SPORADIC_SERVER); + PRINT_MACRO(_POSIX_SYNCHRONIZED_IO); + PRINT_MACRO(_POSIX_THREAD_ATTR_STACKADDR); + PRINT_MACRO(_POSIX_THREAD_ATTR_STACKSIZE); + PRINT_MACRO(_POSIX_THREAD_CPUTIME); + PRINT_MACRO(_POSIX_THREAD_PRIO_INHERIT); + PRINT_MACRO(_POSIX_THREAD_PRIO_PROTECT); + PRINT_MACRO(_POSIX_THREAD_PRIORITY_SCHEDULING); + PRINT_MACRO(_POSIX_THREAD_PROCESS_SHARED); + PRINT_MACRO(_POSIX_THREAD_SAFE_FUNCTIONS); + PRINT_MACRO(_POSIX_THREAD_SPORADIC_SERVER); + PRINT_MACRO(_POSIX_THREADS); + PRINT_MACRO(_POSIX_TIMEOUTS); + PRINT_MACRO(_POSIX_TIMERS); + PRINT_MACRO(_POSIX_TRACE); + PRINT_MACRO(_POSIX_TRACE_EVENT_FILTER); + PRINT_MACRO(_POSIX_TRACE_INHERIT); + PRINT_MACRO(_POSIX_TRACE_LOG); + PRINT_MACRO(_POSIX_TYPED_MEMORY_OBJECTS); + PRINT_MACRO(_POSIX_VDISABLE); + PRINT_MACRO(_POSIX_VERSION); + PRINT_MACRO(_POSIX2_C_BIND); + PRINT_MACRO(_POSIX2_C_DEV); + PRINT_MACRO(_POSIX2_CHAR_TERM); + PRINT_MACRO(_POSIX2_FORT_DEV); + PRINT_MACRO(_POSIX2_FORT_RUN); + PRINT_MACRO(_POSIX2_LOCALEDEF); + PRINT_MACRO(_POSIX2_PBS); + PRINT_MACRO(_POSIX2_PBS_ACCOUNTING); + PRINT_MACRO(_POSIX2_PBS_CHECKPOINT); + PRINT_MACRO(_POSIX2_PBS_LOCATE); + PRINT_MACRO(_POSIX2_PBS_MESSAGE); + PRINT_MACRO(_POSIX2_PBS_TRACK); + PRINT_MACRO(_POSIX2_SW_DEV); + PRINT_MACRO(_POSIX2_UPE); + PRINT_MACRO(_POSIX2_VERSION); + PRINT_MACRO(_V6_ILP32_OFF32); + PRINT_MACRO(_V6_ILP32_OFFBIG); + PRINT_MACRO(_V6_LP64_OFF64); + PRINT_MACRO(_V6_LPBIG_OFFBIG); + PRINT_MACRO(_XBS5_ILP32_OFF32); + PRINT_MACRO(_XBS5_ILP32_OFFBIG); + PRINT_MACRO(_XBS5_LP64_OFF64); + PRINT_MACRO(_XBS5_LPBIG_OFFBIG); + PRINT_MACRO(_XOPEN_CRYPT); + PRINT_MACRO(_XOPEN_ENH_I18N); + PRINT_MACRO(_XOPEN_LEGACY); + PRINT_MACRO(_XOPEN_REALTIME); + PRINT_MACRO(_XOPEN_REALTIME_THREADS); + PRINT_MACRO(_XOPEN_SHM); + PRINT_MACRO(_XOPEN_SOURCE); + PRINT_MACRO(_XOPEN_STREAMS); + PRINT_MACRO(_XOPEN_UNIX); + PRINT_MACRO(_XOPEN_VERSION); + // Misc: + PRINT_MACRO(__USE_BSD); + PRINT_MACRO(_FILE_OFFSET_BITS); +} + +void print_boost_macros() +{ + std::cout << "Boost version " << BOOST_STRINGIZE(BOOST_VERSION) << std::endl; + // config setup macros first: + PRINT_MACRO(BOOST_USER_CONFIG); + PRINT_MACRO(BOOST_COMPILER_CONFIG); + PRINT_MACRO(BOOST_STDLIB_CONFIG); + PRINT_MACRO(BOOST_PLATFORM_CONFIG); + PRINT_MACRO(BOOST_NO_CONFIG); + PRINT_MACRO(BOOST_NO_USER_CONFIG); + PRINT_MACRO(BOOST_NO_COMPILER_CONFIG); + PRINT_MACRO(BOOST_NO_STDLIB_CONFIG); + PRINT_MACRO(BOOST_NO_PLATFORM_CONFIG); + // then defect and feature macros: + PRINT_MACRO(BOOST_DISABLE_THREADS); + PRINT_MACRO(BOOST_DISABLE_WIN32); + PRINT_MACRO(BOOST_HAS_THREADS); + PRINT_MACRO(BOOST_WINDOWS); + + // BEGIN GENERATED BLOCK DO NOT EDIT THIS!!!!!! + PRINT_MACRO(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG); + PRINT_MACRO(BOOST_DEDUCED_TYPENAME); + PRINT_MACRO(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL); + PRINT_MACRO(BOOST_HAS_BETHREADS); + PRINT_MACRO(BOOST_HAS_CLOCK_GETTIME); + PRINT_MACRO(BOOST_HAS_DIRENT_H); + PRINT_MACRO(BOOST_HAS_EXPM1); + PRINT_MACRO(BOOST_HAS_FLOAT128); + PRINT_MACRO(BOOST_HAS_FTIME); + PRINT_MACRO(BOOST_HAS_GETSYSTEMTIMEASFILETIME); + PRINT_MACRO(BOOST_HAS_GETTIMEOFDAY); + PRINT_MACRO(BOOST_HAS_HASH); + PRINT_MACRO(BOOST_HAS_INT128); + PRINT_MACRO(BOOST_HAS_LOG1P); + PRINT_MACRO(BOOST_HAS_LONG_LONG); + PRINT_MACRO(BOOST_HAS_MACRO_USE_FACET); + PRINT_MACRO(BOOST_HAS_MS_INT64); + PRINT_MACRO(BOOST_HAS_NANOSLEEP); + PRINT_MACRO(BOOST_HAS_NL_TYPES_H); + PRINT_MACRO(BOOST_HAS_NRVO); + PRINT_MACRO(BOOST_HAS_PARTIAL_STD_ALLOCATOR); + PRINT_MACRO(BOOST_HAS_PRAGMA_DETECT_MISMATCH); + PRINT_MACRO(BOOST_HAS_PTHREADS); + PRINT_MACRO(BOOST_HAS_PTHREAD_DELAY_NP); + PRINT_MACRO(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE); + PRINT_MACRO(BOOST_HAS_PTHREAD_YIELD); + PRINT_MACRO(BOOST_HAS_RVALUE_REFS); + PRINT_MACRO(BOOST_HAS_SCHED_YIELD); + PRINT_MACRO(BOOST_HAS_SGI_TYPE_TRAITS); + PRINT_MACRO(BOOST_HAS_SIGACTION); + PRINT_MACRO(BOOST_HAS_SLIST); + PRINT_MACRO(BOOST_HAS_STATIC_ASSERT); + PRINT_MACRO(BOOST_HAS_STDINT_H); + PRINT_MACRO(BOOST_HAS_STLP_USE_FACET); + PRINT_MACRO(BOOST_HAS_TWO_ARG_USE_FACET); + PRINT_MACRO(BOOST_HAS_UNISTD_H); + PRINT_MACRO(BOOST_HAS_VARIADIC_TMPL); + PRINT_MACRO(BOOST_HAS_WINTHREADS); + PRINT_MACRO(BOOST_MSVC6_MEMBER_TEMPLATES); + PRINT_MACRO(BOOST_MSVC_STD_ITERATOR); + PRINT_MACRO(BOOST_NO_ADL_BARRIER); + PRINT_MACRO(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP); + PRINT_MACRO(BOOST_NO_ARRAY_TYPE_SPECIALIZATIONS); + PRINT_MACRO(BOOST_NO_AUTO_PTR); + PRINT_MACRO(BOOST_NO_COMPLETE_VALUE_INITIALIZATION); + PRINT_MACRO(BOOST_NO_CTYPE_FUNCTIONS); + PRINT_MACRO(BOOST_NO_CV_SPECIALIZATIONS); + PRINT_MACRO(BOOST_NO_CV_VOID_SPECIALIZATIONS); + PRINT_MACRO(BOOST_NO_CWCHAR); + PRINT_MACRO(BOOST_NO_CWCTYPE); + PRINT_MACRO(BOOST_NO_CXX11_ADDRESSOF); + PRINT_MACRO(BOOST_NO_CXX11_ALIGNAS); + PRINT_MACRO(BOOST_NO_CXX11_ALLOCATOR); + PRINT_MACRO(BOOST_NO_CXX11_ATOMIC_SMART_PTR); + PRINT_MACRO(BOOST_NO_CXX11_AUTO_DECLARATIONS); + PRINT_MACRO(BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS); + PRINT_MACRO(BOOST_NO_CXX11_CHAR16_T); + PRINT_MACRO(BOOST_NO_CXX11_CHAR32_T); + PRINT_MACRO(BOOST_NO_CXX11_CONSTEXPR); + PRINT_MACRO(BOOST_NO_CXX11_DECLTYPE); + PRINT_MACRO(BOOST_NO_CXX11_DECLTYPE_N3276); + PRINT_MACRO(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS); + PRINT_MACRO(BOOST_NO_CXX11_DEFAULTED_MOVES); + PRINT_MACRO(BOOST_NO_CXX11_DELETED_FUNCTIONS); + PRINT_MACRO(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS); + PRINT_MACRO(BOOST_NO_CXX11_EXTERN_TEMPLATE); + PRINT_MACRO(BOOST_NO_CXX11_FINAL); + PRINT_MACRO(BOOST_NO_CXX11_FIXED_LENGTH_VARIADIC_TEMPLATE_EXPANSION_PACKS); + PRINT_MACRO(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS); + PRINT_MACRO(BOOST_NO_CXX11_HDR_ARRAY); + PRINT_MACRO(BOOST_NO_CXX11_HDR_ATOMIC); + PRINT_MACRO(BOOST_NO_CXX11_HDR_CHRONO); + PRINT_MACRO(BOOST_NO_CXX11_HDR_CODECVT); + PRINT_MACRO(BOOST_NO_CXX11_HDR_CONDITION_VARIABLE); + PRINT_MACRO(BOOST_NO_CXX11_HDR_EXCEPTION); + PRINT_MACRO(BOOST_NO_CXX11_HDR_FORWARD_LIST); + PRINT_MACRO(BOOST_NO_CXX11_HDR_FUNCTIONAL); + PRINT_MACRO(BOOST_NO_CXX11_HDR_FUTURE); + PRINT_MACRO(BOOST_NO_CXX11_HDR_INITIALIZER_LIST); + PRINT_MACRO(BOOST_NO_CXX11_HDR_MUTEX); + PRINT_MACRO(BOOST_NO_CXX11_HDR_RANDOM); + PRINT_MACRO(BOOST_NO_CXX11_HDR_RATIO); + PRINT_MACRO(BOOST_NO_CXX11_HDR_REGEX); + PRINT_MACRO(BOOST_NO_CXX11_HDR_SYSTEM_ERROR); + PRINT_MACRO(BOOST_NO_CXX11_HDR_THREAD); + PRINT_MACRO(BOOST_NO_CXX11_HDR_TUPLE); + PRINT_MACRO(BOOST_NO_CXX11_HDR_TYPEINDEX); + PRINT_MACRO(BOOST_NO_CXX11_HDR_TYPE_TRAITS); + PRINT_MACRO(BOOST_NO_CXX11_HDR_UNORDERED_MAP); + PRINT_MACRO(BOOST_NO_CXX11_HDR_UNORDERED_SET); + PRINT_MACRO(BOOST_NO_CXX11_INLINE_NAMESPACES); + PRINT_MACRO(BOOST_NO_CXX11_LAMBDAS); + PRINT_MACRO(BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS); + PRINT_MACRO(BOOST_NO_CXX11_NOEXCEPT); + PRINT_MACRO(BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS); + PRINT_MACRO(BOOST_NO_CXX11_NULLPTR); + PRINT_MACRO(BOOST_NO_CXX11_NUMERIC_LIMITS); + PRINT_MACRO(BOOST_NO_CXX11_POINTER_TRAITS); + PRINT_MACRO(BOOST_NO_CXX11_RANGE_BASED_FOR); + PRINT_MACRO(BOOST_NO_CXX11_RAW_LITERALS); + PRINT_MACRO(BOOST_NO_CXX11_REF_QUALIFIERS); + PRINT_MACRO(BOOST_NO_CXX11_RVALUE_REFERENCES); + PRINT_MACRO(BOOST_NO_CXX11_SCOPED_ENUMS); + PRINT_MACRO(BOOST_NO_CXX11_SFINAE_EXPR); + PRINT_MACRO(BOOST_NO_CXX11_SMART_PTR); + PRINT_MACRO(BOOST_NO_CXX11_STATIC_ASSERT); + PRINT_MACRO(BOOST_NO_CXX11_STD_ALIGN); + PRINT_MACRO(BOOST_NO_CXX11_TEMPLATE_ALIASES); + PRINT_MACRO(BOOST_NO_CXX11_THREAD_LOCAL); + PRINT_MACRO(BOOST_NO_CXX11_TRAILING_RESULT_TYPES); + PRINT_MACRO(BOOST_NO_CXX11_UNICODE_LITERALS); + PRINT_MACRO(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX); + PRINT_MACRO(BOOST_NO_CXX11_USER_DEFINED_LITERALS); + PRINT_MACRO(BOOST_NO_CXX11_VARIADIC_MACROS); + PRINT_MACRO(BOOST_NO_CXX11_VARIADIC_TEMPLATES); + PRINT_MACRO(BOOST_NO_CXX14_AGGREGATE_NSDMI); + PRINT_MACRO(BOOST_NO_CXX14_BINARY_LITERALS); + PRINT_MACRO(BOOST_NO_CXX14_CONSTEXPR); + PRINT_MACRO(BOOST_NO_CXX14_DECLTYPE_AUTO); + PRINT_MACRO(BOOST_NO_CXX14_DIGIT_SEPARATORS); + PRINT_MACRO(BOOST_NO_CXX14_GENERIC_LAMBDAS); + PRINT_MACRO(BOOST_NO_CXX14_HDR_SHARED_MUTEX); + PRINT_MACRO(BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES); + PRINT_MACRO(BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION); + PRINT_MACRO(BOOST_NO_CXX14_STD_EXCHANGE); + PRINT_MACRO(BOOST_NO_CXX14_VARIABLE_TEMPLATES); + PRINT_MACRO(BOOST_NO_CXX17_FOLD_EXPRESSIONS); + PRINT_MACRO(BOOST_NO_CXX17_HDR_OPTIONAL); + PRINT_MACRO(BOOST_NO_CXX17_HDR_STRING_VIEW); + PRINT_MACRO(BOOST_NO_CXX17_HDR_VARIANT); + PRINT_MACRO(BOOST_NO_CXX17_IF_CONSTEXPR); + PRINT_MACRO(BOOST_NO_CXX17_INLINE_VARIABLES); + PRINT_MACRO(BOOST_NO_CXX17_ITERATOR_TRAITS); + PRINT_MACRO(BOOST_NO_CXX17_STD_APPLY); + PRINT_MACRO(BOOST_NO_CXX17_STD_INVOKE); + PRINT_MACRO(BOOST_NO_CXX17_STRUCTURED_BINDINGS); + PRINT_MACRO(BOOST_NO_CXX98_BINDERS); + PRINT_MACRO(BOOST_NO_CXX98_FUNCTION_BASE); + PRINT_MACRO(BOOST_NO_CXX98_RANDOM_SHUFFLE); + PRINT_MACRO(BOOST_NO_DEPENDENT_NESTED_DERIVATIONS); + PRINT_MACRO(BOOST_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS); + PRINT_MACRO(BOOST_NO_EXCEPTIONS); + PRINT_MACRO(BOOST_NO_EXCEPTION_STD_NAMESPACE); + PRINT_MACRO(BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS); + PRINT_MACRO(BOOST_NO_FENV_H); + PRINT_MACRO(BOOST_NO_FUNCTION_TEMPLATE_ORDERING); + PRINT_MACRO(BOOST_NO_FUNCTION_TYPE_SPECIALIZATIONS); + PRINT_MACRO(BOOST_NO_INCLASS_MEMBER_INITIALIZATION); + PRINT_MACRO(BOOST_NO_INTEGRAL_INT64_T); + PRINT_MACRO(BOOST_NO_INTRINSIC_WCHAR_T); + PRINT_MACRO(BOOST_NO_IOSFWD); + PRINT_MACRO(BOOST_NO_IOSTREAM); + PRINT_MACRO(BOOST_NO_IS_ABSTRACT); + PRINT_MACRO(BOOST_NO_LIMITS); + PRINT_MACRO(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS); + PRINT_MACRO(BOOST_NO_LONG_LONG); + PRINT_MACRO(BOOST_NO_LONG_LONG_NUMERIC_LIMITS); + PRINT_MACRO(BOOST_NO_MEMBER_FUNCTION_SPECIALIZATIONS); + PRINT_MACRO(BOOST_NO_MEMBER_TEMPLATES); + PRINT_MACRO(BOOST_NO_MEMBER_TEMPLATE_FRIENDS); + PRINT_MACRO(BOOST_NO_MEMBER_TEMPLATE_KEYWORD); + PRINT_MACRO(BOOST_NO_MS_INT64_NUMERIC_LIMITS); + PRINT_MACRO(BOOST_NO_NESTED_FRIENDSHIP); + PRINT_MACRO(BOOST_NO_OPERATORS_IN_NAMESPACE); + PRINT_MACRO(BOOST_NO_PARTIAL_SPECIALIZATION_IMPLICIT_DEFAULT_ARGS); + PRINT_MACRO(BOOST_NO_POINTER_TO_MEMBER_CONST); + PRINT_MACRO(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS); + PRINT_MACRO(BOOST_NO_PRIVATE_IN_AGGREGATE); + PRINT_MACRO(BOOST_NO_RESTRICT_REFERENCES); + PRINT_MACRO(BOOST_NO_RTTI); + PRINT_MACRO(BOOST_NO_SFINAE); + PRINT_MACRO(BOOST_NO_SFINAE_EXPR); + PRINT_MACRO(BOOST_NO_STDC_NAMESPACE); + PRINT_MACRO(BOOST_NO_STD_ALLOCATOR); + PRINT_MACRO(BOOST_NO_STD_DISTANCE); + PRINT_MACRO(BOOST_NO_STD_ITERATOR); + PRINT_MACRO(BOOST_NO_STD_ITERATOR_TRAITS); + PRINT_MACRO(BOOST_NO_STD_LOCALE); + PRINT_MACRO(BOOST_NO_STD_MESSAGES); + PRINT_MACRO(BOOST_NO_STD_MIN_MAX); + PRINT_MACRO(BOOST_NO_STD_OUTPUT_ITERATOR_ASSIGN); + PRINT_MACRO(BOOST_NO_STD_TYPEINFO); + PRINT_MACRO(BOOST_NO_STD_USE_FACET); + PRINT_MACRO(BOOST_NO_STD_WSTREAMBUF); + PRINT_MACRO(BOOST_NO_STD_WSTRING); + PRINT_MACRO(BOOST_NO_STRINGSTREAM); + PRINT_MACRO(BOOST_NO_SWPRINTF); + PRINT_MACRO(BOOST_NO_TEMPLATED_IOSTREAMS); + PRINT_MACRO(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS); + PRINT_MACRO(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION); + PRINT_MACRO(BOOST_NO_TEMPLATE_TEMPLATES); + PRINT_MACRO(BOOST_NO_TWO_PHASE_NAME_LOOKUP); + PRINT_MACRO(BOOST_NO_TYPEID); + PRINT_MACRO(BOOST_NO_TYPENAME_WITH_CTOR); + PRINT_MACRO(BOOST_NO_UNREACHABLE_RETURN_DETECTION); + PRINT_MACRO(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE); + PRINT_MACRO(BOOST_NO_USING_TEMPLATE); + PRINT_MACRO(BOOST_NO_VOID_RETURNS); + + + // END GENERATED BLOCK + + PRINT_MACRO(BOOST_INTEL); + PRINT_MACRO(BOOST_MSVC); + PRINT_MACRO(BOOST_GCC); + PRINT_MACRO(BOOST_LIBSTDCXX_VERSION); + PRINT_MACRO(BOOST_STD_EXTENSION_NAMESPACE); + PRINT_MACRO(BOOST_UNREACHABLE_RETURN(0)); + PRINT_MACRO(BOOST_CONSTEXPR); + PRINT_MACRO(BOOST_CONSTEXPR_OR_CONST); + PRINT_MACRO(BOOST_STATIC_CONSTEXPR); + PRINT_MACRO(BOOST_NOEXCEPT); + PRINT_MACRO(BOOST_FORCEINLINE); + PRINT_MACRO(BOOST_NOINLINE); + PRINT_MACRO(BOOST_FALLTHROUGH); + PRINT_MACRO(BOOST_MAY_ALIAS); + PRINT_MACRO(BOOST_NO_MAY_ALIAS); + PRINT_MACRO(BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS); + PRINT_MACRO(BOOST_ATTRIBUTE_UNUSED); + PRINT_MACRO(BOOST_UNLIKELY); + PRINT_MACRO(BOOST_NORETURN); +} + +void print_sd6_macros() +{ + // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0096r5.html + + // C++20: + PRINT_MACRO(__cpp_aggregate_paren_init); + PRINT_MACRO(__cpp_char8_t); + PRINT_MACRO(__cpp_char8_type); + PRINT_MACRO(__cpp_conditional_explicit); + PRINT_MACRO(__cpp_coroutines); + PRINT_MACRO(__cpp_impl_destroying_delete); + PRINT_MACRO(__cpp_impl_three_way_comparison); + PRINT_MACRO(__cpp_nontype_template_parameter_class); + + // C++17: + PRINT_MACRO(__cpp_hex_float); + PRINT_MACRO(__cpp_inline_variables); + PRINT_MACRO(__cpp_aligned_new); + PRINT_MACRO(__cpp_guaranteed_copy_elision); + PRINT_MACRO(__cpp_noexcept_function_type); + PRINT_MACRO(__cpp_fold_expressions); + PRINT_MACRO(__cpp_capture_star_this); + PRINT_MACRO(__cpp_constexpr); + PRINT_MACRO(__cpp_if_constexpr); + PRINT_MACRO(__cpp_range_based_for); + PRINT_MACRO(__cpp_static_assert); + PRINT_MACRO(__cpp_deduction_guides); + PRINT_MACRO(__cpp_nontype_template_parameter_auto); + PRINT_MACRO(__cpp_namespace_attributes); + PRINT_MACRO(__cpp_enumerator_attributes); + PRINT_MACRO(__cpp_inheriting_constructors); + PRINT_MACRO(__cpp_variadic_using); + PRINT_MACRO(__cpp_structured_bindings); + PRINT_MACRO(__cpp_aggregate_bases); + PRINT_MACRO(__cpp_nontype_template_args); + PRINT_MACRO(__cpp_template_template_args); + + // C++14: + PRINT_MACRO(__cpp_binary_literals); + PRINT_MACRO(__cpp_init_captures); + PRINT_MACRO(__cpp_generic_lambdas); + PRINT_MACRO(__cpp_sized_deallocation); + PRINT_MACRO(__cpp_decltype_auto); + PRINT_MACRO(__cpp_return_type_deduction); + PRINT_MACRO(__cpp_aggregate_nsdmi); + PRINT_MACRO(__cpp_variable_templates); + + // C++11: + PRINT_MACRO(__cpp_unicode_characters); + PRINT_MACRO(__cpp_raw_strings); + PRINT_MACRO(__cpp_unicode_literals); + PRINT_MACRO(__cpp_user_defined_literals); + PRINT_MACRO(__cpp_threadsafe_static_init); + PRINT_MACRO(__cpp_lambdas); + PRINT_MACRO(__cpp_decltype); + PRINT_MACRO(__cpp_attributes); + PRINT_MACRO(__cpp_rvalue_references); + PRINT_MACRO(__cpp_variadic_templates); + PRINT_MACRO(__cpp_initializer_lists); + PRINT_MACRO(__cpp_delegating_constructors); + PRINT_MACRO(__cpp_nsdmi); + PRINT_MACRO(__cpp_ref_qualifiers); + PRINT_MACRO(__cpp_alias_templates); + + // C++98: + PRINT_MACRO(__cpp_rtti); + PRINT_MACRO(__cpp_exceptions); +} + +void print_separator() +{ + std::cout << +"\n\n*********************************************************************\n\n"; +} + +int main() +{ + + // boost compiler workaround defines + print_compiler_macros(); + print_separator(); + print_stdlib_macros(); + print_separator(); + print_platform_macros(); + print_separator(); + print_boost_macros(); + print_separator(); + print_sd6_macros(); + + return 0; +} diff --git a/libs/context/build/Jamfile.v2 b/libs/context/build/Jamfile.v2 new file mode 100644 index 0000000..a35f1c5 --- /dev/null +++ b/libs/context/build/Jamfile.v2 @@ -0,0 +1,827 @@ + +# Boost.Context Library Build Jamfile + +# Copyright Oliver Kowalke 2009. +# 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) + +import common ; +import feature ; +import indirect ; +import modules ; +import os ; +import toolset ; + import ../../config/checks/config : requires ; + +feature.feature segmented-stacks : on : optional propagated composite ; +feature.compose on : BOOST_USE_SEGMENTED_STACKS ; + +feature.feature htm : tsx : optional propagated composite ; +feature.compose tsx : BOOST_USE_TSX ; + +feature.feature valgrind : on : optional propagated composite ; +feature.compose on : BOOST_USE_VALGRIND ; + +project boost/context + : requirements + windows:_WIN32_WINNT=0x0601 + gcc,on:-fsplit-stack + gcc,on:-DBOOST_USE_SEGMENTED_STACKS + gcc,on:"-static-libgcc" + clang,on:-fsplit-stack + clang,on:-DBOOST_USE_SEGMENTED_STACKS + clang,on:"-static-libgcc" + intel,shared:BOOST_CONTEXT_EXPORT=EXPORT + intel,static:BOOST_CONTEXT_EXPORT= + msvc,shared:BOOST_CONTEXT_EXPORT=EXPORT + msvc,static:BOOST_CONTEXT_EXPORT= + clang-win,shared:BOOST_CONTEXT_EXPORT=EXPORT + clang-win,static:BOOST_CONTEXT_EXPORT= + shared:BOOST_CONTEXT_DYN_LINK=1 + BOOST_CONTEXT_SOURCE + multi + : usage-requirements + shared:BOOST_CONTEXT_DYN_LINK=1 + speed:BOOST_DISABLE_ASSERTS + release:BOOST_DISABLE_ASSERTS + : source-location ../src + ; + + +local rule default_binary_format ( ) +{ + local tmp = elf ; + if [ os.name ] = "NT" { tmp = pe ; } + else if [ os.name ] = "CYGWIN" { tmp = pe ; } + else if [ os.name ] = "AIX" { tmp = xcoff ; } + else if [ os.name ] = "MACOSX" { tmp = mach-o ; } + return $(tmp) ; +} + +feature.feature binary-format + : elf + mach-o + pe + xcoff + : propagated + ; +feature.set-default binary-format : [ default_binary_format ] ; + + +local rule default_abi ( ) +{ + local tmp = sysv ; + if [ os.name ] = "NT" { tmp = ms ; } + else if [ os.name ] = "CYGWIN" { tmp = ms ; } + else if [ os.platform ] = "ARM" { tmp = aapcs ; } + else if [ os.platform ] = "MIPS" { tmp = o32 ; } + return $(tmp) ; +} + +feature.feature abi + : aapcs + eabi + ms + n32 + n64 + o32 + o64 + sysv + x32 + : propagated + ; +feature.set-default abi : [ default_abi ] ; + + +feature.feature context-impl + : fcontext + ucontext + winfib + : propagated + composite + ; +feature.set-default context-impl : fcontext ; +feature.compose ucontext : BOOST_USE_UCONTEXT ; +feature.compose winfib : BOOST_USE_WINFIB ; + +# ARM +# ARM/AAPCS/ELF +alias asm_sources + : asm/make_arm_aapcs_elf_gas.S + asm/jump_arm_aapcs_elf_gas.S + asm/ontop_arm_aapcs_elf_gas.S + : aapcs + 32 + arm + elf + clang + ; + +alias asm_sources + : asm/make_arm_aapcs_elf_gas.S + asm/jump_arm_aapcs_elf_gas.S + asm/ontop_arm_aapcs_elf_gas.S + : aapcs + 32 + arm + elf + gcc + ; + +alias asm_sources + : asm/make_arm_aapcs_elf_gas.S + asm/jump_arm_aapcs_elf_gas.S + asm/ontop_arm_aapcs_elf_gas.S + : aapcs + 32 + arm + elf + qcc + ; + +# ARM/AAPCS/MACH-O +alias asm_sources + : asm/make_arm_aapcs_macho_gas.S + asm/jump_arm_aapcs_macho_gas.S + asm/ontop_arm_aapcs_macho_gas.S + : aapcs + 32 + arm + mach-o + clang + ; + +alias asm_sources + : asm/make_arm_aapcs_macho_gas.S + asm/jump_arm_aapcs_macho_gas.S + asm/ontop_arm_aapcs_macho_gas.S + : aapcs + 32 + arm + mach-o + darwin + ; + +# ARM/AAPCS/PE +alias asm_sources + : asm/make_arm_aapcs_pe_armasm.asm + asm/jump_arm_aapcs_pe_armasm.asm + asm/ontop_arm_aapcs_pe_armasm.asm + untested.cpp + : aapcs + 32 + arm + pe + msvc + ; + +# ARM64 +# ARM64/AAPCS/ELF +alias asm_sources + : asm/make_arm64_aapcs_elf_gas.S + asm/jump_arm64_aapcs_elf_gas.S + asm/ontop_arm64_aapcs_elf_gas.S + : aapcs + 64 + arm + elf + clang + ; + +alias asm_sources + : asm/make_arm64_aapcs_elf_gas.S + asm/jump_arm64_aapcs_elf_gas.S + asm/ontop_arm64_aapcs_elf_gas.S + : aapcs + 64 + arm + elf + gcc + ; + +# ARM64/AAPCS/MACH-O +alias asm_sources + : asm/make_arm64_aapcs_macho_gas.S + asm/jump_arm64_aapcs_macho_gas.S + asm/ontop_arm64_aapcs_macho_gas.S + : aapcs + 64 + arm + mach-o + clang + ; + +alias asm_sources + : asm/make_arm64_aapcs_macho_gas.S + asm/jump_arm64_aapcs_macho_gas.S + asm/ontop_arm64_aapcs_macho_gas.S + : aapcs + 64 + arm + mach-o + darwin + ; + +# MIPS +# MIPS32/O32/ELF +alias asm_sources + : asm/make_mips32_o32_elf_gas.S + asm/jump_mips32_o32_elf_gas.S + asm/ontop_mips32_o32_elf_gas.S + : o32 + 32 + mips1 + elf + clang + ; + +alias asm_sources + : asm/make_mips32_o32_elf_gas.S + asm/jump_mips32_o32_elf_gas.S + asm/ontop_mips32_o32_elf_gas.S + : o32 + 32 + mips1 + elf + gcc + ; + +# MIPS64/N64/ELF +alias asm_sources + : asm/make_mips64_n64_elf_gas.S + asm/jump_mips64_n64_elf_gas.S + asm/ontop_mips64_n64_elf_gas.S + : n64 + 64 + mips1 + elf + clang + ; + +alias asm_sources + : asm/make_mips64_n64_elf_gas.S + asm/jump_mips64_n64_elf_gas.S + asm/ontop_mips64_n64_elf_gas.S + : n64 + 64 + mips1 + elf + gcc + ; + +# POWERPC_32 +# POWERPC_32/SYSV/ELF +alias asm_sources + : asm/make_ppc32_sysv_elf_gas.S + asm/jump_ppc32_sysv_elf_gas.S + asm/ontop_ppc32_sysv_elf_gas.S + asm/tail_ppc32_sysv_elf_gas.cpp + : sysv + 32 + power + elf + clang + ; + +alias asm_sources + : asm/make_ppc32_sysv_elf_gas.S + asm/jump_ppc32_sysv_elf_gas.S + asm/ontop_ppc32_sysv_elf_gas.S + asm/tail_ppc32_sysv_elf_gas.cpp + : sysv + 32 + power + elf + gcc + ; + +alias asm_sources + : asm/make_ppc32_sysv_macho_gas.S + asm/jump_ppc32_sysv_macho_gas.S + asm/ontop_ppc32_sysv_macho_gas.S + : sysv + 32 + power + mach-o + darwin + ; + +#POWERPC_32/SYSV/XCOFF +alias asm_sources + : asm/make_ppc32_sysv_xcoff_gas.S + asm/jump_ppc32_sysv_xcoff_gas.S + asm/ontop_ppc32_sysv_xcoff_gas.S + : sysv + 32 + power + xcoff + clang + ; + +alias asm_sources + : asm/make_ppc32_sysv_xcoff_gas.S + asm/jump_ppc32_sysv_xcoff_gas.S + asm/ontop_ppc32_sysv_xcoff_gas.S + : sysv + 32 + power + xcoff + gcc + ; + +# POWERPC_64 +# POWERPC_64/SYSV/ELF +alias asm_sources + : asm/make_ppc64_sysv_elf_gas.S + asm/jump_ppc64_sysv_elf_gas.S + asm/ontop_ppc64_sysv_elf_gas.S + : sysv + 64 + power + elf + clang + ; + +alias asm_sources + : asm/make_ppc64_sysv_elf_gas.S + asm/jump_ppc64_sysv_elf_gas.S + asm/ontop_ppc64_sysv_elf_gas.S + : sysv + 64 + power + elf + gcc + ; + +# POWERPC_64/SYSV/MACH-O +alias asm_sources + : asm/make_ppc64_sysv_macho_gas.S + asm/jump_ppc64_sysv_macho_gas.S + asm/ontop_ppc64_sysv_macho_gas.S + untested.cpp + : sysv + 64 + power + mach-o + clang + ; + +alias asm_sources + : asm/make_ppc64_sysv_macho_gas.S + asm/jump_ppc64_sysv_macho_gas.S + asm/ontop_ppc64_sysv_macho_gas.S + untested.cpp + : sysv + 64 + power + mach-o + darwin + ; + +# POWERPC_64/SYSV/XCOFF +alias asm_sources + : asm/make_ppc64_sysv_xcoff_gas.S + asm/jump_ppc64_sysv_xcoff_gas.S + asm/ontop_ppc64_sysv_xcoff_gas.S + : sysv + 64 + power + xcoff + clang + ; + +alias asm_sources + : asm/make_ppc64_sysv_xcoff_gas.S + asm/jump_ppc64_sysv_xcoff_gas.S + asm/ontop_ppc64_sysv_xcoff_gas.S + : sysv + 64 + power + xcoff + gcc + ; + +# POWERPC universal +# POWERPC_32_64/SYSV/MACH-O +alias asm_sources + : asm/make_ppc32_ppc64_sysv_macho_gas.S + asm/jump_ppc32_ppc64_sysv_macho_gas.S + asm/ontop_ppc32_ppc64_sysv_macho_gas.S + : sysv + 32_64 + power + mach-o + ; + +# RISCV64 +# RISCV64/SYSV/ELF +alias asm_sources + : asm/make_riscv64_sysv_elf_gas.S + asm/jump_riscv64_sysv_elf_gas.S + asm/ontop_riscv64_sysv_elf_gas.S + : sysv + 64 + riscv + elf + gcc + ; + +# S390X +# S390X/SYSV/ELF +alias asm_sources + : asm/make_s390x_sysv_elf_gas.S + asm/jump_s390x_sysv_elf_gas.S + asm/ontop_s390x_sysv_elf_gas.S + : sysv + 64 + s390x + elf + gcc + ; + +# X86 +# X86/SYSV/ELF +alias asm_sources + : asm/make_i386_sysv_elf_gas.S + asm/jump_i386_sysv_elf_gas.S + asm/ontop_i386_sysv_elf_gas.S + : sysv + 32 + x86 + elf + clang + ; + +alias asm_sources + : asm/make_i386_sysv_elf_gas.S + asm/jump_i386_sysv_elf_gas.S + asm/ontop_i386_sysv_elf_gas.S + : sysv + 32 + x86 + elf + gcc + ; + +alias asm_sources + : asm/make_i386_sysv_elf_gas.S + asm/jump_i386_sysv_elf_gas.S + asm/ontop_i386_sysv_elf_gas.S + : sysv + 32 + x86 + elf + intel + ; + +# X86/SYSV/MACH-O +alias asm_sources + : asm/make_i386_sysv_macho_gas.S + asm/jump_i386_sysv_macho_gas.S + asm/ontop_i386_sysv_macho_gas.S + : sysv + 32 + x86 + mach-o + clang + ; + +alias asm_sources + : asm/make_i386_sysv_macho_gas.S + asm/jump_i386_sysv_macho_gas.S + asm/ontop_i386_sysv_macho_gas.S + : sysv + 32 + x86 + mach-o + darwin + ; + +# X86/MS/PE +alias asm_sources + : asm/make_i386_ms_pe_gas.asm + asm/jump_i386_ms_pe_gas.asm + asm/ontop_i386_ms_pe_gas.asm + dummy.cpp + : ms + 32 + x86 + pe + clang + ; + +alias asm_sources + : asm/make_i386_ms_pe_masm.asm + asm/jump_i386_ms_pe_masm.asm + asm/ontop_i386_ms_pe_masm.asm + dummy.cpp + : ms + 32 + x86 + pe + clang-win + ; + +alias asm_sources + : asm/make_i386_ms_pe_gas.asm + asm/jump_i386_ms_pe_gas.asm + asm/ontop_i386_ms_pe_gas.asm + dummy.cpp + : ms + 32 + x86 + pe + gcc + ; + +alias asm_sources + : asm/make_i386_ms_pe_masm.asm + asm/jump_i386_ms_pe_masm.asm + asm/ontop_i386_ms_pe_masm.asm + dummy.cpp + : ms + 32 + x86 + pe + intel + ; + +alias asm_sources + : asm/make_i386_ms_pe_masm.asm + asm/jump_i386_ms_pe_masm.asm + asm/ontop_i386_ms_pe_masm.asm + dummy.cpp + : ms + 32 + x86 + pe + msvc + ; + +# X86_64 +# X86_64/SYSV/ELF +alias asm_sources + : asm/make_x86_64_sysv_elf_gas.S + asm/jump_x86_64_sysv_elf_gas.S + asm/ontop_x86_64_sysv_elf_gas.S + : sysv + 64 + x86 + elf + clang + ; + +alias asm_sources + : asm/make_x86_64_sysv_elf_gas.S + asm/jump_x86_64_sysv_elf_gas.S + asm/ontop_x86_64_sysv_elf_gas.S + : sysv + 64 + x86 + elf + gcc + ; + +alias asm_sources + : asm/make_x86_64_sysv_elf_gas.S + asm/jump_x86_64_sysv_elf_gas.S + asm/ontop_x86_64_sysv_elf_gas.S + : sysv + 64 + x86 + elf + intel + ; + +# X86_64/SYSV/MACH-O +alias asm_sources + : asm/make_x86_64_sysv_macho_gas.S + asm/jump_x86_64_sysv_macho_gas.S + asm/ontop_x86_64_sysv_macho_gas.S + : sysv + 64 + x86 + mach-o + clang + ; + +alias asm_sources + : asm/make_x86_64_sysv_macho_gas.S + asm/jump_x86_64_sysv_macho_gas.S + asm/ontop_x86_64_sysv_macho_gas.S + : sysv + 64 + x86 + mach-o + darwin + ; + +alias asm_sources + : asm/make_x86_64_sysv_macho_gas.S + asm/jump_x86_64_sysv_macho_gas.S + asm/ontop_x86_64_sysv_macho_gas.S + : sysv + 64 + x86 + mach-o + intel + ; + +# X86_64/MS/PE +alias asm_sources + : asm/make_x86_64_ms_pe_gas.asm + asm/jump_x86_64_ms_pe_gas.asm + asm/ontop_x86_64_ms_pe_gas.asm + dummy.cpp + : ms + 64 + x86 + pe + clang + ; + +alias asm_sources + : asm/make_x86_64_ms_pe_masm.asm + asm/jump_x86_64_ms_pe_masm.asm + asm/ontop_x86_64_ms_pe_masm.asm + dummy.cpp + : ms + 64 + x86 + pe + clang-win + ; + +alias asm_sources + : asm/make_x86_64_ms_pe_gas.asm + asm/jump_x86_64_ms_pe_gas.asm + asm/ontop_x86_64_ms_pe_gas.asm + dummy.cpp + : ms + 64 + x86 + pe + gcc + ; + +alias asm_sources + : asm/make_x86_64_ms_pe_masm.asm + asm/jump_x86_64_ms_pe_masm.asm + asm/ontop_x86_64_ms_pe_masm.asm + dummy.cpp + : ms + 64 + x86 + pe + intel + ; + +alias asm_sources + : asm/make_x86_64_ms_pe_masm.asm + asm/jump_x86_64_ms_pe_masm.asm + asm/ontop_x86_64_ms_pe_masm.asm + dummy.cpp + : ms + 64 + x86 + pe + msvc + ; + +# X86_64/SYSV/X32 +alias asm_sources + : asm/make_x86_64_sysv_elf_gas.S + asm/jump_x86_64_sysv_elf_gas.S + asm/ontop_x86_64_sysv_elf_gas.S + : x32 + 64 + x86 + elf + clang + ; + +alias asm_sources + : asm/make_x86_64_sysv_elf_gas.S + asm/jump_x86_64_sysv_elf_gas.S + asm/ontop_x86_64_sysv_elf_gas.S + : x32 + 64 + x86 + elf + gcc + ; + +alias asm_sources + : asm/make_x86_64_sysv_elf_gas.S + asm/jump_x86_64_sysv_elf_gas.S + asm/ontop_x86_64_sysv_elf_gas.S + : x32 + 64 + x86 + elf + intel + ; + +#X86 universal +alias asm_sources + : asm/make_i386_x86_64_sysv_macho_gas.S + asm/jump_i386_x86_64_sysv_macho_gas.S + asm/ontop_i386_x86_64_sysv_macho_gas.S + : sysv + 32_64 + x86 + mach-o + ; + +# COMBINED +alias asm_sources + : asm/make_combined_sysv_macho_gas.S + asm/jump_combined_sysv_macho_gas.S + asm/ontop_combined_sysv_macho_gas.S + : sysv + combined + mach-o + ; + +explicit asm_sources ; + + +# fcontext_t +alias impl_sources + : asm_sources + : fcontext + ; + +# ucontext_t +alias impl_sources + : continuation.cpp + fiber.cpp + : ucontext + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + ; + +# WinFiber +alias impl_sources + : continuation.cpp + fiber.cpp + : winfib + [ requires cxx11_auto_declarations + cxx11_constexpr + cxx11_defaulted_functions + cxx11_final + cxx11_hdr_thread + cxx11_hdr_tuple + cxx11_lambdas + cxx11_noexcept + cxx11_nullptr + cxx11_rvalue_references + cxx11_template_aliases + cxx11_thread_local + cxx11_variadic_templates ] + ; + +explicit impl_sources ; + +obj cxx11_hdr_mutex_check : ../build/cxx11_hdr_mutex.cpp ; +explicit cxx11_hdr_mutex_check ; +local cxx11_mutex = [ check-target-builds + cxx11_hdr_mutex_check "C++11 mutex" + : + : /boost/thread//boost_thread + ] ; + +alias stack_traits_sources + : windows/stack_traits.cpp + : windows + : + : $(cxx11_mutex) + ; + +alias stack_traits_sources + : posix/stack_traits.cpp + : + : + : $(cxx11_mutex) + ; + +explicit stack_traits_sources ; + +lib boost_context + : impl_sources + stack_traits_sources + ; + +boost-install boost_context ; diff --git a/libs/context/build/architecture.jam b/libs/context/build/architecture.jam new file mode 100644 index 0000000..e00e61e --- /dev/null +++ b/libs/context/build/architecture.jam @@ -0,0 +1,92 @@ +# architecture.jam +# +# Copyright 2012 Steven Watanabe +# +# 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) + +import configure ; +import project ; +import path ; +import property ; + +local here = [ modules.binding $(__name__) ] ; + +project.push-current [ project.current ] ; +project.load [ path.join [ path.make $(here:D) ] ../config ] ; +project.pop-current ; + +rule deduce-address-model ( properties * ) +{ + local result = [ property.select : $(properties) ] ; + if $(result) + { + return $(result) ; + } + else + { + if [ configure.builds /boost/architecture//32 : $(properties) : 32-bit ] + { + return 32 ; + } + else if [ configure.builds /boost/architecture//64 : $(properties) : 64-bit ] + { + return 64 ; + } + } +} + +rule address-model ( ) +{ + return @architecture.deduce-address-model ; +} + +rule deduce-architecture ( properties * ) +{ + local result = [ property.select : $(properties) ] ; + if $(result) + { + return $(result) ; + } + else + { + if [ configure.builds /boost/architecture//arm : $(properties) : arm ] + { + return arm ; + } + else if [ configure.builds /boost/architecture//mips1 : $(properties) : mips1 ] + { + return mips1 ; + } + else if [ configure.builds /boost/architecture//power : $(properties) : power ] + { + return power ; + } + else if [ configure.builds /boost/architecture//riscv : $(properties) : riscv ] + { + return riscv ; + } + else if [ configure.builds /boost/architecture//s390x : $(properties) : s390x ] + { + return s390x ; + } + else if [ configure.builds /boost/architecture//sparc : $(properties) : sparc ] + { + return sparc ; + } + else if [ configure.builds /boost/architecture//x86 : $(properties) : x86 ] + { + return x86 ; + } + else if [ configure.builds /boost/architecture//combined : $(properties) : combined ] + { + return combined ; + } + } +} + +rule architecture ( ) +{ + return @architecture.deduce-architecture ; +} diff --git a/libs/context/build/cxx11_hdr_mutex.cpp b/libs/context/build/cxx11_hdr_mutex.cpp new file mode 100644 index 0000000..d16a7a1 --- /dev/null +++ b/libs/context/build/cxx11_hdr_mutex.cpp @@ -0,0 +1,10 @@ +// Copyright Kohei Takahashi 2016. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#ifdef BOOST_NO_CXX11_HDR_MUTEX +#error "C++11 is not available." +#endif diff --git a/libs/context/src/asm/jump_arm64_aapcs_elf_gas.S b/libs/context/src/asm/jump_arm64_aapcs_elf_gas.S new file mode 100644 index 0000000..cefd183 --- /dev/null +++ b/libs/context/src/asm/jump_arm64_aapcs_elf_gas.S @@ -0,0 +1,114 @@ +/* + Copyright Edward Nevill + Oliver Kowalke 2015 + 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) +*/ +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | d8 | d9 | d10 | d11 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | d12 | d13 | d14 | d15 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| * + * ------------------------------------------------- * + * | x19 | x20 | x21 | x22 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| * + * ------------------------------------------------- * + * | x23 | x24 | x25 | x26 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| * + * ------------------------------------------------- * + * | x27 | x28 | FP | LR | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | | | * + * ------------------------------------------------- * + * | 0xa0| 0xa4| 0xa8| 0xac| | | * + * ------------------------------------------------- * + * | PC | align | | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.file "jump_arm64_aapcs_elf_gas.S" +.text +.align 2 +.global jump_fcontext +.type jump_fcontext, %function +jump_fcontext: + # prepare stack for GP + FPU + sub sp, sp, #0xb0 + + # save d8 - d15 + stp d8, d9, [sp, #0x00] + stp d10, d11, [sp, #0x10] + stp d12, d13, [sp, #0x20] + stp d14, d15, [sp, #0x30] + + # save x19-x30 + stp x19, x20, [sp, #0x40] + stp x21, x22, [sp, #0x50] + stp x23, x24, [sp, #0x60] + stp x25, x26, [sp, #0x70] + stp x27, x28, [sp, #0x80] + stp x29, x30, [sp, #0x90] + + # save LR as PC + str x30, [sp, #0xa0] + + # store RSP (pointing to context-data) in X0 + mov x4, sp + + # restore RSP (pointing to context-data) from X1 + mov sp, x0 + + # load d8 - d15 + ldp d8, d9, [sp, #0x00] + ldp d10, d11, [sp, #0x10] + ldp d12, d13, [sp, #0x20] + ldp d14, d15, [sp, #0x30] + + # load x19-x30 + ldp x19, x20, [sp, #0x40] + ldp x21, x22, [sp, #0x50] + ldp x23, x24, [sp, #0x60] + ldp x25, x26, [sp, #0x70] + ldp x27, x28, [sp, #0x80] + ldp x29, x30, [sp, #0x90] + + # return transfer_t from jump + # pass transfer_t as first arg in context function + # X0 == FCTX, X1 == DATA + mov x0, x4 + + # load pc + ldr x4, [sp, #0xa0] + + # restore stack from GP + FPU + add sp, sp, #0xb0 + + ret x4 +.size jump_fcontext,.-jump_fcontext +# Mark that we don't need executable stack. +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/jump_arm64_aapcs_macho_gas.S b/libs/context/src/asm/jump_arm64_aapcs_macho_gas.S new file mode 100644 index 0000000..31738f7 --- /dev/null +++ b/libs/context/src/asm/jump_arm64_aapcs_macho_gas.S @@ -0,0 +1,109 @@ +/* + Copyright Edward Nevill + Oliver Kowalke 2015 + 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) +*/ +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | d8 | d9 | d10 | d11 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | d12 | d13 | d14 | d15 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| * + * ------------------------------------------------- * + * | x19 | x20 | x21 | x22 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| * + * ------------------------------------------------- * + * | x23 | x24 | x25 | x26 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| * + * ------------------------------------------------- * + * | x27 | x28 | FP | LR | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | | | * + * ------------------------------------------------- * + * | 0xa0| 0xa4| 0xa8| 0xac| | | * + * ------------------------------------------------- * + * | PC | align | | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.text +.globl _jump_fcontext +.balign 16 +_jump_fcontext: + ; prepare stack for GP + FPU + sub sp, sp, #0xb0 + + ; save d8 - d15 + stp d8, d9, [sp, #0x00] + stp d10, d11, [sp, #0x10] + stp d12, d13, [sp, #0x20] + stp d14, d15, [sp, #0x30] + + ; save x19-x30 + stp x19, x20, [sp, #0x40] + stp x21, x22, [sp, #0x50] + stp x23, x24, [sp, #0x60] + stp x25, x26, [sp, #0x70] + stp x27, x28, [sp, #0x80] + stp fp, lr, [sp, #0x90] + + ; save LR as PC + str lr, [sp, #0xa0] + + ; store RSP (pointing to context-data) in X0 + mov x4, sp + + ; restore RSP (pointing to context-data) from X1 + mov sp, x0 + + ; load d8 - d15 + ldp d8, d9, [sp, #0x00] + ldp d10, d11, [sp, #0x10] + ldp d12, d13, [sp, #0x20] + ldp d14, d15, [sp, #0x30] + + ; load x19-x30 + ldp x19, x20, [sp, #0x40] + ldp x21, x22, [sp, #0x50] + ldp x23, x24, [sp, #0x60] + ldp x25, x26, [sp, #0x70] + ldp x27, x28, [sp, #0x80] + ldp fp, lr, [sp, #0x90] + + ; return transfer_t from jump + ; pass transfer_t as first arg in context function + ; X0 == FCTX, X1 == DATA + mov x0, x4 + + ; load pc + ldr x4, [sp, #0xa0] + + ; restore stack from GP + FPU + add sp, sp, #0xb0 + + ret x4 diff --git a/libs/context/src/asm/jump_arm_aapcs_elf_gas.S b/libs/context/src/asm/jump_arm_aapcs_elf_gas.S new file mode 100644 index 0000000..86efe9d --- /dev/null +++ b/libs/context/src/asm/jump_arm_aapcs_elf_gas.S @@ -0,0 +1,88 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | s16 | s17 | s18 | s19 | s20 | s21 | s22 | s23 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | s24 | s25 | s26 | s27 | s28 | s29 | s30 | s31 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| * + * ------------------------------------------------- * + * |hiddn| v1 | v2 | v3 | v4 | v5 | v6 | v7 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| * + * ------------------------------------------------- * + * | v8 | lr | pc | FCTX| DATA| | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.file "jump_arm_aapcs_elf_gas.S" +.text +.globl jump_fcontext +.align 2 +.type jump_fcontext,%function +.syntax unified +jump_fcontext: + @ save LR as PC + push {lr} + @ save hidden,V1-V8,LR + push {a1,v1-v8,lr} + + @ prepare stack for FPU + sub sp, sp, #64 +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + @ save S16-S31 + vstmia sp, {d8-d15} +#endif + + @ store RSP (pointing to context-data) in A1 + mov a1, sp + + @ restore RSP (pointing to context-data) from A2 + mov sp, a2 + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + @ restore S16-S31 + vldmia sp, {d8-d15} +#endif + @ prepare stack for FPU + add sp, sp, #64 + + @ restore hidden,V1-V8,LR + pop {a4,v1-v8,lr} + + @ return transfer_t from jump + str a1, [a4, #0] + str a3, [a4, #4] + @ pass transfer_t as first arg in context function + @ A1 == FCTX, A2 == DATA + mov a2, a3 + + @ restore PC + pop {pc} +.size jump_fcontext,.-jump_fcontext + +@ Mark that we don't need executable stack. +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/jump_arm_aapcs_macho_gas.S b/libs/context/src/asm/jump_arm_aapcs_macho_gas.S new file mode 100644 index 0000000..8edd0d7 --- /dev/null +++ b/libs/context/src/asm/jump_arm_aapcs_macho_gas.S @@ -0,0 +1,95 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | s16 | s17 | s18 | s19 | s20 | s21 | s22 | s23 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | s24 | s25 | s26 | s27 | s28 | s29 | s30 | s31 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | sjlj|hiddn| v1 | v2 | v3 | v4 | v5 | v6 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | v7 | v8 | lr | pc | FCTX| DATA| | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.text +.globl _jump_fcontext +.align 2 +_jump_fcontext: + @ save LR as PC + push {lr} + @ save hidden,V1-V8,LR + push {a1,v1-v8,lr} + + @ locate TLS to save/restore SjLj handler + mrc p15, 0, v2, c13, c0, #3 + bic v2, v2, #3 + + @ load TLS[__PTK_LIBC_DYLD_Unwind_SjLj_Key] + ldr v1, [v2, #8] + @ save SjLj handler + push {v1} + + @ prepare stack for FPU + sub sp, sp, #64 +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + @ save S16-S31 + vstmia sp, {d8-d15} +#endif + + @ store RSP (pointing to context-data) in A1 + mov a1, sp + + @ restore RSP (pointing to context-data) from A2 + mov sp, a2 + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + @ restore S16-S31 + vldmia sp, {d8-d15} +#endif + @ prepare stack for FPU + add sp, sp, #64 + + @ r#estore SjLj handler + pop {v1} + @ store SjLj handler in TLS + str v1, [v2, #8] + + @ restore hidden,V1-V8,LR + pop {a4,v1-v8,lr} + + @ return transfer_t from jump + str a1, [a4, #0] + str a3, [a4, #4] + @ pass transfer_t as first arg in context function + @ A1 == FCTX, A2 == DATA + mov a2, a3 + + @ restore PC + pop {pc} diff --git a/libs/context/src/asm/jump_arm_aapcs_pe_armasm.asm b/libs/context/src/asm/jump_arm_aapcs_pe_armasm.asm new file mode 100644 index 0000000..bca923c --- /dev/null +++ b/libs/context/src/asm/jump_arm_aapcs_pe_armasm.asm @@ -0,0 +1,81 @@ +;/* +; Copyright Oliver Kowalke 2009. +; 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) +;*/ + +; ******************************************************* +; * * +; * ------------------------------------------------- * +; * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * +; * ------------------------------------------------- * +; * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * +; * ------------------------------------------------- * +; * |deall|limit| base|hiddn| v1 | v2 | v3 | v4 | * +; * ------------------------------------------------- * +; * ------------------------------------------------- * +; * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * +; * ------------------------------------------------- * +; * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * +; * ------------------------------------------------- * +; * | v5 | v6 | v7 | v8 | lr | pc | FCTX| DATA| * +; * ------------------------------------------------- * +; * * +; ******************************************************* + + AREA |.text|, CODE + ALIGN 4 + EXPORT jump_fcontext + +jump_fcontext PROC + ; save LR as PC + push {lr} + ; save hidden,V1-V8,LR + push {a1,v1-v8,lr} + + ; load TIB to save/restore thread size and limit. + ; we do not need preserve CPU flag and can use it's arg register + mrc p15, #0, v1, c13, c0, #2 + + ; save current stack base + ldr a5, [v1, #0x04] + push {a5} + ; save current stack limit + ldr a5, [v1, #0x08] + push {a5} + ; save current deallocation stack + ldr a5, [v1, #0xe0c] + push {a5} + + ; store RSP (pointing to context-data) in A1 + mov a1, sp + + ; restore RSP (pointing to context-data) from A2 + mov sp, a2 + + ; restore deallocation stack + pop {a5} + str a5, [v1, #0xe0c] + ; restore stack limit + pop {a5} + str a5, [v1, #0x08] + ; restore stack base + pop {a5} + str a5, [v1, #0x04] + + ; restore hidden,V1-V8,LR + pop {a4,v1-v8,lr} + + ; return transfer_t from jump + str a1, [a4, #0] + str a3, [a4, #4] + ; pass transfer_t as first arg in context function + ; A1 == FCTX, A2 == DATA + mov a2, a3 + + ; restore PC + pop {pc} + + ENDP + END diff --git a/libs/context/src/asm/jump_combined_sysv_macho_gas.S b/libs/context/src/asm/jump_combined_sysv_macho_gas.S new file mode 100644 index 0000000..1d27afa --- /dev/null +++ b/libs/context/src/asm/jump_combined_sysv_macho_gas.S @@ -0,0 +1,20 @@ +/* + Copyright Sergue E. Leontiev 2013. + 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) +*/ + +// Stub file for universal binary + +#if defined(__i386__) + #include "jump_i386_sysv_macho_gas.S" +#elif defined(__x86_64__) + #include "jump_x86_64_sysv_macho_gas.S" +#elif defined(__ppc__) + #include "jump_ppc32_sysv_macho_gas.S" +#elif defined(__ppc64__) + #include "jump_ppc64_sysv_macho_gas.S" +#else + #error "No arch's" +#endif diff --git a/libs/context/src/asm/jump_i386_ms_pe_gas.asm b/libs/context/src/asm/jump_i386_ms_pe_gas.asm new file mode 100644 index 0000000..8512a3d --- /dev/null +++ b/libs/context/src/asm/jump_i386_ms_pe_gas.asm @@ -0,0 +1,117 @@ +/* + Copyright Oliver Kowalke 2009. + Copyright Thomas Sailer 2013. + 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) +*/ + +/************************************************************************************* +* --------------------------------------------------------------------------------- * +* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * +* --------------------------------------------------------------------------------- * +* | 0h | 04h | 08h | 0ch | 010h | 014h | 018h | 01ch | * +* --------------------------------------------------------------------------------- * +* | fc_mxcsr|fc_x87_cw| fc_strg |fc_deallo| limit | base | fc_seh | EDI | * +* --------------------------------------------------------------------------------- * +* --------------------------------------------------------------------------------- * +* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * +* --------------------------------------------------------------------------------- * +* | 020h | 024h | 028h | 02ch | 030h | 034h | 038h | 03ch | * +* --------------------------------------------------------------------------------- * +* | ESI | EBX | EBP | EIP | to | data | EH NXT |SEH HNDLR| * +* --------------------------------------------------------------------------------- * +**************************************************************************************/ + +.file "jump_i386_ms_pe_gas.asm" +.text +.p2align 4,,15 +.globl _jump_fcontext +.def _jump_fcontext; .scl 2; .type 32; .endef +_jump_fcontext: + /* prepare stack */ + leal -0x2c(%esp), %esp + +#if !defined(BOOST_USE_TSX) + /* save MMX control- and status-word */ + stmxcsr (%esp) + /* save x87 control-word */ + fnstcw 0x4(%esp) +#endif + + /* load NT_TIB */ + movl %fs:(0x18), %edx + /* load fiber local storage */ + movl 0x10(%edx), %eax + movl %eax, 0x8(%esp) + /* load current dealloction stack */ + movl 0xe0c(%edx), %eax + movl %eax, 0xc(%esp) + /* load current stack limit */ + movl 0x8(%edx), %eax + movl %eax, 0x10(%esp) + /* load current stack base */ + movl 0x4(%edx), %eax + movl %eax, 0x14(%esp) + /* load current SEH exception list */ + movl (%edx), %eax + movl %eax, 0x18(%esp) + + movl %edi, 0x1c(%esp) /* save EDI */ + movl %esi, 0x20(%esp) /* save ESI */ + movl %ebx, 0x24(%esp) /* save EBX */ + movl %ebp, 0x28(%esp) /* save EBP */ + + /* store ESP (pointing to context-data) in EAX */ + movl %esp, %eax + + /* firstarg of jump_fcontext() == fcontext to jump to */ + movl 0x30(%esp), %ecx + + /* restore ESP (pointing to context-data) from ECX */ + movl %ecx, %esp + +#if !defined(BOOST_USE_TSX) + /* restore MMX control- and status-word */ + ldmxcsr (%esp) + /* restore x87 control-word */ + fldcw 0x4(%esp) +#endif + + /* restore NT_TIB into EDX */ + movl %fs:(0x18), %edx + /* restore fiber local storage */ + movl 0x8(%esp), %ecx + movl %ecx, 0x10(%edx) + /* restore current deallocation stack */ + movl 0xc(%esp), %ecx + movl %ecx, 0xe0c(%edx) + /* restore current stack limit */ + movl 0x10(%esp), %ecx + movl %ecx, 0x8(%edx) + /* restore current stack base */ + movl 0x14(%esp), %ecx + movl %ecx, 0x4(%edx) + /* restore current SEH exception list */ + movl 0x18(%esp), %ecx + movl %ecx, (%edx) + + movl 0x2c(%esp), %ecx /* restore EIP */ + + movl 0x1c(%esp), %edi /* restore EDI */ + movl 0x20(%esp), %esi /* restore ESI */ + movl 0x24(%esp), %ebx /* restore EBX */ + movl 0x28(%esp), %ebp /* restore EBP */ + + /* prepare stack */ + leal 0x30(%esp), %esp + + /* return transfer_t */ + /* FCTX == EAX, DATA == EDX */ + movl 0x34(%eax), %edx + + /* jump to context */ + jmp *%ecx + +.section .drectve +.ascii " -export:\"jump_fcontext\"" diff --git a/libs/context/src/asm/jump_i386_ms_pe_masm.asm b/libs/context/src/asm/jump_i386_ms_pe_masm.asm new file mode 100644 index 0000000..7a9e848 --- /dev/null +++ b/libs/context/src/asm/jump_i386_ms_pe_masm.asm @@ -0,0 +1,116 @@ + +; Copyright Oliver Kowalke 2009. +; 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) + +; --------------------------------------------------------------------------------- +; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | +; --------------------------------------------------------------------------------- +; | 0h | 04h | 08h | 0ch | 010h | 014h | 018h | 01ch | +; --------------------------------------------------------------------------------- +; | fc_mxcsr|fc_x87_cw| fc_strg |fc_deallo| limit | base | fc_seh | EDI | +; --------------------------------------------------------------------------------- +; --------------------------------------------------------------------------------- +; | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | +; --------------------------------------------------------------------------------- +; | 020h | 024h | 028h | 02ch | 030h | 034h | 038h | 03ch | +; --------------------------------------------------------------------------------- +; | ESI | EBX | EBP | EIP | to | data | EH NXT |SEH HNDLR| +; --------------------------------------------------------------------------------- + +.386 +.XMM +.model flat, c +.code + +jump_fcontext PROC BOOST_CONTEXT_EXPORT + ; prepare stack + lea esp, [esp-02ch] + +IFNDEF BOOST_USE_TSX + ; save MMX control- and status-word + stmxcsr [esp] + ; save x87 control-word + fnstcw [esp+04h] +ENDIF + + assume fs:nothing + ; load NT_TIB into ECX + mov edx, fs:[018h] + assume fs:error + ; load fiber local storage + mov eax, [edx+010h] + mov [esp+08h], eax + ; load current deallocation stack + mov eax, [edx+0e0ch] + mov [esp+0ch], eax + ; load current stack limit + mov eax, [edx+08h] + mov [esp+010h], eax + ; load current stack base + mov eax, [edx+04h] + mov [esp+014h], eax + ; load current SEH exception list + mov eax, [edx] + mov [esp+018h], eax + + mov [esp+01ch], edi ; save EDI + mov [esp+020h], esi ; save ESI + mov [esp+024h], ebx ; save EBX + mov [esp+028h], ebp ; save EBP + + ; store ESP (pointing to context-data) in EAX + mov eax, esp + + ; firstarg of jump_fcontext() == fcontext to jump to + mov ecx, [esp+030h] + + ; restore ESP (pointing to context-data) from ECX + mov esp, ecx + +IFNDEF BOOST_USE_TSX + ; restore MMX control- and status-word + ldmxcsr [esp] + ; restore x87 control-word + fldcw [esp+04h] +ENDIF + + assume fs:nothing + ; load NT_TIB into EDX + mov edx, fs:[018h] + assume fs:error + ; restore fiber local storage + mov ecx, [esp+08h] + mov [edx+010h], ecx + ; restore current deallocation stack + mov ecx, [esp+0ch] + mov [edx+0e0ch], ecx + ; restore current stack limit + mov ecx, [esp+010h] + mov [edx+08h], ecx + ; restore current stack base + mov ecx, [esp+014h] + mov [edx+04h], ecx + ; restore current SEH exception list + mov ecx, [esp+018h] + mov [edx], ecx + + mov ecx, [esp+02ch] ; restore EIP + + mov edi, [esp+01ch] ; restore EDI + mov esi, [esp+020h] ; restore ESI + mov ebx, [esp+024h] ; restore EBX + mov ebp, [esp+028h] ; restore EBP + + ; prepare stack + lea esp, [esp+030h] + + ; return transfer_t + ; FCTX == EAX, DATA == EDX + mov edx, [eax+034h] + + ; jump to context + jmp ecx +jump_fcontext ENDP +END diff --git a/libs/context/src/asm/jump_i386_sysv_elf_gas.S b/libs/context/src/asm/jump_i386_sysv_elf_gas.S new file mode 100644 index 0000000..b96d4b5 --- /dev/null +++ b/libs/context/src/asm/jump_i386_sysv_elf_gas.S @@ -0,0 +1,83 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| EDI | ESI | EBX | EBP | EIP | hidden | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | 0x24 | | * + * ---------------------------------------------------------------------------------- * + * | to | data | | * + * ---------------------------------------------------------------------------------- * + * * + ****************************************************************************************/ + +.file "jump_i386_sysv_elf_gas.S" +.text +.globl jump_fcontext +.align 2 +.type jump_fcontext,@function +jump_fcontext: + leal -0x18(%esp), %esp /* prepare stack */ + +#if !defined(BOOST_USE_TSX) + stmxcsr (%esp) /* save MMX control- and status-word */ + fnstcw 0x4(%esp) /* save x87 control-word */ +#endif + + movl %edi, 0x8(%esp) /* save EDI */ + movl %esi, 0xc(%esp) /* save ESI */ + movl %ebx, 0x10(%esp) /* save EBX */ + movl %ebp, 0x14(%esp) /* save EBP */ + + /* store ESP (pointing to context-data) in ECX */ + movl %esp, %ecx + + /* first arg of jump_fcontext() == fcontext to jump to */ + movl 0x20(%esp), %eax + + /* second arg of jump_fcontext() == data to be transferred */ + movl 0x24(%esp), %edx + + /* restore ESP (pointing to context-data) from EAX */ + movl %eax, %esp + + /* address of returned transport_t */ + movl 0x1c(%esp), %eax + /* return parent fcontext_t */ + movl %ecx, (%eax) + /* return data */ + movl %edx, 0x4(%eax) + + movl 0x18(%esp), %ecx /* restore EIP */ + +#if !defined(BOOST_USE_TSX) + ldmxcsr (%esp) /* restore MMX control- and status-word */ + fldcw 0x4(%esp) /* restore x87 control-word */ +#endif + + movl 0x8(%esp), %edi /* restore EDI */ + movl 0xc(%esp), %esi /* restore ESI */ + movl 0x10(%esp), %ebx /* restore EBX */ + movl 0x14(%esp), %ebp /* restore EBP */ + + leal 0x20(%esp), %esp /* prepare stack */ + + /* jump to context */ + jmp *%ecx +.size jump_fcontext,.-jump_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/jump_i386_sysv_macho_gas.S b/libs/context/src/asm/jump_i386_sysv_macho_gas.S new file mode 100644 index 0000000..8ab7c6f --- /dev/null +++ b/libs/context/src/asm/jump_i386_sysv_macho_gas.S @@ -0,0 +1,74 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| EDI | ESI | EBX | EBP | EIP | to | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | | * + * ---------------------------------------------------------------------------------- * + * | data | | * + * ---------------------------------------------------------------------------------- * + * * + ****************************************************************************************/ + +.text +.globl _jump_fcontext +.align 2 +_jump_fcontext: + leal -0x18(%esp), %esp /* prepare stack */ + +#if !defined(BOOST_USE_TSX) + stmxcsr (%esp) /* save MMX control- and status-word */ + fnstcw 0x4(%esp) /* save x87 control-word */ +#endif + + movl %edi, 0x8(%esp) /* save EDI */ + movl %esi, 0xc(%esp) /* save ESI */ + movl %ebx, 0x10(%esp) /* save EBX */ + movl %ebp, 0x14(%esp) /* save EBP */ + + /* store ESP (pointing to context-data) in ECX */ + movl %esp, %ecx + + /* first arg of jump_fcontext() == fcontext to jump to */ + movl 0x1c(%esp), %eax + + /* second arg of jump_fcontext() == data to be transferred */ + movl 0x20(%esp), %edx + + /* restore ESP (pointing to context-data) from EAX */ + movl %eax, %esp + + /* return parent fcontext_t */ + movl %ecx, %eax + /* returned data is stored in EDX */ + + movl 0x18(%esp), %ecx /* restore EIP */ + +#if !defined(BOOST_USE_TSX) + ldmxcsr (%esp) /* restore MMX control- and status-word */ + fldcw 0x4(%esp) /* restore x87 control-word */ +#endif + + movl 0x8(%esp), %edi /* restore EDI */ + movl 0xc(%esp), %esi /* restore ESI */ + movl 0x10(%esp), %ebx /* restore EBX */ + movl 0x14(%esp), %ebp /* restore EBP */ + + leal 0x1c(%esp), %esp /* prepare stack */ + + /* jump to context */ + jmp *%ecx diff --git a/libs/context/src/asm/jump_i386_x86_64_sysv_macho_gas.S b/libs/context/src/asm/jump_i386_x86_64_sysv_macho_gas.S new file mode 100644 index 0000000..959ddac --- /dev/null +++ b/libs/context/src/asm/jump_i386_x86_64_sysv_macho_gas.S @@ -0,0 +1,16 @@ +/* + Copyright Sergue E. Leontiev 2013. + 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) +*/ + +// Stub file for universal binary + +#if defined(__i386__) + #include "jump_i386_sysv_macho_gas.S" +#elif defined(__x86_64__) + #include "jump_x86_64_sysv_macho_gas.S" +#else + #error "No arch's" +#endif diff --git a/libs/context/src/asm/jump_mips32_o32_elf_gas.S b/libs/context/src/asm/jump_mips32_o32_elf_gas.S new file mode 100644 index 0000000..f2b8034 --- /dev/null +++ b/libs/context/src/asm/jump_mips32_o32_elf_gas.S @@ -0,0 +1,119 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | F20 | F22 | F24 | F26 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | F28 | F30 | S0 | S1 | S2 | S3 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | S4 | S5 | S6 | S7 | FP |hiddn| RA | PC | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | ABI ARGS | GP | FCTX| DATA| | * + * ------------------------------------------------- * + * * + * *****************************************************/ + +.file "jump_mips32_o32_elf_gas.S" +.text +.globl jump_fcontext +.align 2 +.type jump_fcontext,@function +.ent jump_fcontext +jump_fcontext: + # reserve space on stack + addiu $sp, $sp, -96 + + sw $s0, 48($sp) # save S0 + sw $s1, 52($sp) # save S1 + sw $s2, 56($sp) # save S2 + sw $s3, 60($sp) # save S3 + sw $s4, 64($sp) # save S4 + sw $s5, 68($sp) # save S5 + sw $s6, 72($sp) # save S6 + sw $s7, 76($sp) # save S7 + sw $fp, 80($sp) # save FP + sw $a0, 84($sp) # save hidden, address of returned transfer_t + sw $ra, 88($sp) # save RA + sw $ra, 92($sp) # save RA as PC + +#if defined(__mips_hard_float) + s.d $f20, ($sp) # save F20 + s.d $f22, 8($sp) # save F22 + s.d $f24, 16($sp) # save F24 + s.d $f26, 24($sp) # save F26 + s.d $f28, 32($sp) # save F28 + s.d $f30, 40($sp) # save F30 +#endif + + # store SP (pointing to context-data) in A0 + move $a0, $sp + + # restore SP (pointing to context-data) from A1 + move $sp, $a1 + +#if defined(__mips_hard_float) + l.d $f20, ($sp) # restore F20 + l.d $f22, 8($sp) # restore F22 + l.d $f24, 16($sp) # restore F24 + l.d $f26, 24($sp) # restore F26 + l.d $f28, 32($sp) # restore F28 + l.d $f30, 40($sp) # restore F30 +#endif + + lw $s0, 48($sp) # restore S0 + lw $s1, 52($sp) # restore S1 + lw $s2, 56($sp) # restore S2 + lw $s3, 60($sp) # restore S3 + lw $s4, 64($sp) # restore S4 + lw $s5, 68($sp) # restore S5 + lw $s6, 72($sp) # restore S6 + lw $s7, 76($sp) # restore S7 + lw $fp, 80($sp) # restore FP + lw $v0, 84($sp) # restore hidden, address of returned transfer_t + lw $ra, 88($sp) # restore RA + + # load PC + lw $t9, 92($sp) + + # adjust stack + addiu $sp, $sp, 96 + + # return transfer_t from jump + sw $a0, ($v0) # fctx of transfer_t + sw $a2, 4($v0) # data of transfer_t + # pass transfer_t as first arg in context function + # A0 == fctx, A1 == data + move $a1, $a2 + + # jump to context + jr $t9 +.end jump_fcontext +.size jump_fcontext, .-jump_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/jump_mips64_n64_elf_gas.S b/libs/context/src/asm/jump_mips64_n64_elf_gas.S new file mode 100644 index 0000000..117bca5 --- /dev/null +++ b/libs/context/src/asm/jump_mips64_n64_elf_gas.S @@ -0,0 +1,121 @@ +/* + Copyright Jiaxun Yang 2018. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 8 | 16 | 24 | * + * ------------------------------------------------- * + * | F24 | F25 | F26 | F27 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 40 | 48 | 56 | * + * ------------------------------------------------- * + * | F28 | F29 | F30 | F31 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 72 | 80 | 88 | * + * ------------------------------------------------- * + * | S0 | S1 | S2 | S3 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | S4 | S5 | S6 | S7 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | FP | GP | RA | PC | * + * ------------------------------------------------- * + * * + * *****************************************************/ + +.file "jump_mips64_n64_elf_gas.S" +.text +.globl jump_fcontext +.align 2 +.type jump_fcontext,@function +.ent jump_fcontext +jump_fcontext: + # reserve space on stack + daddiu $sp, $sp, -160 + + sd $s0, 64($sp) # save S0 + sd $s1, 72($sp) # save S1 + sd $s2, 80($sp) # save S2 + sd $s3, 88($sp) # save S3 + sd $s4, 96($sp) # save S4 + sd $s5, 104($sp) # save S5 + sd $s6, 112($sp) # save S6 + sd $s7, 120($sp) # save S7 + sd $fp, 128($sp) # save FP + sd $ra, 144($sp) # save RA + sd $ra, 152($sp) # save RA as PC + + + s.d $f24, 0($sp) # save F24 + s.d $f25, 8($sp) # save F25 + s.d $f26, 16($sp) # save F26 + s.d $f27, 24($sp) # save F27 + s.d $f28, 32($sp) # save F28 + s.d $f29, 40($sp) # save F29 + s.d $f30, 48($sp) # save F30 + s.d $f31, 56($sp) # save F31 + + # store SP (pointing to old context-data) in v0 as return + move $v0, $sp + + # get SP (pointing to new context-data) from a0 param + move $sp, $a0 + + l.d $f24, 0($sp) # restore F24 + l.d $f25, 8($sp) # restore F25 + l.d $f26, 16($sp) # restore F26 + l.d $f27, 24($sp) # restore F27 + l.d $f28, 32($sp) # restore F28 + l.d $f29, 40($sp) # restore F29 + l.d $f30, 48($sp) # restore F30 + l.d $f31, 56($sp) # restore F31 + + ld $s0, 64($sp) # restore S0 + ld $s1, 72($sp) # restore S1 + ld $s2, 80($sp) # restore S2 + ld $s3, 88($sp) # restore S3 + ld $s4, 96($sp) # restore S4 + ld $s5, 104($sp) # restore S5 + ld $s6, 112($sp) # restore S6 + ld $s7, 120($sp) # restore S7 + ld $fp, 128($sp) # restore FP + ld $ra, 144($sp) # restore RAa + + # load PC + ld $t9, 152($sp) + + # adjust stack + daddiu $sp, $sp, 160 + + move $a0, $v0 # move old sp from v0 to a0 as param + move $v1, $a1 # move *data from a1 to v1 as return + + # jump to context + jr $t9 +.end jump_fcontext +.size jump_fcontext, .-jump_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/jump_ppc32_ppc64_sysv_macho_gas.S b/libs/context/src/asm/jump_ppc32_ppc64_sysv_macho_gas.S new file mode 100644 index 0000000..f175e31 --- /dev/null +++ b/libs/context/src/asm/jump_ppc32_ppc64_sysv_macho_gas.S @@ -0,0 +1,16 @@ +/* + Copyright Sergue E. Leontiev 2013. + 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) +*/ + +// Stub file for universal binary + +#if defined(__ppc__) + #include "jump_ppc32_sysv_macho_gas.S" +#elif defined(__ppc64__) + #include "jump_ppc64_sysv_macho_gas.S" +#else + #error "No arch's" +#endif diff --git a/libs/context/src/asm/jump_ppc32_sysv_elf_gas.S b/libs/context/src/asm/jump_ppc32_sysv_elf_gas.S new file mode 100644 index 0000000..48e09c9 --- /dev/null +++ b/libs/context/src/asm/jump_ppc32_sysv_elf_gas.S @@ -0,0 +1,201 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * |bchai|hiddn| fpscr | PC | CR | R14 | R15 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | R16 | R17 | R18 | R19 | R20 | R21 | R22 | R23 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | R24 | R25 | R26 | R27 | R28 | R29 | R30 | R31 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | F14 | F15 | F16 | F17 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | F18 | F19 | F20 | F21 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | F22 | F23 | F24 | F25 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | F26 | F27 | F28 | F29 | * + * ------------------------------------------------- * + * ------------------------|------------ * + * | 224 | 228 | 232 | 236 | 240 | 244 | * + * ------------------------|------------ * + * | F30 | F31 |bchai| LR | * + * ------------------------|------------ * + * * + *******************************************************/ + +.file "jump_ppc32_sysv_elf_gas.S" +.text +.globl jump_fcontext +.align 2 +.type jump_fcontext,@function +jump_fcontext: + # Linux: jump_fcontext( hidden transfer_t * R3, R4, R5) + # Other: transfer_t R3:R4 = jump_fcontext( R3, R4) + + mflr %r0 # return address from LR + mffs %f0 # FPSCR + mfcr %r8 # condition register + + stwu %r1, -240(%r1) # allocate stack space, R1 % 16 == 0 + stw %r0, 244(%r1) # save LR in caller's frame + +#ifdef __linux__ + stw %r3, 4(%r1) # hidden pointer +#endif + + stfd %f0, 8(%r1) # FPSCR + stw %r0, 16(%r1) # LR as PC + stw %r8, 20(%r1) # CR + + # Save registers R14 to R31. + # Don't change R2, the thread-local storage pointer. + # Don't change R13, the small data pointer. + stw %r14, 24(%r1) + stw %r15, 28(%r1) + stw %r16, 32(%r1) + stw %r17, 36(%r1) + stw %r18, 40(%r1) + stw %r19, 44(%r1) + stw %r20, 48(%r1) + stw %r21, 52(%r1) + stw %r22, 56(%r1) + stw %r23, 60(%r1) + stw %r24, 64(%r1) + stw %r25, 68(%r1) + stw %r26, 72(%r1) + stw %r27, 76(%r1) + stw %r28, 80(%r1) + stw %r29, 84(%r1) + stw %r30, 88(%r1) + stw %r31, 92(%r1) + + # Save registers F14 to F31 in slots with 8-byte alignment. + # 4-byte alignment may stall the pipeline of some processors. + # Less than 4 may cause alignment traps. + stfd %f14, 96(%r1) + stfd %f15, 104(%r1) + stfd %f16, 112(%r1) + stfd %f17, 120(%r1) + stfd %f18, 128(%r1) + stfd %f19, 136(%r1) + stfd %f20, 144(%r1) + stfd %f21, 152(%r1) + stfd %f22, 160(%r1) + stfd %f23, 168(%r1) + stfd %f24, 176(%r1) + stfd %f25, 184(%r1) + stfd %f26, 192(%r1) + stfd %f27, 200(%r1) + stfd %f28, 208(%r1) + stfd %f29, 216(%r1) + stfd %f30, 224(%r1) + stfd %f31, 232(%r1) + + # store RSP (pointing to context-data) in R7/R6 + # restore RSP (pointing to context-data) from R4/R3 +#ifdef __linux__ + mr %r7, %r1 + mr %r1, %r4 + lwz %r3, 4(%r1) # hidden pointer +#else + mr %r6, %r1 + mr %r1, %r3 +#endif + + lfd %f0, 8(%r1) # FPSCR + lwz %r0, 16(%r1) # PC + lwz %r8, 20(%r1) # CR + + mtfsf 0xff, %f0 # restore FPSCR + mtctr %r0 # load CTR with PC + mtcr %r8 # restore CR + + # restore R14 to R31 + lwz %r14, 24(%r1) + lwz %r15, 28(%r1) + lwz %r16, 32(%r1) + lwz %r17, 36(%r1) + lwz %r18, 40(%r1) + lwz %r19, 44(%r1) + lwz %r20, 48(%r1) + lwz %r21, 52(%r1) + lwz %r22, 56(%r1) + lwz %r23, 60(%r1) + lwz %r24, 64(%r1) + lwz %r25, 68(%r1) + lwz %r26, 72(%r1) + lwz %r27, 76(%r1) + lwz %r28, 80(%r1) + lwz %r29, 84(%r1) + lwz %r30, 88(%r1) + lwz %r31, 92(%r1) + + # restore F14 to F31 + lfd %f14, 96(%r1) + lfd %f15, 104(%r1) + lfd %f16, 112(%r1) + lfd %f17, 120(%r1) + lfd %f18, 128(%r1) + lfd %f19, 136(%r1) + lfd %f20, 144(%r1) + lfd %f21, 152(%r1) + lfd %f22, 160(%r1) + lfd %f23, 168(%r1) + lfd %f24, 176(%r1) + lfd %f25, 184(%r1) + lfd %f26, 192(%r1) + lfd %f27, 200(%r1) + lfd %f28, 208(%r1) + lfd %f29, 216(%r1) + lfd %f30, 224(%r1) + lfd %f31, 232(%r1) + + # restore LR from caller's frame + lwz %r0, 244(%r1) + mtlr %r0 + + # adjust stack + addi %r1, %r1, 240 + + # return transfer_t +#ifdef __linux__ + stw %r7, 0(%r3) + stw %r5, 4(%r3) +#else + mr %r3, %r6 + # %r4, %r4 +#endif + + # jump to context + bctr +.size jump_fcontext, .-jump_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/jump_ppc32_sysv_macho_gas.S b/libs/context/src/asm/jump_ppc32_sysv_macho_gas.S new file mode 100644 index 0000000..c555237 --- /dev/null +++ b/libs/context/src/asm/jump_ppc32_sysv_macho_gas.S @@ -0,0 +1,201 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/****************************************************** + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | F14 | F15 | F16 | F17 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | F18 | F19 | F20 | F21 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | F22 | F23 | F24 | F25 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | F26 | F27 | F28 | F29 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | F30 | F31 | fpscr | R13 | R14 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | R15 | R16 | R17 | R18 | R19 | R20 | R21 | R22 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | R23 | R24 | R25 | R26 | R27 | R28 | R29 | R30 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | * + * ------------------------------------------------- * + * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * + * ------------------------------------------------- * + * | R31 |hiddn| CR | LR | PC |bchai|linkr| FCTX| * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 64 | | * + * ------------------------------------------------- * + * | 256 | | * + * ------------------------------------------------- * + * | DATA| | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.text +.globl _jump_fcontext +.align 2 +_jump_fcontext: + ; reserve space on stack + subi r1, r1, 244 + + stfd f14, 0(r1) # save F14 + stfd f15, 8(r1) # save F15 + stfd f16, 16(r1) # save F16 + stfd f17, 24(r1) # save F17 + stfd f18, 32(r1) # save F18 + stfd f19, 40(r1) # save F19 + stfd f20, 48(r1) # save F20 + stfd f21, 56(r1) # save F21 + stfd f22, 64(r1) # save F22 + stfd f23, 72(r1) # save F23 + stfd f24, 80(r1) # save F24 + stfd f25, 88(r1) # save F25 + stfd f26, 96(r1) # save F26 + stfd f27, 104(r1) # save F27 + stfd f28, 112(r1) # save F28 + stfd f29, 120(r1) # save F29 + stfd f30, 128(r1) # save F30 + stfd f31, 136(r1) # save F31 + mffs f0 # load FPSCR + stfd f0, 144(r1) # save FPSCR + + stw r13, 152(r1) # save R13 + stw r14, 156(r1) # save R14 + stw r15, 160(r1) # save R15 + stw r16, 164(r1) # save R16 + stw r17, 168(r1) # save R17 + stw r18, 172(r1) # save R18 + stw r19, 176(r1) # save R19 + stw r20, 180(r1) # save R20 + stw r21, 184(r1) # save R21 + stw r22, 188(r1) # save R22 + stw r23, 192(r1) # save R23 + stw r24, 196(r1) # save R24 + stw r25, 200(r1) # save R25 + stw r26, 204(r1) # save R26 + stw r27, 208(r1) # save R27 + stw r28, 212(r1) # save R28 + stw r29, 216(r1) # save R29 + stw r30, 220(r1) # save R30 + stw r31, 224(r1) # save R31 + stw r3, 228(r1) # save hidden + + # save CR + mfcr r0 + stw r0, 232(r1) + # save LR + mflr r0 + stw r0, 236(r1) + # save LR as PC + stw r0, 240(r1) + + # store RSP (pointing to context-data) in R6 + mr r6, r1 + + # restore RSP (pointing to context-data) from R4 + mr r1, r4 + + lfd f14, 0(r1) # restore F14 + lfd f15, 8(r1) # restore F15 + lfd f16, 16(r1) # restore F16 + lfd f17, 24(r1) # restore F17 + lfd f18, 32(r1) # restore F18 + lfd f19, 40(r1) # restore F19 + lfd f20, 48(r1) # restore F20 + lfd f21, 56(r1) # restore F21 + lfd f22, 64(r1) # restore F22 + lfd f23, 72(r1) # restore F23 + lfd f24, 80(r1) # restore F24 + lfd f25, 88(r1) # restore F25 + lfd f26, 96(r1) # restore F26 + lfd f27, 104(r1) # restore F27 + lfd f28, 112(r1) # restore F28 + lfd f29, 120(r1) # restore F29 + lfd f30, 128(r1) # restore F30 + lfd f31, 136(r1) # restore F31 + lfd f0, 144(r1) # load FPSCR + mtfsf 0xff, f0 # restore FPSCR + + lwz r13, 152(r1) # restore R13 + lwz r14, 156(r1) # restore R14 + lwz r15, 160(r1) # restore R15 + lwz r16, 164(r1) # restore R16 + lwz r17, 168(r1) # restore R17 + lwz r18, 172(r1) # restore R18 + lwz r19, 176(r1) # restore R19 + lwz r20, 180(r1) # restore R20 + lwz r21, 184(r1) # restore R21 + lwz r22, 188(r1) # restore R22 + lwz r23, 192(r1) # restore R23 + lwz r24, 196(r1) # restore R24 + lwz r25, 200(r1) # restore R25 + lwz r26, 204(r1) # restore R26 + lwz r27, 208(r1) # restore R27 + lwz r28, 212(r1) # restore R28 + lwz r29, 216(r1) # restore R29 + lwz r30, 220(r1) # restore R30 + lwz r31, 224(r1) # restore R31 + lwz r3, 228(r1) # restore hidden + + # restore CR + lwz r0, 232(r1) + mtcr r0 + # restore LR + lwz r0, 236(r1) + mtlr r0 + # load PC + lwz r0, 240(r1) + # restore CTR + mtctr r0 + + # adjust stack + addi r1, r1, 244 + + # return transfer_t + stw r6, 0(r3) + stw r5, 4(r3) + + # jump to context + bctr diff --git a/libs/context/src/asm/jump_ppc32_sysv_xcoff_gas.S b/libs/context/src/asm/jump_ppc32_sysv_xcoff_gas.S new file mode 100644 index 0000000..5a96772 --- /dev/null +++ b/libs/context/src/asm/jump_ppc32_sysv_xcoff_gas.S @@ -0,0 +1,203 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/****************************************************** + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | F14 | F15 | F16 | F17 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | F18 | F19 | F20 | F21 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | F22 | F23 | F24 | F25 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | F26 | F27 | F28 | F29 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | F30 | F31 | fpscr | R13 | R14 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | R15 | R16 | R17 | R18 | R19 | R20 | R21 | R22 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | R23 | R24 | R25 | R26 | R27 | R28 | R29 | R30 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | * + * ------------------------------------------------- * + * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * + * ------------------------------------------------- * + * | R31 |hiddn| CR | LR | PC |bchai|linkr| FCTX| * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 64 | | * + * ------------------------------------------------- * + * | 256 | | * + * ------------------------------------------------- * + * | DATA| | * + * ------------------------------------------------- * + * * + *******************************************************/ +.globl .jump_fcontext +.globl jump_fcontext[DS] +.align 2 +.csect jump_fcontext[DS] +jump_fcontext: + .long .jump_fcontext +.jump_fcontext: + # reserve space on stack + subi r1, r1, 244 + + stfd f14, 0(r1) # save F14 + stfd f15, 8(r1) # save F15 + stfd f16, 16(r1) # save F16 + stfd f17, 24(r1) # save F17 + stfd f18, 32(r1) # save F18 + stfd f19, 40(r1) # save F19 + stfd f20, 48(r1) # save F20 + stfd f21, 56(r1) # save F21 + stfd f22, 64(r1) # save F22 + stfd f23, 72(r1) # save F23 + stfd f24, 80(r1) # save F24 + stfd f25, 88(r1) # save F25 + stfd f26, 96(r1) # save F26 + stfd f27, 104(r1) # save F27 + stfd f28, 112(r1) # save F28 + stfd f29, 120(r1) # save F29 + stfd f30, 128(r1) # save F30 + stfd f31, 136(r1) # save F31 + mffs f0 # load FPSCR + stfd f0, 144(r1) # save FPSCR + + stw r13, 152(r1) # save R13 + stw r14, 156(r1) # save R14 + stw r15, 160(r1) # save R15 + stw r16, 164(r1) # save R16 + stw r17, 168(r1) # save R17 + stw r18, 172(r1) # save R18 + stw r19, 176(r1) # save R19 + stw r20, 180(r1) # save R20 + stw r21, 184(r1) # save R21 + stw r22, 188(r1) # save R22 + stw r23, 192(r1) # save R23 + stw r24, 196(r1) # save R24 + stw r25, 200(r1) # save R25 + stw r26, 204(r1) # save R26 + stw r27, 208(r1) # save R27 + stw r28, 212(r1) # save R28 + stw r29, 216(r1) # save R29 + stw r30, 220(r1) # save R30 + stw r31, 224(r1) # save R31 + stw r3, 228(r1) # save hidden + + # save CR + mfcr r0 + stw r0, 232(r1) + # save LR + mflr r0 + stw r0, 236(r1) + # save LR as PC + stw r0, 240(r1) + + # store RSP (pointing to context-data) in R6 + mr r6, r1 + + # restore RSP (pointing to context-data) from R4 + mr r1, r4 + + lfd f14, 0(r1) # restore F14 + lfd f15, 8(r1) # restore F15 + lfd f16, 16(r1) # restore F16 + lfd f17, 24(r1) # restore F17 + lfd f18, 32(r1) # restore F18 + lfd f19, 40(r1) # restore F19 + lfd f20, 48(r1) # restore F20 + lfd f21, 56(r1) # restore F21 + lfd f22, 64(r1) # restore F22 + lfd f23, 72(r1) # restore F23 + lfd f24, 80(r1) # restore F24 + lfd f25, 88(r1) # restore F25 + lfd f26, 96(r1) # restore F26 + lfd f27, 104(r1) # restore F27 + lfd f28, 112(r1) # restore F28 + lfd f29, 120(r1) # restore F29 + lfd f30, 128(r1) # restore F30 + lfd f31, 136(r1) # restore F31 + lfd f0, 144(r1) # load FPSCR + mtfsf 0xff, f0 # restore FPSCR + + lwz r13, 152(r1) # restore R13 + lwz r14, 156(r1) # restore R14 + lwz r15, 160(r1) # restore R15 + lwz r16, 164(r1) # restore R16 + lwz r17, 168(r1) # restore R17 + lwz r18, 172(r1) # restore R18 + lwz r19, 176(r1) # restore R19 + lwz r20, 180(r1) # restore R20 + lwz r21, 184(r1) # restore R21 + lwz r22, 188(r1) # restore R22 + lwz r23, 192(r1) # restore R23 + lwz r24, 196(r1) # restore R24 + lwz r25, 200(r1) # restore R25 + lwz r26, 204(r1) # restore R26 + lwz r27, 208(r1) # restore R27 + lwz r28, 212(r1) # restore R28 + lwz r29, 216(r1) # restore R29 + lwz r30, 220(r1) # restore R30 + lwz r31, 224(r1) # restore R31 + lwz r3, 228(r1) # restore hidden + + # restore CR + lwz r0, 232(r1) + mtcr r0 + # restore LR + lwz r0, 236(r1) + mtlr r0 + # load PC + lwz r0, 240(r1) + # restore CTR + mtctr r0 + + # adjust stack + addi r1, r1, 244 + + # return transfer_t + stw r6, 0(r3) + stw r5, 4(r3) + + # jump to context + bctr diff --git a/libs/context/src/asm/jump_ppc64_sysv_elf_gas.S b/libs/context/src/asm/jump_ppc64_sysv_elf_gas.S new file mode 100644 index 0000000..28907db --- /dev/null +++ b/libs/context/src/asm/jump_ppc64_sysv_elf_gas.S @@ -0,0 +1,221 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | TOC | R14 | R15 | R16 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | R17 | R18 | R19 | R20 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | R21 | R22 | R23 | R24 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | R25 | R26 | R27 | R28 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | R29 | R30 | R31 | hidden | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | CR | LR | PC | back-chain| * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | cr saved | lr saved | compiler | linker | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | * + * ------------------------------------------------- * + * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * + * ------------------------------------------------- * + * | TOC saved | FCTX | DATA | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.file "jump_ppc64_sysv_elf_gas.S" +.globl jump_fcontext +#if _CALL_ELF == 2 + .text + .align 2 +jump_fcontext: + addis %r2, %r12, .TOC.-jump_fcontext@ha + addi %r2, %r2, .TOC.-jump_fcontext@l + .localentry jump_fcontext, . - jump_fcontext +#else + .section ".opd","aw" + .align 3 +jump_fcontext: +# ifdef _CALL_LINUX + .quad .L.jump_fcontext,.TOC.@tocbase,0 + .type jump_fcontext,@function + .text + .align 2 +.L.jump_fcontext: +# else + .hidden .jump_fcontext + .globl .jump_fcontext + .quad .jump_fcontext,.TOC.@tocbase,0 + .size jump_fcontext,24 + .type .jump_fcontext,@function + .text + .align 2 +.jump_fcontext: +# endif +#endif + # reserve space on stack + subi %r1, %r1, 184 + +#if _CALL_ELF != 2 + std %r2, 0(%r1) # save TOC +#endif + std %r14, 8(%r1) # save R14 + std %r15, 16(%r1) # save R15 + std %r16, 24(%r1) # save R16 + std %r17, 32(%r1) # save R17 + std %r18, 40(%r1) # save R18 + std %r19, 48(%r1) # save R19 + std %r20, 56(%r1) # save R20 + std %r21, 64(%r1) # save R21 + std %r22, 72(%r1) # save R22 + std %r23, 80(%r1) # save R23 + std %r24, 88(%r1) # save R24 + std %r25, 96(%r1) # save R25 + std %r26, 104(%r1) # save R26 + std %r27, 112(%r1) # save R27 + std %r28, 120(%r1) # save R28 + std %r29, 128(%r1) # save R29 + std %r30, 136(%r1) # save R30 + std %r31, 144(%r1) # save R31 +#if _CALL_ELF != 2 + std %r3, 152(%r1) # save hidden +#endif + + # save CR + mfcr %r0 + std %r0, 160(%r1) + # save LR + mflr %r0 + std %r0, 168(%r1) + # save LR as PC + std %r0, 176(%r1) + + # store RSP (pointing to context-data) in R6 + mr %r6, %r1 + +#if _CALL_ELF == 2 + # restore RSP (pointing to context-data) from R3 + mr %r1, %r3 +#else + # restore RSP (pointing to context-data) from R4 + mr %r1, %r4 + + ld %r2, 0(%r1) # restore TOC +#endif + ld %r14, 8(%r1) # restore R14 + ld %r15, 16(%r1) # restore R15 + ld %r16, 24(%r1) # restore R16 + ld %r17, 32(%r1) # restore R17 + ld %r18, 40(%r1) # restore R18 + ld %r19, 48(%r1) # restore R19 + ld %r20, 56(%r1) # restore R20 + ld %r21, 64(%r1) # restore R21 + ld %r22, 72(%r1) # restore R22 + ld %r23, 80(%r1) # restore R23 + ld %r24, 88(%r1) # restore R24 + ld %r25, 96(%r1) # restore R25 + ld %r26, 104(%r1) # restore R26 + ld %r27, 112(%r1) # restore R27 + ld %r28, 120(%r1) # restore R28 + ld %r29, 128(%r1) # restore R29 + ld %r30, 136(%r1) # restore R30 + ld %r31, 144(%r1) # restore R31 +#if _CALL_ELF != 2 + ld %r3, 152(%r1) # restore hidden +#endif + + # restore CR + ld %r0, 160(%r1) + mtcr %r0 + # restore LR + ld %r0, 168(%r1) + mtlr %r0 + + # load PC + ld %r12, 176(%r1) + # restore CTR + mtctr %r12 + + # adjust stack + addi %r1, %r1, 184 + +#if _CALL_ELF == 2 + # copy transfer_t into transfer_fn arg registers + mr %r3, %r6 + # arg pointer already in %r4 + + # jump to context + bctr + .size jump_fcontext, .-jump_fcontext +#else + # zero in r3 indicates first jump to context-function + cmpdi %r3, 0 + beq use_entry_arg + + # return transfer_t + std %r6, 0(%r3) + std %r5, 8(%r3) + + # jump to context + bctr + +use_entry_arg: + # copy transfer_t into transfer_fn arg registers + mr %r3, %r6 + mr %r4, %r5 + + # jump to context + bctr +# ifdef _CALL_LINUX + .size .jump_fcontext, .-.L.jump_fcontext +# else + .size .jump_fcontext, .-.jump_fcontext +# endif +#endif + + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/jump_ppc64_sysv_macho_gas.S b/libs/context/src/asm/jump_ppc64_sysv_macho_gas.S new file mode 100644 index 0000000..74fcb2a --- /dev/null +++ b/libs/context/src/asm/jump_ppc64_sysv_macho_gas.S @@ -0,0 +1,164 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | TOC | R14 | R15 | R16 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | R17 | R18 | R19 | R20 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | R21 | R22 | R23 | R24 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | R25 | R26 | R27 | R28 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | R29 | R30 | R31 | hidden | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | CR | LR | PC | back-chain| * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | cr saved | lr saved | compiler | linker | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | * + * ------------------------------------------------- * + * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * + * ------------------------------------------------- * + * | TOC saved | FCTX | DATA | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.text +.align 2 +.globl _jump_fcontext + +_jump_fcontext: + ; reserve space on stack + subi r1, r1, 184 + + std r14, 8(r1) ; save R14 + std r15, 16(r1) ; save R15 + std r16, 24(r1) ; save R16 + std r17, 32(r1) ; save R17 + std r18, 40(r1) ; save R18 + std r19, 48(r1) ; save R19 + std r20, 56(r1) ; save R20 + std r21, 64(r1) ; save R21 + std r22, 72(r1) ; save R22 + std r23, 80(r1) ; save R23 + std r24, 88(r1) ; save R24 + std r25, 96(r1) ; save R25 + std r26, 104(r1) ; save R26 + std r27, 112(r1) ; save R27 + std r28, 120(r1) ; save R28 + std r29, 128(r1) ; save R29 + std r30, 136(r1) ; save R30 + std r31, 144(r1) ; save R31 + std r3, 152(r1) ; save hidden + + ; save CR + mfcr r0 + std r0, 160(r1) + ; save LR + mflr r0 + std r0, 168(r1) + ; save LR as PC + std r0, 176(r1) + + ; store RSP (pointing to context-data) in R6 + mr r6, r1 + + ; restore RSP (pointing to context-data) from R4 + mr r1, r4 + + ld r14, 8(r1) ; restore R14 + ld r15, 16(r1) ; restore R15 + ld r16, 24(r1) ; restore R16 + ld r17, 32(r1) ; restore R17 + ld r18, 40(r1) ; restore R18 + ld r19, 48(r1) ; restore R19 + ld r20, 56(r1) ; restore R20 + ld r21, 64(r1) ; restore R21 + ld r22, 72(r1) ; restore R22 + ld r23, 80(r1) ; restore R23 + ld r24, 88(r1) ; restore R24 + ld r25, 96(r1) ; restore R25 + ld r26, 104(r1) ; restore R26 + ld r27, 112(r1) ; restore R27 + ld r28, 120(r1) ; restore R28 + ld r29, 128(r1) ; restore R29 + ld r30, 136(r1) ; restore R30 + ld r31, 144(r1) ; restore R31 + ld r3, 152(r1) ; restore hidden + + ; restore CR + ld r0, 160(r1) + mtcr r0 + ; restore LR + ld r0, 168(r1) + mtlr r0 + + ; load PC + ld r12, 176(r1) + # restore CTR + mtctr r12 + + # adjust stack + addi r1, r1, 184 + + # zero in r3 indicates first jump to context-function + cmpdi r3, 0 + beq use_entry_arg + + # return transfer_t + std r6, 0(r3) + std r5, 8(r3) + + # jump to context + bctr + +use_entry_arg: + # copy transfer_t into transfer_fn arg registers + mr r3, r6 + mr r4, r5 + + # jump to context + bctr diff --git a/libs/context/src/asm/jump_ppc64_sysv_xcoff_gas.S b/libs/context/src/asm/jump_ppc64_sysv_xcoff_gas.S new file mode 100644 index 0000000..ff0e6ea --- /dev/null +++ b/libs/context/src/asm/jump_ppc64_sysv_xcoff_gas.S @@ -0,0 +1,92 @@ + +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +.align 2 +.globl .jump_fcontext +.jump_fcontext: + # reserve space on stack + subi 1, 1, 184 + + std 13, 0(1) # save R13 + std 14, 8(1) # save R14 + std 15, 16(1) # save R15 + std 16, 24(1) # save R16 + std 17, 32(1) # save R17 + std 18, 40(1) # save R18 + std 19, 48(1) # save R19 + std 20, 56(1) # save R20 + std 21, 64(1) # save R21 + std 22, 72(1) # save R22 + std 23, 80(1) # save R23 + std 24, 88(1) # save R24 + std 25, 96(1) # save R25 + std 26, 104(1) # save R26 + std 27, 112(1) # save R27 + std 29, 120(1) # save R28 + std 29, 128(1) # save R29 + std 30, 136(1) # save R30 + std 31, 144(1) # save R31 + std 3, 152(1) # save hidden + + # save CR + mfcr 0 + std 0, 160(1) + # save LR + mflr 0 + std 0, 168(1) + # save LR as PC + std 0, 176(1) + + # store RSP (pointing to context-data) in R6 + mr 6, 1 + + # restore RSP (pointing to context-data) from R4 + mr 1, 4 + + ld 13, 0(1) # restore R13 + ld 14, 8(1) # restore R14 + ld 15, 16(1) # restore R15 + ld 16, 24(1) # restore R16 + ld 17, 32(1) # restore R17 + ld 18, 40(1) # restore R18 + ld 19, 48(1) # restore R19 + ld 20, 56(1) # restore R20 + ld 21, 64(1) # restore R21 + ld 22, 72(1) # restore R22 + ld 23, 80(1) # restore R23 + ld 24, 88(1) # restore R24 + ld 25, 96(1) # restore R25 + ld 26, 104(1) # restore R26 + ld 27, 112(1) # restore R27 + ld 28, 120(1) # restore R28 + ld 29, 128(1) # restore R29 + ld 30, 136(1) # restore R30 + ld 31, 144(1) # restore R31 + ld 3, 152(1) # restore hidden + + # restore CR + ld 0, 160(1) + mtcr 0 + # restore LR + ld 0, 168(1) + mtlr 0 + + # load PC + ld 0, 176(1) + # restore CTR + mtctr 0 + + # adjust stack + addi 1, 1, 184 + + # return transfer_t + std 6, 0(3) + std 5, 8(3) + + # jump to context + bctr diff --git a/libs/context/src/asm/jump_riscv64_sysv_elf_gas.S b/libs/context/src/asm/jump_riscv64_sysv_elf_gas.S new file mode 100644 index 0000000..5417e5d --- /dev/null +++ b/libs/context/src/asm/jump_riscv64_sysv_elf_gas.S @@ -0,0 +1,150 @@ +/* + 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) +*/ +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | fs0 | fs1 | fs2 | fs3 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | fs4 | fs5 | fs6 | fs7 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| * + * ------------------------------------------------- * + * | fs8 | fs9 | fs10 | fs11 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| * + * ------------------------------------------------- * + * | s0 | s1 | s2 | s3 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| * + * ------------------------------------------------- * + * | s4 | s5 | s6 | s7 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 0xa0| 0xa4| 0xa8| 0xac| 0xb0| 0xb4| 0xb8| 0xbc| * + * ------------------------------------------------- * + * | s8 | s9 | s10 | s11 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | | | | | * + * ------------------------------------------------- * + * | 0xc0| 0xc4| 0xc8| 0xcc| | | | | * + * ------------------------------------------------- * + * | ra | pc | | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.file "jump_riscv64_sysv_elf_gas.S" +.text +.align 1 +.global jump_fcontext +.type jump_fcontext, %function +jump_fcontext: + # prepare stack for GP + FPU + addi sp, sp, -0xd0 + + # save fs0 - fs11 + fsd fs0, 0x00(sp) + fsd fs1, 0x08(sp) + fsd fs2, 0x10(sp) + fsd fs3, 0x18(sp) + fsd fs4, 0x20(sp) + fsd fs5, 0x28(sp) + fsd fs6, 0x30(sp) + fsd fs7, 0x38(sp) + fsd fs8, 0x40(sp) + fsd fs9, 0x48(sp) + fsd fs10, 0x50(sp) + fsd fs11, 0x58(sp) + + # save s0-s11, ra + sd s0, 0x60(sp) + sd s1, 0x68(sp) + sd s2, 0x70(sp) + sd s3, 0x78(sp) + sd s4, 0x80(sp) + sd s5, 0x88(sp) + sd s6, 0x90(sp) + sd s7, 0x98(sp) + sd s8, 0xa0(sp) + sd s9, 0xa8(sp) + sd s10, 0xb0(sp) + sd s11, 0xb8(sp) + sd ra, 0xc0(sp) + + # save RA as PC + sd ra, 0xc8(sp) + + # store SP (pointing to context-data) in A2 + mv a2, sp + + # restore SP (pointing to context-data) from A0 + mv sp, a0 + + # load fs0 - fs11 + fld fs0, 0x00(sp) + fld fs1, 0x08(sp) + fld fs2, 0x10(sp) + fld fs3, 0x18(sp) + fld fs4, 0x20(sp) + fld fs5, 0x28(sp) + fld fs6, 0x30(sp) + fld fs7, 0x38(sp) + fld fs8, 0x40(sp) + fld fs9, 0x48(sp) + fld fs10, 0x50(sp) + fld fs11, 0x58(sp) + + # load s0-s11,ra + ld s0, 0x60(sp) + ld s1, 0x68(sp) + ld s2, 0x70(sp) + ld s3, 0x78(sp) + ld s4, 0x80(sp) + ld s5, 0x88(sp) + ld s6, 0x90(sp) + ld s7, 0x98(sp) + ld s8, 0xa0(sp) + ld s9, 0xa8(sp) + ld s10, 0xb0(sp) + ld s11, 0xb8(sp) + ld ra, 0xc0(sp) + + # return transfer_t from jump + # pass transfer_t as first arg in context function + # a0 == FCTX, a1 == DATA + mv a0, a2 + + # load pc + ld a2, 0xc8(sp) + + # restore stack from GP + FPU + addi sp, sp, 0xd0 + + jr a2 +.size jump_fcontext,.-jump_fcontext +# Mark that we don't need executable stack. +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/jump_s390x_sysv_elf_gas.S b/libs/context/src/asm/jump_s390x_sysv_elf_gas.S new file mode 100644 index 0000000..b2163cc --- /dev/null +++ b/libs/context/src/asm/jump_s390x_sysv_elf_gas.S @@ -0,0 +1,117 @@ +/******************************************************* +* * +* ------------------------------------------------- * +* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * +* ------------------------------------------------- * +* | 0 | 8 | 16 | 24 | * +* ------------------------------------------------- * +* | R6 | R7 | R8 | R9 | * +* ------------------------------------------------- * +* ------------------------------------------------- * +* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * +* ------------------------------------------------- * +* | 32 | 40 | 48 | 56 | * +* ------------------------------------------------- * +* | R10 | R11 | R12 | R13 | * +* ------------------------------------------------- * +* ------------------------------------------------- * +* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * +* ------------------------------------------------- * +* | 64 | 72 | 80 | 88 | * +* ------------------------------------------------- * +* | R14/LR | R15 | F1 | F3 | * +* ------------------------------------------------- * +* ------------------------------------------------- * +* | 24 | 25 | 26 | 27 | 28 | 29 | | * +* ------------------------------------------------- * +* | 96 | 104 | 112 | 120 | * +* ------------------------------------------------- * +* | F5 | F7 | PC | | * +* ------------------------------------------------- * +* *****************************************************/ + +.file "jump_s390x_sysv_elf_gas.S" +.text +.align 4 # According to the sample code in the ELF ABI docs +.global jump_fcontext +.type jump_fcontext, @function + +#define GR_OFFSET 0 +#define LR_OFFSET 64 +#define SP_OFFSET 72 +#define FP_OFFSET 80 +#define PC_OFFSET 112 +#define L_CTX 120 +#define L_STACKFRAME 120 + +jump_fcontext: + + # Reserved the space for stack to store the data of current context + # before we jump to the new context. + aghi %r15,-L_STACKFRAME + + # save the registers to the stack + stmg %r6, %r15, GR_OFFSET(%r15) + + # save the floating point registers + std %f0,FP_OFFSET(%r15) + std %f3,FP_OFFSET+8(%r15) + std %f5,FP_OFFSET+16(%r15) + std %f7,FP_OFFSET+24(%r15) + + # Save LR as PC + stg %r14,PC_OFFSET(%r15) + + # Store the SP pointing to the old context-data into R0 + lgr %r0,%r15 + + # Get the SP pointing to the new context-data + # Note: Since the return type of the jump_fcontext is struct whose + # size is more than 8. The compiler automatically passes the + # address of the transfer_t where the data needs to store into R2. + + # Hence the first param passed to the jump_fcontext which represent + # the fctx we want to switch to is present in R3 + # R2 --> Address of the return transfer_t struct + # R3 --> Context we want to switch to + # R4 --> Data + lgr %r15,%r3 + + # Load the registers with the data present in context-data of the + # context we are going to switch to + lmg %r6, %r14, GR_OFFSET(%r15) + + # Restore Floating point registers + ld %f1,FP_OFFSET(%r15) + ld %f3,FP_OFFSET+8(%r15) + ld %f5,FP_OFFSET+16(%r15) + ld %f7,FP_OFFSET+24(%r15) + + # Load PC + lg %r1,PC_OFFSET(%r15) + + # Adjust the stack + aghi %r15,120 + + # R2 --> Address where the return transfer_t is stored + # R0 --> FCTX + # R4 --> DATA + + # Store the elements to return transfer_t + stg %r15, 0(%r2) + stg %r4, 8(%r2) + + # Note: The address in R2 points to the place where the return + # transfer_t is stored. Since context_function take transfer_t + # as first parameter. And R2 is the register which holds the + # first parameter value. + + #jump to context + br %r1 + +.size jump_fcontext,.-jump_fcontext +# Mark that we don't need executable stack. +.section .note.GNU-stack,"",%progbits + + + diff --git a/libs/context/src/asm/jump_x86_64_ms_pe_gas.asm b/libs/context/src/asm/jump_x86_64_ms_pe_gas.asm new file mode 100644 index 0000000..ec4ecfe --- /dev/null +++ b/libs/context/src/asm/jump_x86_64_ms_pe_gas.asm @@ -0,0 +1,209 @@ +/* + Copyright Oliver Kowalke 2009. + Copyright Thomas Sailer 2013. + 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) +*/ + +/************************************************************************************* +* ---------------------------------------------------------------------------------- * +* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * +* ---------------------------------------------------------------------------------- * +* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * +* ---------------------------------------------------------------------------------- * +* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * +* ---------------------------------------------------------------------------------- * +* | 0xe40 | 0x44 | 0x48 | 0x4c | 0x50 | 0x54 | 0x58 | 0x5c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * +* ---------------------------------------------------------------------------------- * +* | 0x60 | 0x64 | 0x68 | 0x6c | 0x70 | 0x74 | 0x78 | 0x7c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 32 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | * +* ---------------------------------------------------------------------------------- * +* | 0x80 | 0x84 | 0x88 | 0x8c | 0x90 | 0x94 | 0x98 | 0x9c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | * +* ---------------------------------------------------------------------------------- * +* | 0xa0 | 0xa4 | 0xa8 | 0xac | 0xb0 | 0xb4 | 0xb8 | 0xbc | * +* ---------------------------------------------------------------------------------- * +* | fc_mxcsr|fc_x87_cw| | fbr_strg | fc_dealloc | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | * +* ---------------------------------------------------------------------------------- * +* | 0xc0 | 0xc4 | 0xc8 | 0xcc | 0xd0 | 0xd4 | 0xd8 | 0xdc | * +* ---------------------------------------------------------------------------------- * +* | limit | base | R12 | R13 | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | * +* ---------------------------------------------------------------------------------- * +* | 0xe0 | 0xe4 | 0xe8 | 0xec | 0xf0 | 0xf4 | 0xf8 | 0xfc | * +* ---------------------------------------------------------------------------------- * +* | R14 | R15 | RDI | RSI | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | * +* ---------------------------------------------------------------------------------- * +* | 0x100 | 0x104 | 0x108 | 0x10c | 0x110 | 0x114 | 0x118 | 0x11c | * +* ---------------------------------------------------------------------------------- * +* | RBX | RBP | hidden | RIP | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | * +* ---------------------------------------------------------------------------------- * +* | 0x120 | 0x124 | 0x128 | 0x12c | 0x130 | 0x134 | 0x138 | 0x13c | * +* ---------------------------------------------------------------------------------- * +* | parameter area | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | * +* ---------------------------------------------------------------------------------- * +* | 0x140 | 0x144 | 0x148 | 0x14c | 0x150 | 0x154 | 0x158 | 0x15c | * +* ---------------------------------------------------------------------------------- * +* | FCTX | DATA | | * +* ---------------------------------------------------------------------------------- * +**************************************************************************************/ + +.file "jump_x86_64_ms_pe_gas.asm" +.text +.p2align 4,,15 +.globl jump_fcontext +.def jump_fcontext; .scl 2; .type 32; .endef +.seh_proc jump_fcontext +jump_fcontext: +.seh_endprologue + + leaq -0x118(%rsp), %rsp /* prepare stack */ + +#if !defined(BOOST_USE_TSX) + /* save XMM storage */ + movaps %xmm6, 0x0(%rsp) + movaps %xmm7, 0x10(%rsp) + movaps %xmm8, 0x20(%rsp) + movaps %xmm9, 0x30(%rsp) + movaps %xmm10, 0x40(%rsp) + movaps %xmm11, 0x50(%rsp) + movaps %xmm12, 0x60(%rsp) + movaps %xmm13, 0x70(%rsp) + movaps %xmm14, 0x80(%rsp) + movaps %xmm15, 0x90(%rsp) + stmxcsr 0xa0(%rsp) /* save MMX control- and status-word */ + fnstcw 0xa4(%rsp) /* save x87 control-word */ +#endif + + /* load NT_TIB */ + movq %gs:(0x30), %r10 + /* save fiber local storage */ + movq 0x20(%r10), %rax + movq %rax, 0xb0(%rsp) + /* save current deallocation stack */ + movq 0x1478(%r10), %rax + movq %rax, 0xb8(%rsp) + /* save current stack limit */ + movq 0x10(%r10), %rax + movq %rax, 0xc0(%rsp) + /* save current stack base */ + movq 0x08(%r10), %rax + movq %rax, 0xc8(%rsp) + + movq %r12, 0xd0(%rsp) /* save R12 */ + movq %r13, 0xd8(%rsp) /* save R13 */ + movq %r14, 0xe0(%rsp) /* save R14 */ + movq %r15, 0xe8(%rsp) /* save R15 */ + movq %rdi, 0xf0(%rsp) /* save RDI */ + movq %rsi, 0xf8(%rsp) /* save RSI */ + movq %rbx, 0x100(%rsp) /* save RBX */ + movq %rbp, 0x108(%rsp) /* save RBP */ + + movq %rcx, 0x110(%rsp) /* save hidden address of transport_t */ + + /* preserve RSP (pointing to context-data) in R9 */ + movq %rsp, %r9 + + /* restore RSP (pointing to context-data) from RDX */ + movq %rdx, %rsp + +#if !defined(BOOST_USE_TSX) + /* restore XMM storage */ + movaps 0x0(%rsp), %xmm6 + movaps 0x10(%rsp), %xmm7 + movaps 0x20(%rsp), %xmm8 + movaps 0x30(%rsp), %xmm9 + movaps 0x40(%rsp), %xmm10 + movaps 0x50(%rsp), %xmm11 + movaps 0x60(%rsp), %xmm12 + movaps 0x70(%rsp), %xmm13 + movaps 0x80(%rsp), %xmm14 + movaps 0x90(%rsp), %xmm15 + ldmxcsr 0xa0(%rsp) /* restore MMX control- and status-word */ + fldcw 0xa4(%rsp) /* restore x87 control-word */ +#endif + + /* load NT_TIB */ + movq %gs:(0x30), %r10 + /* restore fiber local storage */ + movq 0xb0(%rsp), %rax + movq %rax, 0x20(%r10) + /* restore current deallocation stack */ + movq 0xb8(%rsp), %rax + movq %rax, 0x1478(%r10) + /* restore current stack limit */ + movq 0xc0(%rsp), %rax + movq %rax, 0x10(%r10) + /* restore current stack base */ + movq 0xc8(%rsp), %rax + movq %rax, 0x08(%r10) + + movq 0xd0(%rsp), %r12 /* restore R12 */ + movq 0xd8(%rsp), %r13 /* restore R13 */ + movq 0xe0(%rsp), %r14 /* restore R14 */ + movq 0xe8(%rsp), %r15 /* restore R15 */ + movq 0xf0(%rsp), %rdi /* restore RDI */ + movq 0xf8(%rsp), %rsi /* restore RSI */ + movq 0x100(%rsp), %rbx /* restore RBX */ + movq 0x108(%rsp), %rbp /* restore RBP */ + + movq 0x110(%rsp), %rax /* restore hidden address of transport_t */ + + leaq 0x118(%rsp), %rsp /* prepare stack */ + + /* restore return-address */ + popq %r10 + + /* transport_t returned in RAX */ + /* return parent fcontext_t */ + movq %r9, 0x0(%rax) + /* return data */ + movq %r8, 0x8(%rax) + + /* transport_t as 1.arg of context-function */ + movq %rax, %rcx + + /* indirect jump to context */ + jmp *%r10 +.seh_endproc + +.section .drectve +.ascii " -export:\"jump_fcontext\"" diff --git a/libs/context/src/asm/jump_x86_64_ms_pe_masm.asm b/libs/context/src/asm/jump_x86_64_ms_pe_masm.asm new file mode 100644 index 0000000..c8a28a5 --- /dev/null +++ b/libs/context/src/asm/jump_x86_64_ms_pe_masm.asm @@ -0,0 +1,205 @@ + +; Copyright Oliver Kowalke 2009. +; 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) + +; ---------------------------------------------------------------------------------- +; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | +; ---------------------------------------------------------------------------------- +; | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | +; ---------------------------------------------------------------------------------- +; | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | +; ---------------------------------------------------------------------------------- +; | 0xe40 | 0x44 | 0x48 | 0x4c | 0x50 | 0x54 | 0x58 | 0x5c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | +; ---------------------------------------------------------------------------------- +; | 0x60 | 0x64 | 0x68 | 0x6c | 0x70 | 0x74 | 0x78 | 0x7c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 32 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | +; ---------------------------------------------------------------------------------- +; | 0x80 | 0x84 | 0x88 | 0x8c | 0x90 | 0x94 | 0x98 | 0x9c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | +; ---------------------------------------------------------------------------------- +; | 0xa0 | 0xa4 | 0xa8 | 0xac | 0xb0 | 0xb4 | 0xb8 | 0xbc | +; ---------------------------------------------------------------------------------- +; | fc_mxcsr|fc_x87_cw| | fbr_strg | fc_dealloc | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | +; ---------------------------------------------------------------------------------- +; | 0xc0 | 0xc4 | 0xc8 | 0xcc | 0xd0 | 0xd4 | 0xd8 | 0xdc | +; ---------------------------------------------------------------------------------- +; | limit | base | R12 | R13 | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | +; ---------------------------------------------------------------------------------- +; | 0xe0 | 0xe4 | 0xe8 | 0xec | 0xf0 | 0xf4 | 0xf8 | 0xfc | +; ---------------------------------------------------------------------------------- +; | R14 | R15 | RDI | RSI | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | +; ---------------------------------------------------------------------------------- +; | 0x100 | 0x104 | 0x108 | 0x10c | 0x110 | 0x114 | 0x118 | 0x11c | +; ---------------------------------------------------------------------------------- +; | RBX | RBP | hidden | RIP | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | +; ---------------------------------------------------------------------------------- +; | 0x120 | 0x124 | 0x128 | 0x12c | 0x130 | 0x134 | 0x138 | 0x13c | +; ---------------------------------------------------------------------------------- +; | parameter area | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | +; ---------------------------------------------------------------------------------- +; | 0x140 | 0x144 | 0x148 | 0x14c | 0x150 | 0x154 | 0x158 | 0x15c | +; ---------------------------------------------------------------------------------- +; | FCTX | DATA | | +; ---------------------------------------------------------------------------------- + +.code + +jump_fcontext PROC BOOST_CONTEXT_EXPORT FRAME + .endprolog + + ; prepare stack + lea rsp, [rsp-0118h] + +IFNDEF BOOST_USE_TSX + ; save XMM storage + movaps [rsp], xmm6 + movaps [rsp+010h], xmm7 + movaps [rsp+020h], xmm8 + movaps [rsp+030h], xmm9 + movaps [rsp+040h], xmm10 + movaps [rsp+050h], xmm11 + movaps [rsp+060h], xmm12 + movaps [rsp+070h], xmm13 + movaps [rsp+080h], xmm14 + movaps [rsp+090h], xmm15 + ; save MMX control- and status-word + stmxcsr [rsp+0a0h] + ; save x87 control-word + fnstcw [rsp+0a4h] +ENDIF + + ; load NT_TIB + mov r10, gs:[030h] + ; save fiber local storage + mov rax, [r10+020h] + mov [rsp+0b0h], rax + ; save current deallocation stack + mov rax, [r10+01478h] + mov [rsp+0b8h], rax + ; save current stack limit + mov rax, [r10+010h] + mov [rsp+0c0h], rax + ; save current stack base + mov rax, [r10+08h] + mov [rsp+0c8h], rax + + mov [rsp+0d0h], r12 ; save R12 + mov [rsp+0d8h], r13 ; save R13 + mov [rsp+0e0h], r14 ; save R14 + mov [rsp+0e8h], r15 ; save R15 + mov [rsp+0f0h], rdi ; save RDI + mov [rsp+0f8h], rsi ; save RSI + mov [rsp+0100h], rbx ; save RBX + mov [rsp+0108h], rbp ; save RBP + + mov [rsp+0110h], rcx ; save hidden address of transport_t + + ; preserve RSP (pointing to context-data) in R9 + mov r9, rsp + + ; restore RSP (pointing to context-data) from RDX + mov rsp, rdx + +IFNDEF BOOST_USE_TSX + ; restore XMM storage + movaps xmm6, [rsp] + movaps xmm7, [rsp+010h] + movaps xmm8, [rsp+020h] + movaps xmm9, [rsp+030h] + movaps xmm10, [rsp+040h] + movaps xmm11, [rsp+050h] + movaps xmm12, [rsp+060h] + movaps xmm13, [rsp+070h] + movaps xmm14, [rsp+080h] + movaps xmm15, [rsp+090h] + ; restore MMX control- and status-word + ldmxcsr [rsp+0a0h] + ; save x87 control-word + fldcw [rsp+0a4h] +ENDIF + + ; load NT_TIB + mov r10, gs:[030h] + ; restore fiber local storage + mov rax, [rsp+0b0h] + mov [r10+020h], rax + ; restore current deallocation stack + mov rax, [rsp+0b8h] + mov [r10+01478h], rax + ; restore current stack limit + mov rax, [rsp+0c0h] + mov [r10+010h], rax + ; restore current stack base + mov rax, [rsp+0c8h] + mov [r10+08h], rax + + mov r12, [rsp+0d0h] ; restore R12 + mov r13, [rsp+0d8h] ; restore R13 + mov r14, [rsp+0e0h] ; restore R14 + mov r15, [rsp+0e8h] ; restore R15 + mov rdi, [rsp+0f0h] ; restore RDI + mov rsi, [rsp+0f8h] ; restore RSI + mov rbx, [rsp+0100h] ; restore RBX + mov rbp, [rsp+0108h] ; restore RBP + + mov rax, [rsp+0110h] ; restore hidden address of transport_t + + ; prepare stack + lea rsp, [rsp+0118h] + + ; load return-address + pop r10 + + ; transport_t returned in RAX + ; return parent fcontext_t + mov [rax], r9 + ; return data + mov [rax+08h], r8 + + ; transport_t as 1.arg of context-function + mov rcx, rax + + ; indirect jump to context + jmp r10 +jump_fcontext ENDP +END diff --git a/libs/context/src/asm/jump_x86_64_sysv_elf_gas.S b/libs/context/src/asm/jump_x86_64_sysv_elf_gas.S new file mode 100644 index 0000000..d0defc4 --- /dev/null +++ b/libs/context/src/asm/jump_x86_64_sysv_elf_gas.S @@ -0,0 +1,81 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| R12 | R13 | R14 | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * + * ---------------------------------------------------------------------------------- * + * | R15 | RBX | RBP | RIP | * + * ---------------------------------------------------------------------------------- * + * * + ****************************************************************************************/ + +.file "jump_x86_64_sysv_elf_gas.S" +.text +.globl jump_fcontext +.type jump_fcontext,@function +.align 16 +jump_fcontext: + leaq -0x38(%rsp), %rsp /* prepare stack */ + +#if !defined(BOOST_USE_TSX) + stmxcsr (%rsp) /* save MMX control- and status-word */ + fnstcw 0x4(%rsp) /* save x87 control-word */ +#endif + + movq %r12, 0x8(%rsp) /* save R12 */ + movq %r13, 0x10(%rsp) /* save R13 */ + movq %r14, 0x18(%rsp) /* save R14 */ + movq %r15, 0x20(%rsp) /* save R15 */ + movq %rbx, 0x28(%rsp) /* save RBX */ + movq %rbp, 0x30(%rsp) /* save RBP */ + + /* store RSP (pointing to context-data) in RAX */ + movq %rsp, %rax + + /* restore RSP (pointing to context-data) from RDI */ + movq %rdi, %rsp + + movq 0x38(%rsp), %r8 /* restore return-address */ + +#if !defined(BOOST_USE_TSX) + ldmxcsr (%rsp) /* restore MMX control- and status-word */ + fldcw 0x4(%rsp) /* restore x87 control-word */ +#endif + + movq 0x8(%rsp), %r12 /* restore R12 */ + movq 0x10(%rsp), %r13 /* restore R13 */ + movq 0x18(%rsp), %r14 /* restore R14 */ + movq 0x20(%rsp), %r15 /* restore R15 */ + movq 0x28(%rsp), %rbx /* restore RBX */ + movq 0x30(%rsp), %rbp /* restore RBP */ + + leaq 0x40(%rsp), %rsp /* prepare stack */ + + /* return transfer_t from jump */ + /* RAX == fctx, RDX == data */ + movq %rsi, %rdx + /* pass transfer_t as first arg in context function */ + /* RDI == fctx, RSI == data */ + movq %rax, %rdi + + /* indirect jump to context */ + jmp *%r8 +.size jump_fcontext,.-jump_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/jump_x86_64_sysv_macho_gas.S b/libs/context/src/asm/jump_x86_64_sysv_macho_gas.S new file mode 100644 index 0000000..afc3e5c --- /dev/null +++ b/libs/context/src/asm/jump_x86_64_sysv_macho_gas.S @@ -0,0 +1,75 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| R12 | R13 | R14 | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * + * ---------------------------------------------------------------------------------- * + * | R15 | RBX | RBP | RIP | * + * ---------------------------------------------------------------------------------- * + * * + ****************************************************************************************/ + +.text +.globl _jump_fcontext +.align 8 +_jump_fcontext: + leaq -0x38(%rsp), %rsp /* prepare stack */ + +#if !defined(BOOST_USE_TSX) + stmxcsr (%rsp) /* save MMX control- and status-word */ + fnstcw 0x4(%rsp) /* save x87 control-word */ +#endif + + movq %r12, 0x8(%rsp) /* save R12 */ + movq %r13, 0x10(%rsp) /* save R13 */ + movq %r14, 0x18(%rsp) /* save R14 */ + movq %r15, 0x20(%rsp) /* save R15 */ + movq %rbx, 0x28(%rsp) /* save RBX */ + movq %rbp, 0x30(%rsp) /* save RBP */ + + /* store RSP (pointing to context-data) in RAX */ + movq %rsp, %rax + + /* restore RSP (pointing to context-data) from RDI */ + movq %rdi, %rsp + + movq 0x38(%rsp), %r8 /* restore return-address */ + +#if !defined(BOOST_USE_TSX) + ldmxcsr (%rsp) /* restore MMX control- and status-word */ + fldcw 0x4(%rsp) /* restore x87 control-word */ +#endif + + movq 0x8(%rsp), %r12 /* restore R12 */ + movq 0x10(%rsp), %r13 /* restore R13 */ + movq 0x18(%rsp), %r14 /* restore R14 */ + movq 0x20(%rsp), %r15 /* restore R15 */ + movq 0x28(%rsp), %rbx /* restore RBX */ + movq 0x30(%rsp), %rbp /* restore RBP */ + + leaq 0x40(%rsp), %rsp /* prepare stack */ + + /* return transfer_t from jump */ + /* RAX == fctx, RDX == data */ + movq %rsi, %rdx + /* pass transfer_t as first arg in context function */ + /* RDI == fctx, RSI == data */ + movq %rax, %rdi + + /* indirect jump to context */ + jmp *%r8 diff --git a/libs/context/src/asm/make_arm64_aapcs_elf_gas.S b/libs/context/src/asm/make_arm64_aapcs_elf_gas.S new file mode 100644 index 0000000..66cfb2d --- /dev/null +++ b/libs/context/src/asm/make_arm64_aapcs_elf_gas.S @@ -0,0 +1,85 @@ +/* + Copyright Edward Nevill + Oliver Kowalke 2015 + 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) +*/ +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | d8 | d9 | d10 | d11 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | d12 | d13 | d14 | d15 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| * + * ------------------------------------------------- * + * | x19 | x20 | x21 | x22 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| * + * ------------------------------------------------- * + * | x23 | x24 | x25 | x26 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| * + * ------------------------------------------------- * + * | x27 | x28 | FP | LR | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | | | * + * ------------------------------------------------- * + * | 0xa0| 0xa4| 0xa8| 0xac| | | * + * ------------------------------------------------- * + * | PC | align | | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.file "make_arm64_aapcs_elf_gas.S" +.text +.align 2 +.global make_fcontext +.type make_fcontext, %function +make_fcontext: + # shift address in x0 (allocated stack) to lower 16 byte boundary + and x0, x0, ~0xF + + # reserve space for context-data on context-stack + sub x0, x0, #0xb0 + + # third arg of make_fcontext() == address of context-function + # store address as a PC to jump in + str x2, [x0, #0xa0] + + # save address of finish as return-address for context-function + # will be entered after context-function returns (LR register) + adr x1, finish + str x1, [x0, #0x98] + + ret x30 // return pointer to context-data (x0) + +finish: + # exit code is zero + mov x0, #0 + # exit application + bl _exit + +.size make_fcontext,.-make_fcontext +# Mark that we don't need executable stack. +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/make_arm64_aapcs_macho_gas.S b/libs/context/src/asm/make_arm64_aapcs_macho_gas.S new file mode 100644 index 0000000..a3716ff --- /dev/null +++ b/libs/context/src/asm/make_arm64_aapcs_macho_gas.S @@ -0,0 +1,88 @@ +/* + Copyright Edward Nevill + Oliver Kowalke 2015 + 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) +*/ +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | d8 | d9 | d10 | d11 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | d12 | d13 | d14 | d15 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| * + * ------------------------------------------------- * + * | x19 | x20 | x21 | x22 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| * + * ------------------------------------------------- * + * | x23 | x24 | x25 | x26 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| * + * ------------------------------------------------- * + * | x27 | x28 | FP | LR | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | | | * + * ------------------------------------------------- * + * | 0xa0| 0xa4| 0xa8| 0xac| | | * + * ------------------------------------------------- * + * | PC | align | | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.text +.globl _make_fcontext +.balign 16 + +_make_fcontext: + ; shift address in x0 (allocated stack) to lower 16 byte boundary + and x0, x0, ~0xF + + ; reserve space for context-data on context-stack + sub x0, x0, #0xb0 + + ; third arg of make_fcontext() == address of context-function + ; store address as a PC to jump in + str x2, [x0, #0xa0] + + ; compute abs address of label finish + ; 0x0c = 3 instructions * size (4) before label 'finish' + + ; TODO: Numeric offset since llvm still does not support labels in ADR. Fix: + ; http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20140407/212336.html + adr x1, 0x0c + + ; save address of finish as return-address for context-function + ; will be entered after context-function returns (LR register) + str x1, [x0, #0x98] + + ret lr ; return pointer to context-data (x0) + +finish: + ; exit code is zero + mov x0, #0 + ; exit application + bl __exit + + diff --git a/libs/context/src/asm/make_arm_aapcs_elf_gas.S b/libs/context/src/asm/make_arm_aapcs_elf_gas.S new file mode 100644 index 0000000..98ae64b --- /dev/null +++ b/libs/context/src/asm/make_arm_aapcs_elf_gas.S @@ -0,0 +1,81 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | s16 | s17 | s18 | s19 | s20 | s21 | s22 | s23 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | s24 | s25 | s26 | s27 | s28 | s29 | s30 | s31 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| * + * ------------------------------------------------- * + * |hiddn| v1 | v2 | v3 | v4 | v5 | v6 | v7 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| * + * ------------------------------------------------- * + * | v8 | lr | pc | FCTX| DATA| | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.file "make_arm_aapcs_elf_gas.S" +.text +.globl make_fcontext +.align 2 +.type make_fcontext,%function +.syntax unified +make_fcontext: + @ shift address in A1 to lower 16 byte boundary + bic a1, a1, #15 + + @ reserve space for context-data on context-stack + sub a1, a1, #124 + + @ third arg of make_fcontext() == address of context-function + str a3, [a1, #104] + + @ compute address of returned transfer_t + add a2, a1, #108 + mov a3, a2 + str a3, [a1, #64] + + @ compute abs address of label finish + adr a2, finish + @ save address of finish as return-address for context-function + @ will be entered after context-function returns + str a2, [a1, #100] + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) +#endif + + bx lr @ return pointer to context-data + +finish: + @ exit code is zero + mov a1, #0 + @ exit application + bl _exit@PLT +.size make_fcontext,.-make_fcontext + +@ Mark that we don't need executable stack. +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/make_arm_aapcs_macho_gas.S b/libs/context/src/asm/make_arm_aapcs_macho_gas.S new file mode 100644 index 0000000..c909ae9 --- /dev/null +++ b/libs/context/src/asm/make_arm_aapcs_macho_gas.S @@ -0,0 +1,71 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | s16 | s17 | s18 | s19 | s20 | s21 | s22 | s23 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | s24 | s25 | s26 | s27 | s28 | s29 | s30 | s31 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | sjlj|hiddn| v1 | v2 | v3 | v4 | v5 | v6 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | v7 | v8 | lr | pc | FCTX| DATA| | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.text +.globl _make_fcontext +.align 2 +_make_fcontext: + @ shift address in A1 to lower 16 byte boundary + bic a1, a1, #15 + + @ reserve space for context-data on context-stack + sub a1, a1, #124 + + @ third arg of make_fcontext() == address of context-function + str a3, [a1, #108] + + @ compute address of returned transfer_t + add a2, a1, #112 + mov a3, a2 + str a3, [a1, #68] + + @ compute abs address of label finish + adr a2, finish + @ save address of finish as return-address for context-function + @ will be entered after context-function returns + str a2, [a1, #104] + + bx lr @ return pointer to context-data + +finish: + @ exit code is zero + mov a1, #0 + @ exit application + bl __exit diff --git a/libs/context/src/asm/make_arm_aapcs_pe_armasm.asm b/libs/context/src/asm/make_arm_aapcs_pe_armasm.asm new file mode 100644 index 0000000..27cbfb0 --- /dev/null +++ b/libs/context/src/asm/make_arm_aapcs_pe_armasm.asm @@ -0,0 +1,77 @@ +;/* +; Copyright Oliver Kowalke 2009. +; 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) +;*/ + +; ******************************************************* +; * * +; * ------------------------------------------------- * +; * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * +; * ------------------------------------------------- * +; * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * +; * ------------------------------------------------- * +; * |deall|limit| base|hiddn| v1 | v2 | v3 | v4 | * +; * ------------------------------------------------- * +; * ------------------------------------------------- * +; * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * +; * ------------------------------------------------- * +; * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * +; * ------------------------------------------------- * +; * | v5 | v6 | v7 | v8 | lr | pc | FCTX| DATA| * +; * ------------------------------------------------- * +; * * +; ******************************************************* + + + AREA |.text|, CODE + ALIGN 4 + EXPORT make_fcontext + IMPORT _exit + +make_fcontext PROC + ; first arg of make_fcontext() == top of context-stack + ; save top of context-stack (base) A4 + mov a4, a1 + + ; shift address in A1 to lower 16 byte boundary + bic a1, a1, #0x0f + + ; reserve space for context-data on context-stack + sub a1, a1, #0x48 + + ; save top address of context_stack as 'base' + str a4, [a1, #0x8] + ; second arg of make_fcontext() == size of context-stack + ; compute bottom address of context-stack (limit) + sub a4, a4, a2 + ; save bottom address of context-stack as 'limit' + str a4, [a1, #0x4] + ; save bottom address of context-stack as 'dealloction stack' + str a4, [a1, #0x0] + + ; third arg of make_fcontext() == address of context-function + str a3, [a1, #0x34] + + ; compute address of returned transfer_t + add a2, a1, #0x38 + mov a3, a2 + str a3, [a1, #0xc] + + ; compute abs address of label finish + adr a2, finish + ; save address of finish as return-address for context-function + ; will be entered after context-function returns + str a2, [a1, #0x30] + + bx lr ; return pointer to context-data + +finish + ; exit code is zero + mov a1, #0 + ; exit application + bl _exit + + ENDP + END diff --git a/libs/context/src/asm/make_combined_sysv_macho_gas.S b/libs/context/src/asm/make_combined_sysv_macho_gas.S new file mode 100644 index 0000000..727e904 --- /dev/null +++ b/libs/context/src/asm/make_combined_sysv_macho_gas.S @@ -0,0 +1,20 @@ +/* + Copyright Sergue E. Leontiev 2013. + 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) +*/ + +// Stub file for universal binary + +#if defined(__i386__) + #include "make_i386_sysv_macho_gas.S" +#elif defined(__x86_64__) + #include "make_x86_64_sysv_macho_gas.S" +#elif defined(__ppc__) + #include "make_ppc32_sysv_macho_gas.S" +#elif defined(__ppc64__) + #include "make_ppc64_sysv_macho_gas.S" +#else + #error "No arch's" +#endif diff --git a/libs/context/src/asm/make_i386_ms_pe_gas.asm b/libs/context/src/asm/make_i386_ms_pe_gas.asm new file mode 100644 index 0000000..dcb7700 --- /dev/null +++ b/libs/context/src/asm/make_i386_ms_pe_gas.asm @@ -0,0 +1,147 @@ +/* + Copyright Oliver Kowalke 2009. + Copyright Thomas Sailer 2013. + 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) +*/ + +/************************************************************************************* +* --------------------------------------------------------------------------------- * +* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * +* --------------------------------------------------------------------------------- * +* | 0h | 04h | 08h | 0ch | 010h | 014h | 018h | 01ch | * +* --------------------------------------------------------------------------------- * +* | fc_mxcsr|fc_x87_cw| fc_strg |fc_deallo| limit | base | fc_seh | EDI | * +* --------------------------------------------------------------------------------- * +* --------------------------------------------------------------------------------- * +* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * +* --------------------------------------------------------------------------------- * +* | 020h | 024h | 028h | 02ch | 030h | 034h | 038h | 03ch | * +* --------------------------------------------------------------------------------- * +* | ESI | EBX | EBP | EIP | to | data | EH NXT |SEH HNDLR| * +* --------------------------------------------------------------------------------- * +**************************************************************************************/ + +.file "make_i386_ms_pe_gas.asm" +.text +.p2align 4,,15 +.globl _make_fcontext +.def _make_fcontext; .scl 2; .type 32; .endef +_make_fcontext: + /* first arg of make_fcontext() == top of context-stack */ + movl 0x04(%esp), %eax + + /* reserve space for first argument of context-function */ + /* EAX might already point to a 16byte border */ + leal -0x8(%eax), %eax + + /* shift address in EAX to lower 16 byte boundary */ + andl $-16, %eax + + /* reserve space for context-data on context-stack */ + /* size for fc_mxcsr .. EIP + return-address for context-function */ + /* on context-function entry: (ESP -0x4) % 8 == 0 */ + /* additional space is required for SEH */ + leal -0x40(%eax), %eax + + /* save MMX control- and status-word */ + stmxcsr (%eax) + /* save x87 control-word */ + fnstcw 0x4(%eax) + + /* first arg of make_fcontext() == top of context-stack */ + movl 0x4(%esp), %ecx + /* save top address of context stack as 'base' */ + movl %ecx, 0x14(%eax) + /* second arg of make_fcontext() == size of context-stack */ + movl 0x8(%esp), %edx + /* negate stack size for LEA instruction (== substraction) */ + negl %edx + /* compute bottom address of context stack (limit) */ + leal (%ecx,%edx), %ecx + /* save bottom address of context-stack as 'limit' */ + movl %ecx, 0x10(%eax) + /* save bottom address of context-stack as 'dealloction stack' */ + movl %ecx, 0xc(%eax) + /* set fiber-storage to zero */ + xorl %ecx, %ecx + movl %ecx, 0x8(%eax) + + /* third arg of make_fcontext() == address of context-function */ + /* stored in EBX */ + movl 0xc(%esp), %ecx + movl %ecx, 0x24(%eax) + + /* compute abs address of label trampoline */ + movl $trampoline, %ecx + /* save address of trampoline as return-address for context-function */ + /* will be entered after calling jump_fcontext() first time */ + movl %ecx, 0x2c(%eax) + + /* compute abs address of label finish */ + movl $finish, %ecx + /* save address of finish as return-address for context-function */ + /* will be entered after context-function returns */ + movl %ecx, 0x28(%eax) + + /* traverse current seh chain to get the last exception handler installed by Windows */ + /* note that on Windows Server 2008 and 2008 R2, SEHOP is activated by default */ + /* the exception handler chain is tested for the presence of ntdll.dll!FinalExceptionHandler */ + /* at its end by RaiseException all seh andlers are disregarded if not present and the */ + /* program is aborted */ + /* load NT_TIB into ECX */ + movl %fs:(0x0), %ecx + +walk: + /* load 'next' member of current SEH into EDX */ + movl (%ecx), %edx + /* test if 'next' of current SEH is last (== 0xffffffff) */ + incl %edx + jz found + decl %edx + /* exchange content; ECX contains address of next SEH */ + xchgl %ecx, %edx + /* inspect next SEH */ + jmp walk + +found: + /* load 'handler' member of SEH == address of last SEH handler installed by Windows */ + movl 0x04(%ecx), %ecx + /* save address in ECX as SEH handler for context */ + movl %ecx, 0x3c(%eax) + /* set ECX to -1 */ + movl $0xffffffff, %ecx + /* save ECX as next SEH item */ + movl %ecx, 0x38(%eax) + /* load address of next SEH item */ + leal 0x38(%eax), %ecx + /* save next SEH */ + movl %ecx, 0x18(%eax) + + /* return pointer to context-data */ + ret + +trampoline: + /* move transport_t for entering context-function */ + /* FCTX == EAX, DATA == EDX */ + movl %eax, (%esp) + movl %edx, 0x4(%esp) + /* label finish as return-address */ + pushl %ebp + /* jump to context-function */ + jmp *%ebx + +finish: + /* ESP points to same address as ESP on entry of context function + 0x4 */ + xorl %eax, %eax + /* exit code is zero */ + movl %eax, (%esp) + /* exit application */ + call __exit + hlt + +.def __exit; .scl 2; .type 32; .endef /* standard C library function */ + +.section .drectve +.ascii " -export:\"make_fcontext\"" diff --git a/libs/context/src/asm/make_i386_ms_pe_masm.asm b/libs/context/src/asm/make_i386_ms_pe_masm.asm new file mode 100644 index 0000000..5246465 --- /dev/null +++ b/libs/context/src/asm/make_i386_ms_pe_masm.asm @@ -0,0 +1,140 @@ + +; Copyright Oliver Kowalke 2009. +; 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) + +; --------------------------------------------------------------------------------- +; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | +; --------------------------------------------------------------------------------- +; | 0h | 04h | 08h | 0ch | 010h | 014h | 018h | 01ch | +; --------------------------------------------------------------------------------- +; | fc_mxcsr|fc_x87_cw| fc_strg |fc_deallo| limit | base | fc_seh | EDI | +; --------------------------------------------------------------------------------- +; --------------------------------------------------------------------------------- +; | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | +; --------------------------------------------------------------------------------- +; | 020h | 024h | 028h | 02ch | 030h | 034h | 038h | 03ch | +; --------------------------------------------------------------------------------- +; | ESI | EBX | EBP | EIP | to | data | EH NXT |SEH HNDLR| +; --------------------------------------------------------------------------------- + +.386 +.XMM +.model flat, c +; standard C library function +_exit PROTO, value:SDWORD +.code + +make_fcontext PROC BOOST_CONTEXT_EXPORT + ; first arg of make_fcontext() == top of context-stack + mov eax, [esp+04h] + + ; reserve space for first argument of context-function + ; EAX might already point to a 16byte border + lea eax, [eax-08h] + + ; shift address in EAX to lower 16 byte boundary + and eax, -16 + + ; reserve space for context-data on context-stack + ; on context-function entry: (ESP -0x4) % 8 == 0 + ; additional space is required for SEH + lea eax, [eax-040h] + + ; save MMX control- and status-word + stmxcsr [eax] + ; save x87 control-word + fnstcw [eax+04h] + + ; first arg of make_fcontext() == top of context-stack + mov ecx, [esp+04h] + ; save top address of context stack as 'base' + mov [eax+014h], ecx + ; second arg of make_fcontext() == size of context-stack + mov edx, [esp+08h] + ; negate stack size for LEA instruction (== substraction) + neg edx + ; compute bottom address of context stack (limit) + lea ecx, [ecx+edx] + ; save bottom address of context-stack as 'limit' + mov [eax+010h], ecx + ; save bottom address of context-stack as 'dealloction stack' + mov [eax+0ch], ecx + ; set fiber-storage to zero + xor ecx, ecx + mov [eax+08h], ecx + + ; third arg of make_fcontext() == address of context-function + ; stored in EBX + mov ecx, [esp+0ch] + mov [eax+024h], ecx + + ; compute abs address of label trampoline + mov ecx, trampoline + ; save address of trampoline as return-address for context-function + ; will be entered after calling jump_fcontext() first time + mov [eax+02ch], ecx + + ; compute abs address of label finish + mov ecx, finish + ; save address of finish as return-address for context-function in EBP + ; will be entered after context-function returns + mov [eax+028h], ecx + + ; traverse current seh chain to get the last exception handler installed by Windows + ; note that on Windows Server 2008 and 2008 R2, SEHOP is activated by default + ; the exception handler chain is tested for the presence of ntdll.dll!FinalExceptionHandler + ; at its end by RaiseException all seh-handlers are disregarded if not present and the + ; program is aborted + assume fs:nothing + ; load NT_TIB into ECX + mov ecx, fs:[0h] + assume fs:error + +walk: + ; load 'next' member of current SEH into EDX + mov edx, [ecx] + ; test if 'next' of current SEH is last (== 0xffffffff) + inc edx + jz found + dec edx + ; exchange content; ECX contains address of next SEH + xchg edx, ecx + ; inspect next SEH + jmp walk + +found: + ; load 'handler' member of SEH == address of last SEH handler installed by Windows + mov ecx, [ecx+04h] + ; save address in ECX as SEH handler for context + mov [eax+03ch], ecx + ; set ECX to -1 + mov ecx, 0ffffffffh + ; save ECX as next SEH item + mov [eax+038h], ecx + ; load address of next SEH item + lea ecx, [eax+038h] + ; save next SEH + mov [eax+018h], ecx + + ret ; return pointer to context-data + +trampoline: + ; move transport_t for entering context-function + ; FCTX == EAX, DATA == EDX + mov [esp], eax + mov [esp+04h], edx + push ebp + ; jump to context-function + jmp ebx + +finish: + ; exit code is zero + xor eax, eax + mov [esp], eax + ; exit application + call _exit + hlt +make_fcontext ENDP +END diff --git a/libs/context/src/asm/make_i386_sysv_elf_gas.S b/libs/context/src/asm/make_i386_sysv_elf_gas.S new file mode 100644 index 0000000..b76de26 --- /dev/null +++ b/libs/context/src/asm/make_i386_sysv_elf_gas.S @@ -0,0 +1,107 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| EDI | ESI | EBX | EBP | EIP | hidden | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | 0x24 | | * + * ---------------------------------------------------------------------------------- * + * | to | data | | * + * ---------------------------------------------------------------------------------- * + * * + ****************************************************************************************/ + +.file "make_i386_sysv_elf_gas.S" +.text +.globl make_fcontext +.align 2 +.type make_fcontext,@function +make_fcontext: + /* first arg of make_fcontext() == top of context-stack */ + movl 0x4(%esp), %eax + + /* reserve space for first argument of context-function + eax might already point to a 16byte border */ + leal -0x8(%eax), %eax + + /* shift address in EAX to lower 16 byte boundary */ + andl $-16, %eax + + /* reserve space for context-data on context-stack */ + leal -0x28(%eax), %eax + + /* third arg of make_fcontext() == address of context-function */ + /* stored in EBX */ + movl 0xc(%esp), %ecx + movl %ecx, 0x10(%eax) + + /* save MMX control- and status-word */ + stmxcsr (%eax) + /* save x87 control-word */ + fnstcw 0x4(%eax) + + /* return transport_t */ + /* FCTX == EDI, DATA == ESI */ + leal 0x8(%eax), %ecx + movl %ecx, 0x1c(%eax) + + /* compute abs address of label trampoline */ + call 1f + /* address of trampoline 1 */ +1: popl %ecx + /* compute abs address of label trampoline */ + addl $trampoline-1b, %ecx + /* save address of trampoline as return address */ + /* will be entered after calling jump_fcontext() first time */ + movl %ecx, 0x18(%eax) + + /* compute abs address of label finish */ + call 2f + /* address of label 2 */ +2: popl %ecx + /* compute abs address of label finish */ + addl $finish-2b, %ecx + /* save address of finish as return-address for context-function */ + /* will be entered after context-function returns */ + movl %ecx, 0x14(%eax) + + ret /* return pointer to context-data */ + +trampoline: + /* move transport_t for entering context-function */ + movl %edi, (%esp) + movl %esi, 0x4(%esp) + pushl %ebp + /* jump to context-function */ + jmp *%ebx + +finish: + call 3f + /* address of label 3 */ +3: popl %ebx + /* compute address of GOT and store it in EBX */ + addl $_GLOBAL_OFFSET_TABLE_+[.-3b], %ebx + + /* exit code is zero */ + xorl %eax, %eax + movl %eax, (%esp) + /* exit application */ + call _exit@PLT + hlt +.size make_fcontext,.-make_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/make_i386_sysv_macho_gas.S b/libs/context/src/asm/make_i386_sysv_macho_gas.S new file mode 100644 index 0000000..fdcdb7c --- /dev/null +++ b/libs/context/src/asm/make_i386_sysv_macho_gas.S @@ -0,0 +1,90 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| EDI | ESI | EBX | EBP | EIP | to | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | | * + * ---------------------------------------------------------------------------------- * + * | data | | * + * ---------------------------------------------------------------------------------- * + * * + ****************************************************************************************/ + +.text +.globl _make_fcontext +.align 2 +_make_fcontext: + /* first arg of make_fcontext() == top of context-stack */ + movl 0x4(%esp), %eax + + /* reserve space for first argument of context-function + eax might already point to a 16byte border */ + leal -0x8(%eax), %eax + + /* shift address in EAX to lower 16 byte boundary */ + andl $-16, %eax + + /* reserve space for context-data on context-stack */ + leal -0x2c(%eax), %eax + + /* third arg of make_fcontext() == address of context-function */ + /* stored in EBX */ + movl 0xc(%esp), %ecx + movl %ecx, 0x10(%eax) + + /* save MMX control- and status-word */ + stmxcsr (%eax) + /* save x87 control-word */ + fnstcw 0x4(%eax) + + /* compute abs address of label trampoline */ + call 1f + /* address of trampoline 1 */ +1: popl %ecx + /* compute abs address of label trampoline */ + addl $trampoline-1b, %ecx + /* save address of trampoline as return address */ + /* will be entered after calling jump_fcontext() first time */ + movl %ecx, 0x18(%eax) + + /* compute abs address of label finish */ + call 2f + /* address of label 2 */ +2: popl %ecx + /* compute abs address of label finish */ + addl $finish-2b, %ecx + /* save address of finish as return-address for context-function */ + /* will be entered after context-function returns */ + movl %ecx, 0x14(%eax) + + ret /* return pointer to context-data */ + +trampoline: + /* move transport_t for entering context-function */ + movl %eax, (%esp) + movl %edx, 0x4(%esp) + pushl %ebp + /* jump to context-function */ + jmp *%ebx + +finish: + /* exit code is zero */ + xorl %eax, %eax + movl %eax, (%esp) + /* exit application */ + call __exit + hlt diff --git a/libs/context/src/asm/make_i386_x86_64_sysv_macho_gas.S b/libs/context/src/asm/make_i386_x86_64_sysv_macho_gas.S new file mode 100644 index 0000000..e364b2d --- /dev/null +++ b/libs/context/src/asm/make_i386_x86_64_sysv_macho_gas.S @@ -0,0 +1,16 @@ +/* + Copyright Sergue E. Leontiev 2013. + 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) +*/ + +// Stub file for universal binary + +#if defined(__i386__) + #include "make_i386_sysv_macho_gas.S" +#elif defined(__x86_64__) + #include "make_x86_64_sysv_macho_gas.S" +#else + #error "No arch's" +#endif diff --git a/libs/context/src/asm/make_mips32_o32_elf_gas.S b/libs/context/src/asm/make_mips32_o32_elf_gas.S new file mode 100644 index 0000000..4e11e3d --- /dev/null +++ b/libs/context/src/asm/make_mips32_o32_elf_gas.S @@ -0,0 +1,97 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | F20 | F22 | F24 | F26 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | F28 | F30 | S0 | S1 | S2 | S3 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | S4 | S5 | S6 | S7 | FP |hiddn| RA | PC | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | ABI ARGS | GP | FCTX| DATA| | * + * ------------------------------------------------- * + * * + * *****************************************************/ + +.file "make_mips32_o32_elf_gas.S" +.text +.globl make_fcontext +.align 2 +.type make_fcontext,@function +.ent make_fcontext +make_fcontext: +#ifdef __PIC__ +.set noreorder +.cpload $t9 +.set reorder +#endif + # shift address in A0 to lower 16 byte boundary + li $v1, -16 # 0xfffffffffffffff0 + and $v0, $v1, $a0 + + # reserve space for context-data on context-stack + # includes an extra 32 bytes for: + # - 16-byte incoming argument area required by mips ABI used when + # jump_context calls the initial function + # - 4 bytes to save our GP register used in finish + # - 8 bytes to as space for transfer_t returned to finish + # - 4 bytes for alignment + addiu $v0, $v0, -128 + + # third arg of make_fcontext() == address of context-function + sw $a2, 92($v0) + # save global pointer in context-data + sw $gp, 112($v0) + + # compute address of returned transfer_t + addiu $t0, $v0, 116 + sw $t0, 84($v0) + + # compute abs address of label finish + la $t9, finish + # save address of finish as return-address for context-function + # will be entered after context-function returns + sw $t9, 88($v0) + + jr $ra # return pointer to context-data + +finish: + # reload our gp register (needed for la) + lw $gp, 16($sp) + + # call _exit(0) + # the previous function should have left the 16 bytes incoming argument + # area on the stack which we reuse for calling _exit + la $t9, _exit + move $a0, $zero + jr $t9 +.end make_fcontext +.size make_fcontext, .-make_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/make_mips64_n64_elf_gas.S b/libs/context/src/asm/make_mips64_n64_elf_gas.S new file mode 100644 index 0000000..55419ac --- /dev/null +++ b/libs/context/src/asm/make_mips64_n64_elf_gas.S @@ -0,0 +1,96 @@ +/* + Copyright Jiaxun Yang 2018. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 8 | 16 | 24 | * + * ------------------------------------------------- * + * | F24 | F25 | F26 | F27 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 40 | 48 | 56 | * + * ------------------------------------------------- * + * | F28 | F29 | F30 | F31 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 72 | 80 | 88 | * + * ------------------------------------------------- * + * | S0 | S1 | S2 | S3 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | S4 | S5 | S6 | S7 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | FP | GP | RA | PC | * + * ------------------------------------------------- * + * * + * *****************************************************/ + +.file "make_mips64_n64_elf_gas.S" +.text +.globl make_fcontext +.align 2 +.type make_fcontext,@function +.ent make_fcontext +make_fcontext: +#ifdef __PIC__ +.set noreorder +.cpload $t9 +.set reorder +#endif + # shift address in A0 to lower 16 byte boundary + li $v1, 0xfffffffffffffff0 + and $v0, $v1, $a0 + + # reserve space for context-data on context-stack + daddiu $v0, $v0, -160 + + # third arg of make_fcontext() == address of context-function + sd $a2, 152($v0) + # save global pointer in context-data + sd $gp, 136($v0) + + # psudo instruction compute abs address of label finish based on GP + dla $t9, finish + + # save address of finish as return-address for context-function + # will be entered after context-function returns + sd $t9, 144($v0) + + jr $ra # return pointer to context-data + +finish: + # reload our gp register (needed for la) + daddiu $t0, $sp, -160 + ld $gp, 136($t0) + + # call _exit(0) + # the previous function should have left the 16 bytes incoming argument + # area on the stack which we reuse for calling _exit + dla $t9, _exit + move $a0, $zero + jr $t9 +.end make_fcontext +.size make_fcontext, .-make_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/make_ppc32_ppc64_sysv_macho_gas.S b/libs/context/src/asm/make_ppc32_ppc64_sysv_macho_gas.S new file mode 100644 index 0000000..52e7220 --- /dev/null +++ b/libs/context/src/asm/make_ppc32_ppc64_sysv_macho_gas.S @@ -0,0 +1,16 @@ +/* + Copyright Sergue E. Leontiev 2013. + 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) +*/ + +// Stub file for universal binary + +#if defined(__ppc__) + #include "make_ppc32_sysv_macho_gas.S" +#elif defined(__ppc64__) + #include "make_ppc64_sysv_macho_gas.S" +#else + #error "No arch's" +#endif diff --git a/libs/context/src/asm/make_ppc32_sysv_elf_gas.S b/libs/context/src/asm/make_ppc32_sysv_elf_gas.S new file mode 100644 index 0000000..9616c4c --- /dev/null +++ b/libs/context/src/asm/make_ppc32_sysv_elf_gas.S @@ -0,0 +1,146 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * |bchai|hiddn| fpscr | PC | CR | R14 | R15 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | R16 | R17 | R18 | R19 | R20 | R21 | R22 | R23 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | R24 | R25 | R26 | R27 | R28 | R29 | R30 | R31 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | F14 | F15 | F16 | F17 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | F18 | F19 | F20 | F21 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | F22 | F23 | F24 | F25 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | F26 | F27 | F28 | F29 | * + * ------------------------------------------------- * + * ------------------------|------------ * + * | 224 | 228 | 232 | 236 | 240 | 244 | * + * ------------------------|------------ * + * | F30 | F31 |bchai| LR | * + * ------------------------|------------ * + * * + *******************************************************/ + +.file "make_ppc32_sysv_elf_gas.S" +.text +.globl make_fcontext +.align 2 +.type make_fcontext,@function +make_fcontext: + # save return address into R6 + mflr %r6 + + # first arg of make_fcontext() == top address of context-function + # shift address in R3 to lower 16 byte boundary + clrrwi %r3, %r3, 4 + + # reserve space on context-stack, including 16 bytes of linkage + # and parameter area + 240 bytes of context-data (R1 % 16 == 0) + subi %r3, %r3, 16 + 240 + + # third arg of make_fcontext() == address of context-function +#ifdef __linux__ + # save context-function as PC + stw %r5, 16(%r3) +#else + # save context-function for trampoline + stw %r5, 248(%r3) +#endif + + # set back-chain to zero + li %r0, 0 + stw %r0, 240(%r3) + + # copy FPSCR to new context + mffs %f0 + stfd %f0, 8(%r3) + +#ifdef __linux__ + # set hidden pointer for returning transfer_t + la %r0, 248(%r3) + stw %r0, 4(%r3) +#endif + + # load address of label 1 into R4 + bl 1f +1: mflr %r4 +#ifndef __linux__ + # compute abs address of trampoline, use as PC + addi %r7, %r4, trampoline - 1b + stw %r7, 16(%r3) +#endif + # compute abs address of label finish + addi %r4, %r4, finish - 1b + # save address of finish as return-address for context-function + # will be entered after context-function returns + stw %r4, 244(%r3) + + # restore return address from R6 + mtlr %r6 + + blr # return pointer to context-data + +#ifndef __linux__ +trampoline: + # On systems other than Linux, jump_fcontext is returning the + # transfer_t in R3:R4, but we need to pass transfer_t * R3 to + # our context-function. + lwz %r0, 8(%r1) # address of context-function + mtctr %r0 + stw %r3, 8(%r1) + stw %r4, 12(%r1) + la %r3, 8(%r1) # address of transfer_t + bctr +#endif + +finish: + # Use the secure PLT for _exit(0). If we use the insecure BSS PLT + # here, then the linker may use the insecure BSS PLT even if the + # C++ compiler wanted the secure PLT. + + # set R30 for secure PLT, large model + bl 2f +2: mflr %r30 + addis %r30, %r30, .Ltoc - 2b@ha + addi %r30, %r30, .Ltoc - 2b@l + + # call _exit(0) with special addend 0x8000 for large model + li %r3, 0 + bl _exit + 0x8000@plt +.size make_fcontext, .-make_fcontext + +/* Provide the GOT pointer for secure PLT, large model. */ +.section .got2,"aw" +.Ltoc = . + 0x8000 + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/make_ppc32_sysv_macho_gas.S b/libs/context/src/asm/make_ppc32_sysv_macho_gas.S new file mode 100644 index 0000000..8f35eff --- /dev/null +++ b/libs/context/src/asm/make_ppc32_sysv_macho_gas.S @@ -0,0 +1,137 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/****************************************************** + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | F14 | F15 | F16 | F17 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | F18 | F19 | F20 | F21 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | F22 | F23 | F24 | F25 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | F26 | F27 | F28 | F29 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | F30 | F31 | fpscr | R13 | R14 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | R15 | R16 | R17 | R18 | R19 | R20 | R21 | R22 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | R23 | R24 | R25 | R26 | R27 | R28 | R29 | R30 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | * + * ------------------------------------------------- * + * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * + * ------------------------------------------------- * + * | R31 |hiddn| CR | LR | PC |bchai|linkr| FCTX| * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 64 | | * + * ------------------------------------------------- * + * | 256 | | * + * ------------------------------------------------- * + * | DATA| | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.text +.globl _make_fcontext +.align 2 +_make_fcontext: + # save return address into R6 + mflr r6 + + # first arg of make_fcontext() == top address of context-function + # shift address in R3 to lower 16 byte boundary + clrrwi r3, r3, 4 + + # reserve space for context-data on context-stack + # including 64 byte of linkage + parameter area (R1 16 == 0) + subi r3, r3, 336 + + # third arg of make_fcontext() == address of context-function + stw r5, 240(r3) + + # set back-chain to zero + li r0, 0 + stw r0, 244(r3) + + mffs f0 # load FPSCR + stfd f0, 144(r3) # save FPSCR + + # compute address of returned transfer_t + addi r0, r3, 252 + mr r4, r0 + stw r4, 228(r3) + + # load LR + mflr r0 + # jump to label 1 + bl 1f +1: + # load LR into R4 + mflr r4 + # compute abs address of label finish + addi r4, r4, finish - 1b + # restore LR + mtlr r0 + # save address of finish as return-address for context-function + # will be entered after context-function returns + stw r4, 236(r3) + + # restore return address from R6 + mtlr r6 + + blr # return pointer to context-data + +finish: + # save return address into R0 + mflr r0 + # save return address on stack, set up stack frame + stw r0, 4(r1) + # allocate stack space, R1 16 == 0 + stwu r1, -16(r1) + + # exit code is zero + li r3, 0 + # exit application + bl _exit@plt diff --git a/libs/context/src/asm/make_ppc32_sysv_xcoff_gas.S b/libs/context/src/asm/make_ppc32_sysv_xcoff_gas.S new file mode 100644 index 0000000..f257258 --- /dev/null +++ b/libs/context/src/asm/make_ppc32_sysv_xcoff_gas.S @@ -0,0 +1,138 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/****************************************************** + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | F14 | F15 | F16 | F17 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | F18 | F19 | F20 | F21 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | F22 | F23 | F24 | F25 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | F26 | F27 | F28 | F29 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | F30 | F31 | fpscr | R13 | R14 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | R15 | R16 | R17 | R18 | R19 | R20 | R21 | R22 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | R23 | R24 | R25 | R26 | R27 | R28 | R29 | R30 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | * + * ------------------------------------------------- * + * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * + * ------------------------------------------------- * + * | R31 |hiddn| CR | LR | PC |bchai|linkr| FCTX| * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 64 | | * + * ------------------------------------------------- * + * | 256 | | * + * ------------------------------------------------- * + * | DATA| | * + * ------------------------------------------------- * + * * + *******************************************************/ + .globl make_fcontext[DS] + .globl .make_fcontext[PR] + .align 2 + .csect make_fcontext[DS] +make_fcontext: + .long .make_fcontext[PR] + .csect .make_fcontext[PR], 3 +#.make_fcontext: + # save return address into R6 + mflr 6 + + # first arg of make_fcontext() == top address of context-function + # shift address in R3 to lower 16 byte boundary + clrrwi 3, 3, 4 + + # reserve space for context-data on context-stack + # including 64 byte of linkage + parameter area (R1 % 16 == 0) + subi 3, 3, 336 + + # third arg of make_fcontext() == address of context-function + stw 5, 240(3) + + # set back-chain to zero + li 0, 0 + stw 0, 244(3) + + # compute address of returned transfer_t + addi 0, 3, 252 + mr 4, 0 + stw 4, 228(3) + + # load LR + mflr 0 + # jump to label 1 + bl .Label +.Label: + # load LR into R4 + mflr 4 + # compute abs address of label .L_finish + addi 4, 4, .L_finish - .Label + # restore LR + mtlr 0 + # save address of finish as return-address for context-function + # will be entered after context-function returns + stw 4, 236(3) + + # restore return address from R6 + mtlr 6 + + blr # return pointer to context-data + +.L_finish: + # save return address into R0 + mflr 0 + # save return address on stack, set up stack frame + stw 0, 4(1) + # allocate stack space, R1 % 16 == 0 + stwu 1, -16(1) + + # exit code is zero + li 3, 0 + # exit application + bl ._exit + nop diff --git a/libs/context/src/asm/make_ppc64_sysv_elf_gas.S b/libs/context/src/asm/make_ppc64_sysv_elf_gas.S new file mode 100644 index 0000000..c4d7ee5 --- /dev/null +++ b/libs/context/src/asm/make_ppc64_sysv_elf_gas.S @@ -0,0 +1,177 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | TOC | R14 | R15 | R16 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | R17 | R18 | R19 | R20 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | R21 | R22 | R23 | R24 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | R25 | R26 | R27 | R28 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | R29 | R30 | R31 | hidden | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | CR | LR | PC | back-chain| * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | cr saved | lr saved | compiler | linker | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | * + * ------------------------------------------------- * + * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * + * ------------------------------------------------- * + * | TOC saved | FCTX | DATA | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.file "make_ppc64_sysv_elf_gas.S" +.globl make_fcontext +#if _CALL_ELF == 2 + .text + .align 2 +make_fcontext: + addis %r2, %r12, .TOC.-make_fcontext@ha + addi %r2, %r2, .TOC.-make_fcontext@l + .localentry make_fcontext, . - make_fcontext +#else + .section ".opd","aw" + .align 3 +make_fcontext: +# ifdef _CALL_LINUX + .quad .L.make_fcontext,.TOC.@tocbase,0 + .type make_fcontext,@function + .text + .align 2 +.L.make_fcontext: +# else + .hidden .make_fcontext + .globl .make_fcontext + .quad .make_fcontext,.TOC.@tocbase,0 + .size make_fcontext,24 + .type .make_fcontext,@function + .text + .align 2 +.make_fcontext: +# endif +#endif + # save return address into R6 + mflr %r6 + + # first arg of make_fcontext() == top address of context-stack + # shift address in R3 to lower 16 byte boundary + clrrdi %r3, %r3, 4 + + # reserve space for context-data on context-stack + # including 64 byte of linkage + parameter area (R1 % 16 == 0) + subi %r3, %r3, 248 + + # third arg of make_fcontext() == address of context-function + # entry point (ELFv2) or descriptor (ELFv1) +#if _CALL_ELF == 2 + # save address of context-function entry point + std %r5, 176(%r3) +#else + # save address of context-function entry point + ld %r4, 0(%r5) + std %r4, 176(%r3) + # save TOC of context-function + ld %r4, 8(%r5) + std %r4, 0(%r3) +#endif + + # set back-chain to zero + li %r0, 0 + std %r0, 184(%r3) + +#if _CALL_ELF != 2 + # zero in r3 indicates first jump to context-function + std %r0, 152(%r3) +#endif + + # load LR + mflr %r0 + # jump to label 1 + bl 1f +1: + # load LR into R4 + mflr %r4 + # compute abs address of label finish + addi %r4, %r4, finish - 1b + # restore LR + mtlr %r0 + # save address of finish as return-address for context-function + # will be entered after context-function returns + std %r4, 168(%r3) + + # restore return address from R6 + mtlr %r6 + + blr # return pointer to context-data + +finish: + # save return address into R0 + mflr %r0 + # save return address on stack, set up stack frame + std %r0, 8(%r1) + # allocate stack space, R1 % 16 == 0 + stdu %r1, -32(%r1) + + # exit code is zero + li %r3, 0 + # exit application + bl _exit + nop +#if _CALL_ELF == 2 + .size make_fcontext, .-make_fcontext +#else +# ifdef _CALL_LINUX + .size .make_fcontext, .-.L.make_fcontext +# else + .size .make_fcontext, .-.make_fcontext +# endif +#endif + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/make_ppc64_sysv_macho_gas.S b/libs/context/src/asm/make_ppc64_sysv_macho_gas.S new file mode 100644 index 0000000..7b947bb --- /dev/null +++ b/libs/context/src/asm/make_ppc64_sysv_macho_gas.S @@ -0,0 +1,126 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | TOC | R14 | R15 | R16 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | R17 | R18 | R19 | R20 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | R21 | R22 | R23 | R24 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | R25 | R26 | R27 | R28 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | R29 | R30 | R31 | hidden | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | CR | LR | PC | back-chain| * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | cr saved | lr saved | compiler | linker | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | * + * ------------------------------------------------- * + * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * + * ------------------------------------------------- * + * | TOC saved | FCTX | DATA | | * + * ------------------------------------------------- * + * * + +.text +.globl _make_fcontext +_make_fcontext: + ; save return address into R6 + mflr r6 + + ; first arg of make_fcontext() == top address of context-function + ; shift address in R3 to lower 16 byte boundary + clrrwi r3, r3, 4 + + ; reserve space for context-data on context-stack + ; including 64 byte of linkage + parameter area (R1 16 == 0) + subi r3, r3, 248 + + ; third arg of make_fcontext() == address of context-function + stw r5, 176(r3) + + ; set back-chain to zero + li %r0, 0 + std %r0, 184(%r3) + + ; compute address of returned transfer_t + addi %r0, %r3, 232 + mr %r4, %r0 + std %r4, 152(%r3) + + ; load LR + mflr r0 + ; jump to label 1 + bl l1 +l1: + ; load LR into R4 + mflr r4 + ; compute abs address of label finish + addi r4, r4, lo16((finish - .) + 4) + ; restore LR + mtlr r0 + ; save address of finish as return-address for context-function + ; will be entered after context-function returns + std r4, 168(r3) + + ; restore return address from R6 + mtlr r6 + + blr ; return pointer to context-data + +finish: + ; save return address into R0 + mflr r0 + ; save return address on stack, set up stack frame + stw r0, 8(r1) + ; allocate stack space, R1 16 == 0 + stwu r1, -32(r1) + + ; set return value to zero + li r3, 0 + ; exit application + bl __exit + nop diff --git a/libs/context/src/asm/make_ppc64_sysv_xcoff_gas.S b/libs/context/src/asm/make_ppc64_sysv_xcoff_gas.S new file mode 100644 index 0000000..60ad6b6 --- /dev/null +++ b/libs/context/src/asm/make_ppc64_sysv_xcoff_gas.S @@ -0,0 +1,68 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + .globl make_fcontext[DS] + .globl .make_fcontext[PR] + .align 2 + .csect .make_fcontext[PR], 3 + .globl _make_fcontext +#._make_fcontext: + # save return address into R6 + mflr 6 + + # first arg of make_fcontext() == top address of context-function + # shift address in R3 to lower 16 byte boundary + clrrwi 3, 3, 4 + + # reserve space for context-data on context-stack + # including 64 byte of linkage + parameter area (R1 % 16 == 0) + subi 3, 3, 248 + + # third arg of make_fcontext() == address of context-function + stw 5, 176(3) + + # set back-chain to zero + li 0, 0 + std 0, 184(3) + + # compute address of returned transfer_t + addi 0, 3, 232 + mr 4, 0 + std 4, 152(3) + + # load LR + mflr 0 + # jump to label 1 + bl .Label +.Label: + # load LR into R4 + mflr 4 + # compute abs address of label .L_finish + addi 4, 4, .L_finish - .Label + # restore LR + mtlr 0 + # save address of finish as return-address for context-function + # will be entered after context-function returns + stw 4, 168(3) + + # restore return address from R6 + mtlr 6 + + blr # return pointer to context-data + +.L_finish: + # save return address into R0 + mflr 0 + # save return address on stack, set up stack frame + stw 0, 8(1) + # allocate stack space, R1 % 16 == 0 + stwu 1, -32(1) + + # exit code is zero + li 3, 0 + # exit application + bl ._exit + nop diff --git a/libs/context/src/asm/make_riscv64_sysv_elf_gas.S b/libs/context/src/asm/make_riscv64_sysv_elf_gas.S new file mode 100644 index 0000000..559f61d --- /dev/null +++ b/libs/context/src/asm/make_riscv64_sysv_elf_gas.S @@ -0,0 +1,91 @@ +/* + 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) +*/ +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | fs0 | fs1 | fs2 | fs3 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | fs4 | fs5 | fs6 | fs7 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| * + * ------------------------------------------------- * + * | fs8 | fs9 | fs10 | fs11 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| * + * ------------------------------------------------- * + * | s0 | s1 | s2 | s3 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| * + * ------------------------------------------------- * + * | s4 | s5 | s6 | s7 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 0xa0| 0xa4| 0xa8| 0xac| 0xb0| 0xb4| 0xb8| 0xbc| * + * ------------------------------------------------- * + * | s8 | s9 | s10 | s11 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | | | | | * + * ------------------------------------------------- * + * | 0xc0| 0xc4| 0xc8| 0xcc| | | | | * + * ------------------------------------------------- * + * | ra | pc | | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.file "make_riscv64_sysv_elf_gas.S" +.text +.align 1 +.global make_fcontext +.type make_fcontext, %function +make_fcontext: + # shift address in a0 (allocated stack) to lower 16 byte boundary + andi a0, a0, ~0xF + + # reserve space for context-data on context-stack + addi a0, a0, -0xd0 + + # third arg of make_fcontext() == address of context-function + # store address as a PC to jump in + sd a2, 0xc8(a0) + + # save address of finish as return-address for context-function + # will be entered after context-function returns (RA register) + la a4, finish + sd a4, 0xc0(a0) + + ret // return pointer to context-data (a0) + +finish: + # exit code is zero + li a0, 0 + # exit application + tail _exit + +.size make_fcontext,.-make_fcontext +# Mark that we don't need executable stack. +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/make_s390x_sysv_elf_gas.S b/libs/context/src/asm/make_s390x_sysv_elf_gas.S new file mode 100644 index 0000000..d02856c --- /dev/null +++ b/libs/context/src/asm/make_s390x_sysv_elf_gas.S @@ -0,0 +1,104 @@ +/******************************************************* +* * +* ------------------------------------------------- * +* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * +* ------------------------------------------------- * +* | 0 | 8 | 16 | 24 | * +* ------------------------------------------------- * +* | R6 | R7 | R8 | R9 | * +* ------------------------------------------------- * +* ------------------------------------------------- * +* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * +* ------------------------------------------------- * +* | 32 | 40 | 48 | 56 | * +* ------------------------------------------------- * +* | R10 | R11 | R12 | R13 | * +* ------------------------------------------------- * +* ------------------------------------------------- * +* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * +* ------------------------------------------------- * +* | 64 | 72 | 80 | 88 | * +* ------------------------------------------------- * +* | R14/LR | R15 | F1 | F3 | * +* ------------------------------------------------- * +* ------------------------------------------------- * +* | 24 | 25 | 26 | 27 | 28 | 29 | | * +* ------------------------------------------------- * +* | 96 | 104 | 112 | 120 | * +* ------------------------------------------------- * +* | F5 | F7 | PC | | * +* ------------------------------------------------- * +* *****************************************************/ + +.file "make_s390x_sysv_elf_gas.S" +.text +.align 4 # According to the sample code in the ELF ABI docs +.global make_fcontext +.type make_fcontext, @function + +#define GR_OFFSET 0 +#define LR_OFFSET 64 +#define SP_OFFSET 72 +#define FP_OFFSET 80 +#define PC_OFFSET 112 +#define L_CTX 120 +#define L_STACKFRAME 120 + +make_fcontext: + + # make_fcontext takes in 3 arguments + # arg1 --> The address where the context needs to be made + # arg2 --> The size of the context + # arg3 --> The address of the context function + + # According to the ELF ABI, the register R2 holds the first arg. + # R2 also acts as the register which holds return value + # Register R3 holds the second, R4 the third so on. + + # Shift the address in R2 to a lower 8 byte boundary + + # This is done because according to the ELF ABI Doc, the stack needs + # to be 8 byte aligned. + # In order to do so, we need to make sure that the address is divisible + # by 8. We can check this, by checking if the the last 3 bits of the + # address is zero or not. If not AND it with `-8`. + + # Here we AND the lower 16 bits of the memory address present in the + # R2 with the bits 1111 1111 1111 1000 + nill %r2,0xfff0 + + # Reserve space for context-data on context-stack. + # This is done by shifting the SP/address by 112 bytes. + aghi %r2,-L_CTX + + # third arg of make_fcontext() == address of the context-function + # Store the address as a PC to jump in, whenever we call the + # make_fcontext. + stg %r4,PC_OFFSET(%r2) + + # Save the address of finish as return-address for context-function + # This will be entered after context-function return + # The address of finish will be saved in Link register, this register + # specifies where we need to jump after the function executes + # completely. + larl %r1,finish + stg %r1,LR_OFFSET(%r2) + + # Return pointer to context data + # R14 acts as the link register + # R2 holds the address of the context stack. When we return from the + # make_fcontext, R2 is passed back. + br %r14 + + finish: + + # In finish tasks, you load the exit code and exit the make_fcontext + # This is called when the context-function is entirely executed + + lghi %r2,0 + brasl %r14,_exit@PLT + +.size make_fcontext,.-make_fcontext +# Mark that we don't need executable stack. +.section .note.GNU-stack,"",%progbits + diff --git a/libs/context/src/asm/make_x86_64_ms_pe_gas.asm b/libs/context/src/asm/make_x86_64_ms_pe_gas.asm new file mode 100644 index 0000000..958a2a7 --- /dev/null +++ b/libs/context/src/asm/make_x86_64_ms_pe_gas.asm @@ -0,0 +1,174 @@ +/* + Copyright Oliver Kowalke 2009. + Copyright Thomas Sailer 2013. + 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) +*/ + +/************************************************************************************* +* ---------------------------------------------------------------------------------- * +* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * +* ---------------------------------------------------------------------------------- * +* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * +* ---------------------------------------------------------------------------------- * +* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * +* ---------------------------------------------------------------------------------- * +* | 0xe40 | 0x44 | 0x48 | 0x4c | 0x50 | 0x54 | 0x58 | 0x5c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * +* ---------------------------------------------------------------------------------- * +* | 0x60 | 0x64 | 0x68 | 0x6c | 0x70 | 0x74 | 0x78 | 0x7c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 32 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | * +* ---------------------------------------------------------------------------------- * +* | 0x80 | 0x84 | 0x88 | 0x8c | 0x90 | 0x94 | 0x98 | 0x9c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | * +* ---------------------------------------------------------------------------------- * +* | 0xa0 | 0xa4 | 0xa8 | 0xac | 0xb0 | 0xb4 | 0xb8 | 0xbc | * +* ---------------------------------------------------------------------------------- * +* | fc_mxcsr|fc_x87_cw| | fbr_strg | fc_dealloc | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | * +* ---------------------------------------------------------------------------------- * +* | 0xc0 | 0xc4 | 0xc8 | 0xcc | 0xd0 | 0xd4 | 0xd8 | 0xdc | * +* ---------------------------------------------------------------------------------- * +* | limit | base | R12 | R13 | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | * +* ---------------------------------------------------------------------------------- * +* | 0xe0 | 0xe4 | 0xe8 | 0xec | 0xf0 | 0xf4 | 0xf8 | 0xfc | * +* ---------------------------------------------------------------------------------- * +* | R14 | R15 | RDI | RSI | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | * +* ---------------------------------------------------------------------------------- * +* | 0x100 | 0x104 | 0x108 | 0x10c | 0x110 | 0x114 | 0x118 | 0x11c | * +* ---------------------------------------------------------------------------------- * +* | RBX | RBP | hidden | RIP | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | * +* ---------------------------------------------------------------------------------- * +* | 0x120 | 0x124 | 0x128 | 0x12c | 0x130 | 0x134 | 0x138 | 0x13c | * +* ---------------------------------------------------------------------------------- * +* | parameter area | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | * +* ---------------------------------------------------------------------------------- * +* | 0x140 | 0x144 | 0x148 | 0x14c | 0x150 | 0x154 | 0x158 | 0x15c | * +* ---------------------------------------------------------------------------------- * +* | FCTX | DATA | | * +* ---------------------------------------------------------------------------------- * +**************************************************************************************/ + +.file "make_x86_64_ms_pe_gas.asm" +.text +.p2align 4,,15 +.globl make_fcontext +.def make_fcontext; .scl 2; .type 32; .endef +.seh_proc make_fcontext +make_fcontext: +.seh_endprologue + + /* first arg of make_fcontext() == top of context-stack */ + movq %rcx, %rax + + /* shift address in RAX to lower 16 byte boundary */ + /* == pointer to fcontext_t and address of context stack */ + andq $-16, %rax + + /* reserve space for context-data on context-stack */ + /* on context-function entry: (RSP -0x8) % 16 == 0 */ + leaq -0x150(%rax), %rax + + /* third arg of make_fcontext() == address of context-function */ + movq %r8, 0x100(%rax) + + /* first arg of make_fcontext() == top of context-stack */ + /* save top address of context stack as 'base' */ + movq %rcx, 0xc8(%rax) + /* second arg of make_fcontext() == size of context-stack */ + /* negate stack size for LEA instruction (== substraction) */ + negq %rdx + /* compute bottom address of context stack (limit) */ + leaq (%rcx,%rdx), %rcx + /* save bottom address of context stack as 'limit' */ + movq %rcx, 0xc0(%rax) + /* save address of context stack limit as 'dealloction stack' */ + movq %rcx, 0xb8(%rax) + /* set fiber-storage to zero */ + xorq %rcx, %rcx + movq %rcx, 0xb0(%rax) + + /* save MMX control- and status-word */ + stmxcsr 0xa0(%rax) + /* save x87 control-word */ + fnstcw 0xa4(%rax) + + /* compute address of transport_t */ + leaq 0x140(%rax), %rcx + /* store address of transport_t in hidden field */ + movq %rcx, 0x110(%rax) + + /* compute abs address of label trampoline */ + leaq trampoline(%rip), %rcx + /* save address of finish as return-address for context-function */ + /* will be entered after jump_fcontext() first time */ + movq %rcx, 0x118(%rax) + + /* compute abs address of label finish */ + leaq finish(%rip), %rcx + /* save address of finish as return-address for context-function */ + /* will be entered after context-function returns */ + movq %rcx, 0x108(%rax) + + ret /* return pointer to context-data */ + +trampoline: + /* store return address on stack */ + /* fix stack alignment */ + pushq %rbp + /* jump to context-function */ + jmp *%rbx + +finish: + /* 32byte shadow-space for _exit() */ + andq $-32, %rsp + /* 32byte shadow-space for _exit() are */ + /* already reserved by make_fcontext() */ + /* exit code is zero */ + xorq %rcx, %rcx + /* exit application */ + call _exit + hlt +.seh_endproc + +.def _exit; .scl 2; .type 32; .endef /* standard C library function */ + +.section .drectve +.ascii " -export:\"make_fcontext\"" diff --git a/libs/context/src/asm/make_x86_64_ms_pe_masm.asm b/libs/context/src/asm/make_x86_64_ms_pe_masm.asm new file mode 100644 index 0000000..8f6c959 --- /dev/null +++ b/libs/context/src/asm/make_x86_64_ms_pe_masm.asm @@ -0,0 +1,163 @@ + +; Copyright Oliver Kowalke 2009. +; 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) + +; ---------------------------------------------------------------------------------- +; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | +; ---------------------------------------------------------------------------------- +; | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | +; ---------------------------------------------------------------------------------- +; | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | +; ---------------------------------------------------------------------------------- +; | 0xe40 | 0x44 | 0x48 | 0x4c | 0x50 | 0x54 | 0x58 | 0x5c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | +; ---------------------------------------------------------------------------------- +; | 0x60 | 0x64 | 0x68 | 0x6c | 0x70 | 0x74 | 0x78 | 0x7c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 32 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | +; ---------------------------------------------------------------------------------- +; | 0x80 | 0x84 | 0x88 | 0x8c | 0x90 | 0x94 | 0x98 | 0x9c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | +; ---------------------------------------------------------------------------------- +; | 0xa0 | 0xa4 | 0xa8 | 0xac | 0xb0 | 0xb4 | 0xb8 | 0xbc | +; ---------------------------------------------------------------------------------- +; | fc_mxcsr|fc_x87_cw| | fbr_strg | fc_dealloc | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | +; ---------------------------------------------------------------------------------- +; | 0xc0 | 0xc4 | 0xc8 | 0xcc | 0xd0 | 0xd4 | 0xd8 | 0xdc | +; ---------------------------------------------------------------------------------- +; | limit | base | R12 | R13 | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | +; ---------------------------------------------------------------------------------- +; | 0xe0 | 0xe4 | 0xe8 | 0xec | 0xf0 | 0xf4 | 0xf8 | 0xfc | +; ---------------------------------------------------------------------------------- +; | R14 | R15 | RDI | RSI | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | +; ---------------------------------------------------------------------------------- +; | 0x100 | 0x104 | 0x108 | 0x10c | 0x110 | 0x114 | 0x118 | 0x11c | +; ---------------------------------------------------------------------------------- +; | RBX | RBP | hidden | RIP | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | +; ---------------------------------------------------------------------------------- +; | 0x120 | 0x124 | 0x128 | 0x12c | 0x130 | 0x134 | 0x138 | 0x13c | +; ---------------------------------------------------------------------------------- +; | parameter area | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | +; ---------------------------------------------------------------------------------- +; | 0x140 | 0x144 | 0x148 | 0x14c | 0x150 | 0x154 | 0x158 | 0x15c | +; ---------------------------------------------------------------------------------- +; | FCTX | DATA | | +; ---------------------------------------------------------------------------------- + +; standard C library function +EXTERN _exit:PROC +.code + +; generate function table entry in .pdata and unwind information in +make_fcontext PROC BOOST_CONTEXT_EXPORT FRAME + ; .xdata for a function's structured exception handling unwind behavior + .endprolog + + ; first arg of make_fcontext() == top of context-stack + mov rax, rcx + + ; shift address in RAX to lower 16 byte boundary + ; == pointer to fcontext_t and address of context stack + and rax, -16 + + ; reserve space for context-data on context-stack + ; on context-function entry: (RSP -0x8) % 16 == 0 + sub rax, 0150h + + ; third arg of make_fcontext() == address of context-function + ; stored in RBX + mov [rax+0100h], r8 + + ; first arg of make_fcontext() == top of context-stack + ; save top address of context stack as 'base' + mov [rax+0c8h], rcx + ; second arg of make_fcontext() == size of context-stack + ; negate stack size for LEA instruction (== substraction) + neg rdx + ; compute bottom address of context stack (limit) + lea rcx, [rcx+rdx] + ; save bottom address of context stack as 'limit' + mov [rax+0c0h], rcx + ; save address of context stack limit as 'dealloction stack' + mov [rax+0b8h], rcx + ; set fiber-storage to zero + xor rcx, rcx + mov [rax+0b0h], rcx + + ; save MMX control- and status-word + stmxcsr [rax+0a0h] + ; save x87 control-word + fnstcw [rax+0a4h] + + ; compute address of transport_t + lea rcx, [rax+0140h] + ; store address of transport_t in hidden field + mov [rax+0110h], rcx + + ; compute abs address of label trampoline + lea rcx, trampoline + ; save address of trampoline as return-address for context-function + ; will be entered after calling jump_fcontext() first time + mov [rax+0118h], rcx + + ; compute abs address of label finish + lea rcx, finish + ; save address of finish as return-address for context-function in RBP + ; will be entered after context-function returns + mov [rax+0108h], rcx + + ret ; return pointer to context-data + +trampoline: + ; store return address on stack + ; fix stack alignment + push rbp + ; jump to context-function + jmp rbx + +finish: + ; exit code is zero + xor rcx, rcx + ; exit application + call _exit + hlt +make_fcontext ENDP +END diff --git a/libs/context/src/asm/make_x86_64_sysv_elf_gas.S b/libs/context/src/asm/make_x86_64_sysv_elf_gas.S new file mode 100644 index 0000000..0ef3756 --- /dev/null +++ b/libs/context/src/asm/make_x86_64_sysv_elf_gas.S @@ -0,0 +1,82 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| R12 | R13 | R14 | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * + * ---------------------------------------------------------------------------------- * + * | R15 | RBX | RBP | RIP | * + * ---------------------------------------------------------------------------------- * + * * + ****************************************************************************************/ + +.file "make_x86_64_sysv_elf_gas.S" +.text +.globl make_fcontext +.type make_fcontext,@function +.align 16 +make_fcontext: + /* first arg of make_fcontext() == top of context-stack */ + movq %rdi, %rax + + /* shift address in RAX to lower 16 byte boundary */ + andq $-16, %rax + + /* reserve space for context-data on context-stack */ + /* on context-function entry: (RSP -0x8) % 16 == 0 */ + leaq -0x40(%rax), %rax + + /* third arg of make_fcontext() == address of context-function */ + /* stored in RBX */ + movq %rdx, 0x28(%rax) + + /* save MMX control- and status-word */ + stmxcsr (%rax) + /* save x87 control-word */ + fnstcw 0x4(%rax) + + /* compute abs address of label trampoline */ + leaq trampoline(%rip), %rcx + /* save address of trampoline as return-address for context-function */ + /* will be entered after calling jump_fcontext() first time */ + movq %rcx, 0x38(%rax) + + /* compute abs address of label finish */ + leaq finish(%rip), %rcx + /* save address of finish as return-address for context-function */ + /* will be entered after context-function returns */ + movq %rcx, 0x30(%rax) + + ret /* return pointer to context-data */ + +trampoline: + /* store return address on stack */ + /* fix stack alignment */ + push %rbp + /* jump to context-function */ + jmp *%rbx + +finish: + /* exit code is zero */ + xorq %rdi, %rdi + /* exit application */ + call _exit@PLT + hlt +.size make_fcontext,.-make_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/make_x86_64_sysv_macho_gas.S b/libs/context/src/asm/make_x86_64_sysv_macho_gas.S new file mode 100644 index 0000000..5d6c543 --- /dev/null +++ b/libs/context/src/asm/make_x86_64_sysv_macho_gas.S @@ -0,0 +1,76 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| R12 | R13 | R14 | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * + * ---------------------------------------------------------------------------------- * + * | R15 | RBX | RBP | RIP | * + * ---------------------------------------------------------------------------------- * + * * + ****************************************************************************************/ + +.text +.globl _make_fcontext +.align 8 +_make_fcontext: + /* first arg of make_fcontext() == top of context-stack */ + movq %rdi, %rax + + /* shift address in RAX to lower 16 byte boundary */ + andq $-16, %rax + + /* reserve space for context-data on context-stack */ + /* on context-function entry: (RSP -0x8) % 16 == 0 */ + leaq -0x40(%rax), %rax + + /* third arg of make_fcontext() == address of context-function */ + /* stored in RBX */ + movq %rdx, 0x28(%rax) + + /* save MMX control- and status-word */ + stmxcsr (%rax) + /* save x87 control-word */ + fnstcw 0x4(%rax) + + /* compute abs address of label trampoline */ + leaq trampoline(%rip), %rcx + /* save address of trampoline as return-address for context-function */ + /* will be entered after calling jump_fcontext() first time */ + movq %rcx, 0x38(%rax) + + /* compute abs address of label finish */ + leaq finish(%rip), %rcx + /* save address of finish as return-address for context-function */ + /* will be entered after context-function returns */ + movq %rcx, 0x30(%rax) + + ret /* return pointer to context-data */ + +trampoline: + /* store return address on stack */ + /* fix stack alignment */ + push %rbp + /* jump to context-function */ + jmp *%rbx + +finish: + /* exit code is zero */ + xorq %rdi, %rdi + /* exit application */ + call __exit + hlt diff --git a/libs/context/src/asm/ontop_arm64_aapcs_elf_gas.S b/libs/context/src/asm/ontop_arm64_aapcs_elf_gas.S new file mode 100644 index 0000000..665ca5a --- /dev/null +++ b/libs/context/src/asm/ontop_arm64_aapcs_elf_gas.S @@ -0,0 +1,113 @@ +/* + Copyright Edward Nevill + Oliver Kowalke 2015 + 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) +*/ +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | d8 | d9 | d10 | d11 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | d12 | d13 | d14 | d15 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| * + * ------------------------------------------------- * + * | x19 | x20 | x21 | x22 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| * + * ------------------------------------------------- * + * | x23 | x24 | x25 | x26 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| * + * ------------------------------------------------- * + * | x27 | x28 | FP | LR | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | | | * + * ------------------------------------------------- * + * | 0xa0| 0xa4| 0xa8| 0xac| | | * + * ------------------------------------------------- * + * | PC | align | | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.file "ontop_arm64_aapcs_elf_gas.S" +.text +.align 2 +.global ontop_fcontext +.type ontop_fcontext, %function +ontop_fcontext: + # prepare stack for GP + FPU + sub sp, sp, #0xb0 + + # save d8 - d15 + stp d8, d9, [sp, #0x00] + stp d10, d11, [sp, #0x10] + stp d12, d13, [sp, #0x20] + stp d14, d15, [sp, #0x30] + + # save x19-x30 + stp x19, x20, [sp, #0x40] + stp x21, x22, [sp, #0x50] + stp x23, x24, [sp, #0x60] + stp x25, x26, [sp, #0x70] + stp x27, x28, [sp, #0x80] + stp x29, x30, [sp, #0x90] + + # save LR as PC + str x30, [sp, #0xa0] + + # store RSP (pointing to context-data) in X5 + mov x4, sp + + # restore RSP (pointing to context-data) from X1 + mov sp, x0 + + # load d8 - d15 + ldp d8, d9, [sp, #0x00] + ldp d10, d11, [sp, #0x10] + ldp d12, d13, [sp, #0x20] + ldp d14, d15, [sp, #0x30] + + # load x19-x30 + ldp x19, x20, [sp, #0x40] + ldp x21, x22, [sp, #0x50] + ldp x23, x24, [sp, #0x60] + ldp x25, x26, [sp, #0x70] + ldp x27, x28, [sp, #0x80] + ldp x29, x30, [sp, #0x90] + + # return transfer_t from jump + # pass transfer_t as first arg in context function + # X0 == FCTX, X1 == DATA + mov x0, x4 + + # skip pc + # restore stack from GP + FPU + add sp, sp, #0xb0 + + # jump to ontop-function + ret x2 +.size ontop_fcontext,.-ontop_fcontext +# Mark that we don't need executable stack. +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/ontop_arm64_aapcs_macho_gas.S b/libs/context/src/asm/ontop_arm64_aapcs_macho_gas.S new file mode 100644 index 0000000..a387d06 --- /dev/null +++ b/libs/context/src/asm/ontop_arm64_aapcs_macho_gas.S @@ -0,0 +1,108 @@ +/* + Copyright Edward Nevill + Oliver Kowalke 2015 + 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) +*/ +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | d8 | d9 | d10 | d11 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | d12 | d13 | d14 | d15 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| * + * ------------------------------------------------- * + * | x19 | x20 | x21 | x22 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| * + * ------------------------------------------------- * + * | x23 | x24 | x25 | x26 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| * + * ------------------------------------------------- * + * | x27 | x28 | FP | LR | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | | | * + * ------------------------------------------------- * + * | 0xa0| 0xa4| 0xa8| 0xac| | | * + * ------------------------------------------------- * + * | PC | align | | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.text +.global _ontop_fcontext +.balign 16 +_ontop_fcontext: + ; prepare stack for GP + FPU + sub sp, sp, #0xb0 + + ; save d8 - d15 + stp d8, d9, [sp, #0x00] + stp d10, d11, [sp, #0x10] + stp d12, d13, [sp, #0x20] + stp d14, d15, [sp, #0x30] + + ; save x19-x30 + stp x19, x20, [sp, #0x40] + stp x21, x22, [sp, #0x50] + stp x23, x24, [sp, #0x60] + stp x25, x26, [sp, #0x70] + stp x27, x28, [sp, #0x80] + stp x29, x30, [sp, #0x90] + + ; save LR as PC + str x30, [sp, #0xa0] + + ; store RSP (pointing to context-data) in X5 + mov x4, sp + + ; restore RSP (pointing to context-data) from X1 + mov sp, x0 + + ; load d8 - d15 + ldp d8, d9, [sp, #0x00] + ldp d10, d11, [sp, #0x10] + ldp d12, d13, [sp, #0x20] + ldp d14, d15, [sp, #0x30] + + ; load x19-x30 + ldp x19, x20, [sp, #0x40] + ldp x21, x22, [sp, #0x50] + ldp x23, x24, [sp, #0x60] + ldp x25, x26, [sp, #0x70] + ldp x27, x28, [sp, #0x80] + ldp x29, x30, [sp, #0x90] + + ; return transfer_t from jump + ; pass transfer_t as first arg in context function + ; X0 == FCTX, X1 == DATA + mov x0, x4 + + ; skip pc + ; restore stack from GP + FPU + add sp, sp, #0xb0 + + ; jump to ontop-function + ret x2 diff --git a/libs/context/src/asm/ontop_arm_aapcs_elf_gas.S b/libs/context/src/asm/ontop_arm_aapcs_elf_gas.S new file mode 100644 index 0000000..59ad5ca --- /dev/null +++ b/libs/context/src/asm/ontop_arm_aapcs_elf_gas.S @@ -0,0 +1,93 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | s16 | s17 | s18 | s19 | s20 | s21 | s22 | s23 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | s24 | s25 | s26 | s27 | s28 | s29 | s30 | s31 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| * + * ------------------------------------------------- * + * |hiddn| v1 | v2 | v3 | v4 | v5 | v6 | v7 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| * + * ------------------------------------------------- * + * | v8 | lr | pc | FCTX| DATA| | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.file "ontop_arm_aapcs_elf_gas.S" +.text +.globl ontop_fcontext +.align 2 +.type ontop_fcontext,%function +.syntax unified +ontop_fcontext: + @ save LR as PC + push {lr} + @ save hidden,V1-V8,LR + push {a1,v1-v8,lr} + + @ prepare stack for FPU + sub sp, sp, #64 +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + @ save S16-S31 + vstmia sp, {d8-d15} +#endif + + @ store RSP (pointing to context-data) in A1 + mov a1, sp + + @ restore RSP (pointing to context-data) from A2 + mov sp, a2 + + @ store parent context in A2 + mov a2, a1 + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + @ restore S16-S31 + vldmia sp, {d8-d15} +#endif + @ prepare stack for FPU + add sp, sp, #64 + + @ restore hidden,V1-V8,LR + pop {a1,v1-v8,lr} + + @ return transfer_t from jump + str a2, [a1, #0] + str a3, [a1, #4] + @ pass transfer_t as first arg in context function + @ A1 == hidden, A2 == FCTX, A3 == DATA + + @ skip PC + add sp, sp, #4 + + @ jump to ontop-function + bx a4 +.size ontop_fcontext,.-ontop_fcontext + +@ Mark that we don't need executable stack. +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/ontop_arm_aapcs_macho_gas.S b/libs/context/src/asm/ontop_arm_aapcs_macho_gas.S new file mode 100644 index 0000000..421fcb4 --- /dev/null +++ b/libs/context/src/asm/ontop_arm_aapcs_macho_gas.S @@ -0,0 +1,100 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | s16 | s17 | s18 | s19 | s20 | s21 | s22 | s23 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | s24 | s25 | s26 | s27 | s28 | s29 | s30 | s31 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | sjlj|hiddn| v1 | v2 | v3 | v4 | v5 | v6 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | v7 | v8 | lr | pc | FCTX| DATA| | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.text +.globl _ontop_fcontext +.align 2 +_ontop_fcontext: + @ save LR as PC + push {lr} + @ save hidden,V1-V8,LR + push {a1,v1-v8,lr} + + @ locate TLS to save/restore SjLj handler + mrc p15, 0, v2, c13, c0, #3 + bic v2, v2, #3 + + @ load TLS[__PTK_LIBC_DYLD_Unwind_SjLj_Key] + ldr v1, [v2, #8] + @ save SjLj handler + push {v1} + + @ prepare stack for FPU + sub sp, sp, #64 +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + @ save S16-S31 + vstmia sp, {d8-d15} +#endif + + @ store RSP (pointing to context-data) in A1 + mov a1, sp + + @ restore RSP (pointing to context-data) from A2 + mov sp, a2 + +#if (defined(__VFP_FP__) && !defined(__SOFTFP__)) + @ restore S16-S31 + vldmia sp, {d8-d15} +#endif + @ prepare stack for FPU + add sp, sp, #64 + + @ restore SjLj handler + pop {v1} + @ store SjLj handler in TLS + str v1, [v2, #8] + + @ store parent context in A2 + mov a2, a1 + + @ restore hidden,V1-V8,LR + pop {a1,v1-v8,lr} + + @ return transfer_t from jump + str a2, [a1, #0] + str a3, [a1, #4] + @ pass transfer_t as first arg in context function + @ A1 == hidden, A2 == FCTX, A3 == DATA + + @ skip PC + add sp, sp, #4 + + @ jump to ontop-function + bx a4 diff --git a/libs/context/src/asm/ontop_arm_aapcs_pe_armasm.asm b/libs/context/src/asm/ontop_arm_aapcs_pe_armasm.asm new file mode 100644 index 0000000..f360a8f --- /dev/null +++ b/libs/context/src/asm/ontop_arm_aapcs_pe_armasm.asm @@ -0,0 +1,86 @@ +;/* +; Copyright Oliver Kowalke 2009. +; 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) +;*/ + +; ******************************************************* +; * * +; * ------------------------------------------------- * +; * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * +; * ------------------------------------------------- * +; * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * +; * ------------------------------------------------- * +; * |deall|limit| base|hiddn| v1 | v2 | v3 | v4 | * +; * ------------------------------------------------- * +; * ------------------------------------------------- * +; * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * +; * ------------------------------------------------- * +; * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * +; * ------------------------------------------------- * +; * | v5 | v6 | v7 | v8 | lr | pc | FCTX| DATA| * +; * ------------------------------------------------- * +; * * +; ******************************************************* + + AREA |.text|, CODE + ALIGN 4 + EXPORT ontop_fcontext + +ontop_fcontext PROC + ; save LR as PC + push {lr} + ; save hidden,V1-V8,LR + push {a1,v1-v8,lr} + + ; load TIB to save/restore thread size and limit. + ; we do not need preserve CPU flag and can use it's arg register + mrc p15, #0, v1, c13, c0, #2 + + ; save current stack base + ldr a1, [v1, #0x04] + push {a1} + ; save current stack limit + ldr a1, [v1, #0x08] + push {a1} + ; save current deallocation stack + ldr a1, [v1, #0xe0c] + push {a1} + + ; store RSP (pointing to context-data) in A1 + mov a1, sp + + ; restore RSP (pointing to context-data) from A2 + mov sp, a2 + + ; restore stack base + pop {a1} + str a1, [v1, #0x04] + ; restore stack limit + pop {a1} + str a1, [v1, #0x08] + ; restore deallocation stack + pop {a1} + str a1, [v1, #0xe0c] + + ; store parent context in A2 + mov a2, a1 + + ; restore hidden,V1-V8,LR + pop {a1,v1-v8,lr} + + ; return transfer_t from jump + str a2, [a1, #0] + str a3, [a1, #4] + ; pass transfer_t as first arg in context function + ; A1 == hidden, A2 == FCTX, A3 == DATA + + ; skip PC + add sp, sp, #4 + + ; jump to ontop-function + bx a4 + + ENDP + END diff --git a/libs/context/src/asm/ontop_combined_sysv_macho_gas.S b/libs/context/src/asm/ontop_combined_sysv_macho_gas.S new file mode 100644 index 0000000..20cbeb9 --- /dev/null +++ b/libs/context/src/asm/ontop_combined_sysv_macho_gas.S @@ -0,0 +1,20 @@ +/* + Copyright Sergue E. Leontiev 2013. + 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) +*/ + +// Stub file for universal binary + +#if defined(__i386__) + #include "ontop_i386_sysv_macho_gas.S" +#elif defined(__x86_64__) + #include "ontop_x86_64_sysv_macho_gas.S" +#elif defined(__ppc__) + #include "ontop_ppc32_sysv_macho_gas.S" +#elif defined(__ppc64__) + #include "ontop_ppc64_sysv_macho_gas.S" +#else + #error "No arch's" +#endif diff --git a/libs/context/src/asm/ontop_i386_ms_pe_gas.asm b/libs/context/src/asm/ontop_i386_ms_pe_gas.asm new file mode 100644 index 0000000..41f15f5 --- /dev/null +++ b/libs/context/src/asm/ontop_i386_ms_pe_gas.asm @@ -0,0 +1,125 @@ +/* + Copyright Oliver Kowalke 2009. + Copyright Thomas Sailer 2013. + 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) +*/ + +/************************************************************************************* +* --------------------------------------------------------------------------------- * +* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * +* --------------------------------------------------------------------------------- * +* | 0h | 04h | 08h | 0ch | 010h | 014h | 018h | 01ch | * +* --------------------------------------------------------------------------------- * +* | fc_mxcsr|fc_x87_cw| fc_strg |fc_deallo| limit | base | fc_seh | EDI | * +* --------------------------------------------------------------------------------- * +* --------------------------------------------------------------------------------- * +* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * +* --------------------------------------------------------------------------------- * +* | 020h | 024h | 028h | 02ch | 030h | 034h | 038h | 03ch | * +* --------------------------------------------------------------------------------- * +* | ESI | EBX | EBP | EIP | to | data | EH NXT |SEH HNDLR| * +* --------------------------------------------------------------------------------- * +**************************************************************************************/ + +.file "ontop_i386_ms_pe_gas.asm" +.text +.p2align 4,,15 +.globl _ontop_fcontext +.def _ontop_fcontext; .scl 2; .type 32; .endef +_ontop_fcontext: + /* prepare stack */ + leal -0x2c(%esp), %esp + +#if !defined(BOOST_USE_TSX) + /* save MMX control- and status-word */ + stmxcsr (%esp) + /* save x87 control-word */ + fnstcw 0x4(%esp) +#endif + + /* load NT_TIB */ + movl %fs:(0x18), %edx + /* load fiber local storage */ + movl 0x10(%edx), %eax + movl %eax, 0x8(%esp) + /* load current dealloction stack */ + movl 0xe0c(%edx), %eax + movl %eax, 0xc(%esp) + /* load current stack limit */ + movl 0x8(%edx), %eax + movl %eax, 0x10(%esp) + /* load current stack base */ + movl 0x4(%edx), %eax + movl %eax, 0x14(%esp) + /* load current SEH exception list */ + movl (%edx), %eax + movl %eax, 0x18(%esp) + + movl %edi, 0x1c(%esp) /* save EDI */ + movl %esi, 0x20(%esp) /* save ESI */ + movl %ebx, 0x24(%esp) /* save EBX */ + movl %ebp, 0x28(%esp) /* save EBP */ + + /* store ESP (pointing to context-data) in ECX */ + movl %esp, %ecx + + /* first arg of ontop_fcontext() == fcontext to jump to */ + movl 0x30(%esp), %eax + + /* pass parent fcontext_t */ + movl %ecx, 0x30(%eax) + + /* second arg of ontop_fcontext() == data to be transferred */ + movl 0x34(%esp), %ecx + + /* pass data */ + movl %ecx, 0x34(%eax) + + /* third arg of ontop_fcontext() == ontop-function */ + movl 0x38(%esp), %ecx + + /* restore ESP (pointing to context-data) from EDX */ + movl %eax, %esp + +#if !defined(BOOST_USE_TSX) + /* restore MMX control- and status-word */ + ldmxcsr (%esp) + /* restore x87 control-word */ + fldcw 0x4(%esp) +#endif + + /* restore NT_TIB into EDX */ + movl %fs:(0x18), %edx + /* restore fiber local storage */ + movl 0x8(%esp), %eax + movl %eax, 0x10(%edx) + /* restore current deallocation stack */ + movl 0xc(%esp), %eax + movl %eax, 0xe0c(%edx) + /* restore current stack limit */ + movl 0x10(%esp), %eax + movl %eax, 0x08(%edx) + /* restore current stack base */ + movl 0x14(%esp), %eax + movl %eax, 0x04(%edx) + /* restore current SEH exception list */ + movl 0x18(%esp), %eax + movl %eax, (%edx) + + movl 0x1c(%esp), %edi /* restore EDI */ + movl 0x20(%esp), %esi /* restore ESI */ + movl 0x24(%esp), %ebx /* restore EBX */ + movl 0x28(%esp), %ebp /* restore EBP */ + + /* prepare stack */ + leal 0x2c(%esp), %esp + + /* keep return-address on stack */ + + /* jump to context */ + jmp *%ecx + +.section .drectve +.ascii " -export:\"ontop_fcontext\"" diff --git a/libs/context/src/asm/ontop_i386_ms_pe_masm.asm b/libs/context/src/asm/ontop_i386_ms_pe_masm.asm new file mode 100644 index 0000000..82246a4 --- /dev/null +++ b/libs/context/src/asm/ontop_i386_ms_pe_masm.asm @@ -0,0 +1,124 @@ + +; Copyright Oliver Kowalke 2009. +; 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) + +; --------------------------------------------------------------------------------- +; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | +; --------------------------------------------------------------------------------- +; | 0h | 04h | 08h | 0ch | 010h | 014h | 018h | 01ch | +; --------------------------------------------------------------------------------- +; | fc_mxcsr|fc_x87_cw| fc_strg |fc_deallo| limit | base | fc_seh | EDI | +; --------------------------------------------------------------------------------- +; --------------------------------------------------------------------------------- +; | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | +; --------------------------------------------------------------------------------- +; | 020h | 024h | 028h | 02ch | 030h | 034h | 038h | 03ch | +; --------------------------------------------------------------------------------- +; | ESI | EBX | EBP | EIP | to | data | EH NXT |SEH HNDLR| +; --------------------------------------------------------------------------------- + +.386 +.XMM +.model flat, c +.code + +ontop_fcontext PROC BOOST_CONTEXT_EXPORT + ; prepare stack + lea esp, [esp-02ch] + +IFNDEF BOOST_USE_TSX + ; save MMX control- and status-word + stmxcsr [esp] + ; save x87 control-word + fnstcw [esp+04h] +ENDIF + + assume fs:nothing + ; load NT_TIB into ECX + mov edx, fs:[018h] + assume fs:error + ; load fiber local storage + mov eax, [edx+010h] + mov [esp+08h], eax + ; load current deallocation stack + mov eax, [edx+0e0ch] + mov [esp+0ch], eax + ; load current stack limit + mov eax, [edx+08h] + mov [esp+010h], eax + ; load current stack base + mov eax, [edx+04h] + mov [esp+014h], eax + ; load current SEH exception list + mov eax, [edx] + mov [esp+018h], eax + + mov [esp+01ch], edi ; save EDI + mov [esp+020h], esi ; save ESI + mov [esp+024h], ebx ; save EBX + mov [esp+028h], ebp ; save EBP + + ; store ESP (pointing to context-data) in ECX + mov ecx, esp + + ; first arg of ontop_fcontext() == fcontext to jump to + mov eax, [esp+030h] + + ; pass parent fcontext_t + mov [eax+030h], ecx + + ; second arg of ontop_fcontext() == data to be transferred + mov ecx, [esp+034h] + + ; pass data + mov [eax+034h], ecx + + ; third arg of ontop_fcontext() == ontop-function + mov ecx, [esp+038h] + + ; restore ESP (pointing to context-data) from EAX + mov esp, eax + +IFNDEF BOOST_USE_TSX + ; restore MMX control- and status-word + ldmxcsr [esp] + ; restore x87 control-word + fldcw [esp+04h] +ENDIF + + assume fs:nothing + ; load NT_TIB into EDX + mov edx, fs:[018h] + assume fs:error + ; restore fiber local storage + mov eax, [esp+08h] + mov [edx+010h], eax + ; restore current deallocation stack + mov eax, [esp+0ch] + mov [edx+0e0ch], eax + ; restore current stack limit + mov eax, [esp+010h] + mov [edx+08h], eax + ; restore current stack base + mov eax, [esp+014h] + mov [edx+04h], eax + ; restore current SEH exception list + mov eax, [esp+018h] + mov [edx], eax + + mov edi, [esp+01ch] ; restore EDI + mov esi, [esp+020h] ; restore ESI + mov ebx, [esp+024h] ; restore EBX + mov ebp, [esp+028h] ; restore EBP + + ; prepare stack + lea esp, [esp+02ch] + + ; keep return-address on stack + + ; jump to context + jmp ecx +ontop_fcontext ENDP +END diff --git a/libs/context/src/asm/ontop_i386_sysv_elf_gas.S b/libs/context/src/asm/ontop_i386_sysv_elf_gas.S new file mode 100644 index 0000000..40fe6c2 --- /dev/null +++ b/libs/context/src/asm/ontop_i386_sysv_elf_gas.S @@ -0,0 +1,90 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| EDI | ESI | EBX | EBP | EIP | hidden | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | 0x24 | | * + * ---------------------------------------------------------------------------------- * + * | to | data | | * + * ---------------------------------------------------------------------------------- * + * * + ****************************************************************************************/ + +.file "ontop_i386_sysv_elf_gas.S" +.text +.globl ontop_fcontext +.align 2 +.type ontop_fcontext,@function +ontop_fcontext: + leal -0x18(%esp), %esp /* prepare stack */ + +#if !defined(BOOST_USE_TSX) + stmxcsr (%esp) /* save MMX control- and status-word */ + fnstcw 0x4(%esp) /* save x87 control-word */ +#endif + + movl %edi, 0x8(%esp) /* save EDI */ + movl %esi, 0xc(%esp) /* save ESI */ + movl %ebx, 0x10(%esp) /* save EBX */ + movl %ebp, 0x14(%esp) /* save EBP */ + + /* store ESP (pointing to context-data) in ECX */ + movl %esp, %ecx + + /* first arg of ontop_fcontext() == fcontext to jump to */ + movl 0x20(%esp), %eax + + /* pass parent fcontext_t */ + movl %ecx, 0x20(%eax) + + /* second arg of ontop_fcontext() == data to be transferred */ + movl 0x24(%esp), %ecx + + /* pass data */ + movl %ecx, 0x24(%eax) + + /* third arg of ontop_fcontext() == ontop-function */ + movl 0x28(%esp), %ecx + + /* restore ESP (pointing to context-data) from EAX */ + movl %eax, %esp + + /* address of returned transport_t */ + movl 0x1c(%esp), %eax + /* return parent fcontext_t */ + movl %ecx, (%eax) + /* return data */ + movl %edx, 0x4(%eax) + +#if !defined(BOOST_USE_TSX) + ldmxcsr (%esp) /* restore MMX control- and status-word */ + fldcw 0x4(%esp) /* restore x87 control-word */ +#endif + + movl 0x8(%esp), %edi /* restore EDI */ + movl 0xc(%esp), %esi /* restore ESI */ + movl 0x10(%esp), %ebx /* restore EBX */ + movl 0x14(%esp), %ebp /* restore EBP */ + + leal 0x18(%esp), %esp /* prepare stack */ + + /* jump to context */ + jmp *%ecx +.size ontop_fcontext,.-ontop_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/ontop_i386_sysv_macho_gas.S b/libs/context/src/asm/ontop_i386_sysv_macho_gas.S new file mode 100644 index 0000000..3a88372 --- /dev/null +++ b/libs/context/src/asm/ontop_i386_sysv_macho_gas.S @@ -0,0 +1,81 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| EDI | ESI | EBX | EBP | EIP | to | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | | * + * ---------------------------------------------------------------------------------- * + * | data | | * + * ---------------------------------------------------------------------------------- * + * * + ****************************************************************************************/ + +.text +.globl _ontop_fcontext +.align 2 +_ontop_fcontext: + leal -0x18(%esp), %esp /* prepare stack */ + +#if !defined(BOOST_USE_TSX) + stmxcsr (%esp) /* save MMX control- and status-word */ + fnstcw 0x4(%esp) /* save x87 control-word */ +#endif + + movl %edi, 0x8(%esp) /* save EDI */ + movl %esi, 0xc(%esp) /* save ESI */ + movl %ebx, 0x10(%esp) /* save EBX */ + movl %ebp, 0x14(%esp) /* save EBP */ + + /* store ESP (pointing to context-data) in ECX */ + movl %esp, %ecx + + /* first arg of ontop_fcontext() == fcontext to jump to */ + movl 0x1c(%esp), %eax + + /* pass parent fcontext_t */ + movl %ecx, 0x1c(%eax) + + /* second arg of ontop_fcontext() == data to be transferred */ + movl 0x20(%esp), %ecx + + /* pass data */ + movl %ecx, 0x20(%eax) + + /* third arg of ontop_fcontext() == ontop-function */ + movl 0x24(%esp), %ecx + + /* restore ESP (pointing to context-data) from EAX */ + movl %eax, %esp + + /* return parent fcontext_t */ + movl %ecx, %eax + /* returned data is stored in EDX */ + +#if !defined(BOOST_USE_TSX) + ldmxcsr (%esp) /* restore MMX control- and status-word */ + fldcw 0x4(%esp) /* restore x87 control-word */ +#endif + + movl 0x8(%esp), %edi /* restore EDI */ + movl 0xc(%esp), %esi /* restore ESI */ + movl 0x10(%esp), %ebx /* restore EBX */ + movl 0x14(%esp), %ebp /* restore EBP */ + + leal 0x18(%esp), %esp /* prepare stack */ + + /* jump to context */ + jmp *%ecx diff --git a/libs/context/src/asm/ontop_i386_x86_64_sysv_macho_gas.S b/libs/context/src/asm/ontop_i386_x86_64_sysv_macho_gas.S new file mode 100644 index 0000000..393c5fe --- /dev/null +++ b/libs/context/src/asm/ontop_i386_x86_64_sysv_macho_gas.S @@ -0,0 +1,16 @@ +/* + Copyright Sergue E. Leontiev 2013. + 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) +*/ + +// Stub file for universal binary + +#if defined(__i386__) + #include "ontop_i386_sysv_macho_gas.S" +#elif defined(__x86_64__) + #include "ontop_x86_64_sysv_macho_gas.S" +#else + #error "No arch's" +#endif diff --git a/libs/context/src/asm/ontop_mips32_o32_elf_gas.S b/libs/context/src/asm/ontop_mips32_o32_elf_gas.S new file mode 100644 index 0000000..c69203c --- /dev/null +++ b/libs/context/src/asm/ontop_mips32_o32_elf_gas.S @@ -0,0 +1,120 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | F20 | F22 | F24 | F26 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | F28 | F30 | S0 | S1 | S2 | S3 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | S4 | S5 | S6 | S7 | FP |hiddn| RA | PC | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | ABI ARGS | GP | FCTX| DATA| | * + * ------------------------------------------------- * + * * + * *****************************************************/ + +.file "ontop_mips32_o32_elf_gas.S" +.text +.globl ontop_fcontext +.align 2 +.type ontop_fcontext,@function +.ent ontop_fcontext +ontop_fcontext: + # reserve space on stack + addiu $sp, $sp, -96 + + sw $s0, 48($sp) # save S0 + sw $s1, 52($sp) # save S1 + sw $s2, 56($sp) # save S2 + sw $s3, 60($sp) # save S3 + sw $s4, 64($sp) # save S4 + sw $s5, 68($sp) # save S5 + sw $s6, 72($sp) # save S6 + sw $s7, 76($sp) # save S7 + sw $fp, 80($sp) # save FP + sw $a0, 84($sp) # save hidden, address of returned transfer_t + sw $ra, 88($sp) # save RA + sw $ra, 92($sp) # save RA as PC + +#if defined(__mips_hard_float) + s.d $f20, ($sp) # save F20 + s.d $f22, 8($sp) # save F22 + s.d $f24, 16($sp) # save F24 + s.d $f26, 24($sp) # save F26 + s.d $f28, 32($sp) # save F28 + s.d $f30, 40($sp) # save F30 +#endif + + # store SP (pointing to context-data) in A0 + move $a0, $sp + + # restore SP (pointing to context-data) from A1 + move $sp, $a1 + +#if defined(__mips_hard_float) + l.d $f20, ($sp) # restore F20 + l.d $f22, 8($sp) # restore F22 + l.d $f24, 16($sp) # restore F24 + l.d $f26, 24($sp) # restore F26 + l.d $f28, 32($sp) # restore F28 + l.d $f30, 40($sp) # restore F30 +#endif + + lw $s0, 48($sp) # restore S0 + lw $s1, 52($sp) # restore S1 + lw $s2, 56($sp) # restore S2 + lw $s3, 60($sp) # restore S3 + lw $s4, 64($sp) # restore S4 + lw $s5, 68($sp) # restore S5 + lw $s6, 72($sp) # restore S6 + lw $s7, 76($sp) # restore S7 + lw $fp, 80($sp) # restore FP + lw $v0, 84($sp) # restore hidden, address of returned transfer_t + lw $ra, 88($sp) # restore RA + + # load PC + move $t9, $a3 + + # adjust stack + addiu $sp, $sp, 96 + + # return transfer_t from jump + sw $a0, ($v0) # fctx of transfer_t + sw $a2, 4($v0) # data of transfer_t + # pass transfer_t as first arg in context function + # A0 == hidden, A1 == fctx, A2 == data + move $a1, $a0 + move $a0, $v0 + + # jump to context + jr $t9 +.end ontop_fcontext +.size ontop_fcontext, .-ontop_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/ontop_mips64_n64_elf_gas.S b/libs/context/src/asm/ontop_mips64_n64_elf_gas.S new file mode 100644 index 0000000..2dea458 --- /dev/null +++ b/libs/context/src/asm/ontop_mips64_n64_elf_gas.S @@ -0,0 +1,120 @@ +/* + Copyright Jiaxun Yang 2018. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 8 | 16 | 24 | * + * ------------------------------------------------- * + * | F24 | F25 | F26 | F27 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 40 | 48 | 56 | * + * ------------------------------------------------- * + * | F28 | F29 | F30 | F31 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 72 | 80 | 88 | * + * ------------------------------------------------- * + * | S0 | S1 | S2 | S3 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | S4 | S5 | S6 | S7 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | FP | GP | RA | PC | * + * ------------------------------------------------- * + * * + * *****************************************************/ + +.file "ontop_mips64_n64_elf_gas.S" +.text +.globl ontop_fcontext +.align 2 +.type ontop_fcontext,@function +.ent ontop_fcontext +ontop_fcontext: + # reserve space on stack + daddiu $sp, $sp, -160 + + sd $s0, 64($sp) # save S0 + sd $s1, 72($sp) # save S1 + sd $s2, 80($sp) # save S2 + sd $s3, 88($sp) # save S3 + sd $s4, 96($sp) # save S4 + sd $s5, 104($sp) # save S5 + sd $s6, 112($sp) # save S6 + sd $s7, 120($sp) # save S7 + sd $fp, 128($sp) # save FP + sd $ra, 144($sp) # save RA + sd $ra, 152($sp) # save RA as PC + + + s.d $f24, 0($sp) # save F24 + s.d $f25, 8($sp) # save F25 + s.d $f26, 16($sp) # save F26 + s.d $f27, 24($sp) # save F27 + s.d $f28, 32($sp) # save F28 + s.d $f29, 40($sp) # save F29 + s.d $f30, 48($sp) # save F30 + s.d $f31, 56($sp) # save F31 + + # store SP (pointing to context-data) in t0 + move $t0, $sp + + # restore SP (pointing to context-data) from a0 + move $sp, $a0 + + l.d $f24, 0($sp) # restore F24 + l.d $f25, 8($sp) # restore F25 + l.d $f26, 16($sp) # restore F26 + l.d $f27, 24($sp) # restore F27 + l.d $f28, 32($sp) # restore F28 + l.d $f29, 40($sp) # restore F29 + l.d $f30, 48($sp) # restore F30 + l.d $f31, 56($sp) # restore F31 + + ld $s0, 64($sp) # restore S0 + ld $s1, 72($sp) # restore S1 + ld $s2, 80($sp) # restore S2 + ld $s3, 88($sp) # restore S3 + ld $s4, 96($sp) # restore S4 + ld $s5, 104($sp) # restore S5 + ld $s6, 112($sp) # restore S6 + ld $s7, 120($sp) # restore S7 + ld $fp, 128($sp) # restore FP + ld $ra, 144($sp) # restore RA + + # load PC + move $t9, $a2 + + # adjust stack + daddiu $sp, $sp, 160 + + move $a0, $t0 # move param from t0 to a0 as param + + # jump to context + jr $t9 +.end ontop_fcontext +.size ontop_fcontext, .-ontop_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/ontop_ppc32_ppc64_sysv_macho_gas.S b/libs/context/src/asm/ontop_ppc32_ppc64_sysv_macho_gas.S new file mode 100644 index 0000000..4632f4c --- /dev/null +++ b/libs/context/src/asm/ontop_ppc32_ppc64_sysv_macho_gas.S @@ -0,0 +1,16 @@ +/* + Copyright Sergue E. Leontiev 2013. + 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) +*/ + +// Stub file for universal binary + +#if defined(__ppc__) + #include "ontop_ppc32_sysv_macho_gas.S" +#elif defined(__ppc64__) + #include "ontop_ppc64_sysv_macho_gas.S" +#else + #error "No arch's" +#endif diff --git a/libs/context/src/asm/ontop_ppc32_sysv_elf_gas.S b/libs/context/src/asm/ontop_ppc32_sysv_elf_gas.S new file mode 100644 index 0000000..464d99d --- /dev/null +++ b/libs/context/src/asm/ontop_ppc32_sysv_elf_gas.S @@ -0,0 +1,193 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * |bchai|hiddn| fpscr | PC | CR | R14 | R15 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | R16 | R17 | R18 | R19 | R20 | R21 | R22 | R23 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | R24 | R25 | R26 | R27 | R28 | R29 | R30 | R31 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | F14 | F15 | F16 | F17 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | F18 | F19 | F20 | F21 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | F22 | F23 | F24 | F25 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | F26 | F27 | F28 | F29 | * + * ------------------------------------------------- * + * ------------------------|------------ * + * | 224 | 228 | 232 | 236 | 240 | 244 | * + * ------------------------|------------ * + * | F30 | F31 |bchai| LR | * + * ------------------------|------------ * + * * + *******************************************************/ + +.file "ontop_ppc32_sysv_elf_gas.S" +.text +.globl ontop_fcontext +.align 2 +.type ontop_fcontext,@function +ontop_fcontext: + # Linux: ontop_fcontext( hidden transfer_t * R3, R4, R5, R6) + # Other: transfer_t R3:R4 = jump_fcontext( R3, R4, R5) + + mflr %r0 # return address from LR + mffs %f0 # FPSCR + mfcr %r8 # condition register + + stwu %r1, -240(%r1) # allocate stack space, R1 % 16 == 0 + stw %r0, 244(%r1) # save LR in caller's frame + +#ifdef __linux__ + stw %r3, 4(%r1) # hidden pointer +#endif + + stfd %f0, 8(%r1) # FPSCR + stw %r0, 16(%r1) # LR as PC + stw %r8, 20(%r1) # CR + + # Save registers R14 to R31. + # Don't change R2, the thread-local storage pointer. + # Don't change R13, the small data pointer. + stw %r14, 24(%r1) + stw %r15, 28(%r1) + stw %r16, 32(%r1) + stw %r17, 36(%r1) + stw %r18, 40(%r1) + stw %r19, 44(%r1) + stw %r20, 48(%r1) + stw %r21, 52(%r1) + stw %r22, 56(%r1) + stw %r23, 60(%r1) + stw %r24, 64(%r1) + stw %r25, 68(%r1) + stw %r26, 72(%r1) + stw %r27, 76(%r1) + stw %r28, 80(%r1) + stw %r29, 84(%r1) + stw %r30, 88(%r1) + stw %r31, 92(%r1) + + # Save registers F14 to F31 in slots with 8-byte alignment. + # 4-byte alignment may stall the pipeline of some processors. + # Less than 4 may cause alignment traps. + stfd %f14, 96(%r1) + stfd %f15, 104(%r1) + stfd %f16, 112(%r1) + stfd %f17, 120(%r1) + stfd %f18, 128(%r1) + stfd %f19, 136(%r1) + stfd %f20, 144(%r1) + stfd %f21, 152(%r1) + stfd %f22, 160(%r1) + stfd %f23, 168(%r1) + stfd %f24, 176(%r1) + stfd %f25, 184(%r1) + stfd %f26, 192(%r1) + stfd %f27, 200(%r1) + stfd %f28, 208(%r1) + stfd %f29, 216(%r1) + stfd %f30, 224(%r1) + stfd %f31, 232(%r1) + + # store RSP (pointing to context-data) in R7/R6 + # restore RSP (pointing to context-data) from R4/R3 +#ifdef __linux__ + mr %r7, %r1 + mr %r1, %r4 + lwz %r3, 4(%r1) # hidden pointer +#else + mr %r6, %r1 + mr %r1, %r3 +#endif + + # ignore PC at 16(%r1) + lfd %f0, 8(%r1) # FPSCR + lwz %r8, 20(%r1) # CR + + mtfsf 0xff, %f0 # restore FPSCR + mtcr %r8 # restore CR + + # restore R14 to R31 + lwz %r14, 24(%r1) + lwz %r15, 28(%r1) + lwz %r16, 32(%r1) + lwz %r17, 36(%r1) + lwz %r18, 40(%r1) + lwz %r19, 44(%r1) + lwz %r20, 48(%r1) + lwz %r21, 52(%r1) + lwz %r22, 56(%r1) + lwz %r23, 60(%r1) + lwz %r24, 64(%r1) + lwz %r25, 68(%r1) + lwz %r26, 72(%r1) + lwz %r27, 76(%r1) + lwz %r28, 80(%r1) + lwz %r29, 84(%r1) + lwz %r30, 88(%r1) + lwz %r31, 92(%r1) + + # restore F14 to F31 + lfd %f14, 96(%r1) + lfd %f15, 104(%r1) + lfd %f16, 112(%r1) + lfd %f17, 120(%r1) + lfd %f18, 128(%r1) + lfd %f19, 136(%r1) + lfd %f20, 144(%r1) + lfd %f21, 152(%r1) + lfd %f22, 160(%r1) + lfd %f23, 168(%r1) + lfd %f24, 176(%r1) + lfd %f25, 184(%r1) + lfd %f26, 192(%r1) + lfd %f27, 200(%r1) + lfd %f28, 208(%r1) + lfd %f29, 216(%r1) + lfd %f30, 224(%r1) + lfd %f31, 232(%r1) + + # restore LR from caller's frame + lwz %r0, 244(%r1) + mtlr %r0 + + # adjust stack + addi %r1, %r1, 240 + + # see tail_ppc32_sysv_elf_gas.cpp + # Linux: fcontext_ontop_tail( hidden transfer_t * R3, R4, R5, R6, R7) + # Other: transfer_t R3:R4 = fcontext_ontop_tail( R3, R4, R5, R6) + b ontop_fcontext_tail +.size ontop_fcontext, .-ontop_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/ontop_ppc32_sysv_macho_gas.S b/libs/context/src/asm/ontop_ppc32_sysv_macho_gas.S new file mode 100644 index 0000000..1eb5f93 --- /dev/null +++ b/libs/context/src/asm/ontop_ppc32_sysv_macho_gas.S @@ -0,0 +1,201 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/****************************************************** + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | F14 | F15 | F16 | F17 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | F18 | F19 | F20 | F21 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | F22 | F23 | F24 | F25 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | F26 | F27 | F28 | F29 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | F30 | F31 | fpscr | R13 | R14 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | R15 | R16 | R17 | R18 | R19 | R20 | R21 | R22 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | R23 | R24 | R25 | R26 | R27 | R28 | R29 | R30 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | * + * ------------------------------------------------- * + * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * + * ------------------------------------------------- * + * | R31 |hiddn| CR | LR | PC |bchai|linkr| FCTX| * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 64 | | * + * ------------------------------------------------- * + * | 256 | | * + * ------------------------------------------------- * + * | DATA| | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.text +.globl _ontop_fcontext +.align 2 +_ontop_fcontext: + # reserve space on stack + subi r1, r1, 244 + + stfd f14, 0(r1) # save F14 + stfd f15, 8(r1) # save F15 + stfd f16, 16(r1) # save F16 + stfd f17, 24(r1) # save F17 + stfd f18, 32(r1) # save F18 + stfd f19, 40(r1) # save F19 + stfd f20, 48(r1) # save F20 + stfd f21, 56(r1) # save F21 + stfd f22, 64(r1) # save F22 + stfd f23, 72(r1) # save F23 + stfd f24, 80(r1) # save F24 + stfd f25, 88(r1) # save F25 + stfd f26, 96(r1) # save F26 + stfd f27, 104(r1) # save F27 + stfd f28, 112(r1) # save F28 + stfd f29, 120(r1) # save F29 + stfd f30, 128(r1) # save F30 + stfd f31, 136(r1) # save F31 + mffs f0 # load FPSCR + stfd f0, 144(r1) # save FPSCR + + stw r13, 152(r1) # save R13 + stw r14, 156(r1) # save R14 + stw r15, 160(r1) # save R15 + stw r16, 164(r1) # save R16 + stw r17, 168(r1) # save R17 + stw r18, 172(r1) # save R18 + stw r19, 176(r1) # save R19 + stw r20, 180(r1) # save R20 + stw r21, 184(r1) # save R21 + stw r22, 188(r1) # save R22 + stw r23, 192(r1) # save R23 + stw r24, 196(r1) # save R24 + stw r25, 200(r1) # save R25 + stw r26, 204(r1) # save R26 + stw r27, 208(r1) # save R27 + stw r28, 212(r1) # save R28 + stw r29, 216(r1) # save R29 + stw r30, 220(r1) # save R30 + stw r31, 224(r1) # save R31 + stw r3, 228(r1) # save hidden + + # save CR + mfcr r0 + stw r0, 232(r1) + # save LR + mflr r0 + stw r0, 236(r1) + # save LR as PC + stw r0, 240(r1) + + # store RSP (pointing to context-data) in R7 + mr r7, r1 + + # restore RSP (pointing to context-data) from R4 + mr r1, r4 + + lfd f14, 0(r1) # restore F14 + lfd f15, 8(r1) # restore F15 + lfd f16, 16(r1) # restore F16 + lfd f17, 24(r1) # restore F17 + lfd f18, 32(r1) # restore F18 + lfd f19, 40(r1) # restore F19 + lfd f20, 48(r1) # restore F20 + lfd f21, 56(r1) # restore F21 + lfd f22, 64(r1) # restore F22 + lfd f23, 72(r1) # restore F23 + lfd f24, 80(r1) # restore F24 + lfd f25, 88(r1) # restore F25 + lfd f26, 96(r1) # restore F26 + lfd f27, 104(r1) # restore F27 + lfd f28, 112(r1) # restore F28 + lfd f29, 120(r1) # restore F29 + lfd f30, 128(r1) # restore F30 + lfd f31, 136(r1) # restore F31 + lfd f0, 144(r1) # load FPSCR + mtfsf 0xff, f0 # restore FPSCR + + lwz r13, 152(r1) # restore R13 + lwz r14, 156(r1) # restore R14 + lwz r15, 160(r1) # restore R15 + lwz r16, 164(r1) # restore R16 + lwz r17, 168(r1) # restore R17 + lwz r18, 172(r1) # restore R18 + lwz r19, 176(r1) # restore R19 + lwz r20, 180(r1) # restore R20 + lwz r21, 184(r1) # restore R21 + lwz r22, 188(r1) # restore R22 + lwz r23, 192(r1) # restore R23 + lwz r24, 196(r1) # restore R24 + lwz r25, 200(r1) # restore R25 + lwz r26, 204(r1) # restore R26 + lwz r27, 208(r1) # restore R27 + lwz r28, 212(r1) # restore R28 + lwz r29, 216(r1) # restore R29 + lwz r30, 220(r1) # restore R30 + lwz r31, 224(r1) # restore R31 + lwz r4, 228(r1) # restore hidden + + # restore CR + lwz r0, 232(r1) + mtcr r0 + # restore LR + lwz r0, 236(r1) + mtlr r0 + # ignore PC + + # adjust stack + addi r1, r1, 244 + + # return transfer_t + stw r7, 0(r4) + stw r5, 4(r4) + + # restore CTR + mtctr r6 + + # jump to ontop-function + bctr diff --git a/libs/context/src/asm/ontop_ppc32_sysv_xcoff_gas.S b/libs/context/src/asm/ontop_ppc32_sysv_xcoff_gas.S new file mode 100644 index 0000000..a3c9fa2 --- /dev/null +++ b/libs/context/src/asm/ontop_ppc32_sysv_xcoff_gas.S @@ -0,0 +1,203 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/****************************************************** + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | F14 | F15 | F16 | F17 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | F18 | F19 | F20 | F21 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | F22 | F23 | F24 | F25 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | F26 | F27 | F28 | F29 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | F30 | F31 | fpscr | R13 | R14 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | R15 | R16 | R17 | R18 | R19 | R20 | R21 | R22 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | R23 | R24 | R25 | R26 | R27 | R28 | R29 | R30 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | * + * ------------------------------------------------- * + * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * + * ------------------------------------------------- * + * | R31 |hiddn| CR | LR | PC |bchai|linkr| FCTX| * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 64 | | * + * ------------------------------------------------- * + * | 256 | | * + * ------------------------------------------------- * + * | DATA| | * + * ------------------------------------------------- * + * * + *******************************************************/ +.globl .ontop_fcontext +.globl ontop_fcontext[DS] +.align 2 +.csect ontop_fcontext[DS] +ontop_fcontext: + .long .ontop_fcontext +.ontop_fcontext: + # reserve space on stack + subi r1, r1, 244 + + stfd f14, 0(r1) # save F14 + stfd f15, 8(r1) # save F15 + stfd f16, 16(r1) # save F16 + stfd f17, 24(r1) # save F17 + stfd f18, 32(r1) # save F18 + stfd f19, 40(r1) # save F19 + stfd f20, 48(r1) # save F20 + stfd f21, 56(r1) # save F21 + stfd f22, 64(r1) # save F22 + stfd f23, 72(r1) # save F23 + stfd f24, 80(r1) # save F24 + stfd f25, 88(r1) # save F25 + stfd f26, 96(r1) # save F26 + stfd f27, 104(r1) # save F27 + stfd f28, 112(r1) # save F28 + stfd f29, 120(r1) # save F29 + stfd f30, 128(r1) # save F30 + stfd f31, 136(r1) # save F31 + mffs f0 # load FPSCR + stfd f0, 144(r1) # save FPSCR + + stw r13, 152(r1) # save R13 + stw r14, 156(r1) # save R14 + stw r15, 160(r1) # save R15 + stw r16, 164(r1) # save R16 + stw r17, 168(r1) # save R17 + stw r18, 172(r1) # save R18 + stw r19, 176(r1) # save R19 + stw r20, 180(r1) # save R20 + stw r21, 184(r1) # save R21 + stw r22, 188(r1) # save R22 + stw r23, 192(r1) # save R23 + stw r24, 196(r1) # save R24 + stw r25, 200(r1) # save R25 + stw r26, 204(r1) # save R26 + stw r27, 208(r1) # save R27 + stw r28, 212(r1) # save R28 + stw r29, 216(r1) # save R29 + stw r30, 220(r1) # save R30 + stw r31, 224(r1) # save R31 + stw r3, 228(r1) # save hidden + + # save CR + mfcr r0 + stw r0, 232(r1) + # save LR + mflr r0 + stw r0, 236(r1) + # save LR as PC + stw r0, 240(r1) + + # store RSP (pointing to context-data) in R7 + mr r7, r1 + + # restore RSP (pointing to context-data) from R4 + mr r1, r4 + + lfd f14, 0(r1) # restore F14 + lfd f15, 8(r1) # restore F15 + lfd f16, 16(r1) # restore F16 + lfd f17, 24(r1) # restore F17 + lfd f18, 32(r1) # restore F18 + lfd f19, 40(r1) # restore F19 + lfd f20, 48(r1) # restore F20 + lfd f21, 56(r1) # restore F21 + lfd f22, 64(r1) # restore F22 + lfd f23, 72(r1) # restore F23 + lfd f24, 80(r1) # restore F24 + lfd f25, 88(r1) # restore F25 + lfd f26, 96(r1) # restore F26 + lfd f27, 104(r1) # restore F27 + lfd f28, 112(r1) # restore F28 + lfd f29, 120(r1) # restore F29 + lfd f30, 128(r1) # restore F30 + lfd f31, 136(r1) # restore F31 + lfd f0, 144(r1) # load FPSCR + mtfsf 0xff, f0 # restore FPSCR + + lwz r13, 152(r1) # restore R13 + lwz r14, 156(r1) # restore R14 + lwz r15, 160(r1) # restore R15 + lwz r16, 164(r1) # restore R16 + lwz r17, 168(r1) # restore R17 + lwz r18, 172(r1) # restore R18 + lwz r19, 176(r1) # restore R19 + lwz r20, 180(r1) # restore R20 + lwz r21, 184(r1) # restore R21 + lwz r22, 188(r1) # restore R22 + lwz r23, 192(r1) # restore R23 + lwz r24, 196(r1) # restore R24 + lwz r25, 200(r1) # restore R25 + lwz r26, 204(r1) # restore R26 + lwz r27, 208(r1) # restore R27 + lwz r28, 212(r1) # restore R28 + lwz r29, 216(r1) # restore R29 + lwz r30, 220(r1) # restore R30 + lwz r31, 224(r1) # restore R31 + lwz r4, 228(r1) # restore hidden + + # restore CR + lwz r0, 232(r1) + mtcr r0 + # restore LR + lwz r0, 236(r1) + mtlr r0 + # ignore PC + + # adjust stack + addi r1, r1, 244 + + # return transfer_t + stw r7, 0(r4) + stw r5, 4(r4) + + # restore CTR + mtctr r6 + + # jump to ontop-function + bctr diff --git a/libs/context/src/asm/ontop_ppc64_sysv_elf_gas.S b/libs/context/src/asm/ontop_ppc64_sysv_elf_gas.S new file mode 100644 index 0000000..cd97f45 --- /dev/null +++ b/libs/context/src/asm/ontop_ppc64_sysv_elf_gas.S @@ -0,0 +1,244 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | TOC | R14 | R15 | R16 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | R17 | R18 | R19 | R20 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | R21 | R22 | R23 | R24 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | R25 | R26 | R27 | R28 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | R29 | R30 | R31 | hidden | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | CR | LR | PC | back-chain| * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | cr saved | lr saved | compiler | linker | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | * + * ------------------------------------------------- * + * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * + * ------------------------------------------------- * + * | TOC saved | FCTX | DATA | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.file "ontop_ppc64_sysv_elf_gas.S" +.globl ontop_fcontext +#if _CALL_ELF == 2 + .text + .align 2 +ontop_fcontext: + addis %r2, %r12, .TOC.-ontop_fcontext@ha + addi %r2, %r2, .TOC.-ontop_fcontext@l + .localentry ontop_fcontext, . - ontop_fcontext +#else + .section ".opd","aw" + .align 3 +ontop_fcontext: +# ifdef _CALL_LINUX + .quad .L.ontop_fcontext,.TOC.@tocbase,0 + .type ontop_fcontext,@function + .text + .align 2 +.L.ontop_fcontext: +# else + .hidden .ontop_fcontext + .globl .ontop_fcontext + .quad .ontop_fcontext,.TOC.@tocbase,0 + .size ontop_fcontext,24 + .type .ontop_fcontext,@function + .text + .align 2 +.ontop_fcontext: +# endif +#endif + # reserve space on stack + subi %r1, %r1, 184 + +#if _CALL_ELF != 2 + std %r2, 0(%r1) # save TOC +#endif + std %r14, 8(%r1) # save R14 + std %r15, 16(%r1) # save R15 + std %r16, 24(%r1) # save R16 + std %r17, 32(%r1) # save R17 + std %r18, 40(%r1) # save R18 + std %r19, 48(%r1) # save R19 + std %r20, 56(%r1) # save R20 + std %r21, 64(%r1) # save R21 + std %r22, 72(%r1) # save R22 + std %r23, 80(%r1) # save R23 + std %r24, 88(%r1) # save R24 + std %r25, 96(%r1) # save R25 + std %r26, 104(%r1) # save R26 + std %r27, 112(%r1) # save R27 + std %r28, 120(%r1) # save R28 + std %r29, 128(%r1) # save R29 + std %r30, 136(%r1) # save R30 + std %r31, 144(%r1) # save R31 +#if _CALL_ELF != 2 + std %r3, 152(%r1) # save hidden +#endif + + # save CR + mfcr %r0 + std %r0, 160(%r1) + # save LR + mflr %r0 + std %r0, 168(%r1) + # save LR as PC + std %r0, 176(%r1) + + # store RSP (pointing to context-data) in R7 + mr %r7, %r1 + +#if _CALL_ELF == 2 + # restore RSP (pointing to context-data) from R3 + mr %r1, %r3 +#else + # restore RSP (pointing to context-data) from R4 + mr %r1, %r4 +#endif + + ld %r14, 8(%r1) # restore R14 + ld %r15, 16(%r1) # restore R15 + ld %r16, 24(%r1) # restore R16 + ld %r17, 32(%r1) # restore R17 + ld %r18, 40(%r1) # restore R18 + ld %r19, 48(%r1) # restore R19 + ld %r20, 56(%r1) # restore R20 + ld %r21, 64(%r1) # restore R21 + ld %r22, 72(%r1) # restore R22 + ld %r23, 80(%r1) # restore R23 + ld %r24, 88(%r1) # restore R24 + ld %r25, 96(%r1) # restore R25 + ld %r26, 104(%r1) # restore R26 + ld %r27, 112(%r1) # restore R27 + ld %r28, 120(%r1) # restore R28 + ld %r29, 128(%r1) # restore R29 + ld %r30, 136(%r1) # restore R30 + ld %r31, 144(%r1) # restore R31 +#if _CALL_ELF != 2 + ld %r3, 152(%r1) # restore hidden +#endif + + # restore CR + ld %r0, 160(%r1) + mtcr %r0 + +#if _CALL_ELF == 2 + # restore CTR + mtctr %r5 + + # store cb entrypoint in %r12, used for TOC calculation + mr %r12, %r5 + + # copy transfer_t into ontop_fn arg registers + mr %r3, %r7 + # arg pointer already in %r4 +#else + # copy transfer_t into ontop_fn arg registers + mr %r4, %r7 + # arg pointer already in %r5 + # hidden arg already in %r3 + + # restore CTR + ld %r7, 0(%r6) + mtctr %r7 + # restore TOC + ld %r2, 8(%r6) + + # zero in r3 indicates first jump to context-function + cmpdi %r3, 0 + beq use_entry_arg +#endif + +return_to_ctx: + # restore LR + ld %r0, 168(%r1) + mtlr %r0 + + # adjust stack + addi %r1, %r1, 184 + + # jump to context + bctr + +#if _CALL_ELF == 2 + .size ontop_fcontext, .-ontop_fcontext +#else +use_entry_arg: + # compute return-value struct address + # (passed has hidden arg to ontop_fn) + addi %r3, %r1, 8 + + # jump to context and update LR + bctrl + + # restore CTR + ld %r7, 176(%r1) + mtctr %r7 +#if _CALL_ELF != 2 + # restore TOC + ld %r2, 0(%r1) +#endif + + # copy returned transfer_t into entry_fn arg registers + ld %r3, 8(%r1) + ld %r4, 16(%r1) + + b return_to_ctx +# ifdef _CALL_LINUX + .size .ontop_fcontext, .-.L.ontop_fcontext +# else + .size .ontop_fcontext, .-.ontop_fcontext +# endif +#endif + + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/ontop_ppc64_sysv_macho_gas.S b/libs/context/src/asm/ontop_ppc64_sysv_macho_gas.S new file mode 100644 index 0000000..5de8acd --- /dev/null +++ b/libs/context/src/asm/ontop_ppc64_sysv_macho_gas.S @@ -0,0 +1,151 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | * + * ------------------------------------------------- * + * | TOC | R14 | R15 | R16 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 32 | 36 | 40 | 44 | 48 | 52 | 56 | 60 | * + * ------------------------------------------------- * + * | R17 | R18 | R19 | R20 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 64 | 68 | 72 | 76 | 80 | 84 | 88 | 92 | * + * ------------------------------------------------- * + * | R21 | R22 | R23 | R24 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 96 | 100 | 104 | 108 | 112 | 116 | 120 | 124 | * + * ------------------------------------------------- * + * | R25 | R26 | R27 | R28 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 128 | 132 | 136 | 140 | 144 | 148 | 152 | 156 | * + * ------------------------------------------------- * + * | R29 | R30 | R31 | hidden | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 160 | 164 | 168 | 172 | 176 | 180 | 184 | 188 | * + * ------------------------------------------------- * + * | CR | LR | PC | back-chain| * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | * + * ------------------------------------------------- * + * | 192 | 196 | 200 | 204 | 208 | 212 | 216 | 220 | * + * ------------------------------------------------- * + * | cr saved | lr saved | compiler | linker | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | * + * ------------------------------------------------- * + * | 224 | 228 | 232 | 236 | 240 | 244 | 248 | 252 | * + * ------------------------------------------------- * + * | TOC saved | FCTX | DATA | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.text +.align 2 +.globl _ontop_fcontext + +_ontop_fcontext: + ; reserve space on stack + subi r1, r1, 184 + + std r14, 8(r1) ; save R14 + std r15, 16(r1) ; save R15 + std r16, 24(r1) ; save R16 + std r17, 32(r1) ; save R17 + std r18, 40(r1) ; save R18 + std r19, 48(r1) ; save R19 + std r20, 56(r1) ; save R20 + std r21, 64(r1) ; save R21 + std r22, 72(r1) ; save R22 + std r23, 80(r1) ; save R23 + std r24, 88(r1) ; save R24 + std r25, 96(r1) ; save R25 + std r26, 104(r1) ; save R26 + std r27, 112(r1) ; save R27 + std r28, 120(r1) ; save R28 + std r29, 128(r1) ; save R29 + std r30, 136(r1) ; save R30 + std r31, 144(r1) ; save R31 + std r3, 152(r1) ; save hidden + + ; save CR + mfcr r0 + std r0, 160(r1) + ; save LR + mflr r0 + std r0, 168(r1) + ; save LR as PC + std r0, 176(r1) + + ; store RSP (pointing to context-data) in R7 + mr r7, r1 + + ; restore RSP (pointing to context-data) from R4 + mr r1, r4 + + ld r14, 8(r1) ; restore R14 + ld r15, 16(r1) ; restore R15 + ld r16, 24(r1) ; restore R16 + ld r17, 32(r1) ; restore R17 + ld r18, 40(r1) ; restore R18 + ld r19, 48(r1) ; restore R19 + ld r20, 56(r1) ; restore R20 + ld r21, 64(r1) ; restore R21 + ld r22, 72(r1) ; restore R22 + ld r23, 80(r1) ; restore R23 + ld r24, 88(r1) ; restore R24 + ld r25, 96(r1) ; restore R25 + ld r26, 104(r1) ; restore R26 + ld r27, 112(r1) ; restore R27 + ld r28, 120(r1) ; restore R28 + ld r29, 128(r1) ; restore R29 + ld r30, 136(r1) ; restore R30 + ld r31, 144(r1) ; restore R31 + ld r4, 152(r1) ; restore hidden + + ; restore CR + ld r0, 160(r1) + mtcr r0 + ; restore LR + ld r0, 168(r1) + mtlr r0 + ; ignore PC + + ; adjust stack + addi r1, r1, 184 + + ; return transfer_t + std r7, 0(r4) + std r5, 8(r4) + + ; restore CTR + mtctr r6 + + ; jump to context + bctr diff --git a/libs/context/src/asm/ontop_ppc64_sysv_xcoff_gas.S b/libs/context/src/asm/ontop_ppc64_sysv_xcoff_gas.S new file mode 100644 index 0000000..93f8c23 --- /dev/null +++ b/libs/context/src/asm/ontop_ppc64_sysv_xcoff_gas.S @@ -0,0 +1,83 @@ +.align 2 +.globl .ontop_fcontext +.ontop_fcontext: + # reserve space on stack + subi 1, 1, 184 + + std 13, 0(1) # save R13 + std 14, 8(1) # save R14 + std 15, 16(1) # save R15 + std 16, 24(1) # save R16 + std 17, 32(1) # save R17 + std 18, 40(1) # save R18 + std 19, 48(1) # save R19 + std 20, 56(1) # save R20 + std 21, 64(1) # save R21 + std 22, 72(1) # save R22 + std 23, 80(1) # save R23 + std 24, 88(1) # save R24 + std 25, 96(1) # save R25 + std 26, 104(1) # save R26 + std 27, 112(1) # save R27 + std 29, 120(1) # save R28 + std 29, 128(1) # save R29 + std 30, 136(1) # save R30 + std 31, 144(1) # save R31 + std 3, 152(1) # save hidden + + # save CR + mfcr 0 + std 0, 160(1) + # save LR + mflr 0 + std 0, 168(1) + # save LR as PC + std 0, 176(1) + + # store RSP (pointing to context-data) in R7 + mr 7, 1 + + # restore RSP (pointing to context-data) from R4 + mr 1, 4 + + ld 13, 0(1) # restore R13 + ld 14, 8(1) # restore R14 + ld 15, 16(1) # restore R15 + ld 16, 24(1) # restore R16 + ld 17, 32(1) # restore R17 + ld 18, 40(1) # restore R18 + ld 19, 48(1) # restore R19 + ld 20, 56(1) # restore R20 + ld 21, 64(1) # restore R21 + ld 22, 72(1) # restore R22 + ld 23, 80(1) # restore R23 + ld 24, 88(1) # restore R24 + ld 25, 96(1) # restore R25 + ld 26, 104(1) # restore R26 + ld 27, 112(1) # restore R27 + ld 28, 120(1) # restore R28 + ld 29, 128(1) # restore R29 + ld 30, 136(1) # restore R30 + ld 31, 144(1) # restore R31 + ld 4, 152(1) # restore hidden + + # restore CR + ld 0, 160(1) + mtcr 0 + # restore LR + ld 0, 168(1) + mtlr 0 + # ignore PC + + # adjust stack + addi 1, 1, 184 + + # return transfer_t + std 7, 0(4) + std 5, 8(4) + + # restore CTR + mtctr 6 + + # jump to context + bctr diff --git a/libs/context/src/asm/ontop_riscv64_sysv_elf_gas.S b/libs/context/src/asm/ontop_riscv64_sysv_elf_gas.S new file mode 100644 index 0000000..61ab46b --- /dev/null +++ b/libs/context/src/asm/ontop_riscv64_sysv_elf_gas.S @@ -0,0 +1,149 @@ +/* + 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) +*/ +/******************************************************* + * * + * ------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10| 0x14| 0x18| 0x1c| * + * ------------------------------------------------- * + * | fs0 | fs1 | fs2 | fs3 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ------------------------------------------------- * + * | 0x20| 0x24| 0x28| 0x2c| 0x30| 0x34| 0x38| 0x3c| * + * ------------------------------------------------- * + * | fs4 | fs5 | fs6 | fs7 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * + * ------------------------------------------------- * + * | 0x40| 0x44| 0x48| 0x4c| 0x50| 0x54| 0x58| 0x5c| * + * ------------------------------------------------- * + * | fs8 | fs9 | fs10 | fs11 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * + * ------------------------------------------------- * + * | 0x60| 0x64| 0x68| 0x6c| 0x70| 0x74| 0x78| 0x7c| * + * ------------------------------------------------- * + * | s0 | s1 | s2 | s3 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | * + * ------------------------------------------------- * + * | 0x80| 0x84| 0x88| 0x8c| 0x90| 0x94| 0x98| 0x9c| * + * ------------------------------------------------- * + * | s4 | s5 | s6 | s7 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | * + * ------------------------------------------------- * + * | 0xa0| 0xa4| 0xa8| 0xac| 0xb0| 0xb4| 0xb8| 0xbc| * + * ------------------------------------------------- * + * | s8 | s9 | s10 | s11 | * + * ------------------------------------------------- * + * ------------------------------------------------- * + * | 48 | 49 | 50 | 51 | | | | | * + * ------------------------------------------------- * + * | 0xc0| 0xc4| 0xc8| 0xcc| | | | | * + * ------------------------------------------------- * + * | ra | pc | | | * + * ------------------------------------------------- * + * * + *******************************************************/ + +.file "ontop_riscv64_sysv_elf_gas.S" +.text +.align 1 +.global ontop_fcontext +.type ontop_fcontext, %function +ontop_fcontext: + # prepare stack for GP + FPU + addi sp, sp, -0xd0 + + # save fs0 - fs11 + fsd fs0, 0x00(sp) + fsd fs1, 0x08(sp) + fsd fs2, 0x10(sp) + fsd fs3, 0x18(sp) + fsd fs4, 0x20(sp) + fsd fs5, 0x28(sp) + fsd fs6, 0x30(sp) + fsd fs7, 0x38(sp) + fsd fs8, 0x40(sp) + fsd fs9, 0x48(sp) + fsd fs10, 0x50(sp) + fsd fs11, 0x58(sp) + + # save s0-s11, ra + sd s0, 0x60(sp) + sd s1, 0x68(sp) + sd s2, 0x70(sp) + sd s3, 0x78(sp) + sd s4, 0x80(sp) + sd s5, 0x88(sp) + sd s6, 0x90(sp) + sd s7, 0x98(sp) + sd s8, 0xa0(sp) + sd s9, 0xa8(sp) + sd s10, 0xb0(sp) + sd s11, 0xb8(sp) + sd ra, 0xc0(sp) + + # save RA as PC + sd ra, 0xc8(sp) + + # store SP (pointing to context-data) in A3 + mv a3, sp + + # restore SP (pointing to context-data) from A0 + mv sp, a0 + + # load fs0 - fs11 + fld fs0, 0x00(sp) + fld fs1, 0x08(sp) + fld fs2, 0x10(sp) + fld fs3, 0x18(sp) + fld fs4, 0x20(sp) + fld fs5, 0x28(sp) + fld fs6, 0x30(sp) + fld fs7, 0x38(sp) + fld fs8, 0x40(sp) + fld fs9, 0x48(sp) + fld fs10, 0x50(sp) + fld fs11, 0x58(sp) + + # load s0-s11,ra + ld s0, 0x60(sp) + ld s1, 0x68(sp) + ld s2, 0x70(sp) + ld s3, 0x78(sp) + ld s4, 0x80(sp) + ld s5, 0x88(sp) + ld s6, 0x90(sp) + ld s7, 0x98(sp) + ld s8, 0xa0(sp) + ld s9, 0xa8(sp) + ld s10, 0xb0(sp) + ld s11, 0xb8(sp) + ld ra, 0xc0(sp) + + # return transfer_t from jump + # pass transfer_t as first arg in context function + # a0 == FCTX, a1 == DATA + mv a0, a3 + + # skip pc + # restore stack from GP + FPU + addi sp, sp, 0xd0 + + # jump to ontop-function + jr a2 +.size ontop_fcontext,.-ontop_fcontext +# Mark that we don't need executable stack. +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/ontop_s390x_sysv_elf_gas.S b/libs/context/src/asm/ontop_s390x_sysv_elf_gas.S new file mode 100644 index 0000000..4488654 --- /dev/null +++ b/libs/context/src/asm/ontop_s390x_sysv_elf_gas.S @@ -0,0 +1,112 @@ +/******************************************************* +* * +* ------------------------------------------------- * +* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * +* ------------------------------------------------- * +* | 0 | 8 | 16 | 24 | * +* ------------------------------------------------- * +* | R6 | R7 | R8 | R9 | * +* ------------------------------------------------- * +* ------------------------------------------------- * +* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * +* ------------------------------------------------- * +* | 32 | 40 | 48 | 56 | * +* ------------------------------------------------- * +* | R10 | R11 | R12 | R13 | * +* ------------------------------------------------- * +* ------------------------------------------------- * +* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * +* ------------------------------------------------- * +* | 64 | 72 | 80 | 88 | * +* ------------------------------------------------- * +* | R14/LR | R15 | F1 | F3 | * +* ------------------------------------------------- * +* ------------------------------------------------- * +* | 24 | 25 | 26 | 27 | 28 | 29 | | * +* ------------------------------------------------- * +* | 96 | 104 | 112 | 120 | * +* ------------------------------------------------- * +* | F5 | F7 | PC | | * +* ------------------------------------------------- * +* *****************************************************/ + +.file "ontop_s390x_sysv_elf_gas.S" +.text +.align 4 # According to the sample code in the ELF ABI docs +.global ontop_fcontext +.type ontop_fcontext, @function + +#define GR_OFFSET 0 +#define LR_OFFSET 64 +#define SP_OFFSET 72 +#define FP_OFFSET 80 +#define PC_OFFSET 112 +#define L_CTX 120 + +ontop_fcontext: + + # Reserved the space for stack to store the data of current context + # before we jump to the new context. + aghi %r15,-L_CTX + + # save the registers to the stack + stmg %r6, %r15, GR_OFFSET(%r15) + + # save the floating point registers + std %f0,FP_OFFSET(%r15) + std %f3,FP_OFFSET+8(%r15) + std %f5,FP_OFFSET+16(%r15) + std %f7,FP_OFFSET+24(%r15) + # Save LR as PC + stg %r14,PC_OFFSET(%r15) + + # Store the SP pointing to the old context-data into R0 + lgr %r0,%r15 + + # Get the SP pointing to the new context-data + # Note: Since the return type of the jump_fcontext is struct whose + # size is more than 8. The compiler automatically passes the + # address of the transfer_t where the data needs to store into R2. + + # Hence the first param passed to the jump_fcontext which represent + # the fctx we want to switch to is present in R3 + # R2 --> Address of the return transfer_t struct + # R3 --> Context we want to switch to + # R4 --> Data + lgr %r15,%r3 + + # Load the registers with the data present in context-data of the + # context we are going to switch to + lmg %r6,%r15,GR_OFFSET(%r15) + + # Restore Floating point registers + ld %f1,FP_OFFSET(%r15) + ld %f3,FP_OFFSET+8(%r15) + ld %f5,FP_OFFSET+16(%r15) + ld %f7,FP_OFFSET+24(%r15) + + # Skip PC + + # Adjust the stack + aghi %r15,L_CTX + + # R2 --> Address where the return transfer_t is stored + # R0 --> FCTX + # R4 --> DATA + # R5 --> Context function + + # Store the elements to return transfer_t + stg %r15, 0(%r2) + stg %r4, 8(%r2) + + # Note: The address in R2 points to the place where the return + # transfer_t is stored. Since context_function take transfer_t + # as first parameter. And R2 is the register which holds the + # first parameter value. + + #jump to context function + br %r5 + +.size ontop_fcontext,.-ontop_fcontext +# Mark that we don't need executable stack. +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/ontop_x86_64_ms_pe_gas.asm b/libs/context/src/asm/ontop_x86_64_ms_pe_gas.asm new file mode 100644 index 0000000..02e040c --- /dev/null +++ b/libs/context/src/asm/ontop_x86_64_ms_pe_gas.asm @@ -0,0 +1,211 @@ +/* + Copyright Oliver Kowalke 2009. + Copyright Thomas Sailer 2013. + 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) +*/ + +/************************************************************************************* +* ---------------------------------------------------------------------------------- * +* | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * +* ---------------------------------------------------------------------------------- * +* | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * +* ---------------------------------------------------------------------------------- * +* | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | * +* ---------------------------------------------------------------------------------- * +* | 0xe40 | 0x44 | 0x48 | 0x4c | 0x50 | 0x54 | 0x58 | 0x5c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | * +* ---------------------------------------------------------------------------------- * +* | 0x60 | 0x64 | 0x68 | 0x6c | 0x70 | 0x74 | 0x78 | 0x7c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 32 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | * +* ---------------------------------------------------------------------------------- * +* | 0x80 | 0x84 | 0x88 | 0x8c | 0x90 | 0x94 | 0x98 | 0x9c | * +* ---------------------------------------------------------------------------------- * +* | SEE registers (XMM6-XMM15) | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | * +* ---------------------------------------------------------------------------------- * +* | 0xa0 | 0xa4 | 0xa8 | 0xac | 0xb0 | 0xb4 | 0xb8 | 0xbc | * +* ---------------------------------------------------------------------------------- * +* | fc_mxcsr|fc_x87_cw| | fbr_strg | fc_dealloc | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | * +* ---------------------------------------------------------------------------------- * +* | 0xc0 | 0xc4 | 0xc8 | 0xcc | 0xd0 | 0xd4 | 0xd8 | 0xdc | * +* ---------------------------------------------------------------------------------- * +* | limit | base | R12 | R13 | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | * +* ---------------------------------------------------------------------------------- * +* | 0xe0 | 0xe4 | 0xe8 | 0xec | 0xf0 | 0xf4 | 0xf8 | 0xfc | * +* ---------------------------------------------------------------------------------- * +* | R14 | R15 | RDI | RSI | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | * +* ---------------------------------------------------------------------------------- * +* | 0x100 | 0x104 | 0x108 | 0x10c | 0x110 | 0x114 | 0x118 | 0x11c | * +* ---------------------------------------------------------------------------------- * +* | RBX | RBP | hidden | RIP | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | * +* ---------------------------------------------------------------------------------- * +* | 0x120 | 0x124 | 0x128 | 0x12c | 0x130 | 0x134 | 0x138 | 0x13c | * +* ---------------------------------------------------------------------------------- * +* | parameter area | * +* ---------------------------------------------------------------------------------- * +* ---------------------------------------------------------------------------------- * +* | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | * +* ---------------------------------------------------------------------------------- * +* | 0x140 | 0x144 | 0x148 | 0x14c | 0x150 | 0x154 | 0x158 | 0x15c | * +* ---------------------------------------------------------------------------------- * +* | FCTX | DATA | | * +* ---------------------------------------------------------------------------------- * +**************************************************************************************/ + +.file "ontop_x86_64_ms_pe_gas.asm" +.text +.p2align 4,,15 +.globl ontop_fcontext +.def ontop_fcontext; .scl 2; .type 32; .endef +.seh_proc ontop_fcontext +ontop_fcontext: +.seh_endprologue + + leaq -0x118(%rsp), %rsp /* prepare stack */ + +#if !defined(BOOST_USE_TSX) + /* save XMM storage */ + movaps %xmm6, 0x0(%rsp) + movaps %xmm7, 0x10(%rsp) + movaps %xmm8, 0x20(%rsp) + movaps %xmm9, 0x30(%rsp) + movaps %xmm10, 0x40(%rsp) + movaps %xmm11, 0x50(%rsp) + movaps %xmm12, 0x60(%rsp) + movaps %xmm13, 0x70(%rsp) + movaps %xmm14, 0x80(%rsp) + movaps %xmm15, 0x90(%rsp) + stmxcsr 0xa0(%rsp) /* save MMX control- and status-word */ + fnstcw 0xa4(%rsp) /* save x87 control-word */ +#endif + + /* load NT_TIB */ + movq %gs:(0x30), %r10 + /* save fiber local storage */ + movq 0x20(%r10), %rax + movq %rax, 0xb0(%rsp) + /* save current deallocation stack */ + movq 0x1478(%r10), %rax + movq %rax, 0xb8(%rsp) + /* save current stack limit */ + movq 0x10(%r10), %rax + movq %rax, 0xc0(%rsp) + /* save current stack base */ + movq 0x08(%r10), %rax + movq %rax, 0xc8(%rsp) + + movq %r12, 0xd0(%rsp) /* save R12 */ + movq %r13, 0xd8(%rsp) /* save R13 */ + movq %r14, 0xe0(%rsp) /* save R14 */ + movq %r15, 0xe8(%rsp) /* save R15 */ + movq %rdi, 0xf0(%rsp) /* save RDI */ + movq %rsi, 0xf8(%rsp) /* save RSI */ + movq %rbx, 0x100(%rsp) /* save RBX */ + movq %rbp, 0x108(%rsp) /* save RBP */ + + movq %rcx, 0x110(%rsp) /* save hidden address of transport_t */ + + /* preserve RSP (pointing to context-data) in RCX */ + movq %rsp, %rcx + + /* restore RSP (pointing to context-data) from RDX */ + movq %rdx, %rsp + +#if !defined(BOOST_USE_TSX) + /* restore XMM storage */ + movaps 0x0(%rsp), %xmm6 + movaps 0x10(%rsp), %xmm7 + movaps 0x20(%rsp), %xmm8 + movaps 0x30(%rsp), %xmm9 + movaps 0x40(%rsp), %xmm10 + movaps 0x50(%rsp), %xmm11 + movaps 0x60(%rsp), %xmm12 + movaps 0x70(%rsp), %xmm13 + movaps 0x80(%rsp), %xmm14 + movaps 0x90(%rsp), %xmm15 + ldmxcsr 0xa0(%rsp) /* restore MMX control- and status-word */ + fldcw 0xa4(%rsp) /* restore x87 control-word */ +#endif + + /* load NT_TIB */ + movq %gs:(0x30), %r10 + /* restore fiber local storage */ + movq 0xb0(%rsp), %rax + movq %rax, 0x20(%r10) + /* restore current deallocation stack */ + movq 0xb8(%rsp), %rax + movq %rax, 0x1478(%r10) + /* restore current stack limit */ + movq 0xc0(%rsp), %rax + movq %rax, 0x10(%r10) + /* restore current stack base */ + movq 0xc8(%rsp), %rax + movq %rax, 0x08(%r10) + + movq 0xd0(%rsp), %r12 /* restore R12 */ + movq 0xd8(%rsp), %r13 /* restore R13 */ + movq 0xe0(%rsp), %r14 /* restore R14 */ + movq 0xe8(%rsp), %r15 /* restore R15 */ + movq 0xf0(%rsp), %rdi /* restore RDI */ + movq 0xf8(%rsp), %rsi /* restore RSI */ + movq 0x100(%rsp), %rbx /* restore RBX */ + movq 0x108(%rsp), %rbp /* restore RBP */ + + movq 0x110(%rsp), %rax /* restore hidden address of transport_t */ + + leaq 0x118(%rsp), %rsp /* prepare stack */ + + /* keep return-address on stack */ + + /* transport_t returned in RAX */ + /* return parent fcontext_t */ + movq %rcx, 0x0(%rax) + /* return data */ + movq %r8, 0x8(%rax) + + /* transport_t as 1.arg of context-function */ + /* RCX contains address of returned (hidden) transfer_t */ + movq %rax, %rcx + /* RDX contains address of passed transfer_t */ + movq %rax, %rdx + + /* indirect jump to context */ + jmp *%r9 +.seh_endproc + +.section .drectve +.ascii " -export:\"ontop_fcontext\"" diff --git a/libs/context/src/asm/ontop_x86_64_ms_pe_masm.asm b/libs/context/src/asm/ontop_x86_64_ms_pe_masm.asm new file mode 100644 index 0000000..b57dd15 --- /dev/null +++ b/libs/context/src/asm/ontop_x86_64_ms_pe_masm.asm @@ -0,0 +1,207 @@ + +; Copyright Oliver Kowalke 2009. +; 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) + +; ---------------------------------------------------------------------------------- +; | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | +; ---------------------------------------------------------------------------------- +; | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | +; ---------------------------------------------------------------------------------- +; | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | +; ---------------------------------------------------------------------------------- +; | 0xe40 | 0x44 | 0x48 | 0x4c | 0x50 | 0x54 | 0x58 | 0x5c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | +; ---------------------------------------------------------------------------------- +; | 0x60 | 0x64 | 0x68 | 0x6c | 0x70 | 0x74 | 0x78 | 0x7c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 32 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | +; ---------------------------------------------------------------------------------- +; | 0x80 | 0x84 | 0x88 | 0x8c | 0x90 | 0x94 | 0x98 | 0x9c | +; ---------------------------------------------------------------------------------- +; | SEE registers (XMM6-XMM15) | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | +; ---------------------------------------------------------------------------------- +; | 0xa0 | 0xa4 | 0xa8 | 0xac | 0xb0 | 0xb4 | 0xb8 | 0xbc | +; ---------------------------------------------------------------------------------- +; | fc_mxcsr|fc_x87_cw| | fbr_strg | fc_dealloc | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | +; ---------------------------------------------------------------------------------- +; | 0xc0 | 0xc4 | 0xc8 | 0xcc | 0xd0 | 0xd4 | 0xd8 | 0xdc | +; ---------------------------------------------------------------------------------- +; | limit | base | R12 | R13 | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | +; ---------------------------------------------------------------------------------- +; | 0xe0 | 0xe4 | 0xe8 | 0xec | 0xf0 | 0xf4 | 0xf8 | 0xfc | +; ---------------------------------------------------------------------------------- +; | R14 | R15 | RDI | RSI | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | +; ---------------------------------------------------------------------------------- +; | 0x100 | 0x104 | 0x108 | 0x10c | 0x110 | 0x114 | 0x118 | 0x11c | +; ---------------------------------------------------------------------------------- +; | RBX | RBP | hidden | RIP | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | +; ---------------------------------------------------------------------------------- +; | 0x120 | 0x124 | 0x128 | 0x12c | 0x130 | 0x134 | 0x138 | 0x13c | +; ---------------------------------------------------------------------------------- +; | parameter area | +; ---------------------------------------------------------------------------------- +; ---------------------------------------------------------------------------------- +; | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | +; ---------------------------------------------------------------------------------- +; | 0x140 | 0x144 | 0x148 | 0x14c | 0x150 | 0x154 | 0x158 | 0x15c | +; ---------------------------------------------------------------------------------- +; | FCTX | DATA | | +; ---------------------------------------------------------------------------------- + +.code + +ontop_fcontext PROC BOOST_CONTEXT_EXPORT FRAME + .endprolog + + ; prepare stack + lea rsp, [rsp-0118h] + +IFNDEF BOOST_USE_TSX + ; save XMM storage + movaps [rsp], xmm6 + movaps [rsp+010h], xmm7 + movaps [rsp+020h], xmm8 + movaps [rsp+030h], xmm9 + movaps [rsp+040h], xmm10 + movaps [rsp+050h], xmm11 + movaps [rsp+060h], xmm12 + movaps [rsp+070h], xmm13 + movaps [rsp+080h], xmm14 + movaps [rsp+090h], xmm15 + ; save MMX control- and status-word + stmxcsr [rsp+0a0h] + ; save x87 control-word + fnstcw [rsp+0a4h] +ENDIF + + ; load NT_TIB + mov r10, gs:[030h] + ; save fiber local storage + mov rax, [r10+020h] + mov [rsp+0b0h], rax + ; save current deallocation stack + mov rax, [r10+01478h] + mov [rsp+0b8h], rax + ; save current stack limit + mov rax, [r10+010h] + mov [rsp+0c0h], rax + ; save current stack base + mov rax, [r10+08h] + mov [rsp+0c8h], rax + + mov [rsp+0d0h], r12 ; save R12 + mov [rsp+0d8h], r13 ; save R13 + mov [rsp+0e0h], r14 ; save R14 + mov [rsp+0e8h], r15 ; save R15 + mov [rsp+0f0h], rdi ; save RDI + mov [rsp+0f8h], rsi ; save RSI + mov [rsp+0100h], rbx ; save RBX + mov [rsp+0108h], rbp ; save RBP + + mov [rsp+0110h], rcx ; save hidden address of transport_t + + ; preserve RSP (pointing to context-data) in RCX + mov rcx, rsp + + ; restore RSP (pointing to context-data) from RDX + mov rsp, rdx + +IFNDEF BOOST_USE_TSX + ; restore XMM storage + movaps xmm6, [rsp] + movaps xmm7, [rsp+010h] + movaps xmm8, [rsp+020h] + movaps xmm9, [rsp+030h] + movaps xmm10, [rsp+040h] + movaps xmm11, [rsp+050h] + movaps xmm12, [rsp+060h] + movaps xmm13, [rsp+070h] + movaps xmm14, [rsp+080h] + movaps xmm15, [rsp+090h] + ; restore MMX control- and status-word + ldmxcsr [rsp+0a0h] + ; save x87 control-word + fldcw [rsp+0a4h] +ENDIF + + ; load NT_TIB + mov r10, gs:[030h] + ; restore fiber local storage + mov rax, [rsp+0b0h] + mov [r10+020h], rax + ; restore current deallocation stack + mov rax, [rsp+0b8h] + mov [r10+01478h], rax + ; restore current stack limit + mov rax, [rsp+0c0h] + mov [r10+010h], rax + ; restore current stack base + mov rax, [rsp+0c8h] + mov [r10+08h], rax + + mov r12, [rsp+0d0h] ; restore R12 + mov r13, [rsp+0d8h] ; restore R13 + mov r14, [rsp+0e0h] ; restore R14 + mov r15, [rsp+0e8h] ; restore R15 + mov rdi, [rsp+0f0h] ; restore RDI + mov rsi, [rsp+0f8h] ; restore RSI + mov rbx, [rsp+0100h] ; restore RBX + mov rbp, [rsp+0108h] ; restore RBP + + mov rax, [rsp+0110h] ; restore hidden address of transport_t + + ; prepare stack + lea rsp, [rsp+0118h] + + ; keep return-address on stack + + ; transport_t returned in RAX + ; return parent fcontext_t + mov [rax], rcx + ; return data + mov [rax+08h], r8 + + ; transport_t as 1.arg of context-function + ; RCX contains address of returned (hidden) transfer_t + mov rcx, rax + ; RDX contains address of passed transfer_t + mov rdx, rax + + ; indirect jump to context + jmp r9 +ontop_fcontext ENDP +END diff --git a/libs/context/src/asm/ontop_x86_64_sysv_elf_gas.S b/libs/context/src/asm/ontop_x86_64_sysv_elf_gas.S new file mode 100644 index 0000000..447a1ec --- /dev/null +++ b/libs/context/src/asm/ontop_x86_64_sysv_elf_gas.S @@ -0,0 +1,84 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| R12 | R13 | R14 | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * + * ---------------------------------------------------------------------------------- * + * | R15 | RBX | RBP | RIP | * + * ---------------------------------------------------------------------------------- * + * * + ****************************************************************************************/ + +.file "ontop_x86_64_sysv_elf_gas.S" +.text +.globl ontop_fcontext +.type ontop_fcontext,@function +.align 16 +ontop_fcontext: + /* preserve ontop-function in R8 */ + movq %rdx, %r8 + + leaq -0x38(%rsp), %rsp /* prepare stack */ + +#if !defined(BOOST_USE_TSX) + stmxcsr (%rsp) /* save MMX control- and status-word */ + fnstcw 0x4(%rsp) /* save x87 control-word */ +#endif + + movq %r12, 0x8(%rsp) /* save R12 */ + movq %r13, 0x10(%rsp) /* save R13 */ + movq %r14, 0x18(%rsp) /* save R14 */ + movq %r15, 0x20(%rsp) /* save R15 */ + movq %rbx, 0x28(%rsp) /* save RBX */ + movq %rbp, 0x30(%rsp) /* save RBP */ + + /* store RSP (pointing to context-data) in RAX */ + movq %rsp, %rax + + /* restore RSP (pointing to context-data) from RDI */ + movq %rdi, %rsp + +#if !defined(BOOST_USE_TSX) + ldmxcsr (%rsp) /* restore MMX control- and status-word */ + fldcw 0x4(%rsp) /* restore x87 control-word */ +#endif + + movq 0x8(%rsp), %r12 /* restore R12 */ + movq 0x10(%rsp), %r13 /* restore R13 */ + movq 0x18(%rsp), %r14 /* restore R14 */ + movq 0x20(%rsp), %r15 /* restore R15 */ + movq 0x28(%rsp), %rbx /* restore RBX */ + movq 0x30(%rsp), %rbp /* restore RBP */ + + leaq 0x38(%rsp), %rsp /* prepare stack */ + + /* return transfer_t from jump */ + /* RAX == fctx, RDX == data */ + movq %rsi, %rdx + /* pass transfer_t as first arg in context function */ + /* RDI == fctx, RSI == data */ + movq %rax, %rdi + + /* keep return-address on stack */ + + /* indirect jump to context */ + jmp *%r8 +.size ontop_fcontext,.-ontop_fcontext + +/* Mark that we don't need executable stack. */ +.section .note.GNU-stack,"",%progbits diff --git a/libs/context/src/asm/ontop_x86_64_sysv_macho_gas.S b/libs/context/src/asm/ontop_x86_64_sysv_macho_gas.S new file mode 100644 index 0000000..49755c6 --- /dev/null +++ b/libs/context/src/asm/ontop_x86_64_sysv_macho_gas.S @@ -0,0 +1,78 @@ +/* + Copyright Oliver Kowalke 2009. + 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) +*/ + +/**************************************************************************************** + * * + * ---------------------------------------------------------------------------------- * + * | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | * + * ---------------------------------------------------------------------------------- * + * | 0x0 | 0x4 | 0x8 | 0xc | 0x10 | 0x14 | 0x18 | 0x1c | * + * ---------------------------------------------------------------------------------- * + * | fc_mxcsr|fc_x87_cw| R12 | R13 | R14 | * + * ---------------------------------------------------------------------------------- * + * ---------------------------------------------------------------------------------- * + * | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | * + * ---------------------------------------------------------------------------------- * + * | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c | * + * ---------------------------------------------------------------------------------- * + * | R15 | RBX | RBP | RIP | * + * ---------------------------------------------------------------------------------- * + * * + ****************************************************************************************/ + +.text +.globl _ontop_fcontext +.align 8 +_ontop_fcontext: + /* preserve ontop-function in R8 */ + movq %rdx, %r8 + + leaq -0x38(%rsp), %rsp /* prepare stack */ + +#if !defined(BOOST_USE_TSX) + stmxcsr (%rsp) /* save MMX control- and status-word */ + fnstcw 0x4(%rsp) /* save x87 control-word */ +#endif + + movq %r12, 0x8(%rsp) /* save R12 */ + movq %r13, 0x10(%rsp) /* save R13 */ + movq %r14, 0x18(%rsp) /* save R14 */ + movq %r15, 0x20(%rsp) /* save R15 */ + movq %rbx, 0x28(%rsp) /* save RBX */ + movq %rbp, 0x30(%rsp) /* save RBP */ + + /* store RSP (pointing to context-data) in RAX */ + movq %rsp, %rax + + /* restore RSP (pointing to context-data) from RDI */ + movq %rdi, %rsp + +#if !defined(BOOST_USE_TSX) + ldmxcsr (%rsp) /* restore MMX control- and status-word */ + fldcw 0x4(%rsp) /* restore x87 control-word */ +#endif + + movq 0x8(%rsp), %r12 /* restore R12 */ + movq 0x10(%rsp), %r13 /* restore R13 */ + movq 0x18(%rsp), %r14 /* restore R14 */ + movq 0x20(%rsp), %r15 /* restore R15 */ + movq 0x28(%rsp), %rbx /* restore RBX */ + movq 0x30(%rsp), %rbp /* restore RBP */ + + leaq 0x38(%rsp), %rsp /* prepare stack */ + + /* return transfer_t from jump */ + /* RAX == fctx, RDX == data */ + movq %rsi, %rdx + /* pass transfer_t as first arg in context function */ + /* RDI == fctx, RSI == data */ + movq %rax, %rdi + + /* keep return-address on stack */ + + /* indirect jump to context */ + jmp *%r8 diff --git a/libs/context/src/asm/tail_ppc32_sysv_elf_gas.cpp b/libs/context/src/asm/tail_ppc32_sysv_elf_gas.cpp new file mode 100644 index 0000000..3486084 --- /dev/null +++ b/libs/context/src/asm/tail_ppc32_sysv_elf_gas.cpp @@ -0,0 +1,18 @@ + +// Copyright Oliver Kowalke 2009. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +using boost::context::detail::fcontext_t; +using boost::context::detail::transfer_t; + +// This C++ tail of ontop_fcontext() allocates transfer_t{ from, vp } +// on the stack. If fn() throws a C++ exception, then the C++ runtime +// must remove this tail's stack frame. +extern "C" transfer_t +ontop_fcontext_tail( int ignore, void * vp, transfer_t (* fn)(transfer_t), fcontext_t const from) { + return fn( transfer_t{ from, vp }); +} diff --git a/libs/context/src/continuation.cpp b/libs/context/src/continuation.cpp new file mode 100644 index 0000000..0779baa --- /dev/null +++ b/libs/context/src/continuation.cpp @@ -0,0 +1,60 @@ + +// Copyright Oliver Kowalke 2017. +// 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) + +#if defined(BOOST_USE_UCONTEXT) +#include "boost/context/continuation_ucontext.hpp" +#elif defined(BOOST_USE_WINFIB) +#include "boost/context/continuation_winfib.hpp" +#else +#include "boost/context/execution_context.hpp" +#endif + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +// zero-initialization +thread_local activation_record * current_rec; +thread_local static std::size_t counter; + +// schwarz counter +activation_record_initializer::activation_record_initializer() noexcept { + if ( 0 == counter++) { + current_rec = new activation_record(); + } +} + +activation_record_initializer::~activation_record_initializer() { + if ( 0 == --counter) { + BOOST_ASSERT( current_rec->is_main_context() ); + delete current_rec; + } +} + +} + +namespace detail { + +activation_record *& +activation_record::current() noexcept { + // initialized the first time control passes; per thread + thread_local static activation_record_initializer initializer; + return current_rec; +} + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/libs/context/src/dummy.cpp b/libs/context/src/dummy.cpp new file mode 100644 index 0000000..e69de29 diff --git a/libs/context/src/fiber.cpp b/libs/context/src/fiber.cpp new file mode 100644 index 0000000..b6b790d --- /dev/null +++ b/libs/context/src/fiber.cpp @@ -0,0 +1,58 @@ + +// Copyright Oliver Kowalke 2017. +// 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) + +#if defined(BOOST_USE_UCONTEXT) +#include "boost/context/fiber_ucontext.hpp" +#elif defined(BOOST_USE_WINFIB) +#include "boost/context/fiber_winfib.hpp" +#endif + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost { +namespace context { +namespace detail { + +// zero-initialization +thread_local fiber_activation_record * fib_current_rec; +thread_local static std::size_t counter; + +// schwarz counter +fiber_activation_record_initializer::fiber_activation_record_initializer() noexcept { + if ( 0 == counter++) { + fib_current_rec = new fiber_activation_record(); + } +} + +fiber_activation_record_initializer::~fiber_activation_record_initializer() { + if ( 0 == --counter) { + BOOST_ASSERT( fib_current_rec->is_main_context() ); + delete fib_current_rec; + } +} + +} + +namespace detail { + +fiber_activation_record *& +fiber_activation_record::current() noexcept { + // initialized the first time control passes; per thread + thread_local static fiber_activation_record_initializer initializer; + return fib_current_rec; +} + +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/libs/context/src/posix/stack_traits.cpp b/libs/context/src/posix/stack_traits.cpp new file mode 100644 index 0000000..ca42088 --- /dev/null +++ b/libs/context/src/posix/stack_traits.cpp @@ -0,0 +1,122 @@ + +// Copyright Oliver Kowalke 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "boost/context/stack_traits.hpp" + +extern "C" { +#include +#include +#include +#include +} + +//#if _POSIX_C_SOURCE >= 200112L + +#include +#include + +#include +#include +#if defined(BOOST_NO_CXX11_HDR_MUTEX) +# include +#else +# include +#endif + +#if !defined (SIGSTKSZ) +# define SIGSTKSZ (32768) // 32kb minimum allowable stack +# define UDEF_SIGSTKSZ +#endif + +#if !defined (MINSIGSTKSZ) +# define MINSIGSTKSZ (131072) // 128kb recommended stack size +# define UDEF_MINSIGSTKSZ +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace { + +void pagesize_( std::size_t * size) BOOST_NOEXCEPT_OR_NOTHROW { + // conform to POSIX.1-2001 + * size = ::sysconf( _SC_PAGESIZE); +} + +void stacksize_limit_( rlimit * limit) BOOST_NOEXCEPT_OR_NOTHROW { + // conforming to POSIX.1-2001 + ::getrlimit( RLIMIT_STACK, limit); +} + +std::size_t pagesize() BOOST_NOEXCEPT_OR_NOTHROW { + static std::size_t size = 0; +#if defined(BOOST_NO_CXX11_HDR_MUTEX) + static boost::once_flag flag = BOOST_ONCE_INIT; + boost::call_once( flag, pagesize_, & size); +#else + static std::once_flag flag; + std::call_once( flag, pagesize_, & size); +#endif + return size; +} + +rlimit stacksize_limit() BOOST_NOEXCEPT_OR_NOTHROW { + static rlimit limit; +#if defined(BOOST_NO_CXX11_HDR_MUTEX) + static boost::once_flag flag = BOOST_ONCE_INIT; + boost::call_once( flag, stacksize_limit_, & limit); +#else + static std::once_flag flag; + std::call_once( flag, stacksize_limit_, & limit); +#endif + return limit; +} + +} + +namespace boost { +namespace context { + +bool +stack_traits::is_unbounded() BOOST_NOEXCEPT_OR_NOTHROW { + return RLIM_INFINITY == stacksize_limit().rlim_max; +} + +std::size_t +stack_traits::page_size() BOOST_NOEXCEPT_OR_NOTHROW { + return pagesize(); +} + +std::size_t +stack_traits::default_size() BOOST_NOEXCEPT_OR_NOTHROW { + return 128 * 1024; +} + +std::size_t +stack_traits::minimum_size() BOOST_NOEXCEPT_OR_NOTHROW { + return MINSIGSTKSZ; +} + +std::size_t +stack_traits::maximum_size() BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT( ! is_unbounded() ); + return static_cast< std::size_t >( stacksize_limit().rlim_max); +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#ifdef UDEF_SIGSTKSZ +# undef SIGSTKSZ; +#endif + +#ifdef UDEF_MINSIGSTKSZ +# undef MINSIGSTKSZ +#endif diff --git a/libs/context/src/untested.cpp b/libs/context/src/untested.cpp new file mode 100644 index 0000000..d6e2086 --- /dev/null +++ b/libs/context/src/untested.cpp @@ -0,0 +1,7 @@ + +// Copyright Oliver Kowalke 2009. +// 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) + +#error "! code for this platform is untested - please remove this file from build/Jamfile.v2 and report the test-result on boost-track !" diff --git a/libs/context/src/windows/stack_traits.cpp b/libs/context/src/windows/stack_traits.cpp new file mode 100644 index 0000000..14016b1 --- /dev/null +++ b/libs/context/src/windows/stack_traits.cpp @@ -0,0 +1,116 @@ + +// Copyright Oliver Kowalke 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include "boost/context/stack_traits.hpp" + +extern "C" { +#include +} + +//#if defined (BOOST_WINDOWS) || _POSIX_C_SOURCE >= 200112L + +#include +#include +#include +#include +#include + +#include +#include +#if defined(BOOST_NO_CXX11_HDR_MUTEX) +# include +#else +# include +#endif + +#include + +// x86_64 +// test x86_64 before i386 because icc might +// define __i686__ for x86_64 too +#if defined(__x86_64__) || defined(__x86_64) \ + || defined(__amd64__) || defined(__amd64) \ + || defined(_M_X64) || defined(_M_AMD64) + +// Windows seams not to provide a constant or function +// telling the minimal stacksize +# define MIN_STACKSIZE 8 * 1024 +#else +# define MIN_STACKSIZE 4 * 1024 +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace { + +void system_info_( SYSTEM_INFO * si) BOOST_NOEXCEPT_OR_NOTHROW { + ::GetSystemInfo( si); +} + +SYSTEM_INFO system_info() BOOST_NOEXCEPT_OR_NOTHROW { + static SYSTEM_INFO si; +#if defined(BOOST_NO_CXX11_HDR_MUTEX) + static boost::once_flag flag = BOOST_ONCE_INIT; + boost::call_once( flag, static_cast< void(*)( SYSTEM_INFO *) >( system_info_), & si); +#else + static std::once_flag flag; + std::call_once( flag, static_cast< void(*)( SYSTEM_INFO *) >( system_info_), & si); +#endif + return si; +} + +std::size_t pagesize() BOOST_NOEXCEPT_OR_NOTHROW { + return static_cast< std::size_t >( system_info().dwPageSize); +} + +} + +namespace boost { +namespace context { + +// Windows seams not to provide a limit for the stacksize +// libcoco uses 32k+4k bytes as minimum +BOOST_CONTEXT_DECL +bool +stack_traits::is_unbounded() BOOST_NOEXCEPT_OR_NOTHROW { + return true; +} + +BOOST_CONTEXT_DECL +std::size_t +stack_traits::page_size() BOOST_NOEXCEPT_OR_NOTHROW { + return pagesize(); +} + +BOOST_CONTEXT_DECL +std::size_t +stack_traits::default_size() BOOST_NOEXCEPT_OR_NOTHROW { + return 128 * 1024; +} + +// because Windows seams not to provide a limit for minimum stacksize +BOOST_CONTEXT_DECL +std::size_t +stack_traits::minimum_size() BOOST_NOEXCEPT_OR_NOTHROW { + return MIN_STACKSIZE; +} + +// because Windows seams not to provide a limit for maximum stacksize +// maximum_size() can never be called (pre-condition ! is_unbounded() ) +BOOST_CONTEXT_DECL +std::size_t +stack_traits::maximum_size() BOOST_NOEXCEPT_OR_NOTHROW { + BOOST_ASSERT( ! is_unbounded() ); + return 1 * 1024 * 1024 * 1024; // 1GB +} + +}} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif diff --git a/libs/date_time/build/Jamfile.v2 b/libs/date_time/build/Jamfile.v2 new file mode 100644 index 0000000..cacc08a --- /dev/null +++ b/libs/date_time/build/Jamfile.v2 @@ -0,0 +1,33 @@ +# Copyright (c) 2002-2005 CrystalClear Software, Inc. +# Use, modification and distribution is subject to the +# Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +# +# Boost.date_time build and test Jamfile +# +# Based on boost.python Jamfile +# +# To run all tests quietly: jam test +# +# Declares the following targets: +# 1. libboost_date_time, a static link library to be linked with all +# Boost.date_time modules +# + + +project boost/date_time + : requirements + DATE_TIME_INLINE + shared:BOOST_ALL_DYN_LINK=1 + : usage-requirements + DATE_TIME_INLINE + shared:BOOST_DATE_TIME_DYN_LINK=1 + : source-location ../src + ; + +# Base names of the source files for libboost_date_time +CPP_SOURCES = greg_month greg_weekday date_generators ; + +lib boost_date_time : gregorian/$(CPP_SOURCES).cpp ; + +boost-install boost_date_time ; diff --git a/libs/date_time/src/date_time.doc b/libs/date_time/src/date_time.doc new file mode 100644 index 0000000..920fac2 --- /dev/null +++ b/libs/date_time/src/date_time.doc @@ -0,0 +1,72 @@ +/* Copyright (c) 2001-2004 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland + * $Date$ + */ + + +/*! @mainpage Boost Date-Time Library Reference Documentation + * + * + *@section intro Introduction + * + * The Boost Date-Time Library (originally the Generic Date-Time Library or GDTL) + * is a set of C++ date-time libraries based on the concepts of generic programming. + * This is an online reference guide generated from the source code + * that provides a handy way to learn about the details of the + * library. If you are a user you should start with the + * User Documentation. + * + *@section using Using This Documentation + * + * The online documentation provides extensive information about the details + * of the library including: + * - Class hierarchy + * - Namespace Documentation + * - List of source files + * - Annotated list of classes and structs + * (Compound List) + * + * For example, suppose you wanted to learn more about the + * gregorian::greg_month class. + * You could alternatively browse the + * - Class documentation page + * - Include dependencies for greg_month.hpp + * - Hyperlinked and colorized source files: [hpp file] [cpp file] + * + * The main navigation bar at the top provides that access to many + * different modes of naviation through the library. + + * + */ + +//! Overall boost namespace -- library does not put any symbols here +namespace boost { + +//! Namespace for basic templates and components used to construct date-time systems +/*! + This namespace encapsulates various types of templates and classes used + to construct coherent date-time systems including date, time, etc. These + components should be considered helper components to be utilized in the + construction of specific date-time system implementations. See namespace + gregorian for one such example. +*/ +namespace date_time {} + +} +/*! Namespace for the c++ standard library. Library does not define any symbols in the namespace, but uses some classes from this namespace. +*/ +namespace std {} + +/*!\class std::out_of_range + \brief Exception class defined in c++ standard library. + A derivative of std::logic_error and std::exception and base class for + many exceptions in the library. See also: + + Mandragor docs for libstdcpp_v3 std::out_of_range +*/ + + + diff --git a/libs/date_time/src/gregorian/date_generators.cpp b/libs/date_time/src/gregorian/date_generators.cpp new file mode 100644 index 0000000..32a58c1 --- /dev/null +++ b/libs/date_time/src/gregorian/date_generators.cpp @@ -0,0 +1,38 @@ +/* Copyright (c) 2002,2003 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date$ + */ + + + +#ifndef BOOST_DATE_TIME_SOURCE +#define BOOST_DATE_TIME_SOURCE +#endif +#include "boost/date_time/date_generators.hpp" + +namespace boost { +namespace date_time { + + const char* const _nth_as_str[] = {"out of range", "first", "second", + "third", "fourth", "fifth"}; + + //! Returns nth arg as string. 1 -> "first", 2 -> "second", max is 5. + BOOST_DATE_TIME_DECL const char* nth_as_str(int ele) + { + if(ele >= 1 && ele <= 5) { + return _nth_as_str[ele]; + } + else { + return _nth_as_str[0]; + } + } + +} } //namespace date_time + + + + + diff --git a/libs/date_time/src/gregorian/greg_month.cpp b/libs/date_time/src/gregorian/greg_month.cpp new file mode 100644 index 0000000..8232378 --- /dev/null +++ b/libs/date_time/src/gregorian/greg_month.cpp @@ -0,0 +1,173 @@ +/* Copyright (c) 2002-2005 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date$ + */ + + + +#ifndef BOOST_DATE_TIME_SOURCE +#define BOOST_DATE_TIME_SOURCE +#endif +#include "boost/date_time/gregorian/greg_month.hpp" +#include "boost/date_time/gregorian/greg_facet.hpp" +#include "boost/date_time/date_format_simple.hpp" +#include "boost/date_time/compiler_config.hpp" +#if defined(BOOST_DATE_TIME_INCLUDE_LIMITED_HEADERS) +#include "boost/date_time/gregorian/formatters_limited.hpp" +#else +#include "boost/date_time/gregorian/formatters.hpp" +#endif +#include "boost/date_time/date_parsing.hpp" +#include "boost/date_time/gregorian/parsers.hpp" + +#include "greg_names.hpp" +namespace boost { +namespace gregorian { + + /*! Returns a shared pointer to a map of Month strings & numbers. + * Strings are both full names and abbreviations. + * Ex. ("jan",1), ("february",2), etc... + * Note: All characters are lowercase - for case insensitivity + */ + greg_month::month_map_ptr_type greg_month::get_month_map_ptr() + { + static month_map_ptr_type month_map_ptr(new greg_month::month_map_type()); + + if(month_map_ptr->empty()) { + std::string s(""); + for(unsigned short i = 1; i <= 12; ++i) { + greg_month m(static_cast(i)); + s = m.as_long_string(); + s = date_time::convert_to_lower(s); + month_map_ptr->insert(std::make_pair(s, i)); + s = m.as_short_string(); + s = date_time::convert_to_lower(s); + month_map_ptr->insert(std::make_pair(s, i)); + } + } + return month_map_ptr; + } + + + //! Returns 3 char english string for the month ex: Jan, Feb, Mar, Apr + const char* + greg_month::as_short_string() const + { + return short_month_names[value_-1]; + } + + //! Returns full name of month as string in english ex: January, February + const char* + greg_month::as_long_string() const + { + return long_month_names[value_-1]; + } + + //! Return special_value from string argument + /*! Return special_value from string argument. If argument is + * not one of the special value names (defined in names.hpp), + * return 'not_special' */ + special_values special_value_from_string(const std::string& s) { + short i = date_time::find_match(special_value_names, + special_value_names, + date_time::NumSpecialValues, + s); + if(i >= date_time::NumSpecialValues) { // match not found + return not_special; + } + else { + return static_cast(i); + } + } + + +#ifndef BOOST_NO_STD_WSTRING + //! Returns 3 wchar_t english string for the month ex: Jan, Feb, Mar, Apr + const wchar_t* + greg_month::as_short_wstring() const + { + return w_short_month_names[value_-1]; + } + + //! Returns full name of month as wchar_t string in english ex: January, February + const wchar_t* + greg_month::as_long_wstring() const + { + return w_long_month_names[value_-1]; + } +#endif // BOOST_NO_STD_WSTRING + +#ifndef BOOST_DATE_TIME_NO_LOCALE + /*! creates an all_date_names_put object with the correct set of names. + * This function is only called in the event of an exception where + * the imbued locale containing the needed facet is for some reason + * unreachable. + */ + BOOST_DATE_TIME_DECL + boost::date_time::all_date_names_put* + create_facet_def(char /*type*/) + { + typedef + boost::date_time::all_date_names_put facet_def; + + return new facet_def(short_month_names, + long_month_names, + special_value_names, + short_weekday_names, + long_weekday_names); + } + + //! generates a locale with the set of gregorian name-strings of type char* + BOOST_DATE_TIME_DECL std::locale generate_locale(std::locale& loc, char /*type*/){ + typedef boost::date_time::all_date_names_put facet_def; + return std::locale(loc, new facet_def(short_month_names, + long_month_names, + special_value_names, + short_weekday_names, + long_weekday_names) + ); + } + +#ifndef BOOST_NO_STD_WSTRING + /*! creates an all_date_names_put object with the correct set of names. + * This function is only called in the event of an exception where + * the imbued locale containing the needed facet is for some reason + * unreachable. + */ + BOOST_DATE_TIME_DECL + boost::date_time::all_date_names_put* + create_facet_def(wchar_t /*type*/) + { + typedef + boost::date_time::all_date_names_put facet_def; + + return new facet_def(w_short_month_names, + w_long_month_names, + w_special_value_names, + w_short_weekday_names, + w_long_weekday_names); + } + + //! generates a locale with the set of gregorian name-strings of type wchar_t* + BOOST_DATE_TIME_DECL std::locale generate_locale(std::locale& loc, wchar_t /*type*/){ + typedef boost::date_time::all_date_names_put facet_def; + return std::locale(loc, new facet_def(w_short_month_names, + w_long_month_names, + w_special_value_names, + w_short_weekday_names, + w_long_weekday_names) + ); + } +#endif // BOOST_NO_STD_WSTRING +#endif // BOOST_DATE_TIME_NO_LOCALE + +} } //namespace gregorian + + + + + + diff --git a/libs/date_time/src/gregorian/greg_names.hpp b/libs/date_time/src/gregorian/greg_names.hpp new file mode 100644 index 0000000..f20b320 --- /dev/null +++ b/libs/date_time/src/gregorian/greg_names.hpp @@ -0,0 +1,43 @@ +/* Copyright (c) 2002-2004 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date$ + */ + + + +#ifndef DATE_TIME_SRC_GREG_NAMES_HPP___ +#define DATE_TIME_SRC_GREG_NAMES_HPP___ + +#include "boost/date_time/gregorian/greg_month.hpp" +#include "boost/date_time/special_defs.hpp" +namespace boost { +namespace gregorian { + + + const char* const short_month_names[NumMonths]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec", "NAM"}; + const char* const long_month_names[NumMonths]={"January","February","March","April","May","June","July","August","September","October","November","December","NotAMonth"}; + const char* const special_value_names[date_time::NumSpecialValues]={"not-a-date-time","-infinity","+infinity","min_date_time","max_date_time","not_special"}; + + + const char* const short_weekday_names[]={"Sun", "Mon", "Tue", + "Wed", "Thu", "Fri", "Sat"}; + const char* const long_weekday_names[]= {"Sunday","Monday","Tuesday", + "Wednesday", "Thursday", + "Friday", "Saturday"}; + +#ifndef BOOST_NO_STD_WSTRING + const wchar_t* const w_short_month_names[NumMonths]={L"Jan",L"Feb",L"Mar",L"Apr",L"May",L"Jun",L"Jul",L"Aug",L"Sep",L"Oct",L"Nov",L"Dec",L"NAM"}; + const wchar_t* const w_long_month_names[NumMonths]={L"January",L"February",L"March",L"April",L"May",L"June",L"July",L"August",L"September",L"October",L"November",L"December",L"NotAMonth"}; + const wchar_t* const w_special_value_names[date_time::NumSpecialValues]={L"not-a-date-time",L"-infinity",L"+infinity",L"min_date_time",L"max_date_time",L"not_special"}; + + const wchar_t* const w_short_weekday_names[]={L"Sun", L"Mon", L"Tue", + L"Wed", L"Thu", L"Fri", L"Sat"}; + const wchar_t* const w_long_weekday_names[]= {L"Sunday",L"Monday",L"Tuesday", + L"Wednesday", L"Thursday", + L"Friday", L"Saturday"}; +#endif // BOOST_NO_STD_WSTRING +} } // boost::gregorian +#endif // DATE_TIME_SRC_GREG_NAMES_HPP___ diff --git a/libs/date_time/src/gregorian/greg_weekday.cpp b/libs/date_time/src/gregorian/greg_weekday.cpp new file mode 100644 index 0000000..ffdc96f --- /dev/null +++ b/libs/date_time/src/gregorian/greg_weekday.cpp @@ -0,0 +1,50 @@ +/* Copyright (c) 2002-2004 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date$ + */ + + + +#ifndef BOOST_DATE_TIME_SOURCE +#define BOOST_DATE_TIME_SOURCE +#endif +#include "boost/date_time/gregorian/greg_weekday.hpp" + +#include "greg_names.hpp" + +namespace boost { +namespace gregorian { + + //! Return a 3 digit english string of the day of week (eg: Sun) + const char* + greg_weekday::as_short_string() const + { + return short_weekday_names[value_]; + } + //! Return a point to a long english string representing day of week + const char* + greg_weekday::as_long_string() const + { + return long_weekday_names[value_]; + } + +#ifndef BOOST_NO_STD_WSTRING + //! Return a 3 digit english wchar_t string of the day of week (eg: Sun) + const wchar_t* + greg_weekday::as_short_wstring() const + { + return w_short_weekday_names[value_]; + } + //! Return a point to a long english wchar_t string representing day of week + const wchar_t* + greg_weekday::as_long_wstring() const + { + return w_long_weekday_names[value_]; + } +#endif // BOOST_NO_STD_WSTRING + +} } //namespace gregorian + diff --git a/libs/date_time/src/gregorian/gregorian_types.cpp b/libs/date_time/src/gregorian/gregorian_types.cpp new file mode 100644 index 0000000..7dd7f22 --- /dev/null +++ b/libs/date_time/src/gregorian/gregorian_types.cpp @@ -0,0 +1,62 @@ +/* Copyright (c) 2002,2003 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland + * $Date$ + */ + + +/** @defgroup date_basics Date Basics + This page summarizes some of the key user types and functions needed + to write programs using the gregorian date system. This is not a + comprehensive list, but rather some key types to start exploring. + + +**/ + +/** @defgroup date_alg Date Algorithms / Generators + Date algorithms or generators are tools for generating other dates or + schedules of dates. A generator function starts with some part of a + date such as a month and day and is supplied another part to then + generate a final date. + +**/ + +/** @defgroup date_format Date Formatting + The functions on these page are some of the key formatting functions + for dates. +**/ + + +//File doesn't have a current purpose except to generate docs +//and keep it changeable without recompiles +/*! @example days_alive.cpp + Calculate the number of days you have been living using durations and dates. +*/ +/*! @example days_till_new_year.cpp + Calculate the number of days till new years +*/ +/*! @example print_month.cpp + Simple utility to print out days of the month with the days of a month. Demontstrates date iteration (date_time::date_itr). +*/ +/*! @example localization.cpp + An example showing localized stream-based I/O. +*/ +/*! @example dates_as_strings.cpp + Various parsing and output of strings (mostly supported for + compilers that do not support localized streams). +*/ +/*! @example period_calc.cpp + Calculates if a date is in an 'irregular' collection of periods using + period calculation functions. +*/ +/*! @example print_holidays.cpp + This is an example of using functors to define a holiday schedule + */ +/*! @example localization.cpp + Demonstrates the use of facets to localize date output for Gregorian dates. + */ + + + diff --git a/libs/date_time/src/posix_time/posix_time_types.cpp b/libs/date_time/src/posix_time/posix_time_types.cpp new file mode 100644 index 0000000..4395301 --- /dev/null +++ b/libs/date_time/src/posix_time/posix_time_types.cpp @@ -0,0 +1,35 @@ + +/* Copyright (c) 2002-2004 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland + * $Date$ + */ + + +//File doesn't have a current purpose except to generate docs +//and keep it changeable without recompiles + +/** @defgroup time_basics Time Basics + +**/ + +/** @defgroup time_format Time Formatting + +**/ + + + +/*! @example local_utc_conversion.cpp + Demonstrate utc to local and local to utc calculations including dst. +*/ +/*! @example time_periods.cpp Demonstrate some simple uses of time periods. +*/ +/*! @example print_hours.cpp Demonstrate time iteration, clock retrieval, and simple calculation. + */ +/*! @example time_math.cpp Various types of calculations with times and time durations. + */ + + + diff --git a/libs/exception/build/Jamfile.v2 b/libs/exception/build/Jamfile.v2 new file mode 100644 index 0000000..fb47659 --- /dev/null +++ b/libs/exception/build/Jamfile.v2 @@ -0,0 +1,14 @@ +# Boost Exception Library build Jamfile +# +# Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +project boost/exception + : source-location ../src + : requirements static + ; + +lib boost_exception : clone_current_exception_non_intrusive.cpp ; +boost-install boost_exception ; diff --git a/libs/exception/src/clone_current_exception_non_intrusive.cpp b/libs/exception/src/clone_current_exception_non_intrusive.cpp new file mode 100644 index 0000000..932bca8 --- /dev/null +++ b/libs/exception/src/clone_current_exception_non_intrusive.cpp @@ -0,0 +1,349 @@ +//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. + +//Distributed under the Boost Software License, Version 1.0. (See accompanying +//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +//This MSVC-specific cpp file implements non-intrusive cloning of exception objects. +//Based on an exception_ptr implementation by Anthony Williams. + +#ifdef BOOST_NO_EXCEPTIONS +#error This file requires exception handling to be enabled. +#endif + +#include +#include + +#if defined(BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR) && defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) + +//Non-intrusive cloning support implemented below, only for MSVC versions mentioned above. +//Thanks Anthony Williams! +//Thanks to Martin Weiss for implementing 64-bit support! + +#include +#include +#include +#include + +namespace + { + unsigned const exception_maximum_parameters=15; + unsigned const exception_noncontinuable=1; + +#if _MSC_VER==1310 + int const exception_info_offset=0x74; +#elif ((_MSC_VER==1400 || _MSC_VER==1500) && !defined _M_X64) + int const exception_info_offset=0x80; +#elif ((_MSC_VER==1400 || _MSC_VER==1500) && defined _M_X64) + int const exception_info_offset=0xE0; +#else + int const exception_info_offset=-1; +#endif + + struct + exception_record + { + unsigned long ExceptionCode; + unsigned long ExceptionFlags; + exception_record * ExceptionRecord; + void * ExceptionAddress; + unsigned long NumberParameters; + ULONG_PTR ExceptionInformation[exception_maximum_parameters]; + }; + + struct + exception_pointers + { + exception_record * ExceptionRecord; + void * ContextRecord; + }; + + unsigned const cpp_exception_code=0xE06D7363; + unsigned const cpp_exception_magic_flag=0x19930520; +#ifdef _M_X64 + unsigned const cpp_exception_parameter_count=4; +#else + unsigned const cpp_exception_parameter_count=3; +#endif + + struct + dummy_exception_type + { + }; + + typedef int(dummy_exception_type::*normal_copy_constructor_ptr)(void * src); + typedef int(dummy_exception_type::*copy_constructor_with_virtual_base_ptr)(void * src,void * dst); + typedef void (dummy_exception_type::*destructor_ptr)(); + + union + cpp_copy_constructor + { + void * address; + normal_copy_constructor_ptr normal_copy_constructor; + copy_constructor_with_virtual_base_ptr copy_constructor_with_virtual_base; + }; + + union + cpp_destructor + { + void * address; + destructor_ptr destructor; + }; + + enum + cpp_type_flags + { + class_is_simple_type=1, + class_has_virtual_base=4 + }; + + // ATTENTION: On x86 fields such as type_info and copy_constructor are really pointers + // but on 64bit these are 32bit offsets from HINSTANCE. Hints on the 64bit handling from + // http://blogs.msdn.com/b/oldnewthing/archive/2010/07/30/10044061.aspx . + struct + cpp_type_info + { + unsigned flags; + int type_info; + int this_offset; + int vbase_descr; + int vbase_offset; + unsigned long size; + int copy_constructor; + }; + + struct + cpp_type_info_table + { + unsigned count; + int info; + }; + + struct + cpp_exception_type + { + unsigned flags; + int destructor; + int custom_handler; + int type_info_table; + }; + + struct + exception_object_deleter + { + cpp_exception_type const & et_; + size_t image_base_; + + exception_object_deleter( cpp_exception_type const & et, size_t image_base ): + et_(et), + image_base_(image_base) + { + } + + void + operator()( void * obj ) + { + BOOST_ASSERT(obj!=0); + dummy_exception_type* dummy_exception_ptr = static_cast(obj); + if( et_.destructor ) + { + cpp_destructor destructor; + destructor.address = reinterpret_cast(et_.destructor + image_base_); + (dummy_exception_ptr->*(destructor.destructor))(); + } + free(obj); + } + }; + + cpp_type_info const & + get_cpp_type_info( cpp_exception_type const & et, size_t image_base ) + { + cpp_type_info_table * const typearray = reinterpret_cast(et.type_info_table + image_base); + cpp_type_info * const ti = reinterpret_cast(typearray->info + image_base); + BOOST_ASSERT(ti!=0); + return *ti; + } + + void + copy_msvc_exception( void * dst, void * src, cpp_type_info const & ti, size_t image_base ) + { + cpp_copy_constructor copy_constructor; + copy_constructor.address = reinterpret_cast(ti.copy_constructor + image_base); + + if( !(ti.flags & class_is_simple_type) && copy_constructor.normal_copy_constructor ) + { + dummy_exception_type * dummy_exception_ptr = static_cast(dst); + if( ti.flags & class_has_virtual_base ) + (dummy_exception_ptr->*(copy_constructor.copy_constructor_with_virtual_base))(src,dst); + else + (dummy_exception_ptr->*(copy_constructor.normal_copy_constructor))(src); + } + else + memmove(dst,src,ti.size); + } + + boost::shared_ptr + clone_msvc_exception( void * src, cpp_exception_type const & et, size_t image_base ) + { + BOOST_ASSERT(src!=0); + cpp_type_info const & ti=get_cpp_type_info(et,image_base); + if( void * dst = malloc(ti.size) ) + { + try + { + copy_msvc_exception(dst,src,ti,image_base); + } + catch( + ... ) + { + free(dst); + throw; + } + return boost::shared_ptr(dst,exception_object_deleter(et,image_base)); + } + else + throw std::bad_alloc(); + } + + class + cloned_exception: + public boost::exception_detail::clone_base + { + cloned_exception( cloned_exception const & ); + cloned_exception & operator=( cloned_exception const & ); + + cpp_exception_type const & et_; + size_t image_base_; + boost::shared_ptr exc_; + + public: + cloned_exception( EXCEPTION_RECORD const * record ): + et_(*reinterpret_cast(record->ExceptionInformation[2])), + image_base_((cpp_exception_parameter_count==4) ? record->ExceptionInformation[3] : 0), + exc_(clone_msvc_exception(reinterpret_cast(record->ExceptionInformation[1]),et_,image_base_)) + { + } + + cloned_exception( void * exc, cpp_exception_type const & et, size_t image_base ): + et_(et), + image_base_(image_base), + exc_(clone_msvc_exception(exc,et_,image_base)) + { + } + + ~cloned_exception() BOOST_NOEXCEPT_OR_NOTHROW + { + } + + boost::exception_detail::clone_base const * + clone() const + { + return new cloned_exception(exc_.get(),et_,image_base_); + } + + void + rethrow() const + { + cpp_type_info const & ti=get_cpp_type_info(et_,image_base_); + void * dst = _alloca(ti.size); + copy_msvc_exception(dst,exc_.get(),ti,image_base_); + ULONG_PTR args[cpp_exception_parameter_count]; + args[0]=cpp_exception_magic_flag; + args[1]=reinterpret_cast(dst); + args[2]=reinterpret_cast(&et_); + if (cpp_exception_parameter_count==4) + args[3]=image_base_; + + RaiseException(cpp_exception_code,EXCEPTION_NONCONTINUABLE,cpp_exception_parameter_count,args); + } + }; + + bool + is_cpp_exception( EXCEPTION_RECORD const * record ) + { + return record && + (record->ExceptionCode==cpp_exception_code) && + (record->NumberParameters==cpp_exception_parameter_count) && + (record->ExceptionInformation[0]==cpp_exception_magic_flag); + } + + unsigned long + exception_cloning_filter( int & result, boost::exception_detail::clone_base const * & ptr, void * info_ ) + { + BOOST_ASSERT(exception_info_offset>=0); + BOOST_ASSERT(info_!=0); + EXCEPTION_RECORD* record = static_cast(info_)->ExceptionRecord; + if( is_cpp_exception(record) ) + { + if( !record->ExceptionInformation[2] ) + record = *reinterpret_cast(reinterpret_cast(_errno())+exception_info_offset); + if( is_cpp_exception(record) && record->ExceptionInformation[2] ) + try + { + ptr = new cloned_exception(record); + result = boost::exception_detail::clone_current_exception_result::success; + } + catch( + std::bad_alloc & ) + { + result = boost::exception_detail::clone_current_exception_result::bad_alloc; + } + catch( + ... ) + { + result = boost::exception_detail::clone_current_exception_result::bad_exception; + } + } + return EXCEPTION_EXECUTE_HANDLER; + } + } + +namespace +boost + { + namespace + exception_detail + { + int + clone_current_exception_non_intrusive( clone_base const * & cloned ) + { + BOOST_ASSERT(!cloned); + int result = clone_current_exception_result::not_supported; + if( exception_info_offset>=0 ) + { + clone_base const * ptr=0; + __try + { + throw; + } + __except(exception_cloning_filter(result,ptr,GetExceptionInformation())) + { + } + if( result==clone_current_exception_result::success ) + cloned=ptr; + } + BOOST_ASSERT(result!=clone_current_exception_result::success || cloned); + return result; + } + } + } + +#else + +//On all other compilers, return clone_current_exception_result::not_supported. +//On such platforms, only the intrusive enable_current_exception() cloning will work. + +namespace +boost + { + namespace + exception_detail + { + int + clone_current_exception_non_intrusive( clone_base const * & ) + { + return clone_current_exception_result::not_supported; + } + } + } + +#endif diff --git a/libs/regex/build/Jamfile.v2 b/libs/regex/build/Jamfile.v2 new file mode 100644 index 0000000..f541572 --- /dev/null +++ b/libs/regex/build/Jamfile.v2 @@ -0,0 +1,158 @@ +# copyright John Maddock 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. + +import modules ; +import testing ; +import errors ; + +project : requirements + # default to all warnings on: + all + ; + +local disable-icu = [ MATCH (--disable-icu) : [ modules.peek : ARGV ] ] ; + +rule path_options ( properties * ) +{ + local result ; + if 64 in $(properties) && msvc in $(properties) + { + result = $(ICU_PATH)/bin64 $(ICU_PATH)/lib64 ; + } + else + { + result = $(ICU_PATH)/bin $(ICU_PATH)/lib ; + } + return $(result) ; +} + +# +# ICU configuration: +# +if ! $(disable-icu) +{ + if [ modules.peek : ICU_LINK ] + { + errors.user-error : "The ICU_LINK option is no longer supported by the Boost.Regex build - please refer to the documentation for equivalent options" ; + } + + if [ modules.peek : ICU_PATH ] + { + ICU_PATH = [ modules.peek : ICU_PATH ] ; + } + if [ modules.peek : ICU_ICUUC_NAME ] + { + ICU_ICUUC_NAME = [ modules.peek : ICU_ICUUC_NAME ] ; + } + if [ modules.peek : ICU_ICUDT_NAME ] + { + ICU_ICUDT_NAME = [ modules.peek : ICU_ICUDT_NAME ] ; + } + if [ modules.peek : ICU_ICUIN_NAME ] + { + ICU_ICUIN_NAME = [ modules.peek : ICU_ICUIN_NAME ] ; + } + + if $(ICU_ICUUC_NAME) + { + lib icuuc : : $(ICU_ICUUC_NAME) ; + } + else + { + lib icuuc : : shared @path_options ; + lib icuuc : : msvc debug icuucd shared @path_options ; + lib icuuc : : intel windows debug icuucd shared @path_options ; + lib icuuc : : sicuuc static @path_options ; + lib icuuc : : msvc debug sicuucd static @path_options ; + lib icuuc : : intel windows debug sicuucd static @path_options ; + lib icuuc : : this_is_an_invalid_library_name ; + } + if $(ICU_ICUDT_NAME) + { + lib icudt : : $(ICU_ICUDT_NAME) ; + } + else + { + lib icudt : : icudata shared @path_options ; + lib icudt : : icudt msvc shared @path_options ; + lib icudt : : icudt intel windows shared @path_options ; + lib icudt : : sicudata static @path_options ; + lib icudt : : sicudt msvc static @path_options ; + lib icudt : : sicudt intel windows static @path_options ; + lib icudt : : this_is_an_invalid_library_name ; + } + if $(ICU_ICUIN_NAME) + { + lib icuin : : $(ICU_ICUIN_NAME) ; + } + else + { + lib icuin : : icui18n shared @path_options ; + lib icuin : : msvc debug icuind shared @path_options ; + lib icuin : : msvc icuin shared @path_options ; + lib icuin : : intel windows debug icuind shared @path_options ; + lib icuin : : intel windows icuin shared @path_options ; + lib icuin : : sicui18n static @path_options ; + lib icuin : : msvc debug sicuind static @path_options ; + lib icuin : : msvc sicuin static @path_options ; + lib icuin : : intel windows debug sicuind static @path_options ; + lib icuin : : intel windows sicuin static @path_options ; + lib icuin : : this_is_an_invalid_library_name ; + } + + ICU_OPTS = + $(ICU_PATH)/include + shared:icuuc/shared + shared:icudt/shared + shared:icuin/shared + static:icuuc + static:icudt + static:icuin + BOOST_HAS_ICU=1 + static:U_STATIC_IMPLEMENTATION=1 + ; + +} + +unit-test has_icu : has_icu_test.cpp : $(ICU_OPTS) ; +explicit has_icu ; + +alias icu_options : : : : [ check-target-builds has_icu : $(ICU_OPTS) : ] ; + +SOURCES = + c_regex_traits.cpp + cpp_regex_traits.cpp + cregex.cpp + fileiter.cpp + icu.cpp + instances.cpp + posix_api.cpp + regex.cpp + regex_debug.cpp + regex_raw_buffer.cpp + regex_traits_defaults.cpp + static_mutex.cpp + w32_regex_traits.cpp + wc_regex_traits.cpp + wide_posix_api.cpp + winstances.cpp + usinstances.cpp ; + + +lib boost_regex : ../src/$(SOURCES) icu_options + : + shared:BOOST_REGEX_DYN_LINK=1 + gcc-cygwin:static + ; + +boost-install boost_regex ; + + + + + + + + diff --git a/libs/regex/build/has_icu_test.cpp b/libs/regex/build/has_icu_test.cpp new file mode 100644 index 0000000..31c964e --- /dev/null +++ b/libs/regex/build/has_icu_test.cpp @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2010 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && !defined(_DLL) +//#error "Mixing ICU with a static runtime doesn't work" +#endif + +void print_error(UErrorCode err, const char* func) +{ + std::cerr << "Error from function " << func << " with error: " << ::u_errorName(err) << std::endl; +} + +int main() +{ + // To detect possible binary mismatches between the installed ICU build, and whatever + // C++ std lib's we're using, we need to: + // * Make sure we call ICU C++ API's + // * Make sure we call std lib C++ API's as well (cout). + // * Be sure this program is run, not just built. + UErrorCode err = U_ZERO_ERROR; + UChar32 c = ::u_charFromName(U_UNICODE_CHAR_NAME, "GREEK SMALL LETTER ALPHA", &err); + std::cout << (int)c << std::endl; + if(err > 0) + { + print_error(err, "u_charFromName"); + return err; + } + U_NAMESPACE_QUALIFIER Locale l; + boost::scoped_ptr p_col(U_NAMESPACE_QUALIFIER Collator::createInstance(l, err)); + if(err > 0) + { + print_error(err, "Collator::createInstance"); + return err; + } + return err > 0 ? err : 0; +} diff --git a/libs/regex/src/c_regex_traits.cpp b/libs/regex/src/c_regex_traits.cpp new file mode 100644 index 0000000..a0b52ee --- /dev/null +++ b/libs/regex/src/c_regex_traits.cpp @@ -0,0 +1,206 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE: c_regex_traits.cpp + * VERSION: see + * DESCRIPTION: Implements out of line c_regex_traits members + */ + + +#define BOOST_REGEX_SOURCE + +#include +#include +#include "internals.hpp" + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x560) + +#include +#include +#include + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std{ + using ::strxfrm; using ::isspace; + using ::ispunct; using ::isalpha; + using ::isalnum; using ::iscntrl; + using ::isprint; using ::isupper; + using ::islower; using ::isdigit; + using ::isxdigit; using ::strtol; +} +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +namespace boost{ + +c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::transform(const char* p1, const char* p2) +{ + std::string result(10, ' '); + std::size_t s = result.size(); + std::size_t r; + std::string src(p1, p2); + while(s < (r = std::strxfrm(&*result.begin(), src.c_str(), s))) + { +#if defined(_CPPLIB_VER) + // + // A bug in VC11 and 12 causes the program to hang if we pass a null-string + // to std::strxfrm, but only for certain locales :-( + // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware). + // + if(r == INT_MAX) + { + result.erase(); + result.insert(result.begin(), static_cast(0)); + return result; + } +#endif + result.append(r - s + 3, ' '); + s = result.size(); + } + result.erase(r); + return result; +} + +c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::transform_primary(const char* p1, const char* p2) +{ + static char s_delim; + static const int s_collate_type = ::boost::BOOST_REGEX_DETAIL_NS::find_sort_syntax(static_cast*>(0), &s_delim); + std::string result; + // + // What we do here depends upon the format of the sort key returned by + // sort key returned by this->transform: + // + switch(s_collate_type) + { + case ::boost::BOOST_REGEX_DETAIL_NS::sort_C: + case ::boost::BOOST_REGEX_DETAIL_NS::sort_unknown: + // the best we can do is translate to lower case, then get a regular sort key: + { + result.assign(p1, p2); + for(std::string::size_type i = 0; i < result.size(); ++i) + result[i] = static_cast((std::tolower)(static_cast(result[i]))); + result = transform(&*result.begin(), &*result.begin() + result.size()); + break; + } + case ::boost::BOOST_REGEX_DETAIL_NS::sort_fixed: + { + // get a regular sort key, and then truncate it: + result = transform(p1, p2); + result.erase(s_delim); + break; + } + case ::boost::BOOST_REGEX_DETAIL_NS::sort_delim: + // get a regular sort key, and then truncate everything after the delim: + result = transform(p1, p2); + if(result.size() && (result[0] == s_delim)) + break; + std::size_t i; + for(i = 0; i < result.size(); ++i) + { + if(result[i] == s_delim) + break; + } + result.erase(i); + break; + } + if(result.empty()) + result = std::string(1, char(0)); + return result; +} + +c_regex_traits::char_class_type BOOST_REGEX_CALL c_regex_traits::lookup_classname(const char* p1, const char* p2) +{ + static const char_class_type masks[] = + { + 0, + char_class_alnum, + char_class_alpha, + char_class_blank, + char_class_cntrl, + char_class_digit, + char_class_digit, + char_class_graph, + char_class_horizontal, + char_class_lower, + char_class_lower, + char_class_print, + char_class_punct, + char_class_space, + char_class_space, + char_class_upper, + char_class_unicode, + char_class_upper, + char_class_vertical, + char_class_alnum | char_class_word, + char_class_alnum | char_class_word, + char_class_xdigit, + }; + + int idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + if(idx < 0) + { + std::string s(p1, p2); + for(std::string::size_type i = 0; i < s.size(); ++i) + s[i] = static_cast((std::tolower)(static_cast(s[i]))); + idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size()); + } + BOOST_ASSERT(std::size_t(idx+1) < sizeof(masks) / sizeof(masks[0])); + return masks[idx+1]; +} + +bool BOOST_REGEX_CALL c_regex_traits::isctype(char c, char_class_type mask) +{ + return + ((mask & char_class_space) && (std::isspace)(static_cast(c))) + || ((mask & char_class_print) && (std::isprint)(static_cast(c))) + || ((mask & char_class_cntrl) && (std::iscntrl)(static_cast(c))) + || ((mask & char_class_upper) && (std::isupper)(static_cast(c))) + || ((mask & char_class_lower) && (std::islower)(static_cast(c))) + || ((mask & char_class_alpha) && (std::isalpha)(static_cast(c))) + || ((mask & char_class_digit) && (std::isdigit)(static_cast(c))) + || ((mask & char_class_punct) && (std::ispunct)(static_cast(c))) + || ((mask & char_class_xdigit) && (std::isxdigit)(static_cast(c))) + || ((mask & char_class_blank) && (std::isspace)(static_cast(c)) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c)) + || ((mask & char_class_word) && (c == '_')) + || ((mask & char_class_vertical) && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == '\v'))) + || ((mask & char_class_horizontal) && (std::isspace)(static_cast(c)) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) && (c != '\v')); +} + +c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::lookup_collatename(const char* p1, const char* p2) +{ + std::string s(p1, p2); + s = ::boost::BOOST_REGEX_DETAIL_NS::lookup_default_collate_name(s); + if(s.empty() && (p2-p1 == 1)) + s.append(1, *p1); + return s; +} + +int BOOST_REGEX_CALL c_regex_traits::value(char c, int radix) +{ + char b[2] = { c, '\0', }; + char* ep; + int result = std::strtol(b, &ep, radix); + if(ep == b) + return -1; + return result; +} + +} +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif diff --git a/libs/regex/src/cpp_regex_traits.cpp b/libs/regex/src/cpp_regex_traits.cpp new file mode 100644 index 0000000..05bbc50 --- /dev/null +++ b/libs/regex/src/cpp_regex_traits.cpp @@ -0,0 +1,117 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE cpp_regex_traits.cpp + * VERSION see + * DESCRIPTION: Implements cpp_regex_traits (and associated helper classes). + */ + +#define BOOST_REGEX_SOURCE +#include +#ifndef BOOST_NO_STD_LOCALE +#include +#include + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std{ + using ::memset; +} +#endif + +namespace boost{ namespace BOOST_REGEX_DETAIL_NS{ + +void cpp_regex_traits_char_layer::init() +{ + // we need to start by initialising our syntax map so we know which + // character is used for which purpose: + std::memset(m_char_map, 0, sizeof(m_char_map)); +#ifndef BOOST_NO_STD_MESSAGES +#ifndef __IBMCPP__ + std::messages::catalog cat = static_cast::catalog>(-1); +#else + std::messages::catalog cat = reinterpret_cast::catalog>(-1); +#endif + std::string cat_name(cpp_regex_traits::get_catalog_name()); + if(cat_name.size() && (m_pmessages != 0)) + { + cat = this->m_pmessages->open( + cat_name, + this->m_locale); + if((int)cat < 0) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if((int)cat >= 0) + { +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + string_type mss = this->m_pmessages->get(cat, 0, i, get_default_syntax(i)); + for(string_type::size_type j = 0; j < mss.size(); ++j) + { + m_char_map[static_cast(mss[j])] = i; + } + } + this->m_pmessages->close(cat); +#ifndef BOOST_NO_EXCEPTIONS + } + catch(...) + { + this->m_pmessages->close(cat); + throw; + } +#endif + } + else + { +#endif + for(regex_constants::syntax_type j = 1; j < regex_constants::syntax_max; ++j) + { + const char* ptr = get_default_syntax(j); + while(ptr && *ptr) + { + m_char_map[static_cast(*ptr)] = j; + ++ptr; + } + } +#ifndef BOOST_NO_STD_MESSAGES + } +#endif + // + // finish off by calculating our escape types: + // + unsigned char i = 'A'; + do + { + if(m_char_map[i] == 0) + { + if(this->m_pctype->is(std::ctype_base::lower, i)) + m_char_map[i] = regex_constants::escape_type_class; + else if(this->m_pctype->is(std::ctype_base::upper, i)) + m_char_map[i] = regex_constants::escape_type_not_class; + } + }while(0xFF != i++); +} + +} // BOOST_REGEX_DETAIL_NS +} // boost +#endif + diff --git a/libs/regex/src/cregex.cpp b/libs/regex/src/cregex.cpp new file mode 100644 index 0000000..a1ae3b0 --- /dev/null +++ b/libs/regex/src/cregex.cpp @@ -0,0 +1,660 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE: cregex.cpp + * VERSION: see + * DESCRIPTION: Implements high level class boost::RexEx + */ + + +#define BOOST_REGEX_SOURCE + +#include +#include +#if !defined(BOOST_NO_STD_STRING) +#include +#include +#include +typedef boost::match_flag_type match_flag_type; +#include + +#ifdef BOOST_MSVC +#pragma warning(disable:4309) +#endif +#ifdef BOOST_INTEL +#pragma warning(disable:981 383) +#endif + +namespace boost{ + +#ifdef __BORLANDC__ +#if __BORLANDC__ < 0x530 +// +// we need to instantiate the vector classes we use +// since declaring a reference to type doesn't seem to +// do the job... +std::vector inst1; +std::vector inst2; +#endif +#endif + +namespace{ + +template +std::string to_string(iterator i, iterator j) +{ + std::string s; + while(i != j) + { + s.append(1, *i); + ++i; + } + return s; +} + +inline std::string to_string(const char* i, const char* j) +{ + return std::string(i, j); +} + +} +namespace BOOST_REGEX_DETAIL_NS{ + +class RegExData +{ +public: + enum type + { + type_pc, + type_pf, + type_copy + }; + regex e; + cmatch m; +#ifndef BOOST_REGEX_NO_FILEITER + match_results fm; +#endif + type t; + const char* pbase; +#ifndef BOOST_REGEX_NO_FILEITER + mapfile::iterator fbase; +#endif + std::map > strings; + std::map > positions; + void update(); + void clean(); + RegExData() : e(), m(), +#ifndef BOOST_REGEX_NO_FILEITER + fm(), +#endif + t(type_copy), pbase(0), +#ifndef BOOST_REGEX_NO_FILEITER + fbase(), +#endif + strings(), positions() {} +}; + +void RegExData::update() +{ + strings.erase(strings.begin(), strings.end()); + positions.erase(positions.begin(), positions.end()); + if(t == type_pc) + { + for(unsigned int i = 0; i < m.size(); ++i) + { + if(m[i].matched) strings[i] = std::string(m[i].first, m[i].second); + positions[i] = m[i].matched ? m[i].first - pbase : -1; + } + } +#ifndef BOOST_REGEX_NO_FILEITER + else + { + for(unsigned int i = 0; i < fm.size(); ++i) + { + if(fm[i].matched) strings[i] = to_string(fm[i].first, fm[i].second); + positions[i] = fm[i].matched ? fm[i].first - fbase : -1; + } + } +#endif + t = type_copy; +} + +void RegExData::clean() +{ +#ifndef BOOST_REGEX_NO_FILEITER + fbase = mapfile::iterator(); + fm = match_results(); +#endif +} + +} // namespace + +RegEx::RegEx() +{ + pdata = new BOOST_REGEX_DETAIL_NS::RegExData(); +} + +RegEx::RegEx(const RegEx& o) +{ + pdata = new BOOST_REGEX_DETAIL_NS::RegExData(*(o.pdata)); +} + +RegEx::~RegEx() +{ + delete pdata; +} + +RegEx::RegEx(const char* c, bool icase) +{ + pdata = new BOOST_REGEX_DETAIL_NS::RegExData(); + SetExpression(c, icase); +} + +RegEx::RegEx(const std::string& s, bool icase) +{ + pdata = new BOOST_REGEX_DETAIL_NS::RegExData(); + SetExpression(s.c_str(), icase); +} + +RegEx& RegEx::operator=(const RegEx& o) +{ + *pdata = *(o.pdata); + return *this; +} + +RegEx& RegEx::operator=(const char* p) +{ + SetExpression(p, false); + return *this; +} + +unsigned int RegEx::SetExpression(const char* p, bool icase) +{ + boost::uint_fast32_t f = icase ? regex::normal | regex::icase : regex::normal; + return pdata->e.set_expression(p, f); +} + +unsigned int RegEx::error_code()const +{ + return pdata->e.error_code(); +} + + +std::string RegEx::Expression()const +{ + return pdata->e.expression(); +} + +// +// now matching operators: +// +bool RegEx::Match(const char* p, match_flag_type flags) +{ + pdata->t = BOOST_REGEX_DETAIL_NS::RegExData::type_pc; + pdata->pbase = p; + const char* end = p; + while(*end)++end; + + if(regex_match(p, end, pdata->m, pdata->e, flags)) + { + pdata->update(); + return true; + } + return false; +} + +bool RegEx::Search(const char* p, match_flag_type flags) +{ + pdata->t = BOOST_REGEX_DETAIL_NS::RegExData::type_pc; + pdata->pbase = p; + const char* end = p; + while(*end)++end; + + if(regex_search(p, end, pdata->m, pdata->e, flags)) + { + pdata->update(); + return true; + } + return false; +} +namespace BOOST_REGEX_DETAIL_NS{ +struct pred1 +{ + GrepCallback cb; + RegEx* pe; + pred1(GrepCallback c, RegEx* i) : cb(c), pe(i) {} + bool operator()(const cmatch& m) + { + pe->pdata->m = m; + return cb(*pe); + } +}; +} +unsigned int RegEx::Grep(GrepCallback cb, const char* p, match_flag_type flags) +{ + pdata->t = BOOST_REGEX_DETAIL_NS::RegExData::type_pc; + pdata->pbase = p; + const char* end = p; + while(*end)++end; + + unsigned int result = regex_grep(BOOST_REGEX_DETAIL_NS::pred1(cb, this), p, end, pdata->e, flags); + if(result) + pdata->update(); + return result; +} +namespace BOOST_REGEX_DETAIL_NS{ +struct pred2 +{ + std::vector& v; + RegEx* pe; + pred2(std::vector& o, RegEx* e) : v(o), pe(e) {} + bool operator()(const cmatch& m) + { + pe->pdata->m = m; + v.push_back(std::string(m[0].first, m[0].second)); + return true; + } +private: + pred2& operator=(const pred2&); +}; +} + +unsigned int RegEx::Grep(std::vector& v, const char* p, match_flag_type flags) +{ + pdata->t = BOOST_REGEX_DETAIL_NS::RegExData::type_pc; + pdata->pbase = p; + const char* end = p; + while(*end)++end; + + unsigned int result = regex_grep(BOOST_REGEX_DETAIL_NS::pred2(v, this), p, end, pdata->e, flags); + if(result) + pdata->update(); + return result; +} +namespace BOOST_REGEX_DETAIL_NS{ +struct pred3 +{ + std::vector& v; + const char* base; + RegEx* pe; + pred3(std::vector& o, const char* pb, RegEx* p) : v(o), base(pb), pe(p) {} + bool operator()(const cmatch& m) + { + pe->pdata->m = m; + v.push_back(static_cast(m[0].first - base)); + return true; + } +private: + pred3& operator=(const pred3&); +}; +} +unsigned int RegEx::Grep(std::vector& v, const char* p, match_flag_type flags) +{ + pdata->t = BOOST_REGEX_DETAIL_NS::RegExData::type_pc; + pdata->pbase = p; + const char* end = p; + while(*end)++end; + + unsigned int result = regex_grep(BOOST_REGEX_DETAIL_NS::pred3(v, p, this), p, end, pdata->e, flags); + if(result) + pdata->update(); + return result; +} +#ifndef BOOST_REGEX_NO_FILEITER +namespace BOOST_REGEX_DETAIL_NS{ +struct pred4 +{ + GrepFileCallback cb; + RegEx* pe; + const char* file; + bool ok; + pred4(GrepFileCallback c, RegEx* i, const char* f) : cb(c), pe(i), file(f), ok(true) {} + bool operator()(const match_results& m) + { + pe->pdata->t = RegExData::type_pf; + pe->pdata->fm = m; + pe->pdata->update(); + ok = cb(file, *pe); + return ok; + } +}; +} +namespace{ +void BuildFileList(std::list* pl, const char* files, bool recurse) +{ + file_iterator start(files); + file_iterator end; + if(recurse) + { + // go through sub directories: + char buf[MAX_PATH]; + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(buf, MAX_PATH, start.root())); + if(*buf == 0) + { + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(buf, MAX_PATH, ".")); + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcat_s(buf, MAX_PATH, directory_iterator::separator())); + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcat_s(buf, MAX_PATH, "*")); + } + else + { + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcat_s(buf, MAX_PATH, directory_iterator::separator())); + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcat_s(buf, MAX_PATH, "*")); + } + directory_iterator dstart(buf); + directory_iterator dend; + + // now get the file mask bit of "files": + const char* ptr = files; + while(*ptr) ++ptr; + while((ptr != files) && (*ptr != *directory_iterator::separator()) && (*ptr != '/'))--ptr; + if(ptr != files) ++ptr; + + while(dstart != dend) + { + // Verify that sprintf will not overflow: + if(std::strlen(dstart.path()) + std::strlen(directory_iterator::separator()) + std::strlen(ptr) >= MAX_PATH) + { + // Oops overflow, skip this item: + ++dstart; + continue; + } +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(_WIN32_WCE) && !defined(UNDER_CE) + int r = (::sprintf_s)(buf, sizeof(buf), "%s%s%s", dstart.path(), directory_iterator::separator(), ptr); +#else + int r = (std::sprintf)(buf, "%s%s%s", dstart.path(), directory_iterator::separator(), ptr); +#endif + if(r < 0) + { + // sprintf failed, skip this item: + ++dstart; + continue; + } + BuildFileList(pl, buf, recurse); + ++dstart; + } + } + while(start != end) + { + pl->push_back(*start); + ++start; + } +} +} + +unsigned int RegEx::GrepFiles(GrepFileCallback cb, const char* files, bool recurse, match_flag_type flags) +{ + unsigned int result = 0; + std::list file_list; + BuildFileList(&file_list, files, recurse); + std::list::iterator start, end; + start = file_list.begin(); + end = file_list.end(); + + while(start != end) + { + mapfile map((*start).c_str()); + pdata->t = BOOST_REGEX_DETAIL_NS::RegExData::type_pf; + pdata->fbase = map.begin(); + BOOST_REGEX_DETAIL_NS::pred4 pred(cb, this, (*start).c_str()); + int r = regex_grep(pred, map.begin(), map.end(), pdata->e, flags); + result += r; + ++start; + pdata->clean(); + if(pred.ok == false) + return result; + } + + return result; +} + + +unsigned int RegEx::FindFiles(FindFilesCallback cb, const char* files, bool recurse, match_flag_type flags) +{ + unsigned int result = 0; + std::list file_list; + BuildFileList(&file_list, files, recurse); + std::list::iterator start, end; + start = file_list.begin(); + end = file_list.end(); + + while(start != end) + { + mapfile map((*start).c_str()); + pdata->t = BOOST_REGEX_DETAIL_NS::RegExData::type_pf; + pdata->fbase = map.begin(); + + if(regex_search(map.begin(), map.end(), pdata->fm, pdata->e, flags)) + { + ++result; + if(false == cb((*start).c_str())) + return result; + } + //pdata->update(); + ++start; + //pdata->clean(); + } + + return result; +} +#endif + +#ifdef BOOST_REGEX_V3 +#define regex_replace regex_merge +#endif + +std::string RegEx::Merge(const std::string& in, const std::string& fmt, + bool copy, match_flag_type flags) +{ + std::string result; + BOOST_REGEX_DETAIL_NS::string_out_iterator i(result); + if(!copy) flags |= format_no_copy; + regex_replace(i, in.begin(), in.end(), pdata->e, fmt.c_str(), flags); + return result; +} + +std::string RegEx::Merge(const char* in, const char* fmt, + bool copy, match_flag_type flags) +{ + std::string result; + if(!copy) flags |= format_no_copy; + BOOST_REGEX_DETAIL_NS::string_out_iterator i(result); + regex_replace(i, in, in + std::strlen(in), pdata->e, fmt, flags); + return result; +} + +std::size_t RegEx::Split(std::vector& v, + std::string& s, + match_flag_type flags, + unsigned max_count) +{ + return regex_split(std::back_inserter(v), s, pdata->e, flags, max_count); +} + + + +// +// now operators for returning what matched in more detail: +// +std::size_t RegEx::Position(int i)const +{ + switch(pdata->t) + { + case BOOST_REGEX_DETAIL_NS::RegExData::type_pc: + return pdata->m[i].matched ? pdata->m[i].first - pdata->pbase : RegEx::npos; + case BOOST_REGEX_DETAIL_NS::RegExData::type_pf: +#ifndef BOOST_REGEX_NO_FILEITER + return pdata->fm[i].matched ? pdata->fm[i].first - pdata->fbase : RegEx::npos; +#endif + case BOOST_REGEX_DETAIL_NS::RegExData::type_copy: + { + std::map >::iterator pos = pdata->positions.find(i); + if(pos == pdata->positions.end()) + return RegEx::npos; + return (*pos).second; + } + } + return RegEx::npos; +} + +std::size_t RegEx::Marks()const +{ + return pdata->e.mark_count(); +} + + +std::size_t RegEx::Length(int i)const +{ + switch(pdata->t) + { + case BOOST_REGEX_DETAIL_NS::RegExData::type_pc: + return pdata->m[i].matched ? pdata->m[i].second - pdata->m[i].first : RegEx::npos; + case BOOST_REGEX_DETAIL_NS::RegExData::type_pf: +#ifndef BOOST_REGEX_NO_FILEITER + return pdata->fm[i].matched ? pdata->fm[i].second - pdata->fm[i].first : RegEx::npos; +#endif + case BOOST_REGEX_DETAIL_NS::RegExData::type_copy: + { + std::map >::iterator pos = pdata->strings.find(i); + if(pos == pdata->strings.end()) + return RegEx::npos; + return (*pos).second.size(); + } + } + return RegEx::npos; +} + +bool RegEx::Matched(int i)const +{ + switch(pdata->t) + { + case BOOST_REGEX_DETAIL_NS::RegExData::type_pc: + return pdata->m[i].matched; + case BOOST_REGEX_DETAIL_NS::RegExData::type_pf: +#ifndef BOOST_REGEX_NO_FILEITER + return pdata->fm[i].matched; +#endif + case BOOST_REGEX_DETAIL_NS::RegExData::type_copy: + { + std::map >::iterator pos = pdata->strings.find(i); + if(pos == pdata->strings.end()) + return false; + return true; + } + } + return false; +} + + +std::string RegEx::What(int i)const +{ + std::string result; + switch(pdata->t) + { + case BOOST_REGEX_DETAIL_NS::RegExData::type_pc: + if(pdata->m[i].matched) + result.assign(pdata->m[i].first, pdata->m[i].second); + break; + case BOOST_REGEX_DETAIL_NS::RegExData::type_pf: + if(pdata->m[i].matched) + result.assign(to_string(pdata->m[i].first, pdata->m[i].second)); + break; + case BOOST_REGEX_DETAIL_NS::RegExData::type_copy: + { + std::map >::iterator pos = pdata->strings.find(i); + if(pos != pdata->strings.end()) + result = (*pos).second; + break; + } + } + return result; +} + +const std::size_t RegEx::npos = ~static_cast(0); + +} // namespace boost + +#if defined(__BORLANDC__) && (__BORLANDC__ >= 0x550) && (__BORLANDC__ <= 0x551) && !defined(_RWSTD_COMPILE_INSTANTIATE) +// +// this is an ugly hack to work around an ugly problem: +// by default this file will produce unresolved externals during +// linking unless _RWSTD_COMPILE_INSTANTIATE is defined (Borland bug). +// However if _RWSTD_COMPILE_INSTANTIATE is defined then we get separate +// copies of basic_string's static data in the RTL and this DLL, this messes +// with basic_string's memory management and results in run-time crashes, +// Oh sweet joy of Catch 22.... +// +namespace std{ +template<> template<> +basic_string& BOOST_REGEX_DECL +basic_string::replace(char* f1, char* f2, const char* i1, const char* i2) +{ + unsigned insert_pos = f1 - begin(); + unsigned remove_len = f2 - f1; + unsigned insert_len = i2 - i1; + unsigned org_size = size(); + if(insert_len > remove_len) + { + append(insert_len-remove_len, ' '); + std::copy_backward(begin() + insert_pos + remove_len, begin() + org_size, end()); + std::copy(i1, i2, begin() + insert_pos); + } + else + { + std::copy(begin() + insert_pos + remove_len, begin() + org_size, begin() + insert_pos + insert_len); + std::copy(i1, i2, begin() + insert_pos); + erase(size() + insert_len - remove_len); + } + return *this; +} +template<> template<> +basic_string& BOOST_REGEX_DECL +basic_string::replace(wchar_t* f1, wchar_t* f2, const wchar_t* i1, const wchar_t* i2) +{ + unsigned insert_pos = f1 - begin(); + unsigned remove_len = f2 - f1; + unsigned insert_len = i2 - i1; + unsigned org_size = size(); + if(insert_len > remove_len) + { + append(insert_len-remove_len, ' '); + std::copy_backward(begin() + insert_pos + remove_len, begin() + org_size, end()); + std::copy(i1, i2, begin() + insert_pos); + } + else + { + std::copy(begin() + insert_pos + remove_len, begin() + org_size, begin() + insert_pos + insert_len); + std::copy(i1, i2, begin() + insert_pos); + erase(size() + insert_len - remove_len); + } + return *this; +} +} // namespace std +#endif + +#endif + + + + + + + + + + + + + + + + diff --git a/libs/regex/src/fileiter.cpp b/libs/regex/src/fileiter.cpp new file mode 100644 index 0000000..c80459b --- /dev/null +++ b/libs/regex/src/fileiter.cpp @@ -0,0 +1,928 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE: fileiter.cpp + * VERSION: see + * DESCRIPTION: Implements file io primitives + directory searching for class boost::RegEx. + */ + + +#define BOOST_REGEX_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#if defined(BOOST_NO_STDC_NAMESPACE) +namespace std{ + using ::sprintf; + using ::fseek; + using ::fread; + using ::ftell; + using ::fopen; + using ::fclose; + using ::FILE; + using ::strcpy; + using ::strcpy; + using ::strcat; + using ::strcmp; + using ::strlen; +} +#endif + + +#ifndef BOOST_REGEX_NO_FILEITER + +#if defined(__CYGWIN__) || defined(__CYGWIN32__) +#include +#endif + +#ifdef BOOST_MSVC +# pragma warning(disable: 4800) +#endif + +namespace boost{ + namespace BOOST_REGEX_DETAIL_NS{ +// start with the operating system specific stuff: + +#if (defined(__BORLANDC__) || defined(BOOST_REGEX_FI_WIN32_DIR) || defined(BOOST_MSVC)) && !defined(BOOST_RE_NO_WIN32) + +// platform is DOS or Windows +// directories are separated with '\\' +// and names are insensitive of case + +BOOST_REGEX_DECL const char* _fi_sep = "\\"; +const char* _fi_sep_alt = "/"; +#define BOOST_REGEX_FI_TRANSLATE(c) std::tolower(c) + +#else + +// platform is not DOS or Windows +// directories are separated with '/' +// and names are sensitive of case + +BOOST_REGEX_DECL const char* _fi_sep = "/"; +const char* _fi_sep_alt = _fi_sep; +#define BOOST_REGEX_FI_TRANSLATE(c) c + +#endif + +#ifdef BOOST_REGEX_FI_WIN32_MAP + +void mapfile::open(const char* file) +{ +#if defined(BOOST_NO_ANSI_APIS) + int filename_size = strlen(file); + LPWSTR wide_file = (LPWSTR)_alloca( (filename_size + 1) * sizeof(WCHAR) ); + if(::MultiByteToWideChar(CP_ACP, 0, file, filename_size, wide_file, filename_size + 1) == 0) + hfile = INVALID_HANDLE_VALUE; + else + hfile = CreateFileW(wide_file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); +#elif defined(__CYGWIN__)||defined(__CYGWIN32__) + char win32file[ MAX_PATH ]; + cygwin_conv_to_win32_path( file, win32file ); + hfile = CreateFileA(win32file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); +#else + hfile = CreateFileA(file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); +#endif + if(hfile != INVALID_HANDLE_VALUE) + { + hmap = CreateFileMapping(hfile, 0, PAGE_READONLY, 0, 0, 0); + if((hmap == INVALID_HANDLE_VALUE) || (hmap == NULL)) + { + CloseHandle(hfile); + hmap = 0; + hfile = 0; + std::runtime_error err("Unable to create file mapping."); + boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + _first = static_cast(MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0)); + if(_first == 0) + { + CloseHandle(hmap); + CloseHandle(hfile); + hmap = 0; + hfile = 0; + std::runtime_error err("Unable to create file mapping."); + } + _last = _first + GetFileSize(hfile, 0); + } + else + { + hfile = 0; +#ifndef BOOST_NO_EXCEPTIONS + throw std::runtime_error("Unable to open file."); +#else + BOOST_REGEX_NOEH_ASSERT(hfile != INVALID_HANDLE_VALUE); +#endif + } +} + +void mapfile::close() +{ + if(hfile != INVALID_HANDLE_VALUE) + { + UnmapViewOfFile((void*)_first); + CloseHandle(hmap); + CloseHandle(hfile); + hmap = hfile = 0; + _first = _last = 0; + } +} + +#elif !defined(BOOST_RE_NO_STL) + +mapfile_iterator& mapfile_iterator::operator = (const mapfile_iterator& i) +{ + if(file && node) + file->unlock(node); + file = i.file; + node = i.node; + offset = i.offset; + if(file) + file->lock(node); + return *this; +} + +mapfile_iterator& mapfile_iterator::operator++ () +{ + if((++offset == mapfile::buf_size) && file) + { + ++node; + offset = 0; + file->lock(node); + file->unlock(node-1); + } + return *this; +} + +mapfile_iterator mapfile_iterator::operator++ (int) +{ + mapfile_iterator temp(*this); + if((++offset == mapfile::buf_size) && file) + { + ++node; + offset = 0; + file->lock(node); + file->unlock(node-1); + } + return temp; +} + +mapfile_iterator& mapfile_iterator::operator-- () +{ + if((offset == 0) && file) + { + --node; + offset = mapfile::buf_size - 1; + file->lock(node); + file->unlock(node + 1); + } + else + --offset; + return *this; +} + +mapfile_iterator mapfile_iterator::operator-- (int) +{ + mapfile_iterator temp(*this); + if((offset == 0) && file) + { + --node; + offset = mapfile::buf_size - 1; + file->lock(node); + file->unlock(node + 1); + } + else + --offset; + return temp; +} + +mapfile_iterator operator + (const mapfile_iterator& i, long off) +{ + mapfile_iterator temp(i); + temp += off; + return temp; +} + +mapfile_iterator operator - (const mapfile_iterator& i, long off) +{ + mapfile_iterator temp(i); + temp -= off; + return temp; +} + +mapfile::iterator mapfile::begin()const +{ + return mapfile_iterator(this, 0); +} + +mapfile::iterator mapfile::end()const +{ + return mapfile_iterator(this, _size); +} + +void mapfile::lock(pointer* node)const +{ + BOOST_ASSERT(node >= _first); + BOOST_ASSERT(node <= _last); + if(node < _last) + { + if(*node == 0) + { + if(condemed.empty()) + { + *node = new char[sizeof(int) + buf_size]; + *(reinterpret_cast(*node)) = 1; + } + else + { + pointer* p = condemed.front(); + condemed.pop_front(); + *node = *p; + *p = 0; + *(reinterpret_cast(*node)) = 1; + } + + std::size_t read_size = 0; + int read_pos = std::fseek(hfile, (node - _first) * buf_size, SEEK_SET); + + if(0 == read_pos && node == _last - 1) + read_size = std::fread(*node + sizeof(int), _size % buf_size, 1, hfile); + else + read_size = std::fread(*node + sizeof(int), buf_size, 1, hfile); + if((read_size == 0) || (std::ferror(hfile))) + { +#ifndef BOOST_NO_EXCEPTIONS + unlock(node); + throw std::runtime_error("Unable to read file."); +#else + BOOST_REGEX_NOEH_ASSERT((0 == std::ferror(hfile)) && (read_size != 0)); +#endif + } + } + else + { + if(*reinterpret_cast(*node) == 0) + { + *reinterpret_cast(*node) = 1; + condemed.remove(node); + } + else + ++(*reinterpret_cast(*node)); + } + } +} + +void mapfile::unlock(pointer* node)const +{ + BOOST_ASSERT(node >= _first); + BOOST_ASSERT(node <= _last); + if(node < _last) + { + if(--(*reinterpret_cast(*node)) == 0) + { + condemed.push_back(node); + } + } +} + +long int get_file_length(std::FILE* hfile) +{ + long int result; + std::fseek(hfile, 0, SEEK_END); + result = std::ftell(hfile); + std::fseek(hfile, 0, SEEK_SET); + return result; +} + + +void mapfile::open(const char* file) +{ + hfile = std::fopen(file, "rb"); +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + if(hfile != 0) + { + _size = get_file_length(hfile); + long cnodes = (_size + buf_size - 1) / buf_size; + + // check that number of nodes is not too high: + if(cnodes > (long)((INT_MAX) / sizeof(pointer*))) + { + std::fclose(hfile); + hfile = 0; + _size = 0; + return; + } + + _first = new pointer[(int)cnodes]; + _last = _first + cnodes; + std::memset(_first, 0, cnodes*sizeof(pointer)); + } + else + { + std::runtime_error err("Unable to open file."); + } +#ifndef BOOST_NO_EXCEPTIONS + }catch(...) + { close(); throw; } +#endif +} + +void mapfile::close() +{ + if(hfile != 0) + { + pointer* p = _first; + while(p != _last) + { + if(*p) + delete[] *p; + ++p; + } + delete[] _first; + _size = 0; + _first = _last = 0; + std::fclose(hfile); + hfile = 0; + condemed.erase(condemed.begin(), condemed.end()); + } +} + + +#endif + +inline _fi_find_handle find_first_file(const char* wild, _fi_find_data& data) +{ +#ifdef BOOST_NO_ANSI_APIS + std::size_t wild_size = std::strlen(wild); + LPWSTR wide_wild = (LPWSTR)_alloca( (wild_size + 1) * sizeof(WCHAR) ); + if (::MultiByteToWideChar(CP_ACP, 0, wild, wild_size, wide_wild, wild_size + 1) == 0) + return _fi_invalid_handle; + + return FindFirstFileW(wide_wild, &data); +#else + return FindFirstFileA(wild, &data); +#endif +} + +inline bool find_next_file(_fi_find_handle hf, _fi_find_data& data) +{ +#ifdef BOOST_NO_ANSI_APIS + return FindNextFileW(hf, &data); +#else + return FindNextFileA(hf, &data); +#endif +} + +inline void copy_find_file_result_with_overflow_check(const _fi_find_data& data, char* path, size_t max_size) +{ +#ifdef BOOST_NO_ANSI_APIS + if (::WideCharToMultiByte(CP_ACP, 0, data.cFileName, -1, path, max_size, NULL, NULL) == 0) + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(1); +#else + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(path, max_size, data.cFileName)); +#endif +} + +inline bool is_not_current_or_parent_path_string(const _fi_find_data& data) +{ +#ifdef BOOST_NO_ANSI_APIS + return (std::wcscmp(data.cFileName, L".") && std::wcscmp(data.cFileName, L"..")); +#else + return (std::strcmp(data.cFileName, ".") && std::strcmp(data.cFileName, "..")); +#endif +} + + +file_iterator::file_iterator() +{ + _root = _path = 0; + ref = 0; +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + _root = new char[MAX_PATH]; + BOOST_REGEX_NOEH_ASSERT(_root) + _path = new char[MAX_PATH]; + BOOST_REGEX_NOEH_ASSERT(_path) + ptr = _path; + *_path = 0; + *_root = 0; + ref = new file_iterator_ref(); + BOOST_REGEX_NOEH_ASSERT(ref) + ref->hf = _fi_invalid_handle; + ref->count = 1; +#ifndef BOOST_NO_EXCEPTIONS + } + catch(...) + { + delete[] _root; + delete[] _path; + delete ref; + throw; + } +#endif +} + +file_iterator::file_iterator(const char* wild) +{ + _root = _path = 0; + ref = 0; +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + _root = new char[MAX_PATH]; + BOOST_REGEX_NOEH_ASSERT(_root) + _path = new char[MAX_PATH]; + BOOST_REGEX_NOEH_ASSERT(_path) + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, wild)); + ptr = _root; + while(*ptr)++ptr; + while((ptr > _root) && (*ptr != *_fi_sep) && (*ptr != *_fi_sep_alt))--ptr; + if((ptr == _root) && ( (*ptr== *_fi_sep) || (*ptr==*_fi_sep_alt) ) ) + { + _root[1]='\0'; + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, _root)); + } + else + { + *ptr = 0; + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, _root)); + if(*_path == 0) + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, ".")); + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcat_s(_path, MAX_PATH, _fi_sep)); + } + ptr = _path + std::strlen(_path); + + ref = new file_iterator_ref(); + BOOST_REGEX_NOEH_ASSERT(ref) + ref->hf = find_first_file(wild, ref->_data); + ref->count = 1; + + if(ref->hf == _fi_invalid_handle) + { + *_path = 0; + ptr = _path; + } + else + { + copy_find_file_result_with_overflow_check(ref->_data, ptr, (MAX_PATH - (ptr - _path))); + if(ref->_data.dwFileAttributes & _fi_dir) + next(); + } +#ifndef BOOST_NO_EXCEPTIONS + } + catch(...) + { + delete[] _root; + delete[] _path; + delete ref; + throw; + } +#endif +} + +file_iterator::file_iterator(const file_iterator& other) +{ + _root = _path = 0; + ref = 0; +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + _root = new char[MAX_PATH]; + BOOST_REGEX_NOEH_ASSERT(_root) + _path = new char[MAX_PATH]; + BOOST_REGEX_NOEH_ASSERT(_path) + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, other._root)); + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, other._path)); + ptr = _path + (other.ptr - other._path); + ref = other.ref; +#ifndef BOOST_NO_EXCEPTIONS + } + catch(...) + { + delete[] _root; + delete[] _path; + throw; + } +#endif + ++(ref->count); +} + +file_iterator& file_iterator::operator=(const file_iterator& other) +{ + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, other._root)); + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, other._path)); + ptr = _path + (other.ptr - other._path); + if(--(ref->count) == 0) + { + if(ref->hf != _fi_invalid_handle) + FindClose(ref->hf); + delete ref; + } + ref = other.ref; + ++(ref->count); + return *this; +} + + +file_iterator::~file_iterator() +{ + delete[] _root; + delete[] _path; + if(--(ref->count) == 0) + { + if(ref->hf != _fi_invalid_handle) + FindClose(ref->hf); + delete ref; + } +} + +file_iterator file_iterator::operator++(int) +{ + file_iterator temp(*this); + next(); + return temp; +} + + +void file_iterator::next() +{ + if(ref->hf != _fi_invalid_handle) + { + bool cont = true; + while(cont) + { + cont = find_next_file(ref->hf, ref->_data); + if(cont && ((ref->_data.dwFileAttributes & _fi_dir) == 0)) + break; + } + if(!cont) + { + // end of sequence + FindClose(ref->hf); + ref->hf = _fi_invalid_handle; + *_path = 0; + ptr = _path; + } + else + copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path)); + } +} + + + +directory_iterator::directory_iterator() +{ + _root = _path = 0; + ref = 0; +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + _root = new char[MAX_PATH]; + BOOST_REGEX_NOEH_ASSERT(_root) + _path = new char[MAX_PATH]; + BOOST_REGEX_NOEH_ASSERT(_path) + ptr = _path; + *_path = 0; + *_root = 0; + ref = new file_iterator_ref(); + BOOST_REGEX_NOEH_ASSERT(ref) + ref->hf = _fi_invalid_handle; + ref->count = 1; +#ifndef BOOST_NO_EXCEPTIONS + } + catch(...) + { + delete[] _root; + delete[] _path; + delete ref; + throw; + } +#endif +} + +directory_iterator::directory_iterator(const char* wild) +{ + _root = _path = 0; + ref = 0; +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + _root = new char[MAX_PATH]; + BOOST_REGEX_NOEH_ASSERT(_root) + _path = new char[MAX_PATH]; + BOOST_REGEX_NOEH_ASSERT(_path) + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, wild)); + ptr = _root; + while(*ptr)++ptr; + while((ptr > _root) && (*ptr != *_fi_sep) && (*ptr != *_fi_sep_alt))--ptr; + + if((ptr == _root) && ( (*ptr== *_fi_sep) || (*ptr==*_fi_sep_alt) ) ) + { + _root[1]='\0'; + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, _root)); + } + else + { + *ptr = 0; + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, _root)); + if(*_path == 0) + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, ".")); + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcat_s(_path, MAX_PATH, _fi_sep)); + } + ptr = _path + std::strlen(_path); + + ref = new file_iterator_ref(); + BOOST_REGEX_NOEH_ASSERT(ref) + ref->count = 1; + ref->hf = find_first_file(wild, ref->_data); + if(ref->hf == _fi_invalid_handle) + { + *_path = 0; + ptr = _path; + } + else + { + copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path)); + if(((ref->_data.dwFileAttributes & _fi_dir) == 0) || (std::strcmp(ptr, ".") == 0) || (std::strcmp(ptr, "..") == 0)) + next(); + } +#ifndef BOOST_NO_EXCEPTIONS + } + catch(...) + { + delete[] _root; + delete[] _path; + delete ref; + throw; + } +#endif +} + +directory_iterator::~directory_iterator() +{ + delete[] _root; + delete[] _path; + if(--(ref->count) == 0) + { + if(ref->hf != _fi_invalid_handle) + FindClose(ref->hf); + delete ref; + } +} + +directory_iterator::directory_iterator(const directory_iterator& other) +{ + _root = _path = 0; + ref = 0; +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + _root = new char[MAX_PATH]; + BOOST_REGEX_NOEH_ASSERT(_root) + _path = new char[MAX_PATH]; + BOOST_REGEX_NOEH_ASSERT(_path) + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, other._root)); + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, other._path)); + ptr = _path + (other.ptr - other._path); + ref = other.ref; +#ifndef BOOST_NO_EXCEPTIONS + } + catch(...) + { + delete[] _root; + delete[] _path; + throw; + } +#endif + ++(ref->count); +} + +directory_iterator& directory_iterator::operator=(const directory_iterator& other) +{ + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, other._root)); + BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, other._path)); + ptr = _path + (other.ptr - other._path); + if(--(ref->count) == 0) + { + if(ref->hf != _fi_invalid_handle) + FindClose(ref->hf); + delete ref; + } + ref = other.ref; + ++(ref->count); + return *this; +} + +directory_iterator directory_iterator::operator++(int) +{ + directory_iterator temp(*this); + next(); + return temp; +} + +void directory_iterator::next() +{ + if(ref->hf != _fi_invalid_handle) + { + bool cont = true; + while(cont) + { + cont = find_next_file(ref->hf, ref->_data); + if(cont && (ref->_data.dwFileAttributes & _fi_dir)) + { + if(is_not_current_or_parent_path_string(ref->_data)) + break; + } + } + if(!cont) + { + // end of sequence + FindClose(ref->hf); + ref->hf = _fi_invalid_handle; + *_path = 0; + ptr = _path; + } + else + copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path)); + } +} + + +#ifdef BOOST_REGEX_FI_POSIX_DIR + +struct _fi_priv_data +{ + char root[MAX_PATH]; + char* mask; + DIR* d; + _fi_priv_data(const char* p); +}; + +_fi_priv_data::_fi_priv_data(const char* p) +{ + std::strcpy(root, p); + mask = root; + while(*mask) ++mask; + while((mask > root) && (*mask != *_fi_sep) && (*mask != *_fi_sep_alt)) --mask; + if(mask == root && ((*mask== *_fi_sep) || (*mask == *_fi_sep_alt)) ) + { + root[1] = '\0'; + std::strcpy(root+2, p+1); + mask = root+2; + } + else if(mask == root) + { + root[0] = '.'; + root[1] = '\0'; + std::strcpy(root+2, p); + mask = root+2; + } + else + { + *mask = 0; + ++mask; + } +} + +bool iswild(const char* mask, const char* name) +{ + while(*mask && *name) + { + switch(*mask) + { + case '?': + ++name; + ++mask; + continue; + case '*': + ++mask; + if(*mask == 0) + return true; + while(*name) + { + if(iswild(mask, name)) + return true; + ++name; + } + return false; + case '.': + if(0 == *name) + { + ++mask; + continue; + } + // fall through + default: + if(BOOST_REGEX_FI_TRANSLATE(*mask) != BOOST_REGEX_FI_TRANSLATE(*name)) + return false; + ++mask; + ++name; + continue; + } + } + if(*mask != *name) + return false; + return true; +} + +unsigned _fi_attributes(const char* root, const char* name) +{ + char buf[MAX_PATH]; + // verify that we can not overflow: + if(std::strlen(root) + std::strlen(_fi_sep) + std::strlen(name) >= MAX_PATH) + return 0; + int r; + if( ( (root[0] == *_fi_sep) || (root[0] == *_fi_sep_alt) ) && (root[1] == '\0') ) + r = (std::sprintf)(buf, "%s%s", root, name); + else + r = (std::sprintf)(buf, "%s%s%s", root, _fi_sep, name); + if(r < 0) + return 0; // sprintf failed + DIR* d = opendir(buf); + if(d) + { + closedir(d); + return _fi_dir; + } + return 0; +} + +_fi_find_handle _fi_FindFirstFile(const char* lpFileName, _fi_find_data* lpFindFileData) +{ + _fi_find_handle dat = new _fi_priv_data(lpFileName); + + DIR* h = opendir(dat->root); + dat->d = h; + if(h != 0) + { + if(_fi_FindNextFile(dat, lpFindFileData)) + return dat; + closedir(h); + } + delete dat; + return 0; +} + +bool _fi_FindNextFile(_fi_find_handle dat, _fi_find_data* lpFindFileData) +{ + dirent* d; + do + { + d = readdir(dat->d); + } while(d && !iswild(dat->mask, d->d_name)); + + if(d) + { + std::strcpy(lpFindFileData->cFileName, d->d_name); + lpFindFileData->dwFileAttributes = _fi_attributes(dat->root, d->d_name); + return true; + } + return false; +} + +bool _fi_FindClose(_fi_find_handle dat) +{ + closedir(dat->d); + delete dat; + return true; +} + +#endif + +} // namespace BOOST_REGEX_DETAIL_NS +} // namspace boost + +#endif // BOOST_REGEX_NO_FILEITER + + + + + + + + + + + + diff --git a/libs/regex/src/icu.cpp b/libs/regex/src/icu.cpp new file mode 100644 index 0000000..5f249e2 --- /dev/null +++ b/libs/regex/src/icu.cpp @@ -0,0 +1,511 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE icu.cpp + * VERSION see + * DESCRIPTION: Unicode regular expressions on top of the ICU Library. + */ +#define BOOST_REGEX_SOURCE + +#include +#ifdef BOOST_HAS_ICU +#define BOOST_REGEX_ICU_INSTANTIATE +#include + +#ifdef BOOST_INTEL +#pragma warning(disable:981 2259 383) +#endif + +namespace boost{ + +namespace BOOST_REGEX_DETAIL_NS{ + +icu_regex_traits_implementation::string_type icu_regex_traits_implementation::do_transform(const char_type* p1, const char_type* p2, const U_NAMESPACE_QUALIFIER Collator* pcoll) const +{ + // TODO make thread safe!!!! : + typedef u32_to_u16_iterator itt; + itt i(p1), j(p2); +#ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS + std::vector< ::UChar> t(i, j); +#else + std::vector< ::UChar> t; + while(i != j) + t.push_back(*i++); +#endif + ::uint8_t result[100]; + ::int32_t len; + if(t.size()) + len = pcoll->getSortKey(&*t.begin(), static_cast< ::int32_t>(t.size()), result, sizeof(result)); + else + len = pcoll->getSortKey(static_cast(0), static_cast< ::int32_t>(0), result, sizeof(result)); + if(std::size_t(len) > sizeof(result)) + { + scoped_array< ::uint8_t> presult(new ::uint8_t[len+1]); + if(t.size()) + len = pcoll->getSortKey(&*t.begin(), static_cast< ::int32_t>(t.size()), presult.get(), len+1); + else + len = pcoll->getSortKey(static_cast(0), static_cast< ::int32_t>(0), presult.get(), len+1); + if((0 == presult[len-1]) && (len > 1)) + --len; +#ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS + return string_type(presult.get(), presult.get()+len); +#else + string_type sresult; + ::uint8_t const* ia = presult.get(); + ::uint8_t const* ib = presult.get()+len; + while(ia != ib) + sresult.push_back(*ia++); + return sresult; +#endif + } + if((0 == result[len-1]) && (len > 1)) + --len; +#ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS + return string_type(result, result+len); +#else + string_type sresult; + ::uint8_t const* ia = result; + ::uint8_t const* ib = result+len; + while(ia != ib) + sresult.push_back(*ia++); + return sresult; +#endif +} + +} + +icu_regex_traits::size_type icu_regex_traits::length(const char_type* p) +{ + size_type result = 0; + while(*p) + { + ++p; + ++result; + } + return result; +} + +// +// define our bitmasks: +// +const icu_regex_traits::char_class_type icu_regex_traits::mask_blank = icu_regex_traits::char_class_type(1) << offset_blank; +const icu_regex_traits::char_class_type icu_regex_traits::mask_space = icu_regex_traits::char_class_type(1) << offset_space; +const icu_regex_traits::char_class_type icu_regex_traits::mask_xdigit = icu_regex_traits::char_class_type(1) << offset_xdigit; +const icu_regex_traits::char_class_type icu_regex_traits::mask_underscore = icu_regex_traits::char_class_type(1) << offset_underscore; +const icu_regex_traits::char_class_type icu_regex_traits::mask_unicode = icu_regex_traits::char_class_type(1) << offset_unicode; +const icu_regex_traits::char_class_type icu_regex_traits::mask_any = icu_regex_traits::char_class_type(1) << offset_any; +const icu_regex_traits::char_class_type icu_regex_traits::mask_ascii = icu_regex_traits::char_class_type(1) << offset_ascii; +const icu_regex_traits::char_class_type icu_regex_traits::mask_horizontal = icu_regex_traits::char_class_type(1) << offset_horizontal; +const icu_regex_traits::char_class_type icu_regex_traits::mask_vertical = icu_regex_traits::char_class_type(1) << offset_vertical; + +icu_regex_traits::char_class_type icu_regex_traits::lookup_icu_mask(const ::UChar32* p1, const ::UChar32* p2) +{ + static const ::UChar32 prop_name_table[] = { + /* any */ 'a', 'n', 'y', + /* ascii */ 'a', 's', 'c', 'i', 'i', + /* assigned */ 'a', 's', 's', 'i', 'g', 'n', 'e', 'd', + /* c* */ 'c', '*', + /* cc */ 'c', 'c', + /* cf */ 'c', 'f', + /* closepunctuation */ 'c', 'l', 'o', 's', 'e', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* cn */ 'c', 'n', + /* co */ 'c', 'o', + /* connectorpunctuation */ 'c', 'o', 'n', 'n', 'e', 'c', 't', 'o', 'r', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* control */ 'c', 'o', 'n', 't', 'r', 'o', 'l', + /* cs */ 'c', 's', + /* currencysymbol */ 'c', 'u', 'r', 'r', 'e', 'n', 'c', 'y', 's', 'y', 'm', 'b', 'o', 'l', + /* dashpunctuation */ 'd', 'a', 's', 'h', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* decimaldigitnumber */ 'd', 'e', 'c', 'i', 'm', 'a', 'l', 'd', 'i', 'g', 'i', 't', 'n', 'u', 'm', 'b', 'e', 'r', + /* enclosingmark */ 'e', 'n', 'c', 'l', 'o', 's', 'i', 'n', 'g', 'm', 'a', 'r', 'k', + /* finalpunctuation */ 'f', 'i', 'n', 'a', 'l', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* format */ 'f', 'o', 'r', 'm', 'a', 't', + /* initialpunctuation */ 'i', 'n', 'i', 't', 'i', 'a', 'l', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* l* */ 'l', '*', + /* letter */ 'l', 'e', 't', 't', 'e', 'r', + /* letternumber */ 'l', 'e', 't', 't', 'e', 'r', 'n', 'u', 'm', 'b', 'e', 'r', + /* lineseparator */ 'l', 'i', 'n', 'e', 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', + /* ll */ 'l', 'l', + /* lm */ 'l', 'm', + /* lo */ 'l', 'o', + /* lowercaseletter */ 'l', 'o', 'w', 'e', 'r', 'c', 'a', 's', 'e', 'l', 'e', 't', 't', 'e', 'r', + /* lt */ 'l', 't', + /* lu */ 'l', 'u', + /* m* */ 'm', '*', + /* mark */ 'm', 'a', 'r', 'k', + /* mathsymbol */ 'm', 'a', 't', 'h', 's', 'y', 'm', 'b', 'o', 'l', + /* mc */ 'm', 'c', + /* me */ 'm', 'e', + /* mn */ 'm', 'n', + /* modifierletter */ 'm', 'o', 'd', 'i', 'f', 'i', 'e', 'r', 'l', 'e', 't', 't', 'e', 'r', + /* modifiersymbol */ 'm', 'o', 'd', 'i', 'f', 'i', 'e', 'r', 's', 'y', 'm', 'b', 'o', 'l', + /* n* */ 'n', '*', + /* nd */ 'n', 'd', + /* nl */ 'n', 'l', + /* no */ 'n', 'o', + /* nonspacingmark */ 'n', 'o', 'n', 's', 'p', 'a', 'c', 'i', 'n', 'g', 'm', 'a', 'r', 'k', + /* notassigned */ 'n', 'o', 't', 'a', 's', 's', 'i', 'g', 'n', 'e', 'd', + /* number */ 'n', 'u', 'm', 'b', 'e', 'r', + /* openpunctuation */ 'o', 'p', 'e', 'n', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* other */ 'o', 't', 'h', 'e', 'r', + /* otherletter */ 'o', 't', 'h', 'e', 'r', 'l', 'e', 't', 't', 'e', 'r', + /* othernumber */ 'o', 't', 'h', 'e', 'r', 'n', 'u', 'm', 'b', 'e', 'r', + /* otherpunctuation */ 'o', 't', 'h', 'e', 'r', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* othersymbol */ 'o', 't', 'h', 'e', 'r', 's', 'y', 'm', 'b', 'o', 'l', + /* p* */ 'p', '*', + /* paragraphseparator */ 'p', 'a', 'r', 'a', 'g', 'r', 'a', 'p', 'h', 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', + /* pc */ 'p', 'c', + /* pd */ 'p', 'd', + /* pe */ 'p', 'e', + /* pf */ 'p', 'f', + /* pi */ 'p', 'i', + /* po */ 'p', 'o', + /* privateuse */ 'p', 'r', 'i', 'v', 'a', 't', 'e', 'u', 's', 'e', + /* ps */ 'p', 's', + /* punctuation */ 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* s* */ 's', '*', + /* sc */ 's', 'c', + /* separator */ 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', + /* sk */ 's', 'k', + /* sm */ 's', 'm', + /* so */ 's', 'o', + /* spaceseparator */ 's', 'p', 'a', 'c', 'e', 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', + /* spacingcombiningmark */ 's', 'p', 'a', 'c', 'i', 'n', 'g', 'c', 'o', 'm', 'b', 'i', 'n', 'i', 'n', 'g', 'm', 'a', 'r', 'k', + /* surrogate */ 's', 'u', 'r', 'r', 'o', 'g', 'a', 't', 'e', + /* symbol */ 's', 'y', 'm', 'b', 'o', 'l', + /* titlecase */ 't', 'i', 't', 'l', 'e', 'c', 'a', 's', 'e', + /* titlecaseletter */ 't', 'i', 't', 'l', 'e', 'c', 'a', 's', 'e', 'l', 'e', 't', 't', 'e', 'r', + /* uppercaseletter */ 'u', 'p', 'p', 'e', 'r', 'c', 'a', 's', 'e', 'l', 'e', 't', 't', 'e', 'r', + /* z* */ 'z', '*', + /* zl */ 'z', 'l', + /* zp */ 'z', 'p', + /* zs */ 'z', 's', + }; + + static const BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32> range_data[] = { + { prop_name_table+0, prop_name_table+3, }, // any + { prop_name_table+3, prop_name_table+8, }, // ascii + { prop_name_table+8, prop_name_table+16, }, // assigned + { prop_name_table+16, prop_name_table+18, }, // c* + { prop_name_table+18, prop_name_table+20, }, // cc + { prop_name_table+20, prop_name_table+22, }, // cf + { prop_name_table+22, prop_name_table+38, }, // closepunctuation + { prop_name_table+38, prop_name_table+40, }, // cn + { prop_name_table+40, prop_name_table+42, }, // co + { prop_name_table+42, prop_name_table+62, }, // connectorpunctuation + { prop_name_table+62, prop_name_table+69, }, // control + { prop_name_table+69, prop_name_table+71, }, // cs + { prop_name_table+71, prop_name_table+85, }, // currencysymbol + { prop_name_table+85, prop_name_table+100, }, // dashpunctuation + { prop_name_table+100, prop_name_table+118, }, // decimaldigitnumber + { prop_name_table+118, prop_name_table+131, }, // enclosingmark + { prop_name_table+131, prop_name_table+147, }, // finalpunctuation + { prop_name_table+147, prop_name_table+153, }, // format + { prop_name_table+153, prop_name_table+171, }, // initialpunctuation + { prop_name_table+171, prop_name_table+173, }, // l* + { prop_name_table+173, prop_name_table+179, }, // letter + { prop_name_table+179, prop_name_table+191, }, // letternumber + { prop_name_table+191, prop_name_table+204, }, // lineseparator + { prop_name_table+204, prop_name_table+206, }, // ll + { prop_name_table+206, prop_name_table+208, }, // lm + { prop_name_table+208, prop_name_table+210, }, // lo + { prop_name_table+210, prop_name_table+225, }, // lowercaseletter + { prop_name_table+225, prop_name_table+227, }, // lt + { prop_name_table+227, prop_name_table+229, }, // lu + { prop_name_table+229, prop_name_table+231, }, // m* + { prop_name_table+231, prop_name_table+235, }, // mark + { prop_name_table+235, prop_name_table+245, }, // mathsymbol + { prop_name_table+245, prop_name_table+247, }, // mc + { prop_name_table+247, prop_name_table+249, }, // me + { prop_name_table+249, prop_name_table+251, }, // mn + { prop_name_table+251, prop_name_table+265, }, // modifierletter + { prop_name_table+265, prop_name_table+279, }, // modifiersymbol + { prop_name_table+279, prop_name_table+281, }, // n* + { prop_name_table+281, prop_name_table+283, }, // nd + { prop_name_table+283, prop_name_table+285, }, // nl + { prop_name_table+285, prop_name_table+287, }, // no + { prop_name_table+287, prop_name_table+301, }, // nonspacingmark + { prop_name_table+301, prop_name_table+312, }, // notassigned + { prop_name_table+312, prop_name_table+318, }, // number + { prop_name_table+318, prop_name_table+333, }, // openpunctuation + { prop_name_table+333, prop_name_table+338, }, // other + { prop_name_table+338, prop_name_table+349, }, // otherletter + { prop_name_table+349, prop_name_table+360, }, // othernumber + { prop_name_table+360, prop_name_table+376, }, // otherpunctuation + { prop_name_table+376, prop_name_table+387, }, // othersymbol + { prop_name_table+387, prop_name_table+389, }, // p* + { prop_name_table+389, prop_name_table+407, }, // paragraphseparator + { prop_name_table+407, prop_name_table+409, }, // pc + { prop_name_table+409, prop_name_table+411, }, // pd + { prop_name_table+411, prop_name_table+413, }, // pe + { prop_name_table+413, prop_name_table+415, }, // pf + { prop_name_table+415, prop_name_table+417, }, // pi + { prop_name_table+417, prop_name_table+419, }, // po + { prop_name_table+419, prop_name_table+429, }, // privateuse + { prop_name_table+429, prop_name_table+431, }, // ps + { prop_name_table+431, prop_name_table+442, }, // punctuation + { prop_name_table+442, prop_name_table+444, }, // s* + { prop_name_table+444, prop_name_table+446, }, // sc + { prop_name_table+446, prop_name_table+455, }, // separator + { prop_name_table+455, prop_name_table+457, }, // sk + { prop_name_table+457, prop_name_table+459, }, // sm + { prop_name_table+459, prop_name_table+461, }, // so + { prop_name_table+461, prop_name_table+475, }, // spaceseparator + { prop_name_table+475, prop_name_table+495, }, // spacingcombiningmark + { prop_name_table+495, prop_name_table+504, }, // surrogate + { prop_name_table+504, prop_name_table+510, }, // symbol + { prop_name_table+510, prop_name_table+519, }, // titlecase + { prop_name_table+519, prop_name_table+534, }, // titlecaseletter + { prop_name_table+534, prop_name_table+549, }, // uppercaseletter + { prop_name_table+549, prop_name_table+551, }, // z* + { prop_name_table+551, prop_name_table+553, }, // zl + { prop_name_table+553, prop_name_table+555, }, // zp + { prop_name_table+555, prop_name_table+557, }, // zs + }; + + static const icu_regex_traits::char_class_type icu_class_map[] = { + icu_regex_traits::mask_any, // any + icu_regex_traits::mask_ascii, // ascii + (0x3FFFFFFFu) & ~(U_GC_CN_MASK), // assigned + U_GC_C_MASK, // c* + U_GC_CC_MASK, // cc + U_GC_CF_MASK, // cf + U_GC_PE_MASK, // closepunctuation + U_GC_CN_MASK, // cn + U_GC_CO_MASK, // co + U_GC_PC_MASK, // connectorpunctuation + U_GC_CC_MASK, // control + U_GC_CS_MASK, // cs + U_GC_SC_MASK, // currencysymbol + U_GC_PD_MASK, // dashpunctuation + U_GC_ND_MASK, // decimaldigitnumber + U_GC_ME_MASK, // enclosingmark + U_GC_PF_MASK, // finalpunctuation + U_GC_CF_MASK, // format + U_GC_PI_MASK, // initialpunctuation + U_GC_L_MASK, // l* + U_GC_L_MASK, // letter + U_GC_NL_MASK, // letternumber + U_GC_ZL_MASK, // lineseparator + U_GC_LL_MASK, // ll + U_GC_LM_MASK, // lm + U_GC_LO_MASK, // lo + U_GC_LL_MASK, // lowercaseletter + U_GC_LT_MASK, // lt + U_GC_LU_MASK, // lu + U_GC_M_MASK, // m* + U_GC_M_MASK, // mark + U_GC_SM_MASK, // mathsymbol + U_GC_MC_MASK, // mc + U_GC_ME_MASK, // me + U_GC_MN_MASK, // mn + U_GC_LM_MASK, // modifierletter + U_GC_SK_MASK, // modifiersymbol + U_GC_N_MASK, // n* + U_GC_ND_MASK, // nd + U_GC_NL_MASK, // nl + U_GC_NO_MASK, // no + U_GC_MN_MASK, // nonspacingmark + U_GC_CN_MASK, // notassigned + U_GC_N_MASK, // number + U_GC_PS_MASK, // openpunctuation + U_GC_C_MASK, // other + U_GC_LO_MASK, // otherletter + U_GC_NO_MASK, // othernumber + U_GC_PO_MASK, // otherpunctuation + U_GC_SO_MASK, // othersymbol + U_GC_P_MASK, // p* + U_GC_ZP_MASK, // paragraphseparator + U_GC_PC_MASK, // pc + U_GC_PD_MASK, // pd + U_GC_PE_MASK, // pe + U_GC_PF_MASK, // pf + U_GC_PI_MASK, // pi + U_GC_PO_MASK, // po + U_GC_CO_MASK, // privateuse + U_GC_PS_MASK, // ps + U_GC_P_MASK, // punctuation + U_GC_S_MASK, // s* + U_GC_SC_MASK, // sc + U_GC_Z_MASK, // separator + U_GC_SK_MASK, // sk + U_GC_SM_MASK, // sm + U_GC_SO_MASK, // so + U_GC_ZS_MASK, // spaceseparator + U_GC_MC_MASK, // spacingcombiningmark + U_GC_CS_MASK, // surrogate + U_GC_S_MASK, // symbol + U_GC_LT_MASK, // titlecase + U_GC_LT_MASK, // titlecaseletter + U_GC_LU_MASK, // uppercaseletter + U_GC_Z_MASK, // z* + U_GC_ZL_MASK, // zl + U_GC_ZP_MASK, // zp + U_GC_ZS_MASK, // zs + }; + + + static const BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32>* ranges_begin = range_data; + static const BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32>* ranges_end = range_data + (sizeof(range_data)/sizeof(range_data[0])); + + BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32> t = { p1, p2, }; + const BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32>* p = std::lower_bound(ranges_begin, ranges_end, t); + if((p != ranges_end) && (t == *p)) + return icu_class_map[p - ranges_begin]; + return 0; +} + +icu_regex_traits::char_class_type icu_regex_traits::lookup_classname(const char_type* p1, const char_type* p2) const +{ + static const char_class_type masks[] = + { + 0, + U_GC_L_MASK | U_GC_ND_MASK, + U_GC_L_MASK, + mask_blank, + U_GC_CC_MASK | U_GC_CF_MASK | U_GC_ZL_MASK | U_GC_ZP_MASK, + U_GC_ND_MASK, + U_GC_ND_MASK, + (0x3FFFFFFFu) & ~(U_GC_CC_MASK | U_GC_CF_MASK | U_GC_CS_MASK | U_GC_CN_MASK | U_GC_Z_MASK), + mask_horizontal, + U_GC_LL_MASK, + U_GC_LL_MASK, + ~(U_GC_C_MASK), + U_GC_P_MASK, + char_class_type(U_GC_Z_MASK) | mask_space, + char_class_type(U_GC_Z_MASK) | mask_space, + U_GC_LU_MASK, + mask_unicode, + U_GC_LU_MASK, + mask_vertical, + char_class_type(U_GC_L_MASK | U_GC_ND_MASK | U_GC_MN_MASK) | mask_underscore, + char_class_type(U_GC_L_MASK | U_GC_ND_MASK | U_GC_MN_MASK) | mask_underscore, + char_class_type(U_GC_ND_MASK) | mask_xdigit, + }; + + int idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + if(idx >= 0) + return masks[idx+1]; + char_class_type result = lookup_icu_mask(p1, p2); + if(result != 0) + return result; + + if(idx < 0) + { + string_type s(p1, p2); + string_type::size_type i = 0; + while(i < s.size()) + { + s[i] = static_cast((::u_tolower)(s[i])); + if(::u_isspace(s[i]) || (s[i] == '-') || (s[i] == '_')) + s.erase(s.begin()+i, s.begin()+i+1); + else + { + s[i] = static_cast((::u_tolower)(s[i])); + ++i; + } + } + if(s.size()) + idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size()); + if(idx >= 0) + return masks[idx+1]; + if(s.size()) + result = lookup_icu_mask(&*s.begin(), &*s.begin() + s.size()); + if(result != 0) + return result; + } + BOOST_ASSERT(std::size_t(idx+1) < sizeof(masks) / sizeof(masks[0])); + return masks[idx+1]; +} + +icu_regex_traits::string_type icu_regex_traits::lookup_collatename(const char_type* p1, const char_type* p2) const +{ + string_type result; +#ifdef BOOST_NO_CXX98_BINDERS + if(std::find_if(p1, p2, std::bind(std::greater< ::UChar32>(), std::placeholders::_1, 0x7f)) == p2) +#else + if(std::find_if(p1, p2, std::bind2nd(std::greater< ::UChar32>(), 0x7f)) == p2) +#endif + { +#ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS + std::string s(p1, p2); +#else + std::string s; + const char_type* p3 = p1; + while(p3 != p2) + s.append(1, *p3++); +#endif + // Try Unicode name: + UErrorCode err = U_ZERO_ERROR; + UChar32 c = ::u_charFromName(U_UNICODE_CHAR_NAME, s.c_str(), &err); + if(U_SUCCESS(err)) + { + result.push_back(c); + return result; + } + // Try Unicode-extended name: + err = U_ZERO_ERROR; + c = ::u_charFromName(U_EXTENDED_CHAR_NAME, s.c_str(), &err); + if(U_SUCCESS(err)) + { + result.push_back(c); + return result; + } + // try POSIX name: + s = ::boost::BOOST_REGEX_DETAIL_NS::lookup_default_collate_name(s); +#ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS + result.assign(s.begin(), s.end()); +#else + result.clear(); + std::string::const_iterator si, sj; + si = s.begin(); + sj = s.end(); + while(si != sj) + result.push_back(*si++); +#endif + } + if(result.empty() && (p2-p1 == 1)) + result.push_back(*p1); + return result; +} + +bool icu_regex_traits::isctype(char_type c, char_class_type f) const +{ + // check for standard catagories first: + char_class_type m = char_class_type(static_cast(1) << u_charType(c)); + if((m & f) != 0) + return true; + // now check for special cases: + if(((f & mask_blank) != 0) && u_isblank(c)) + return true; + if(((f & mask_space) != 0) && u_isspace(c)) + return true; + if(((f & mask_xdigit) != 0) && (u_digit(c, 16) >= 0)) + return true; + if(((f & mask_unicode) != 0) && (c >= 0x100)) + return true; + if(((f & mask_underscore) != 0) && (c == '_')) + return true; + if(((f & mask_any) != 0) && (c <= 0x10FFFF)) + return true; + if(((f & mask_ascii) != 0) && (c <= 0x7F)) + return true; + if(((f & mask_vertical) != 0) && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == static_cast('\v')) || (m == U_GC_ZL_MASK) || (m == U_GC_ZP_MASK))) + return true; + if(((f & mask_horizontal) != 0) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) && u_isspace(c) && (c != static_cast('\v'))) + return true; + return false; +} + +} + +#endif // BOOST_HAS_ICU diff --git a/libs/regex/src/instances.cpp b/libs/regex/src/instances.cpp new file mode 100644 index 0000000..69d72ad --- /dev/null +++ b/libs/regex/src/instances.cpp @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE: instances.cpp + * VERSION: see + * DESCRIPTION: regex narrow character template instances. + */ + +#define BOOST_REGEX_SOURCE + +#include + +#if !defined(BOOST_REGEX_NO_EXTERNAL_TEMPLATES) +#define BOOST_REGEX_NARROW_INSTANTIATE + +#ifdef __BORLANDC__ +#pragma hrdstop +#endif + +#include + +#endif diff --git a/libs/regex/src/internals.hpp b/libs/regex/src/internals.hpp new file mode 100644 index 0000000..3a15cc6 --- /dev/null +++ b/libs/regex/src/internals.hpp @@ -0,0 +1,35 @@ +/* + * + * Copyright (c) 2011 + * John Maddock + * + * Use, modification and distribution are subject to 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_REGEX_SRC_INTERNALS_HPP +#define BOOST_REGEX_SRC_INTERNALS_HPP + +enum +{ + char_class_space=1<<0, + char_class_print=1<<1, + char_class_cntrl=1<<2, + char_class_upper=1<<3, + char_class_lower=1<<4, + char_class_alpha=1<<5, + char_class_digit=1<<6, + char_class_punct=1<<7, + char_class_xdigit=1<<8, + char_class_alnum=char_class_alpha|char_class_digit, + char_class_graph=char_class_alnum|char_class_punct, + char_class_blank=1<<9, + char_class_word=1<<10, + char_class_unicode=1<<11, + char_class_horizontal=1<<12, + char_class_vertical=1<<13 +}; + +#endif // BOOST_REGEX_SRC_INTERNALS_HPP diff --git a/libs/regex/src/posix_api.cpp b/libs/regex/src/posix_api.cpp new file mode 100644 index 0000000..1531d94 --- /dev/null +++ b/libs/regex/src/posix_api.cpp @@ -0,0 +1,295 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE: posix_api.cpp + * VERSION: see + * DESCRIPTION: Implements the Posix API wrappers. + */ + +#define BOOST_REGEX_SOURCE + +#include +#include +#include +#include + +#if defined(BOOST_NO_STDC_NAMESPACE) +namespace std{ + using ::sprintf; + using ::strcpy; + using ::strcmp; +} +#endif + + +namespace boost{ + +namespace{ + +unsigned int magic_value = 25631; + +const char* names[] = { + "REG_NOERROR", + "REG_NOMATCH", + "REG_BADPAT", + "REG_ECOLLATE", + "REG_ECTYPE", + "REG_EESCAPE", + "REG_ESUBREG", + "REG_EBRACK", + "REG_EPAREN", + "REG_EBRACE", + "REG_BADBR", + "REG_ERANGE", + "REG_ESPACE", + "REG_BADRPT", + "REG_EEND", + "REG_ESIZE", + "REG_ERPAREN", + "REG_EMPTY", + "REG_ECOMPLEXITY", + "REG_ESTACK", + "REG_E_PERL", + "REG_E_UNKNOWN", +}; +} // namespace + +typedef boost::basic_regex > c_regex_type; + +BOOST_REGEX_DECL int BOOST_REGEX_CCALL regcompA(regex_tA* expression, const char* ptr, int f) +{ +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + expression->guts = new c_regex_type(); +#ifndef BOOST_NO_EXCEPTIONS + } catch(...) + { + expression->guts = 0; + return REG_ESPACE; + } +#else + if(0 == expression->guts) + return REG_E_MEMORY; +#endif + // set default flags: + boost::uint_fast32_t flags = (f & REG_PERLEX) ? 0 : ((f & REG_EXTENDED) ? regex::extended : regex::basic); + expression->eflags = (f & REG_NEWLINE) ? match_not_dot_newline : match_default; + // and translate those that are actually set: + + if(f & REG_NOCOLLATE) + { + flags |= regex::nocollate; +#ifndef BOOST_REGEX_V3 + flags &= ~regex::collate; +#endif + } + + if(f & REG_NOSUB) + { + //expression->eflags |= match_any; + flags |= regex::nosubs; + } + + if(f & REG_NOSPEC) + flags |= regex::literal; + if(f & REG_ICASE) + flags |= regex::icase; + if(f & REG_ESCAPE_IN_LISTS) + flags &= ~regex::no_escape_in_lists; + if(f & REG_NEWLINE_ALT) + flags |= regex::newline_alt; + + const char* p2; + if(f & REG_PEND) + p2 = expression->re_endp; + else p2 = ptr + std::strlen(ptr); + + int result; + +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + expression->re_magic = magic_value; + static_cast(expression->guts)->set_expression(ptr, p2, flags); + expression->re_nsub = static_cast(expression->guts)->mark_count(); + result = static_cast(expression->guts)->error_code(); +#ifndef BOOST_NO_EXCEPTIONS + } + catch(const boost::regex_error& be) + { + result = be.code(); + } + catch(...) + { + result = REG_E_UNKNOWN; + } +#endif + if(result) + regfreeA(expression); + return result; + +} + +BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorA(int code, const regex_tA* e, char* buf, regsize_t buf_size) +{ + std::size_t result = 0; + if(code & REG_ITOA) + { + code &= ~REG_ITOA; + if(code <= (int)REG_E_UNKNOWN) + { + result = std::strlen(names[code]) + 1; + if(buf_size >= result) + BOOST_REGEX_DETAIL_NS::strcpy_s(buf, buf_size, names[code]); + return result; + } + return result; + } + if(code == REG_ATOI) + { + char localbuf[5]; + if(e == 0) + return 0; + for(int i = 0; i <= (int)REG_E_UNKNOWN; ++i) + { + if(std::strcmp(e->re_endp, names[i]) == 0) + { + // + // We're converting an integer i to a string, and since i <= REG_E_UNKNOWN + // a five character string is *always* large enough: + // +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(_WIN32_WCE) && !defined(UNDER_CE) + int r = (::sprintf_s)(localbuf, 5, "%d", i); +#else + int r = (std::sprintf)(localbuf, "%d", i); +#endif + if(r < 0) + return 0; // sprintf failed + if(std::strlen(localbuf) < buf_size) + BOOST_REGEX_DETAIL_NS::strcpy_s(buf, buf_size, localbuf); + return std::strlen(localbuf) + 1; + } + } +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(_WIN32_WCE) && !defined(UNDER_CE) + int r = (::sprintf_s)(localbuf, 5, "%d", 0); +#else + int r = (std::sprintf)(localbuf, "%d", 0); +#endif + if(r < 0) + return 0; // sprintf failed + if(std::strlen(localbuf) < buf_size) + BOOST_REGEX_DETAIL_NS::strcpy_s(buf, buf_size, localbuf); + return std::strlen(localbuf) + 1; + } + if(code <= (int)REG_E_UNKNOWN) + { + std::string p; + if((e) && (e->re_magic == magic_value)) + p = static_cast(e->guts)->get_traits().error_string(static_cast< ::boost::regex_constants::error_type>(code)); + else + { + p = BOOST_REGEX_DETAIL_NS::get_default_error_string(static_cast< ::boost::regex_constants::error_type>(code)); + } + std::size_t len = p.size(); + if(len < buf_size) + { + BOOST_REGEX_DETAIL_NS::strcpy_s(buf, buf_size, p.c_str()); + } + return len + 1; + } + if(buf_size) + *buf = 0; + return 0; +} + +BOOST_REGEX_DECL int BOOST_REGEX_CCALL regexecA(const regex_tA* expression, const char* buf, regsize_t n, regmatch_t* array, int eflags) +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4267) +#endif + bool result = false; + match_flag_type flags = match_default | expression->eflags; + const char* end; + const char* start; + cmatch m; + + if(eflags & REG_NOTBOL) + flags |= match_not_bol; + if(eflags & REG_NOTEOL) + flags |= match_not_eol; + if(eflags & REG_STARTEND) + { + start = buf + array[0].rm_so; + end = buf + array[0].rm_eo; + } + else + { + start = buf; + end = buf + std::strlen(buf); + } + +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + if(expression->re_magic == magic_value) + { + result = regex_search(start, end, m, *static_cast(expression->guts), flags); + } + else + return result; +#ifndef BOOST_NO_EXCEPTIONS + } catch(...) + { + return REG_E_UNKNOWN; + } +#endif + + if(result) + { + // extract what matched: + std::size_t i; + for(i = 0; (i < n) && (i < expression->re_nsub + 1); ++i) + { + array[i].rm_so = (m[i].matched == false) ? -1 : (m[i].first - buf); + array[i].rm_eo = (m[i].matched == false) ? -1 : (m[i].second - buf); + } + // and set anything else to -1: + for(i = expression->re_nsub + 1; i < n; ++i) + { + array[i].rm_so = -1; + array[i].rm_eo = -1; + } + return 0; + } + return REG_NOMATCH; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +BOOST_REGEX_DECL void BOOST_REGEX_CCALL regfreeA(regex_tA* expression) +{ + if(expression->re_magic == magic_value) + { + delete static_cast(expression->guts); + } + expression->re_magic = 0; +} + +} // namespace boost + + + + diff --git a/libs/regex/src/regex.cpp b/libs/regex/src/regex.cpp new file mode 100644 index 0000000..5a8bbdc --- /dev/null +++ b/libs/regex/src/regex.cpp @@ -0,0 +1,231 @@ +/* + * + * Copyright (c) 1998-2004 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE: regex.cpp + * VERSION: see + * DESCRIPTION: Misc boost::regbase member funnctions. + */ + + +#define BOOST_REGEX_SOURCE + +#include +#include +#include +#include + +#if defined(BOOST_REGEX_HAS_MS_STACK_GUARD) && defined(_MSC_VER) && (_MSC_VER >= 1300) +# include +#endif +#ifdef BOOST_REGEX_HAS_MS_STACK_GUARD +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +# define NOMINMAX +#endif +#define NOGDI +#define NOUSER +#include +#endif + +#if defined(BOOST_REGEX_NON_RECURSIVE) && !defined(BOOST_REGEX_V3) +#if BOOST_REGEX_MAX_CACHE_BLOCKS == 0 +#include +#else +#include +#endif +#endif + +#ifdef BOOST_INTEL +#pragma warning(disable:383) +#endif + +namespace boost{ + +// +// fix: these are declared out of line here to ensure +// that dll builds contain the Virtual table for these +// types - this ensures that exceptions can be thrown +// from the dll and caught in an exe. +regex_error::regex_error(const std::string& s, regex_constants::error_type err, std::ptrdiff_t pos) + : std::runtime_error(s) + , m_error_code(err) + , m_position(pos) +{ +} + +regex_error::regex_error(regex_constants::error_type err) + : std::runtime_error(::boost::BOOST_REGEX_DETAIL_NS::get_default_error_string(err)) + , m_error_code(err) + , m_position(0) +{ +} + +regex_error::~regex_error() throw() +{ +} + +void regex_error::raise()const +{ +#ifndef BOOST_NO_EXCEPTIONS + ::boost::throw_exception(*this); +#endif +} + + + +namespace BOOST_REGEX_DETAIL_NS{ + +BOOST_REGEX_DECL void BOOST_REGEX_CALL raise_runtime_error(const std::runtime_error& ex) +{ + ::boost::throw_exception(ex); +} +// +// error checking API: +// +BOOST_REGEX_DECL void BOOST_REGEX_CALL verify_options(boost::regex::flag_type /*ef*/, match_flag_type mf) +{ +#ifndef BOOST_REGEX_V3 + // + // can't mix match_extra with POSIX matching rules: + // + if((mf & match_extra) && (mf & match_posix)) + { + std::logic_error msg("Usage Error: Can't mix regular expression captures with POSIX matching rules"); + throw_exception(msg); + } +#endif +} + +#ifdef BOOST_REGEX_HAS_MS_STACK_GUARD + +static void execute_eror() +{ + // we only get here after a stack overflow, + // this has to be a separate proceedure because we + // can't mix __try{}__except block with local objects + // that have destructors: + reset_stack_guard_page(); + std::runtime_error err("Out of stack space, while attempting to match a regular expression."); + raise_runtime_error(err); +} + +bool BOOST_REGEX_CALL abstract_protected_call::execute()const +{ + __try{ + return this->call(); + }__except(EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) + { + execute_eror(); + } + // We never really get here at all: + return false; +} + +BOOST_REGEX_DECL void BOOST_REGEX_CALL reset_stack_guard_page() +{ +#if defined(BOOST_REGEX_HAS_MS_STACK_GUARD) && defined(_MSC_VER) && (_MSC_VER >= 1300) + _resetstkoflw(); +#else + // + // We need to locate the current page being used by the stack, + // move to the page below it and then deallocate and protect + // that page. Note that ideally we would protect only the lowest + // stack page that has been allocated: in practice there + // seems to be no easy way to locate this page, in any case as + // long as the next page is protected, then Windows will figure + // the rest out for us... + // + SYSTEM_INFO si; + GetSystemInfo(&si); + MEMORY_BASIC_INFORMATION mi; + DWORD previous_protection_status; + // + // this is an address in our stack space: + // + LPBYTE page = (LPBYTE)&page; + // + // Get the current memory page in use: + // + VirtualQuery(page, &mi, sizeof(mi)); + // + // Go to the page one below this: + // + page = (LPBYTE)(mi.BaseAddress)-si.dwPageSize; + // + // Free and protect everything from the start of the + // allocation range, to the end of the page below the + // one in use: + // + if (!VirtualFree(mi.AllocationBase, (LPBYTE)page - (LPBYTE)mi.AllocationBase, MEM_DECOMMIT) + || !VirtualProtect(page, si.dwPageSize, PAGE_GUARD | PAGE_READWRITE, &previous_protection_status)) + { + throw std::bad_exception(); + } +#endif +} +#endif + +#if defined(BOOST_REGEX_NON_RECURSIVE) && !defined(BOOST_REGEX_V3) + +#if BOOST_REGEX_MAX_CACHE_BLOCKS == 0 + +BOOST_REGEX_DECL void* BOOST_REGEX_CALL get_mem_block() +{ + return ::operator new(BOOST_REGEX_BLOCKSIZE); +} + +BOOST_REGEX_DECL void BOOST_REGEX_CALL put_mem_block(void* p) +{ + ::operator delete(p); +} + +#else + +#if defined(BOOST_REGEX_MEM_BLOCK_CACHE_LOCK_FREE) +mem_block_cache block_cache = { { {nullptr} } } ; +#elif defined(BOOST_HAS_THREADS) +mem_block_cache block_cache = { 0, 0, BOOST_STATIC_MUTEX_INIT, }; +#else +mem_block_cache block_cache = { 0, 0, }; +#endif + +BOOST_REGEX_DECL void* BOOST_REGEX_CALL get_mem_block() +{ + return block_cache.get(); +} + +BOOST_REGEX_DECL void BOOST_REGEX_CALL put_mem_block(void* p) +{ + block_cache.put(p); +} + +#endif + +#endif + +} // namespace BOOST_REGEX_DETAIL_NS + + + +} // namespace boost + +#if defined(BOOST_RE_USE_VCL) && defined(BOOST_REGEX_DYN_LINK) + +int WINAPI DllEntryPoint(HINSTANCE , unsigned long , void*) +{ + return 1; +} +#endif + diff --git a/libs/regex/src/regex_debug.cpp b/libs/regex/src/regex_debug.cpp new file mode 100644 index 0000000..9306a82 --- /dev/null +++ b/libs/regex/src/regex_debug.cpp @@ -0,0 +1,59 @@ +/* + * + * Copyright (c) 1998-2004 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE: regex_debug.cpp + * VERSION: see + * DESCRIPTION: Misc. debugging helpers. + */ + + +#define BOOST_REGEX_SOURCE + +#include + + +// +// regex configuration information: this prints out the settings used +// when the library was built - include in debugging builds only: +// +#ifdef BOOST_REGEX_CONFIG_INFO + +#define print_macro regex_lib_print_macro +#define print_expression regex_lib_print_expression +#define print_byte_order regex_lib_print_byte_order +#define print_sign regex_lib_print_sign +#define print_compiler_macros regex_lib_print_compiler_macros +#define print_stdlib_macros regex_lib_print_stdlib_macros +#define print_platform_macros regex_lib_print_platform_macros +#define print_boost_macros regex_lib_print_boost_macros +#define print_separator regex_lib_print_separator +#define OLD_MAIN regex_lib_main +#define NEW_MAIN regex_lib_main2 +#define NO_RECURSE + +#include + +BOOST_REGEX_DECL void BOOST_REGEX_CALL print_regex_library_info() +{ + std::cout << "\n\n"; + print_separator(); + std::cout << "Regex library build configuration:\n\n"; + regex_lib_main2(); +} + +#endif + + + + + diff --git a/libs/regex/src/regex_raw_buffer.cpp b/libs/regex/src/regex_raw_buffer.cpp new file mode 100644 index 0000000..bb49229 --- /dev/null +++ b/libs/regex/src/regex_raw_buffer.cpp @@ -0,0 +1,72 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_raw_buffer.cpp + * VERSION see + * DESCRIPTION: Member functions for class raw_storage. + */ + + +#define BOOST_REGEX_SOURCE +#include +#include +#include +#include +#include + +#if defined(BOOST_NO_STDC_NAMESPACE) +namespace std{ + using ::memcpy; + using ::memmove; +} +#endif + + +namespace boost{ namespace BOOST_REGEX_DETAIL_NS{ + +void BOOST_REGEX_CALL raw_storage::resize(size_type n) +{ + size_type newsize = start ? last - start : 1024; + while(newsize < n) + newsize *= 2; + size_type datasize = end - start; + // extend newsize to WORD/DWORD boundary: + newsize = (newsize + padding_mask) & ~(padding_mask); + + // allocate and copy data: + pointer ptr = static_cast(::operator new(newsize)); + BOOST_REGEX_NOEH_ASSERT(ptr) + if(start) + std::memcpy(ptr, start, datasize); + + // get rid of old buffer: + ::operator delete(start); + + // and set up pointers: + start = ptr; + end = ptr + datasize; + last = ptr + newsize; +} + +void* BOOST_REGEX_CALL raw_storage::insert(size_type pos, size_type n) +{ + BOOST_ASSERT(pos <= size_type(end - start)); + if(size_type(last - end) < n) + resize(n + (end - start)); + void* result = start + pos; + std::memmove(start + pos + n, start + pos, (end - start) - pos); + end += n; + return result; +} + +}} // namespaces diff --git a/libs/regex/src/regex_traits_defaults.cpp b/libs/regex/src/regex_traits_defaults.cpp new file mode 100644 index 0000000..0b66c68 --- /dev/null +++ b/libs/regex/src/regex_traits_defaults.cpp @@ -0,0 +1,692 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_traits_defaults.cpp + * VERSION see + * DESCRIPTION: Declares API's for access to regex_traits default properties. + */ + +#define BOOST_REGEX_SOURCE +#include + +#include +#ifndef BOOST_NO_WREGEX +#include +#endif + +#if defined(BOOST_NO_STDC_NAMESPACE) +namespace std{ + using ::tolower; + using ::toupper; +#ifndef BOOST_NO_WREGEX + using ::towlower; + using ::towupper; +#endif +} +#endif + + +namespace boost{ namespace BOOST_REGEX_DETAIL_NS{ + +BOOST_REGEX_DECL const char* BOOST_REGEX_CALL get_default_syntax(regex_constants::syntax_type n) +{ + // if the user hasn't supplied a message catalog, then this supplies + // default "messages" for us to load in the range 1-100. + const char* messages[] = { + "", + "(", + ")", + "$", + "^", + ".", + "*", + "+", + "?", + "[", + "]", + "|", + "\\", + "#", + "-", + "{", + "}", + "0123456789", + "b", + "B", + "<", + ">", + "", + "", + "A`", + "z'", + "\n", + ",", + "a", + "f", + "n", + "r", + "t", + "v", + "x", + "c", + ":", + "=", + "e", + "", + "", + "", + "", + "", + "", + "", + "", + "E", + "Q", + "X", + "C", + "Z", + "G", + "!", + "p", + "P", + "N", + "gk", + "K", + "R", + }; + + return ((n >= (sizeof(messages) / sizeof(messages[1]))) ? "" : messages[n]); +} + +BOOST_REGEX_DECL const char* BOOST_REGEX_CALL get_default_error_string(regex_constants::error_type n) +{ + static const char* const s_default_error_messages[] = { + "Success", /* REG_NOERROR 0 error_ok */ + "No match", /* REG_NOMATCH 1 error_no_match */ + "Invalid regular expression.", /* REG_BADPAT 2 error_bad_pattern */ + "Invalid collation character.", /* REG_ECOLLATE 3 error_collate */ + "Invalid character class name, collating name, or character range.", /* REG_ECTYPE 4 error_ctype */ + "Invalid or unterminated escape sequence.", /* REG_EESCAPE 5 error_escape */ + "Invalid back reference: specified capturing group does not exist.", /* REG_ESUBREG 6 error_backref */ + "Unmatched [ or [^ in character class declaration.", /* REG_EBRACK 7 error_brack */ + "Unmatched marking parenthesis ( or \\(.", /* REG_EPAREN 8 error_paren */ + "Unmatched quantified repeat operator { or \\{.", /* REG_EBRACE 9 error_brace */ + "Invalid content of repeat range.", /* REG_BADBR 10 error_badbrace */ + "Invalid range end in character class", /* REG_ERANGE 11 error_range */ + "Out of memory.", /* REG_ESPACE 12 error_space NOT USED */ + "Invalid preceding regular expression prior to repetition operator.", /* REG_BADRPT 13 error_badrepeat */ + "Premature end of regular expression", /* REG_EEND 14 error_end NOT USED */ + "Regular expression is too large.", /* REG_ESIZE 15 error_size NOT USED */ + "Unmatched ) or \\)", /* REG_ERPAREN 16 error_right_paren NOT USED */ + "Empty regular expression.", /* REG_EMPTY 17 error_empty */ + "The complexity of matching the regular expression exceeded predefined bounds. " + "Try refactoring the regular expression to make each choice made by the state machine unambiguous. " + "This exception is thrown to prevent \"eternal\" matches that take an " + "indefinite period time to locate.", /* REG_ECOMPLEXITY 18 error_complexity */ + "Ran out of stack space trying to match the regular expression.", /* REG_ESTACK 19 error_stack */ + "Invalid or unterminated Perl (?...) sequence.", /* REG_E_PERL 20 error_perl */ + "Unknown error.", /* REG_E_UNKNOWN 21 error_unknown */ + }; + + return (n > ::boost::regex_constants::error_unknown) ? s_default_error_messages[ ::boost::regex_constants::error_unknown] : s_default_error_messages[n]; +} + +BOOST_REGEX_DECL bool BOOST_REGEX_CALL is_combining_implementation(boost::uint_least16_t c) +{ + const boost::uint_least16_t combining_ranges[] = { 0x0300, 0x0361, + 0x0483, 0x0486, + 0x0903, 0x0903, + 0x093E, 0x0940, + 0x0949, 0x094C, + 0x0982, 0x0983, + 0x09BE, 0x09C0, + 0x09C7, 0x09CC, + 0x09D7, 0x09D7, + 0x0A3E, 0x0A40, + 0x0A83, 0x0A83, + 0x0ABE, 0x0AC0, + 0x0AC9, 0x0ACC, + 0x0B02, 0x0B03, + 0x0B3E, 0x0B3E, + 0x0B40, 0x0B40, + 0x0B47, 0x0B4C, + 0x0B57, 0x0B57, + 0x0B83, 0x0B83, + 0x0BBE, 0x0BBF, + 0x0BC1, 0x0BCC, + 0x0BD7, 0x0BD7, + 0x0C01, 0x0C03, + 0x0C41, 0x0C44, + 0x0C82, 0x0C83, + 0x0CBE, 0x0CBE, + 0x0CC0, 0x0CC4, + 0x0CC7, 0x0CCB, + 0x0CD5, 0x0CD6, + 0x0D02, 0x0D03, + 0x0D3E, 0x0D40, + 0x0D46, 0x0D4C, + 0x0D57, 0x0D57, + 0x0F7F, 0x0F7F, + 0x20D0, 0x20E1, + 0x3099, 0x309A, + 0xFE20, 0xFE23, + 0xffff, 0xffff, }; + + const boost::uint_least16_t* p = combining_ranges + 1; + while(*p < c) p += 2; + --p; + if((c >= *p) && (c <= *(p+1))) + return true; + return false; +} + +// +// these are the POSIX collating names: +// +BOOST_REGEX_DECL const char* def_coll_names[] = { +"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "alert", "backspace", "tab", "newline", +"vertical-tab", "form-feed", "carriage-return", "SO", "SI", "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", +"SYN", "ETB", "CAN", "EM", "SUB", "ESC", "IS4", "IS3", "IS2", "IS1", "space", "exclamation-mark", +"quotation-mark", "number-sign", "dollar-sign", "percent-sign", "ampersand", "apostrophe", +"left-parenthesis", "right-parenthesis", "asterisk", "plus-sign", "comma", "hyphen", +"period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", +"colon", "semicolon", "less-than-sign", "equals-sign", "greater-than-sign", +"question-mark", "commercial-at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", +"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "left-square-bracket", "backslash", +"right-square-bracket", "circumflex", "underscore", "grave-accent", "a", "b", "c", "d", "e", "f", +"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "left-curly-bracket", +"vertical-line", "right-curly-bracket", "tilde", "DEL", "", +}; + +// these multi-character collating elements +// should keep most Western-European locales +// happy - we should really localise these a +// little more - but this will have to do for +// now: + +BOOST_REGEX_DECL const char* def_multi_coll[] = { + "ae", + "Ae", + "AE", + "ch", + "Ch", + "CH", + "ll", + "Ll", + "LL", + "ss", + "Ss", + "SS", + "nj", + "Nj", + "NJ", + "dz", + "Dz", + "DZ", + "lj", + "Lj", + "LJ", + "", +}; + + + +BOOST_REGEX_DECL std::string BOOST_REGEX_CALL lookup_default_collate_name(const std::string& name) +{ + unsigned int i = 0; + while(*def_coll_names[i]) + { + if(def_coll_names[i] == name) + { + return std::string(1, char(i)); + } + ++i; + } + i = 0; + while(*def_multi_coll[i]) + { + if(def_multi_coll[i] == name) + { + return def_multi_coll[i]; + } + ++i; + } + return std::string(); +} + +BOOST_REGEX_DECL char BOOST_REGEX_CALL do_global_lower(char c) +{ + return static_cast((std::tolower)((unsigned char)c)); +} + +BOOST_REGEX_DECL char BOOST_REGEX_CALL do_global_upper(char c) +{ + return static_cast((std::toupper)((unsigned char)c)); +} +#ifndef BOOST_NO_WREGEX +BOOST_REGEX_DECL wchar_t BOOST_REGEX_CALL do_global_lower(wchar_t c) +{ + return (std::towlower)(c); +} + +BOOST_REGEX_DECL wchar_t BOOST_REGEX_CALL do_global_upper(wchar_t c) +{ + return (std::towupper)(c); +} +#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T +BOOST_REGEX_DECL unsigned short BOOST_REGEX_CALL do_global_lower(unsigned short c) +{ + return (std::towlower)(c); +} + +BOOST_REGEX_DECL unsigned short BOOST_REGEX_CALL do_global_upper(unsigned short c) +{ + return (std::towupper)(c); +} +#endif + +#endif + +BOOST_REGEX_DECL regex_constants::escape_syntax_type BOOST_REGEX_CALL get_default_escape_syntax_type(char c) +{ + // + // char_syntax determines how the compiler treats a given character + // in a regular expression. + // + static regex_constants::escape_syntax_type char_syntax[] = { + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /* */ // 32 + regex_constants::escape_type_identity, /*!*/ + regex_constants::escape_type_identity, /*"*/ + regex_constants::escape_type_identity, /*#*/ + regex_constants::escape_type_identity, /*$*/ + regex_constants::escape_type_identity, /*%*/ + regex_constants::escape_type_identity, /*&*/ + regex_constants::escape_type_end_buffer, /*'*/ + regex_constants::syntax_open_mark, /*(*/ + regex_constants::syntax_close_mark, /*)*/ + regex_constants::escape_type_identity, /***/ + regex_constants::syntax_plus, /*+*/ + regex_constants::escape_type_identity, /*,*/ + regex_constants::escape_type_identity, /*-*/ + regex_constants::escape_type_identity, /*.*/ + regex_constants::escape_type_identity, /*/*/ + regex_constants::escape_type_decimal, /*0*/ + regex_constants::escape_type_backref, /*1*/ + regex_constants::escape_type_backref, /*2*/ + regex_constants::escape_type_backref, /*3*/ + regex_constants::escape_type_backref, /*4*/ + regex_constants::escape_type_backref, /*5*/ + regex_constants::escape_type_backref, /*6*/ + regex_constants::escape_type_backref, /*7*/ + regex_constants::escape_type_backref, /*8*/ + regex_constants::escape_type_backref, /*9*/ + regex_constants::escape_type_identity, /*:*/ + regex_constants::escape_type_identity, /*;*/ + regex_constants::escape_type_left_word, /*<*/ + regex_constants::escape_type_identity, /*=*/ + regex_constants::escape_type_right_word, /*>*/ + regex_constants::syntax_question, /*?*/ + regex_constants::escape_type_identity, /*@*/ + regex_constants::escape_type_start_buffer, /*A*/ + regex_constants::escape_type_not_word_assert, /*B*/ + regex_constants::escape_type_C, /*C*/ + regex_constants::escape_type_not_class, /*D*/ + regex_constants::escape_type_E, /*E*/ + regex_constants::escape_type_not_class, /*F*/ + regex_constants::escape_type_G, /*G*/ + regex_constants::escape_type_not_class, /*H*/ + regex_constants::escape_type_not_class, /*I*/ + regex_constants::escape_type_not_class, /*J*/ + regex_constants::escape_type_reset_start_mark, /*K*/ + regex_constants::escape_type_not_class, /*L*/ + regex_constants::escape_type_not_class, /*M*/ + regex_constants::escape_type_named_char, /*N*/ + regex_constants::escape_type_not_class, /*O*/ + regex_constants::escape_type_not_property, /*P*/ + regex_constants::escape_type_Q, /*Q*/ + regex_constants::escape_type_line_ending, /*R*/ + regex_constants::escape_type_not_class, /*S*/ + regex_constants::escape_type_not_class, /*T*/ + regex_constants::escape_type_not_class, /*U*/ + regex_constants::escape_type_not_class, /*V*/ + regex_constants::escape_type_not_class, /*W*/ + regex_constants::escape_type_X, /*X*/ + regex_constants::escape_type_not_class, /*Y*/ + regex_constants::escape_type_Z, /*Z*/ + regex_constants::escape_type_identity, /*[*/ + regex_constants::escape_type_identity, /*\*/ + regex_constants::escape_type_identity, /*]*/ + regex_constants::escape_type_identity, /*^*/ + regex_constants::escape_type_identity, /*_*/ + regex_constants::escape_type_start_buffer, /*`*/ + regex_constants::escape_type_control_a, /*a*/ + regex_constants::escape_type_word_assert, /*b*/ + regex_constants::escape_type_ascii_control, /*c*/ + regex_constants::escape_type_class, /*d*/ + regex_constants::escape_type_e, /*e*/ + regex_constants::escape_type_control_f, /*f*/ + regex_constants::escape_type_extended_backref, /*g*/ + regex_constants::escape_type_class, /*h*/ + regex_constants::escape_type_class, /*i*/ + regex_constants::escape_type_class, /*j*/ + regex_constants::escape_type_extended_backref, /*k*/ + regex_constants::escape_type_class, /*l*/ + regex_constants::escape_type_class, /*m*/ + regex_constants::escape_type_control_n, /*n*/ + regex_constants::escape_type_class, /*o*/ + regex_constants::escape_type_property, /*p*/ + regex_constants::escape_type_class, /*q*/ + regex_constants::escape_type_control_r, /*r*/ + regex_constants::escape_type_class, /*s*/ + regex_constants::escape_type_control_t, /*t*/ + regex_constants::escape_type_class, /*u*/ + regex_constants::escape_type_control_v, /*v*/ + regex_constants::escape_type_class, /*w*/ + regex_constants::escape_type_hex, /*x*/ + regex_constants::escape_type_class, /*y*/ + regex_constants::escape_type_end_buffer, /*z*/ + regex_constants::syntax_open_brace, /*{*/ + regex_constants::syntax_or, /*|*/ + regex_constants::syntax_close_brace, /*}*/ + regex_constants::escape_type_identity, /*~*/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + }; + + return char_syntax[(unsigned char)c]; +} + +BOOST_REGEX_DECL regex_constants::syntax_type BOOST_REGEX_CALL get_default_syntax_type(char c) +{ + // + // char_syntax determines how the compiler treats a given character + // in a regular expression. + // + static regex_constants::syntax_type char_syntax[] = { + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_newline, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /* */ // 32 + regex_constants::syntax_not, /*!*/ + regex_constants::syntax_char, /*"*/ + regex_constants::syntax_hash, /*#*/ + regex_constants::syntax_dollar, /*$*/ + regex_constants::syntax_char, /*%*/ + regex_constants::syntax_char, /*&*/ + regex_constants::escape_type_end_buffer, /*'*/ + regex_constants::syntax_open_mark, /*(*/ + regex_constants::syntax_close_mark, /*)*/ + regex_constants::syntax_star, /***/ + regex_constants::syntax_plus, /*+*/ + regex_constants::syntax_comma, /*,*/ + regex_constants::syntax_dash, /*-*/ + regex_constants::syntax_dot, /*.*/ + regex_constants::syntax_char, /*/*/ + regex_constants::syntax_digit, /*0*/ + regex_constants::syntax_digit, /*1*/ + regex_constants::syntax_digit, /*2*/ + regex_constants::syntax_digit, /*3*/ + regex_constants::syntax_digit, /*4*/ + regex_constants::syntax_digit, /*5*/ + regex_constants::syntax_digit, /*6*/ + regex_constants::syntax_digit, /*7*/ + regex_constants::syntax_digit, /*8*/ + regex_constants::syntax_digit, /*9*/ + regex_constants::syntax_colon, /*:*/ + regex_constants::syntax_char, /*;*/ + regex_constants::escape_type_left_word, /*<*/ + regex_constants::syntax_equal, /*=*/ + regex_constants::escape_type_right_word, /*>*/ + regex_constants::syntax_question, /*?*/ + regex_constants::syntax_char, /*@*/ + regex_constants::syntax_char, /*A*/ + regex_constants::syntax_char, /*B*/ + regex_constants::syntax_char, /*C*/ + regex_constants::syntax_char, /*D*/ + regex_constants::syntax_char, /*E*/ + regex_constants::syntax_char, /*F*/ + regex_constants::syntax_char, /*G*/ + regex_constants::syntax_char, /*H*/ + regex_constants::syntax_char, /*I*/ + regex_constants::syntax_char, /*J*/ + regex_constants::syntax_char, /*K*/ + regex_constants::syntax_char, /*L*/ + regex_constants::syntax_char, /*M*/ + regex_constants::syntax_char, /*N*/ + regex_constants::syntax_char, /*O*/ + regex_constants::syntax_char, /*P*/ + regex_constants::syntax_char, /*Q*/ + regex_constants::syntax_char, /*R*/ + regex_constants::syntax_char, /*S*/ + regex_constants::syntax_char, /*T*/ + regex_constants::syntax_char, /*U*/ + regex_constants::syntax_char, /*V*/ + regex_constants::syntax_char, /*W*/ + regex_constants::syntax_char, /*X*/ + regex_constants::syntax_char, /*Y*/ + regex_constants::syntax_char, /*Z*/ + regex_constants::syntax_open_set, /*[*/ + regex_constants::syntax_escape, /*\*/ + regex_constants::syntax_close_set, /*]*/ + regex_constants::syntax_caret, /*^*/ + regex_constants::syntax_char, /*_*/ + regex_constants::syntax_char, /*`*/ + regex_constants::syntax_char, /*a*/ + regex_constants::syntax_char, /*b*/ + regex_constants::syntax_char, /*c*/ + regex_constants::syntax_char, /*d*/ + regex_constants::syntax_char, /*e*/ + regex_constants::syntax_char, /*f*/ + regex_constants::syntax_char, /*g*/ + regex_constants::syntax_char, /*h*/ + regex_constants::syntax_char, /*i*/ + regex_constants::syntax_char, /*j*/ + regex_constants::syntax_char, /*k*/ + regex_constants::syntax_char, /*l*/ + regex_constants::syntax_char, /*m*/ + regex_constants::syntax_char, /*n*/ + regex_constants::syntax_char, /*o*/ + regex_constants::syntax_char, /*p*/ + regex_constants::syntax_char, /*q*/ + regex_constants::syntax_char, /*r*/ + regex_constants::syntax_char, /*s*/ + regex_constants::syntax_char, /*t*/ + regex_constants::syntax_char, /*u*/ + regex_constants::syntax_char, /*v*/ + regex_constants::syntax_char, /*w*/ + regex_constants::syntax_char, /*x*/ + regex_constants::syntax_char, /*y*/ + regex_constants::syntax_char, /*z*/ + regex_constants::syntax_open_brace, /*{*/ + regex_constants::syntax_or, /*|*/ + regex_constants::syntax_close_brace, /*}*/ + regex_constants::syntax_char, /*~*/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + }; + + return char_syntax[(unsigned char)c]; +} + + +} // BOOST_REGEX_DETAIL_NS +} // boost diff --git a/libs/regex/src/static_mutex.cpp b/libs/regex/src/static_mutex.cpp new file mode 100644 index 0000000..35dd0c7 --- /dev/null +++ b/libs/regex/src/static_mutex.cpp @@ -0,0 +1,185 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE static_mutex.cpp + * VERSION see + * DESCRIPTION: Declares static_mutex lock type. + */ + +#define BOOST_REGEX_SOURCE +#include +#include + +#ifdef BOOST_HAS_THREADS + +#include + +#if defined(BOOST_HAS_WINTHREADS) +#ifndef NOMINMAX +# define NOMINMAX +#endif +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#endif + + +namespace boost{ + +#if defined(BOOST_HAS_PTHREADS) && defined(PTHREAD_MUTEX_INITIALIZER) + +scoped_static_mutex_lock::scoped_static_mutex_lock(static_mutex& m, bool lk) +: m_mutex(m), m_have_lock(false) +{ + if(lk) + lock(); +} + +scoped_static_mutex_lock::~scoped_static_mutex_lock() +{ + if(m_have_lock) + unlock(); +} + +void scoped_static_mutex_lock::lock() +{ + if(0 == m_have_lock) + { + // Client code will throw if this fails: + m_have_lock = (pthread_mutex_lock(&(m_mutex.m_mutex)) == 0); + } +} + +void scoped_static_mutex_lock::unlock() +{ + if(m_have_lock) + { + // If this fails there's nothing we can do except assert, + // exceptions are out of the question as this code is called + // from the lock's destructor: + BOOST_VERIFY(pthread_mutex_unlock(&(m_mutex.m_mutex)) == 0); + m_have_lock = false; + } +} + +#elif defined(BOOST_HAS_WINTHREADS) + +BOOST_STATIC_ASSERT(sizeof(LONG) == sizeof(boost::int32_t)); + +scoped_static_mutex_lock::scoped_static_mutex_lock(static_mutex& m, bool lk) +: m_mutex(m), m_have_lock(false) +{ + if(lk) + lock(); +} + +scoped_static_mutex_lock::~scoped_static_mutex_lock() +{ + if(m_have_lock) + unlock(); +} + +void scoped_static_mutex_lock::lock() +{ + if(0 == m_have_lock) + { +#if !defined(InterlockedCompareExchangePointer) + while(0 != InterlockedCompareExchange(reinterpret_cast((boost::uint_least16_t*)&(m_mutex.m_mutex)), (void*)1, 0)) +#else + while(0 != InterlockedCompareExchange(reinterpret_cast(&(m_mutex.m_mutex)), 1, 0)) +#endif + { + Sleep(0); + } + m_have_lock = true; + } +} + +void scoped_static_mutex_lock::unlock() +{ + if(m_have_lock) + { +#if !defined(InterlockedCompareExchangePointer) + InterlockedExchange((LONG*)&(m_mutex.m_mutex), 0); +#else + InterlockedExchange(reinterpret_cast(&(m_mutex.m_mutex)), 0); +#endif + m_have_lock = false; + } +} + +#else +// +// Portable version of a static mutex based on Boost.Thread library: +// +#include +#include + +boost::recursive_mutex* static_mutex::m_pmutex = 0; +boost::once_flag static_mutex::m_once = BOOST_ONCE_INIT; + +extern "C" BOOST_REGEX_DECL void boost_regex_free_static_mutex() +{ + delete static_mutex::m_pmutex; + static_mutex::m_pmutex = 0; +} + +void static_mutex::init() +{ + m_pmutex = new boost::recursive_mutex(); + int r = atexit(boost_regex_free_static_mutex); + BOOST_ASSERT(0 == r); +} + +scoped_static_mutex_lock::scoped_static_mutex_lock(static_mutex& , bool lk) +: m_plock(0), m_have_lock(false) +{ + if(lk) + lock(); +} + +scoped_static_mutex_lock::~scoped_static_mutex_lock() +{ + if(m_have_lock) + unlock(); + delete m_plock; +} + +void scoped_static_mutex_lock::lock() +{ + if(0 == m_have_lock) + { + boost::call_once(static_mutex::m_once,&static_mutex::init); + if(0 == m_plock) + m_plock = new boost::unique_lock(*static_mutex::m_pmutex, boost::defer_lock); + m_plock->lock(); + m_have_lock = true; + } +} + +void scoped_static_mutex_lock::unlock() +{ + if(m_have_lock) + { + m_plock->unlock(); + m_have_lock = false; + } +} + +#endif + +} + +#endif // BOOST_HAS_THREADS diff --git a/libs/regex/src/usinstances.cpp b/libs/regex/src/usinstances.cpp new file mode 100644 index 0000000..44ebd28 --- /dev/null +++ b/libs/regex/src/usinstances.cpp @@ -0,0 +1,81 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE: winstances.cpp + * VERSION: see + * DESCRIPTION: regex unsigned short template instances (MSVC only). + */ + +#define BOOST_REGEX_SOURCE +#ifdef _MSC_VER +#pragma warning(disable:4506) // 'no definition for inline function' +#endif + +#include +#include +#include + +#if defined(_DLL_CPPLIB) && !defined(_M_CEE_PURE) && defined(_NATIVE_WCHAR_T_DEFINED) \ + && !(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION) || defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER))\ + && BOOST_WORKAROUND(BOOST_MSVC, <1600) +// +// This is a horrible workaround, but without declaring these symbols extern we get +// duplicate symbol errors when linking if the application is built without +// /Zc:wchar_t +// +#ifdef _CRTIMP2_PURE +# define BOOST_REGEX_STDLIB_DECL _CRTIMP2_PURE +#else +# define BOOST_REGEX_STDLIB_DECL _CRTIMP2 +#endif + +namespace std{ + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +template class BOOST_REGEX_STDLIB_DECL allocator; +template class BOOST_REGEX_STDLIB_DECL _String_val >; +template class BOOST_REGEX_STDLIB_DECL basic_string, allocator >; +#endif + +#if BOOST_WORKAROUND(BOOST_MSVC, > 1300) && BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400)) +template<> BOOST_REGEX_STDLIB_DECL std::size_t __cdecl char_traits::length(unsigned short const*); +#endif + +template BOOST_REGEX_STDLIB_DECL bool __cdecl operator==( + const basic_string, allocator >&, + const basic_string, allocator >&); +template BOOST_REGEX_STDLIB_DECL bool __cdecl operator==( + const unsigned short *, + const basic_string, allocator >&); +template BOOST_REGEX_STDLIB_DECL bool __cdecl operator==( + const basic_string, allocator >&, + const unsigned short *); +template BOOST_REGEX_STDLIB_DECL bool __cdecl operator<( + const basic_string, allocator >&, + const basic_string, allocator >&); +template BOOST_REGEX_STDLIB_DECL bool __cdecl operator>( + const basic_string, allocator >&, + const basic_string, allocator >&); +} +#endif + +#include + +#if !defined(BOOST_NO_WREGEX) && defined(BOOST_REGEX_HAS_OTHER_WCHAR_T) && !defined(BOOST_REGEX_NO_EXTERNAL_TEMPLATES) +#define BOOST_REGEX_US_INSTANTIATE + +#include + +#endif + + diff --git a/libs/regex/src/w32_regex_traits.cpp b/libs/regex/src/w32_regex_traits.cpp new file mode 100644 index 0000000..5b5236a --- /dev/null +++ b/libs/regex/src/w32_regex_traits.cpp @@ -0,0 +1,654 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE w32_regex_traits.cpp + * VERSION see + * DESCRIPTION: Implements w32_regex_traits (and associated helper classes). + */ + +#define BOOST_REGEX_SOURCE +#include + +#if defined(_WIN32) && !defined(BOOST_REGEX_NO_W32) && !defined(BOOST_REGEX_NO_WIN32_LOCALE) +#include +#include + +#ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +# define NOMINMAX +#endif +#define NOGDI +#include + +#if defined(_MSC_VER) && !defined(_WIN32_WCE) && !defined(UNDER_CE) +#pragma comment(lib, "user32.lib") +#endif + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std{ + using ::memset; +} +#endif + +namespace boost{ namespace BOOST_REGEX_DETAIL_NS{ + +#ifdef BOOST_NO_ANSI_APIS +UINT get_code_page_for_locale_id(lcid_type idx) +{ + WCHAR code_page_string[7]; + if (::GetLocaleInfoW(idx, LOCALE_IDEFAULTANSICODEPAGE, code_page_string, 7) == 0) + return 0; + + return static_cast(_wtol(code_page_string)); +} +#endif + + +void w32_regex_traits_char_layer::init() +{ + // we need to start by initialising our syntax map so we know which + // character is used for which purpose: + std::memset(m_char_map, 0, sizeof(m_char_map)); + cat_type cat; + std::string cat_name(w32_regex_traits::get_catalog_name()); + if(cat_name.size()) + { + cat = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_open(cat_name); + if(!cat) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + ::boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if(cat) + { + for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + string_type mss = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, i, get_default_syntax(i)); + for(string_type::size_type j = 0; j < mss.size(); ++j) + { + m_char_map[static_cast(mss[j])] = i; + } + } + } + else + { + for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + const char* ptr = get_default_syntax(i); + while(ptr && *ptr) + { + m_char_map[static_cast(*ptr)] = i; + ++ptr; + } + } + } + // + // finish off by calculating our escape types: + // + unsigned char i = 'A'; + do + { + if(m_char_map[i] == 0) + { + if(::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, 0x0002u, (char)i)) + m_char_map[i] = regex_constants::escape_type_class; + else if(::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, 0x0001u, (char)i)) + m_char_map[i] = regex_constants::escape_type_not_class; + } + }while(0xFF != i++); + + // + // fill in lower case map: + // + char char_map[1 << CHAR_BIT]; + for(int ii = 0; ii < (1 << CHAR_BIT); ++ii) + char_map[ii] = static_cast(ii); +#ifndef BOOST_NO_ANSI_APIS + int r = ::LCMapStringA(this->m_locale, LCMAP_LOWERCASE, char_map, 1 << CHAR_BIT, this->m_lower_map, 1 << CHAR_BIT); + BOOST_ASSERT(r != 0); +#else + UINT code_page = get_code_page_for_locale_id(this->m_locale); + BOOST_ASSERT(code_page != 0); + + WCHAR wide_char_map[1 << CHAR_BIT]; + int conv_r = ::MultiByteToWideChar(code_page, 0, char_map, 1 << CHAR_BIT, wide_char_map, 1 << CHAR_BIT); + BOOST_ASSERT(conv_r != 0); + + WCHAR wide_lower_map[1 << CHAR_BIT]; + int r = ::LCMapStringW(this->m_locale, LCMAP_LOWERCASE, wide_char_map, 1 << CHAR_BIT, wide_lower_map, 1 << CHAR_BIT); + BOOST_ASSERT(r != 0); + + conv_r = ::WideCharToMultiByte(code_page, 0, wide_lower_map, r, this->m_lower_map, 1 << CHAR_BIT, NULL, NULL); + BOOST_ASSERT(conv_r != 0); +#endif + if(r < (1 << CHAR_BIT)) + { + // if we have multibyte characters then not all may have been given + // a lower case mapping: + for(int jj = r; jj < (1 << CHAR_BIT); ++jj) + this->m_lower_map[jj] = static_cast(jj); + } + +#ifndef BOOST_NO_ANSI_APIS + r = ::GetStringTypeExA(this->m_locale, CT_CTYPE1, char_map, 1 << CHAR_BIT, this->m_type_map); +#else + r = ::GetStringTypeExW(this->m_locale, CT_CTYPE1, wide_char_map, 1 << CHAR_BIT, this->m_type_map); +#endif + BOOST_ASSERT(0 != r); +} + +BOOST_REGEX_DECL lcid_type BOOST_REGEX_CALL w32_get_default_locale() +{ + return ::GetUserDefaultLCID(); +} + +BOOST_REGEX_DECL bool BOOST_REGEX_CALL w32_is_lower(char c, lcid_type idx) +{ +#ifndef BOOST_NO_ANSI_APIS + WORD mask; + if(::GetStringTypeExA(idx, CT_CTYPE1, &c, 1, &mask) && (mask & C1_LOWER)) + return true; + return false; +#else + UINT code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return false; + + WCHAR wide_c; + if (::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return false; + + WORD mask; + if(::GetStringTypeExW(idx, CT_CTYPE1, &wide_c, 1, &mask) && (mask & C1_LOWER)) + return true; + return false; +#endif +} + +BOOST_REGEX_DECL bool BOOST_REGEX_CALL w32_is_lower(wchar_t c, lcid_type idx) +{ + WORD mask; + if(::GetStringTypeExW(idx, CT_CTYPE1, &c, 1, &mask) && (mask & C1_LOWER)) + return true; + return false; +} +#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T +BOOST_REGEX_DECL bool BOOST_REGEX_CALL w32_is_lower(unsigned short ca, lcid_type idx) +{ + WORD mask; + wchar_t c = ca; + if(::GetStringTypeExW(idx, CT_CTYPE1, &c, 1, &mask) && (mask & C1_LOWER)) + return true; + return false; +} +#endif + +BOOST_REGEX_DECL bool BOOST_REGEX_CALL w32_is_upper(char c, lcid_type idx) +{ +#ifndef BOOST_NO_ANSI_APIS + WORD mask; + if(::GetStringTypeExA(idx, CT_CTYPE1, &c, 1, &mask) && (mask & C1_UPPER)) + return true; + return false; +#else + UINT code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return false; + + WCHAR wide_c; + if (::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return false; + + WORD mask; + if(::GetStringTypeExW(idx, CT_CTYPE1, &wide_c, 1, &mask) && (mask & C1_UPPER)) + return true; + return false; +#endif +} + +BOOST_REGEX_DECL bool BOOST_REGEX_CALL w32_is_upper(wchar_t c, lcid_type idx) +{ + WORD mask; + if(::GetStringTypeExW(idx, CT_CTYPE1, &c, 1, &mask) && (mask & C1_UPPER)) + return true; + return false; +} +#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T +BOOST_REGEX_DECL bool BOOST_REGEX_CALL w32_is_upper(unsigned short ca, lcid_type idx) +{ + WORD mask; + wchar_t c = ca; + if(::GetStringTypeExW(idx, CT_CTYPE1, &c, 1, &mask) && (mask & C1_UPPER)) + return true; + return false; +} +#endif + +void free_module(void* mod) +{ + ::FreeLibrary(static_cast(mod)); +} + +BOOST_REGEX_DECL cat_type BOOST_REGEX_CALL w32_cat_open(const std::string& name) +{ +#ifndef BOOST_NO_ANSI_APIS + cat_type result(::LoadLibraryA(name.c_str()), &free_module); + return result; +#else + LPWSTR wide_name = (LPWSTR)_alloca( (name.size() + 1) * sizeof(WCHAR) ); + if (::MultiByteToWideChar(CP_ACP, 0, name.c_str(), name.size(), wide_name, name.size() + 1) == 0) + return cat_type(); + + cat_type result(::LoadLibraryW(wide_name), &free_module); + return result; +#endif +} + +BOOST_REGEX_DECL std::string BOOST_REGEX_CALL w32_cat_get(const cat_type& cat, lcid_type, int i, const std::string& def) +{ +#ifndef BOOST_NO_ANSI_APIS + char buf[256]; + if(0 == ::LoadStringA( + static_cast(cat.get()), + i, + buf, + 256 + )) + { + return def; + } +#else + WCHAR wbuf[256]; + int r = ::LoadStringW( + static_cast(cat.get()), + i, + wbuf, + 256 + ); + if (r == 0) + return def; + + + int buf_size = 1 + ::WideCharToMultiByte(CP_ACP, 0, wbuf, r, NULL, 0, NULL, NULL); + LPSTR buf = (LPSTR)_alloca(buf_size); + if (::WideCharToMultiByte(CP_ACP, 0, wbuf, r, buf, buf_size, NULL, NULL) == 0) + return def; // failed conversion. +#endif + return std::string(buf); +} + +#ifndef BOOST_NO_WREGEX +BOOST_REGEX_DECL std::wstring BOOST_REGEX_CALL w32_cat_get(const cat_type& cat, lcid_type, int i, const std::wstring& def) +{ + wchar_t buf[256]; + if(0 == ::LoadStringW( + static_cast(cat.get()), + i, + buf, + 256 + )) + { + return def; + } + return std::wstring(buf); +} +#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T +BOOST_REGEX_DECL std::basic_string BOOST_REGEX_CALL w32_cat_get(const cat_type& cat, lcid_type, int i, const std::basic_string& def) +{ + unsigned short buf[256]; + if(0 == ::LoadStringW( + static_cast(cat.get()), + i, + (LPWSTR)buf, + 256 + )) + { + return def; + } + return std::basic_string(buf); +} +#endif +#endif +BOOST_REGEX_DECL std::string BOOST_REGEX_CALL w32_transform(lcid_type idx, const char* p1, const char* p2) +{ +#ifndef BOOST_NO_ANSI_APIS + int bytes = ::LCMapStringA( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + p1, // source string + static_cast(p2 - p1), // number of characters in source string + 0, // destination buffer + 0 // size of destination buffer + ); + if(!bytes) + return std::string(p1, p2); + std::string result(++bytes, '\0'); + bytes = ::LCMapStringA( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + p1, // source string + static_cast(p2 - p1), // number of characters in source string + &*result.begin(), // destination buffer + bytes // size of destination buffer + ); +#else + UINT code_page = get_code_page_for_locale_id(idx); + if(code_page == 0) + return std::string(p1, p2); + + int src_len = static_cast(p2 - p1); + LPWSTR wide_p1 = (LPWSTR)_alloca( (src_len + 1) * 2 ); + if(::MultiByteToWideChar(code_page, 0, p1, src_len, wide_p1, src_len + 1) == 0) + return std::string(p1, p2); + + int bytes = ::LCMapStringW( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + wide_p1, // source string + src_len, // number of characters in source string + 0, // destination buffer + 0 // size of destination buffer + ); + if(!bytes) + return std::string(p1, p2); + std::string result(++bytes, '\0'); + bytes = ::LCMapStringW( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + wide_p1, // source string + src_len, // number of characters in source string + (LPWSTR)&*result.begin(), // destination buffer + bytes // size of destination buffer + ); +#endif + if(bytes > static_cast(result.size())) + return std::string(p1, p2); + while(result.size() && result[result.size()-1] == '\0') + { + result.erase(result.size()-1); + } + return result; +} + +#ifndef BOOST_NO_WREGEX +BOOST_REGEX_DECL std::wstring BOOST_REGEX_CALL w32_transform(lcid_type idx, const wchar_t* p1, const wchar_t* p2) +{ + int bytes = ::LCMapStringW( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + p1, // source string + static_cast(p2 - p1), // number of characters in source string + 0, // destination buffer + 0 // size of destination buffer + ); + if(!bytes) + return std::wstring(p1, p2); + std::string result(++bytes, '\0'); + bytes = ::LCMapStringW( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + p1, // source string + static_cast(p2 - p1), // number of characters in source string + reinterpret_cast(&*result.begin()), // destination buffer *of bytes* + bytes // size of destination buffer + ); + if(bytes > static_cast(result.size())) + return std::wstring(p1, p2); + while(result.size() && result[result.size()-1] == L'\0') + { + result.erase(result.size()-1); + } + std::wstring r2; + for(std::string::size_type i = 0; i < result.size(); ++i) + r2.append(1, static_cast(static_cast(result[i]))); + return r2; +} +#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T +BOOST_REGEX_DECL std::basic_string BOOST_REGEX_CALL w32_transform(lcid_type idx, const unsigned short* p1, const unsigned short* p2) +{ + int bytes = ::LCMapStringW( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + (LPCWSTR)p1, // source string + static_cast(p2 - p1), // number of characters in source string + 0, // destination buffer + 0 // size of destination buffer + ); + if(!bytes) + return std::basic_string(p1, p2); + std::string result(++bytes, '\0'); + bytes = ::LCMapStringW( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + (LPCWSTR)p1, // source string + static_cast(p2 - p1), // number of characters in source string + reinterpret_cast(&*result.begin()), // destination buffer *of bytes* + bytes // size of destination buffer + ); + if(bytes > static_cast(result.size())) + return std::basic_string(p1, p2); + while(result.size() && result[result.size()-1] == L'\0') + { + result.erase(result.size()-1); + } + std::basic_string r2; + for(std::string::size_type i = 0; i < result.size(); ++i) + r2.append(1, static_cast(static_cast(result[i]))); + return r2; +} +#endif +#endif +BOOST_REGEX_DECL char BOOST_REGEX_CALL w32_tolower(char c, lcid_type idx) +{ + char result[2]; +#ifndef BOOST_NO_ANSI_APIS + int b = ::LCMapStringA( + idx, // locale identifier + LCMAP_LOWERCASE, // mapping transformation type + &c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if(b == 0) + return c; +#else + UINT code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return c; + + WCHAR wide_c; + if (::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return c; + + WCHAR wide_result; + int b = ::LCMapStringW( + idx, // locale identifier + LCMAP_LOWERCASE, // mapping transformation type + &wide_c, // source string + 1, // number of characters in source string + &wide_result, // destination buffer + 1); // size of destination buffer + if(b == 0) + return c; + + if (::WideCharToMultiByte(code_page, 0, &wide_result, 1, result, 2, NULL, NULL) == 0) + return c; // No single byte lower case equivalent available +#endif + return result[0]; +} + +#ifndef BOOST_NO_WREGEX +BOOST_REGEX_DECL wchar_t BOOST_REGEX_CALL w32_tolower(wchar_t c, lcid_type idx) +{ + wchar_t result[2]; + int b = ::LCMapStringW( + idx, // locale identifier + LCMAP_LOWERCASE, // mapping transformation type + &c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if(b == 0) + return c; + return result[0]; +} +#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T +BOOST_REGEX_DECL unsigned short BOOST_REGEX_CALL w32_tolower(unsigned short c, lcid_type idx) +{ + wchar_t result[2]; + int b = ::LCMapStringW( + idx, // locale identifier + LCMAP_LOWERCASE, // mapping transformation type + (wchar_t const*)&c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if(b == 0) + return c; + return result[0]; +} +#endif +#endif +BOOST_REGEX_DECL char BOOST_REGEX_CALL w32_toupper(char c, lcid_type idx) +{ + char result[2]; +#ifndef BOOST_NO_ANSI_APIS + int b = ::LCMapStringA( + idx, // locale identifier + LCMAP_UPPERCASE, // mapping transformation type + &c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if(b == 0) + return c; +#else + UINT code_page = get_code_page_for_locale_id(idx); + if(code_page == 0) + return c; + + WCHAR wide_c; + if (::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return c; + + WCHAR wide_result; + int b = ::LCMapStringW( + idx, // locale identifier + LCMAP_UPPERCASE, // mapping transformation type + &wide_c, // source string + 1, // number of characters in source string + &wide_result, // destination buffer + 1); // size of destination buffer + if(b == 0) + return c; + + if (::WideCharToMultiByte(code_page, 0, &wide_result, 1, result, 2, NULL, NULL) == 0) + return c; // No single byte upper case equivalent available. +#endif + return result[0]; +} + +#ifndef BOOST_NO_WREGEX +BOOST_REGEX_DECL wchar_t BOOST_REGEX_CALL w32_toupper(wchar_t c, lcid_type idx) +{ + wchar_t result[2]; + int b = ::LCMapStringW( + idx, // locale identifier + LCMAP_UPPERCASE, // mapping transformation type + &c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if(b == 0) + return c; + return result[0]; +} +#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T +BOOST_REGEX_DECL unsigned short BOOST_REGEX_CALL w32_toupper(unsigned short c, lcid_type idx) +{ + wchar_t result[2]; + int b = ::LCMapStringW( + idx, // locale identifier + LCMAP_UPPERCASE, // mapping transformation type + (wchar_t const*)&c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if(b == 0) + return c; + return result[0]; +} +#endif +#endif +BOOST_REGEX_DECL bool BOOST_REGEX_CALL w32_is(lcid_type idx, boost::uint32_t m, char c) +{ + WORD mask; +#ifndef BOOST_NO_ANSI_APIS + if(::GetStringTypeExA(idx, CT_CTYPE1, &c, 1, &mask) && (mask & m & w32_regex_traits_implementation::mask_base)) + return true; +#else + UINT code_page = get_code_page_for_locale_id(idx); + if(code_page == 0) + return false; + + WCHAR wide_c; + if (::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return false; + + if(::GetStringTypeExW(idx, CT_CTYPE1, &wide_c, 1, &mask) && (mask & m & w32_regex_traits_implementation::mask_base)) + return true; +#endif + if((m & w32_regex_traits_implementation::mask_word) && (c == '_')) + return true; + return false; +} + +#ifndef BOOST_NO_WREGEX +BOOST_REGEX_DECL bool BOOST_REGEX_CALL w32_is(lcid_type idx, boost::uint32_t m, wchar_t c) +{ + WORD mask; + if(::GetStringTypeExW(idx, CT_CTYPE1, &c, 1, &mask) && (mask & m & w32_regex_traits_implementation::mask_base)) + return true; + if((m & w32_regex_traits_implementation::mask_word) && (c == '_')) + return true; + if((m & w32_regex_traits_implementation::mask_unicode) && (c > 0xff)) + return true; + return false; +} +#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T +BOOST_REGEX_DECL bool BOOST_REGEX_CALL w32_is(lcid_type idx, boost::uint32_t m, unsigned short c) +{ + WORD mask; + if(::GetStringTypeExW(idx, CT_CTYPE1, (wchar_t const*)&c, 1, &mask) && (mask & m & w32_regex_traits_implementation::mask_base)) + return true; + if((m & w32_regex_traits_implementation::mask_word) && (c == '_')) + return true; + if((m & w32_regex_traits_implementation::mask_unicode) && (c > 0xff)) + return true; + return false; +} +#endif +#endif + +} // BOOST_REGEX_DETAIL_NS +} // boost + +#endif + diff --git a/libs/regex/src/wc_regex_traits.cpp b/libs/regex/src/wc_regex_traits.cpp new file mode 100644 index 0000000..e7fcfb8 --- /dev/null +++ b/libs/regex/src/wc_regex_traits.cpp @@ -0,0 +1,314 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE: wc_regex_traits.cpp + * VERSION: see + * DESCRIPTION: Implements out of line members for c_regex_traits + */ + + +#define BOOST_REGEX_SOURCE + +#include +#include +#include +#include "internals.hpp" + +#if defined(_DLL_CPPLIB) && !defined(_M_CEE_PURE) && defined(_NATIVE_WCHAR_T_DEFINED) \ + && !(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION) || defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER))\ + && BOOST_WORKAROUND(BOOST_MSVC, <1600) +// +// This is a horrible workaround, but without declaring these symbols extern we get +// duplicate symbol errors when linking if the application is built without +// /Zc:wchar_t +// +#ifdef _CRTIMP2_PURE +# define BOOST_REGEX_STDLIB_DECL _CRTIMP2_PURE +#else +# define BOOST_REGEX_STDLIB_DECL _CRTIMP2 +#endif + +namespace std{ + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +template class BOOST_REGEX_STDLIB_DECL allocator; +template class BOOST_REGEX_STDLIB_DECL _String_val >; +template class BOOST_REGEX_STDLIB_DECL basic_string, allocator >; +#endif + +#if BOOST_WORKAROUND(BOOST_MSVC, > 1300) && BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1400)) +template<> BOOST_REGEX_STDLIB_DECL std::size_t __cdecl char_traits::length(unsigned short const*); +#endif + +template BOOST_REGEX_STDLIB_DECL bool __cdecl operator==( + const basic_string, allocator >&, + const basic_string, allocator >&); +template BOOST_REGEX_STDLIB_DECL bool __cdecl operator==( + const unsigned short *, + const basic_string, allocator >&); +template BOOST_REGEX_STDLIB_DECL bool __cdecl operator==( + const basic_string, allocator >&, + const unsigned short *); +template BOOST_REGEX_STDLIB_DECL bool __cdecl operator<( + const basic_string, allocator >&, + const basic_string, allocator >&); +template BOOST_REGEX_STDLIB_DECL bool __cdecl operator>( + const basic_string, allocator >&, + const basic_string, allocator >&); +} +#endif + +#include +#include + +#if !BOOST_WORKAROUND(__BORLANDC__, < 0x560) + +#include +#ifndef BOOST_NO_WREGEX +#include +#include + +#if defined(BOOST_NO_STDC_NAMESPACE) +namespace std{ + using ::wcstol; +} +#endif + +namespace boost{ + +c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::transform(const wchar_t* p1, const wchar_t* p2) +{ + std::size_t r; + std::size_t s = 10; + std::wstring src(p1, p2); + std::wstring result(s, L' '); + while(s < (r = std::wcsxfrm(&*result.begin(), src.c_str(), s))) + { +#if defined(_CPPLIB_VER) + // + // A bug in VC11 and 12 causes the program to hang if we pass a null-string + // to std::strxfrm, but only for certain locales :-( + // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware). + // + if(r == INT_MAX) + { + result.erase(); + result.insert(result.begin(), static_cast(0)); + return result; + } +#endif + result.append(r - s + 3, L' '); + s = result.size(); + } + result.erase(r); + return result; +} + +c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::transform_primary(const wchar_t* p1, const wchar_t* p2) +{ + static wchar_t s_delim; + static const int s_collate_type = ::boost::BOOST_REGEX_DETAIL_NS::find_sort_syntax(static_cast*>(0), &s_delim); + std::wstring result; + // + // What we do here depends upon the format of the sort key returned by + // sort key returned by this->transform: + // + switch(s_collate_type) + { + case ::boost::BOOST_REGEX_DETAIL_NS::sort_C: + case ::boost::BOOST_REGEX_DETAIL_NS::sort_unknown: + // the best we can do is translate to lower case, then get a regular sort key: + { + result.assign(p1, p2); + for(std::wstring::size_type i = 0; i < result.size(); ++i) + result[i] = (std::towlower)(result[i]); + result = c_regex_traits::transform(&*result.begin(), &*result.begin() + result.size()); + break; + } + case ::boost::BOOST_REGEX_DETAIL_NS::sort_fixed: + { + // get a regular sort key, and then truncate it: + result = c_regex_traits::transform(&*result.begin(), &*result.begin() + result.size()); + result.erase(s_delim); + break; + } + case ::boost::BOOST_REGEX_DETAIL_NS::sort_delim: + // get a regular sort key, and then truncate everything after the delim: + result = c_regex_traits::transform(&*result.begin(), &*result.begin() + result.size()); + if(result.size() && (result[0] == s_delim)) + break; + std::size_t i; + for(i = 0; i < result.size(); ++i) + { + if(result[i] == s_delim) + break; + } + result.erase(i); + break; + } + if(result.empty()) + result = std::wstring(1, char(0)); + return result; +} + +c_regex_traits::char_class_type BOOST_REGEX_CALL c_regex_traits::lookup_classname(const wchar_t* p1, const wchar_t* p2) +{ + static const char_class_type masks[] = + { + 0, + char_class_alnum, + char_class_alpha, + char_class_blank, + char_class_cntrl, + char_class_digit, + char_class_digit, + char_class_graph, + char_class_horizontal, + char_class_lower, + char_class_lower, + char_class_print, + char_class_punct, + char_class_space, + char_class_space, + char_class_upper, + char_class_unicode, + char_class_upper, + char_class_vertical, + char_class_alnum | char_class_word, + char_class_alnum | char_class_word, + char_class_xdigit, + }; + + int idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + if(idx < 0) + { + std::wstring s(p1, p2); + for(std::wstring::size_type i = 0; i < s.size(); ++i) + s[i] = (std::towlower)(s[i]); + idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size()); + } + BOOST_ASSERT(idx+1 < static_cast(sizeof(masks) / sizeof(masks[0]))); + return masks[idx+1]; +} + +bool BOOST_REGEX_CALL c_regex_traits::isctype(wchar_t c, char_class_type mask) +{ + return + ((mask & char_class_space) && (std::iswspace)(c)) + || ((mask & char_class_print) && (std::iswprint)(c)) + || ((mask & char_class_cntrl) && (std::iswcntrl)(c)) + || ((mask & char_class_upper) && (std::iswupper)(c)) + || ((mask & char_class_lower) && (std::iswlower)(c)) + || ((mask & char_class_alpha) && (std::iswalpha)(c)) + || ((mask & char_class_digit) && (std::iswdigit)(c)) + || ((mask & char_class_punct) && (std::iswpunct)(c)) + || ((mask & char_class_xdigit) && (std::iswxdigit)(c)) + || ((mask & char_class_blank) && (std::iswspace)(c) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c)) + || ((mask & char_class_word) && (c == '_')) + || ((mask & char_class_unicode) && (c & ~static_cast(0xff))) + || ((mask & char_class_vertical) && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == L'\v'))) + || ((mask & char_class_horizontal) && (std::iswspace)(c) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) && (c != L'\v')); +} + +c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::lookup_collatename(const wchar_t* p1, const wchar_t* p2) +{ +#if !defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)\ + && !BOOST_WORKAROUND(BOOST_MSVC, < 1300)\ + && !BOOST_WORKAROUND(__BORLANDC__, <= 0x0551) + std::string name(p1, p2); +#else + std::string name; + const wchar_t* p0 = p1; + while(p0 != p2) + name.append(1, char(*p0++)); +#endif + name = ::boost::BOOST_REGEX_DETAIL_NS::lookup_default_collate_name(name); +#if !defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)\ + && !BOOST_WORKAROUND(BOOST_MSVC, < 1300)\ + && !BOOST_WORKAROUND(__BORLANDC__, <= 0x0551) + if(name.size()) + return string_type(name.begin(), name.end()); +#else + if(name.size()) + { + string_type result; + typedef std::string::const_iterator iter; + iter b = name.begin(); + iter e = name.end(); + while(b != e) + result.append(1, wchar_t(*b++)); + return result; + } +#endif + if(p2 - p1 == 1) + return string_type(1, *p1); + return string_type(); +} + +int BOOST_REGEX_CALL c_regex_traits::value(wchar_t c, int radix) +{ +#ifdef __BORLANDC__ + // workaround for broken wcstol: + if((std::iswxdigit)(c) == 0) + return -1; +#endif + wchar_t b[2] = { c, '\0', }; + wchar_t* ep; + int result = std::wcstol(b, &ep, radix); + if(ep == b) + return -1; + return result; +} + +#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T +c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::transform(const unsigned short* p1, const unsigned short* p2) +{ + std::wstring result = c_regex_traits::transform((const wchar_t*)p1, (const wchar_t*)p2); + return string_type(result.begin(), result.end()); +} + +c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::transform_primary(const unsigned short* p1, const unsigned short* p2) +{ + std::wstring result = c_regex_traits::transform_primary((const wchar_t*)p1, (const wchar_t*)p2); + return string_type(result.begin(), result.end()); +} + +c_regex_traits::char_class_type BOOST_REGEX_CALL c_regex_traits::lookup_classname(const unsigned short* p1, const unsigned short* p2) +{ + return c_regex_traits::lookup_classname((const wchar_t*)p1, (const wchar_t*)p2); +} + +c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::lookup_collatename(const unsigned short* p1, const unsigned short* p2) +{ + std::wstring result = c_regex_traits::lookup_collatename((const wchar_t*)p1, (const wchar_t*)p2); + return string_type(result.begin(), result.end()); +} + +bool BOOST_REGEX_CALL c_regex_traits::isctype(unsigned short c, char_class_type m) +{ + return c_regex_traits::isctype(c, m); +} + +int BOOST_REGEX_CALL c_regex_traits::value(unsigned short c, int radix) +{ + return c_regex_traits::value(c, radix); +} + +#endif + +} + +#endif // BOOST_NO_WREGEX + +#endif // __BORLANDC__ + diff --git a/libs/regex/src/wide_posix_api.cpp b/libs/regex/src/wide_posix_api.cpp new file mode 100644 index 0000000..bc1c0af --- /dev/null +++ b/libs/regex/src/wide_posix_api.cpp @@ -0,0 +1,312 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE: wide_posix_api.cpp + * VERSION: see + * DESCRIPTION: Implements the wide character POSIX API wrappers. + */ + +#define BOOST_REGEX_SOURCE + +#include + +#ifndef BOOST_NO_WREGEX + +#include +#include + +#include +#include +#include + +#ifdef BOOST_INTEL +#pragma warning(disable:981) +#endif + +#if defined(BOOST_NO_STDC_NAMESPACE) || defined(__NetBSD__) +namespace std{ +# ifndef BOOST_NO_SWPRINTF + using ::swprintf; +# endif +} +#endif + + +namespace boost{ + +namespace { + +unsigned int wmagic_value = 28631; + +const wchar_t* wnames[] = { + L"REG_NOERROR", + L"REG_NOMATCH", + L"REG_BADPAT", + L"REG_ECOLLATE", + L"REG_ECTYPE", + L"REG_EESCAPE", + L"REG_ESUBREG", + L"REG_EBRACK", + L"REG_EPAREN", + L"REG_EBRACE", + L"REG_BADBR", + L"REG_ERANGE", + L"REG_ESPACE", + L"REG_BADRPT", + L"REG_EEND", + L"REG_ESIZE", + L"REG_ERPAREN", + L"REG_EMPTY", + L"REG_ECOMPLEXITY", + L"REG_ESTACK", + L"REG_E_PERL", + L"REG_E_UNKNOWN", +}; +} + +typedef boost::basic_regex > wc_regex_type; + +BOOST_REGEX_DECL int BOOST_REGEX_CCALL regcompW(regex_tW* expression, const wchar_t* ptr, int f) +{ +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + expression->guts = new wc_regex_type(); +#ifndef BOOST_NO_EXCEPTIONS + } catch(...) + { + expression->guts = 0; + return REG_ESPACE; + } +#else + if(0 == expression->guts) + return REG_E_MEMORY; +#endif + // set default flags: + boost::uint_fast32_t flags = (f & REG_PERLEX) ? 0 : ((f & REG_EXTENDED) ? wregex::extended : wregex::basic); + expression->eflags = (f & REG_NEWLINE) ? match_not_dot_newline : match_default; + + // and translate those that are actually set: + if(f & REG_NOCOLLATE) + { + flags |= wregex::nocollate; +#ifndef BOOST_REGEX_V3 + flags &= ~wregex::collate; +#endif + } + + if(f & REG_NOSUB) + { + //expression->eflags |= match_any; + flags |= wregex::nosubs; + } + + if(f & REG_NOSPEC) + flags |= wregex::literal; + if(f & REG_ICASE) + flags |= wregex::icase; + if(f & REG_ESCAPE_IN_LISTS) + flags &= ~wregex::no_escape_in_lists; + if(f & REG_NEWLINE_ALT) + flags |= wregex::newline_alt; + + const wchar_t* p2; + if(f & REG_PEND) + p2 = expression->re_endp; + else p2 = ptr + std::wcslen(ptr); + + int result; + +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + expression->re_magic = wmagic_value; + static_cast(expression->guts)->set_expression(ptr, p2, flags); + expression->re_nsub = static_cast(expression->guts)->mark_count(); + result = static_cast(expression->guts)->error_code(); +#ifndef BOOST_NO_EXCEPTIONS + } + catch(const boost::regex_error& be) + { + result = be.code(); + } + catch(...) + { + result = REG_E_UNKNOWN; + } +#endif + if(result) + regfreeW(expression); + return result; + +} + +BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorW(int code, const regex_tW* e, wchar_t* buf, regsize_t buf_size) +{ + std::size_t result = 0; + if(code & REG_ITOA) + { + code &= ~REG_ITOA; + if((code <= (int)REG_E_UNKNOWN) && (code >= 0)) + { + result = std::wcslen(wnames[code]) + 1; + if(buf_size >= result) +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(_WIN32_WCE) && !defined(UNDER_CE) + ::wcscpy_s(buf, buf_size, wnames[code]); +#else + std::wcscpy(buf, wnames[code]); +#endif + return result; + } + return result; + } +#if !defined(BOOST_NO_SWPRINTF) + if(code == REG_ATOI) + { + wchar_t localbuf[5]; + if(e == 0) + return 0; + for(int i = 0; i <= (int)REG_E_UNKNOWN; ++i) + { + if(std::wcscmp(e->re_endp, wnames[i]) == 0) + { +#if defined(_WIN32_WCE) && !defined(UNDER_CE) + (std::swprintf)(localbuf, L"%d", i); +#else + (std::swprintf)(localbuf, 5, L"%d", i); +#endif + if(std::wcslen(localbuf) < buf_size) +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(_WIN32_WCE) && !defined(UNDER_CE) + ::wcscpy_s(buf, buf_size, localbuf); +#else + std::wcscpy(buf, localbuf); +#endif + return std::wcslen(localbuf) + 1; + } + } +#if defined(_WIN32_WCE) && !defined(UNDER_CE) + (std::swprintf)(localbuf, L"%d", 0); +#else + (std::swprintf)(localbuf, 5, L"%d", 0); +#endif + if(std::wcslen(localbuf) < buf_size) +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) && !defined(_WIN32_WCE) && !defined(UNDER_CE) + ::wcscpy_s(buf, buf_size, localbuf); +#else + std::wcscpy(buf, localbuf); +#endif + return std::wcslen(localbuf) + 1; + } +#endif + if(code <= (int)REG_E_UNKNOWN) + { + std::string p; + if((e) && (e->re_magic == wmagic_value)) + p = static_cast(e->guts)->get_traits().error_string(static_cast< ::boost::regex_constants::error_type>(code)); + else + { + p = BOOST_REGEX_DETAIL_NS::get_default_error_string(static_cast< ::boost::regex_constants::error_type>(code)); + } + std::size_t len = p.size(); + if(len < buf_size) + { + BOOST_REGEX_DETAIL_NS::copy(p.c_str(), p.c_str() + p.size() + 1, buf); + } + return len + 1; + } + if(buf_size) + *buf = 0; + return 0; +} + +BOOST_REGEX_DECL int BOOST_REGEX_CCALL regexecW(const regex_tW* expression, const wchar_t* buf, regsize_t n, regmatch_t* array, int eflags) +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4267) +#endif + bool result = false; + match_flag_type flags = match_default | expression->eflags; + const wchar_t* end; + const wchar_t* start; + wcmatch m; + + if(eflags & REG_NOTBOL) + flags |= match_not_bol; + if(eflags & REG_NOTEOL) + flags |= match_not_eol; + if(eflags & REG_STARTEND) + { + start = buf + array[0].rm_so; + end = buf + array[0].rm_eo; + } + else + { + start = buf; + end = buf + std::wcslen(buf); + } + +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + if(expression->re_magic == wmagic_value) + { + result = regex_search(start, end, m, *static_cast(expression->guts), flags); + } + else + return result; +#ifndef BOOST_NO_EXCEPTIONS + } catch(...) + { + return REG_E_UNKNOWN; + } +#endif + if(result) + { + // extract what matched: + std::size_t i; + for(i = 0; (i < n) && (i < expression->re_nsub + 1); ++i) + { + array[i].rm_so = (m[i].matched == false) ? -1 : (m[i].first - buf); + array[i].rm_eo = (m[i].matched == false) ? -1 : (m[i].second - buf); + } + // and set anything else to -1: + for(i = expression->re_nsub + 1; i < n; ++i) + { + array[i].rm_so = -1; + array[i].rm_eo = -1; + } + return 0; + } + return REG_NOMATCH; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +BOOST_REGEX_DECL void BOOST_REGEX_CCALL regfreeW(regex_tW* expression) +{ + if(expression->re_magic == wmagic_value) + { + delete static_cast(expression->guts); + } + expression->re_magic = 0; +} + +} // namespace boost; + +#endif + + + + diff --git a/libs/regex/src/winstances.cpp b/libs/regex/src/winstances.cpp new file mode 100644 index 0000000..1e0b859 --- /dev/null +++ b/libs/regex/src/winstances.cpp @@ -0,0 +1,35 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE: winstances.cpp + * VERSION: see + * DESCRIPTION: regex wide character template instances. + */ + +#define BOOST_REGEX_SOURCE + +#include + +#if !defined(BOOST_NO_WREGEX) && !defined(BOOST_REGEX_NO_EXTERNAL_TEMPLATES) +#define BOOST_REGEX_WIDE_INSTANTIATE + +#ifdef __BORLANDC__ +#pragma hrdstop +#endif + +#include + +#endif + + + diff --git a/libs/regex/test/config_info/regex_config_info.cpp b/libs/regex/test/config_info/regex_config_info.cpp new file mode 100644 index 0000000..211e9ec --- /dev/null +++ b/libs/regex/test/config_info/regex_config_info.cpp @@ -0,0 +1,73 @@ +/* + * + * Copyright (c) 2003 + * John Maddock + * + * Use, modification and distribution are subject to 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) + * + */ + +// +// This program extends config_info to print out regex library +// configuration information. We do this by redfining the main +// provided by config_info, our real main will call it later: +// +#ifndef OLD_MAIN +# define OLD_MAIN info_main +#endif + +#define main OLD_MAIN +#include +#undef main +#ifndef NEW_MAIN +# define NEW_MAIN main +#endif +#include + +int NEW_MAIN() +{ + OLD_MAIN(); + + print_separator(); + PRINT_MACRO(BOOST_REGEX_USER_CONFIG); + PRINT_MACRO(BOOST_REGEX_USE_C_LOCALE); + PRINT_MACRO(BOOST_REGEX_USE_CPP_LOCALE); + PRINT_MACRO(BOOST_REGEX_HAS_DLL_RUNTIME); + PRINT_MACRO(BOOST_REGEX_DYN_LINK); + PRINT_MACRO(BOOST_REGEX_NO_LIB); + PRINT_MACRO(BOOST_REGEX_NO_TEMPLATE_SWITCH_MERGE); + PRINT_MACRO(BOOST_REGEX_NO_W32); + PRINT_MACRO(BOOST_REGEX_NO_BOOL); + PRINT_MACRO(BOOST_REGEX_NO_EXTERNAL_TEMPLATES); + PRINT_MACRO(BOOST_REGEX_NO_FWD); + PRINT_MACRO(BOOST_REGEX_V3); + PRINT_MACRO(BOOST_REGEX_HAS_MS_STACK_GUARD); + PRINT_MACRO(BOOST_REGEX_RECURSIVE); + PRINT_MACRO(BOOST_REGEX_NON_RECURSIVE); + PRINT_MACRO(BOOST_REGEX_BLOCKSIZE); + PRINT_MACRO(BOOST_REGEX_MAX_BLOCKS); + PRINT_MACRO(BOOST_REGEX_MAX_CACHE_BLOCKS); + PRINT_MACRO(BOOST_NO_WREGEX); + PRINT_MACRO(BOOST_REGEX_NO_FILEITER); + PRINT_MACRO(BOOST_REGEX_STATIC_LINK); + PRINT_MACRO(BOOST_REGEX_DYN_LINK); + PRINT_MACRO(BOOST_REGEX_DECL); + PRINT_MACRO(BOOST_REGEX_CALL); + PRINT_MACRO(BOOST_REGEX_CCALL); + PRINT_MACRO(BOOST_REGEX_MAX_STATE_COUNT); + PRINT_MACRO(BOOST_REGEX_BUGGY_CTYPE_FACET); + PRINT_MACRO(BOOST_REGEX_MATCH_EXTRA); + PRINT_MACRO(BOOST_HAS_ICU); + PRINT_MACRO(BOOST_REGEX_HAS_OTHER_WCHAR_T); + +#if defined(BOOST_REGEX_CONFIG_INFO) && !defined(NO_RECURSE) + print_regex_library_info(); +#endif + + return 0; +} + + + diff --git a/libs/system/build/Jamfile.v2 b/libs/system/build/Jamfile.v2 new file mode 100644 index 0000000..3052704 --- /dev/null +++ b/libs/system/build/Jamfile.v2 @@ -0,0 +1,25 @@ +# Boost System Library Build Jamfile + +# (C) Copyright Beman Dawes 2002, 2006 + +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or www.boost.org/LICENSE_1_0.txt) + +# See library home page at http://www.boost.org/libs/system + +project boost/system + : source-location ../src + : usage-requirements # pass these requirement to dependents (i.e. users) + shared:BOOST_SYSTEM_DYN_LINK=1 + static:BOOST_SYSTEM_STATIC_LINK=1 + ; + +SOURCES = error_code ; + +lib boost_system + : $(SOURCES).cpp + : shared:BOOST_SYSTEM_DYN_LINK=1 + static:BOOST_SYSTEM_STATIC_LINK=1 + ; + +boost-install boost_system ; diff --git a/libs/system/src/error_code.cpp b/libs/system/src/error_code.cpp new file mode 100644 index 0000000..b86a38c --- /dev/null +++ b/libs/system/src/error_code.cpp @@ -0,0 +1,31 @@ +// error_code stub implementation, for compatibility only + +// Copyright Beman Dawes 2002, 2006 +// Copyright Peter Dimov 2018 + +// 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 library home page at http://www.boost.org/libs/system + +//----------------------------------------------------------------------------// + +// define BOOST_SYSTEM_SOURCE so that knows +// the library is being built (possibly exporting rather than importing code) +#define BOOST_SYSTEM_SOURCE + +#include + +namespace boost +{ + +namespace system +{ + +BOOST_SYSTEM_DECL void dummy_exported_function() +{ +} + +} // namespace system + +} // namespace boost diff --git a/libs/thread/build/Jamfile.v2 b/libs/thread/build/Jamfile.v2 new file mode 100644 index 0000000..1a88d01 --- /dev/null +++ b/libs/thread/build/Jamfile.v2 @@ -0,0 +1,319 @@ +# $Id$ +# Copyright 2006-2007 Roland Schwarz. +# Copyright 2007 Anthony Williams +# Copyright 2011-2012 Vicente J.Botet Escriba. +# 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) + +######################################################################### +# The boost threading library can be built on top of different API's +# Currently this is the win32 API and the pthreads API. +# Pthread is native on unix variants. +# To get pthread on windows you need the pthread win32 library +# http://sourceware.org/pthreads-win32 which is available under LGPL. +# +# You need to provide the include path and lib path in the variables +# PTW32_INCLUDE and PTW32_LIB respectively. You can specify these +# paths in site-config.jam, user-config.jam or in the environment. +# A new feature is provided to request a specific API: +# win32 and pthread. +# +# The naming of the resulting libraries is mostly the same for the +# variant native to the build platform, i.e. +# boost_thread and the boost specific tagging. +# For the library variant that is not native on the build platform +# an additional tag is applied: +# boost_thread_pthread for the pthread variant on windows, and +# boost_thread_win32 for the win32 variant (likely when built on cygwin). +# +# To request the pthread variant on windows, from boost root you would +# say e.g: +# bjam msvc-8.0 --with-thread install threadapi=pthread +######################################################################### + +import os ; +import indirect ; +import path ; +import configure ; +import threadapi-feature ; + +exe has_atomic_flag_lockfree : ../build/has_atomic_flag_lockfree_test.cpp ; + +project boost/thread + : source-location ../src + : requirements multi + #static:BOOST_THREAD_STATIC_LINK=1 + #shared:BOOST_THREAD_DYN_LINK=1 + static:BOOST_THREAD_BUILD_LIB=1 + shared:BOOST_THREAD_BUILD_DLL=1 + -@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + @$(__name__).tag + gcc:-Wno-long-long + #BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED + #BOOST_SYSTEM_NO_DEPRECATED + #BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS + + #-pedantic -ansi -std=gnu++0x -Wextra -fpermissive + all + gcc:-Wextra + gcc:-pedantic + gcc:-Wno-long-long + #gcc:-ansi + #gcc:-fpermissive + gcc-4:-Wno-variadic-macros + gcc-5:-Wno-variadic-macros + #gcc:-Wunused-local-typedefs + gcc:-Wunused-function + gcc:-Wno-unused-parameter + + darwin:-Wextra + darwin:-pedantic + #darwin:-ansi + darwin:-fpermissive + darwin:-Wno-long-long + #darwin:-Wno-variadic-macros + darwin-4:-Wno-variadic-macros + darwin-5:-Wno-variadic-macros + #darwin:-Wunused-local-typedefs + darwin:-Wunused-function + darwin:-Wno-unused-parameter + + #pathscale:-Wextra + pathscale:-Wno-long-long + pathscale:-pedantic + + clang:on + clang:-Wextra + #clang:-ansi + #clang:-fpermissive + clang:-Wno-long-long + clang:-Wunused-function + clang:-Wno-variadic-macros + clang:-Wno-unused-parameter + + #gcc-mingw-4.4.0:-fdiagnostics-show-option + #gcc-mingw-4.5.0:-fdiagnostics-show-option + #gcc-mingw-4.6.0:-fdiagnostics-show-option + #gcc-mingw-4.6.3:-fdiagnostics-show-option + #gcc-mingw-4.7.0:-fdiagnostics-show-option + #gcc-mingw-4.8.0:-fdiagnostics-show-option + #gcc:-Wno-missing-field-initializers + + darwin-4.6.2:-Wno-delete-non-virtual-dtor + darwin-4.7.0:-Wno-delete-non-virtual-dtor + + #clang-2.8:-Wno-delete-non-virtual-dtor + #clang-2.8:-Wno-unused-function + #clang-2.9:-Wno-delete-non-virtual-dtor + #clang-2.9:-Wno-unused-function + clang-3.0:-Wno-delete-non-virtual-dtor + #clang-3.0:-Wno-unused-function + #clang-3.0:-Wno-unused-variable + +# Note: Some of the remarks from the Intel compiler are disabled +# remark #193: zero used for undefined preprocessing identifier "XXX" +# remark #304: access control not specified ("public" by default) +# remark #593: variable "XXX" was set but never used +# remark #1418: external function definition with no prior declaration +# remark #2415: variable "XXX" of static storage duration was declared but never referenced + + intel:-wd193,304,383,444 + intel:-wd593,981 + intel:-wd1418 + intel:-wd2415 + + msvc:/wd4100 + msvc:/wd4512 + msvc:/wd6246 + + windows:WIN32_LEAN_AND_MEAN + windows:BOOST_USE_WINDOWS_H + + # : default-build multi + : usage-requirements # pass these requirement to dependents (i.e. users) + #static:BOOST_THREAD_STATIC_LINK=1 + #shared:BOOST_THREAD_DYN_LINK=1 + static:BOOST_THREAD_BUILD_LIB=1 + shared:BOOST_THREAD_BUILD_DLL=1 + #BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED + #BOOST_SYSTEM_NO_DEPRECATED + #BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS + ; + +rule tag ( name : type ? : property-set ) +{ + local result = $(name) ; + + if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB + { + local api = [ $(property-set).get ] ; + + # non native api gets additional tag + if $(api) != [ threadapi-feature.get-default $(property-set) ] { + result = $(result)_$(api) ; + } + } + + # forward to the boost tagging rule + return [ indirect.call $(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag + $(result) : $(type) : $(property-set) ] ; +} + +rule win32_pthread_paths ( properties * ) +{ + local result ; + local PTW32_INCLUDE ; + local PTW32_LIB ; + PTW32_INCLUDE = [ modules.peek : PTW32_INCLUDE ] ; + PTW32_LIB = [ modules.peek : PTW32_LIB ] ; + PTW32_INCLUDE ?= [ modules.peek user-config : PTW32_INCLUDE ] ; + PTW32_LIB ?= [ modules.peek user-config : PTW32_LIB ] ; + PTW32_INCLUDE ?= [ modules.peek site-config : PTW32_INCLUDE ] ; + PTW32_LIB ?= [ modules.peek site-config : PTW32_LIB ] ; + + if ! ( $(PTW32_INCLUDE) && $(PTW32_LIB) ) + { + if ! $(.notified) + { + echo "************************************************************" ; + echo "Trying to build Boost.Thread with pthread support." ; + echo "If you need pthread you should specify the paths." ; + echo "You can specify them in site-config.jam, user-config.jam" ; + echo "or in the environment." ; + echo "For example:" ; + echo "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ; + echo "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib" ; + echo "************************************************************" ; + .notified = true ; + } + } + else + { + local include_path = [ path.make $(PTW32_INCLUDE) ] ; + local lib_path = [ path.make $(PTW32_LIB) ] ; + local libname = pthread ; + if msvc in $(properties) + { + libname = $(libname)VC2.lib ; + } + if gcc in $(properties) + { + libname = lib$(libname)GC2.a ; + } + lib_path = [ path.glob $(lib_path) : $(libname) ] ; + if ! $(lib_path) + { + if ! $(.notified) + { + echo "************************************************************" ; + echo "Trying to build Boost.Thread with pthread support." ; + echo "But the library" $(libname) "could not be found in path" ; + echo $(PTW32_LIB) ; + echo "************************************************************" ; + .notified = true ; + } + } + else + { + result += $(include_path) ; + result += $(lib_path) ; + } + } + return $(result) ; +} + +rule usage-requirements ( properties * ) +{ + local result ; + if pthread in $(properties) + { + result += BOOST_THREAD_POSIX ; + if windows in $(properties) + { + result += [ win32_pthread_paths $(properties) ] ; + # TODO: What is for static linking? Is the also needed + # in that case? + } + } + if win32 in $(properties) + { + result += BOOST_THREAD_WIN32 ; + } + + #if ! vacpp in $(properties) || 11.1 in $(properties) || 12.1.0.1 in $(properties) || 12.1 in $(properties) + #{ + result += /boost/chrono//boost_chrono ; + #} + + return $(result) ; +} + +rule requirements ( properties * ) +{ + local result ; + + if pthread in $(properties) + { + result += BOOST_THREAD_POSIX ; + if windows in $(properties) + { + local paths = [ win32_pthread_paths $(properties) ] ; + if $(paths) + { + result += $(paths) ; + } + else + { + result = no ; + } + } + result += BOOST_THREAD_DONT_USE_CHRONO ; + if ! [ configure.builds has_atomic_flag_lockfree + : $(properties) : "lockfree boost::atomic_flag" ] { + result += /boost/atomic//boost_atomic ; + } + } else { + if win32 in $(properties) + { + result += BOOST_THREAD_WIN32 ; + } + result += BOOST_THREAD_USES_CHRONO ; + result += /boost/chrono//boost_chrono ; + } + + return $(result) ; +} + +alias thread_sources + : ## win32 sources ## + win32/thread.cpp + win32/tss_dll.cpp + win32/tss_pe.cpp + win32/thread_primitives.cpp + future.cpp + : ## requirements ## + win32 + ; + +alias thread_sources + : ## pthread sources ## + pthread/thread.cpp + pthread/once.cpp + future.cpp + : ## requirements ## + pthread + ; + +explicit thread_sources ; + +lib boost_thread + : thread_sources + : @requirements + : + : shared:BOOST_THREAD_USE_DLL=1 + static:BOOST_THREAD_USE_LIB=1 + @usage-requirements + ; + +boost-install boost_thread ; \ No newline at end of file diff --git a/libs/thread/build/has_atomic_flag_lockfree_test.cpp b/libs/thread/build/has_atomic_flag_lockfree_test.cpp new file mode 100644 index 0000000..ca69405 --- /dev/null +++ b/libs/thread/build/has_atomic_flag_lockfree_test.cpp @@ -0,0 +1,13 @@ +// Copyright (c) 2013, Petr Machata, Red Hat Inc. +// +// Use modification and distribution are subject to the boost Software +// License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt). + +#include "../../../boost/atomic.hpp" +#include "../../../boost/static_assert.hpp" + +int main(int argc, char *argv[]) +{ + BOOST_STATIC_ASSERT(BOOST_ATOMIC_FLAG_LOCK_FREE); + return 0; +} diff --git a/libs/thread/src/future.cpp b/libs/thread/src/future.cpp new file mode 100644 index 0000000..a477e70 --- /dev/null +++ b/libs/thread/src/future.cpp @@ -0,0 +1,64 @@ +// (C) Copyright 2012 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#ifndef BOOST_NO_EXCEPTIONS + +#include +#include + +namespace boost +{ + + namespace thread_detail + { + + class future_error_category : + public boost::system::error_category + { + public: + virtual const char* name() const BOOST_NOEXCEPT; + virtual std::string message(int ev) const; + }; + + const char* + future_error_category::name() const BOOST_NOEXCEPT + { + return "future"; + } + + std::string + future_error_category::message(int ev) const + { + switch (BOOST_SCOPED_ENUM_NATIVE(future_errc)(ev)) + { + case future_errc::broken_promise: + return std::string("The associated promise has been destructed prior " + "to the associated state becoming ready."); + case future_errc::future_already_retrieved: + return std::string("The future has already been retrieved from " + "the promise or packaged_task."); + case future_errc::promise_already_satisfied: + return std::string("The state of the promise has already been set."); + case future_errc::no_state: + return std::string("Operation not permitted on an object without " + "an associated state."); + } + return std::string("unspecified future_errc value\n"); + } + future_error_category future_error_category_var; + } + + BOOST_THREAD_DECL + const system::error_category& + future_category() BOOST_NOEXCEPT + { + return thread_detail::future_error_category_var; + } + +} +#endif + diff --git a/libs/thread/src/pthread/once.cpp b/libs/thread/src/pthread/once.cpp new file mode 100644 index 0000000..3de1fe4 --- /dev/null +++ b/libs/thread/src/pthread/once.cpp @@ -0,0 +1,82 @@ +// Copyright (C) 2007 Anthony Williams +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#ifdef BOOST_THREAD_ONCE_ATOMIC +#include "./once_atomic.cpp" +#else +#define __STDC_CONSTANT_MACROS +#include +#include +#include +#include +#include +#include +#include // memcmp. +namespace boost +{ + namespace thread_detail + { + BOOST_THREAD_DECL uintmax_atomic_t once_global_epoch=BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C; + BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER; + BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER; + + namespace + { + pthread_key_t epoch_tss_key; + pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT; + + extern "C" + { + static void delete_epoch_tss_data(void* data) + { + free(data); + } + + static void create_epoch_tss_key() + { + BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data)); + } + } + +#if defined BOOST_THREAD_PATCH + const pthread_once_t pthread_once_init_value=PTHREAD_ONCE_INIT; + struct BOOST_THREAD_DECL delete_epoch_tss_key_on_dlclose_t + { + delete_epoch_tss_key_on_dlclose_t() + { + } + ~delete_epoch_tss_key_on_dlclose_t() + { + if(memcmp(&epoch_tss_key_flag, &pthread_once_init_value, sizeof(pthread_once_t))) + { + void* data = pthread_getspecific(epoch_tss_key); + if (data) + delete_epoch_tss_data(data); + pthread_key_delete(epoch_tss_key); + } + } + }; + delete_epoch_tss_key_on_dlclose_t delete_epoch_tss_key_on_dlclose; +#endif + } + + uintmax_atomic_t& get_once_per_thread_epoch() + { + BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key)); + void* data=pthread_getspecific(epoch_tss_key); + if(!data) + { + data=malloc(sizeof(thread_detail::uintmax_atomic_t)); + if(!data) BOOST_THROW_EXCEPTION(std::bad_alloc()); + BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data)); + *static_cast(data)=BOOST_THREAD_DETAIL_UINTMAX_ATOMIC_MAX_C; + } + return *static_cast(data); + } + } + +} +#endif // diff --git a/libs/thread/src/pthread/once_atomic.cpp b/libs/thread/src/pthread/once_atomic.cpp new file mode 100644 index 0000000..69f5be8 --- /dev/null +++ b/libs/thread/src/pthread/once_atomic.cpp @@ -0,0 +1,91 @@ +// (C) Copyright 2013 Andrey Semashev +// (C) Copyright 2013 Vicente J. Botet Escriba +// +// 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) + +//#define __STDC_CONSTANT_MACROS +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace thread_detail + { + + enum flag_states + { + uninitialized, in_progress, initialized + }; + + +#ifndef BOOST_THREAD_PROVIDES_ONCE_CXX11 + BOOST_STATIC_ASSERT_MSG(sizeof(atomic_int_type) == sizeof(atomic_type), "Boost.Thread: unsupported platform"); +#endif + + static pthread_mutex_t once_mutex = PTHREAD_MUTEX_INITIALIZER; + static pthread_cond_t once_cv = PTHREAD_COND_INITIALIZER; + + BOOST_THREAD_DECL bool enter_once_region(once_flag& flag) BOOST_NOEXCEPT + { + atomic_type& f = get_atomic_storage(flag); + if (f.load(memory_order_acquire) != initialized) + { + pthread::pthread_mutex_scoped_lock lk(&once_mutex); + if (f.load(memory_order_acquire) != initialized) + { + for (;;) + { + atomic_int_type expected = uninitialized; + if (f.compare_exchange_strong(expected, in_progress, memory_order_acq_rel, memory_order_acquire)) + { + // We have set the flag to in_progress + return true; + } + else if (expected == initialized) + { + // Another thread managed to complete the initialization + return false; + } + else + { + // Wait until the initialization is complete + //pthread::pthread_mutex_scoped_lock lk(&once_mutex); + BOOST_VERIFY(!posix::pthread_cond_wait(&once_cv, &once_mutex)); + } + } + } + } + return false; + } + + BOOST_THREAD_DECL void commit_once_region(once_flag& flag) BOOST_NOEXCEPT + { + atomic_type& f = get_atomic_storage(flag); + { + pthread::pthread_mutex_scoped_lock lk(&once_mutex); + f.store(initialized, memory_order_release); + } + BOOST_VERIFY(!posix::pthread_cond_broadcast(&once_cv)); + } + + BOOST_THREAD_DECL void rollback_once_region(once_flag& flag) BOOST_NOEXCEPT + { + atomic_type& f = get_atomic_storage(flag); + { + pthread::pthread_mutex_scoped_lock lk(&once_mutex); + f.store(uninitialized, memory_order_release); + } + BOOST_VERIFY(!posix::pthread_cond_broadcast(&once_cv)); + } + + } // namespace thread_detail + +} // namespace boost diff --git a/libs/thread/src/pthread/thread.cpp b/libs/thread/src/pthread/thread.cpp new file mode 100644 index 0000000..c17aca2 --- /dev/null +++ b/libs/thread/src/pthread/thread.cpp @@ -0,0 +1,801 @@ +// Copyright (C) 2001-2003 +// William E. Kempf +// Copyright (C) 2007-8 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#include +#if defined BOOST_THREAD_USES_DATETIME +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#ifdef __GLIBC__ +#include +#elif defined(__APPLE__) || defined(__FreeBSD__) +#include +#include +#elif defined BOOST_HAS_UNISTD_H +#include +#endif + +#if defined(__VXWORKS__) +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include // memcmp. + +namespace boost +{ + namespace detail + { + thread_data_base::~thread_data_base() + { + for (notify_list_t::iterator i = notify.begin(), e = notify.end(); + i != e; ++i) + { + i->second->unlock(); + i->first->notify_all(); + } +//#ifndef BOOST_NO_EXCEPTIONS + for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end(); + i != e; ++i) + { + (*i)->notify_deferred(); + } +//#endif + } + + struct thread_exit_callback_node + { + boost::detail::thread_exit_function_base* func; + thread_exit_callback_node* next; + + thread_exit_callback_node(boost::detail::thread_exit_function_base* func_, + thread_exit_callback_node* next_): + func(func_),next(next_) + {} + }; + + namespace + { +#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 + boost::once_flag current_thread_tls_init_flag; +#else + boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT; +#endif + pthread_key_t current_thread_tls_key; + + extern "C" + { + static void tls_destructor(void* data) + { + //boost::detail::thread_data_base* thread_info=static_cast(data); + boost::detail::thread_data_ptr thread_info = static_cast(data)->shared_from_this(); + + if(thread_info) + { + while(!thread_info->tss_data.empty() || thread_info->thread_exit_callbacks) + { + + while(thread_info->thread_exit_callbacks) + { + detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks; + thread_info->thread_exit_callbacks=current_node->next; + if(current_node->func) + { + (*current_node->func)(); + delete current_node->func; + } + delete current_node; + } + while (!thread_info->tss_data.empty()) + { + std::map::iterator current + = thread_info->tss_data.begin(); + if(current->second.func && (current->second.value!=0)) + { + (*current->second.caller)(current->second.func,current->second.value); + } + thread_info->tss_data.erase(current); + } + } + thread_info->self.reset(); + } + } + } + +#if defined BOOST_THREAD_PATCH + struct delete_current_thread_tls_key_on_dlclose_t + { + delete_current_thread_tls_key_on_dlclose_t() + { + } + ~delete_current_thread_tls_key_on_dlclose_t() + { + const boost::once_flag uninitialized = BOOST_ONCE_INIT; + if (memcmp(¤t_thread_tls_init_flag, &uninitialized, sizeof(boost::once_flag))) + { + void* data = pthread_getspecific(current_thread_tls_key); + if (data) + tls_destructor(data); + pthread_key_delete(current_thread_tls_key); + } + } + }; + delete_current_thread_tls_key_on_dlclose_t delete_current_thread_tls_key_on_dlclose; +#endif + void create_current_thread_tls_key() + { + BOOST_VERIFY(!pthread_key_create(¤t_thread_tls_key,&tls_destructor)); + } + } + + boost::detail::thread_data_base* get_current_thread_data() + { + boost::call_once(current_thread_tls_init_flag,&create_current_thread_tls_key); + return (boost::detail::thread_data_base*)pthread_getspecific(current_thread_tls_key); + } + + void set_current_thread_data(detail::thread_data_base* new_data) + { + boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); + BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data)); + } + } + + namespace + { + extern "C" + { + static void* thread_proxy(void* param) + { + //boost::detail::thread_data_ptr thread_info = static_cast(param)->self; + boost::detail::thread_data_ptr thread_info = static_cast(param)->shared_from_this(); + thread_info->self.reset(); + detail::set_current_thread_data(thread_info.get()); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + BOOST_TRY + { +#endif + thread_info->run(); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + + } + BOOST_CATCH (thread_interrupted const&) + { + } +// Removed as it stops the debugger identifying the cause of the exception +// Unhandled exceptions still cause the application to terminate +// BOOST_CATCH(...) +// { +// throw; +// +// std::terminate(); +// } + BOOST_CATCH_END +#endif + detail::tls_destructor(thread_info.get()); + detail::set_current_thread_data(0); + boost::lock_guard lock(thread_info->data_mutex); + thread_info->done=true; + thread_info->done_condition.notify_all(); + + return 0; + } + } + } + namespace detail + { + struct externally_launched_thread: + detail::thread_data_base + { + externally_launched_thread() + { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + interrupt_enabled=false; +#endif + } + ~externally_launched_thread() { + BOOST_ASSERT(notify.empty()); + notify.clear(); +//#ifndef BOOST_NO_EXCEPTIONS + BOOST_ASSERT(async_states_.empty()); + async_states_.clear(); +//#endif + } + void run() + {} + void notify_all_at_thread_exit(condition_variable*, mutex*) + {} + + private: + externally_launched_thread(externally_launched_thread&); + void operator=(externally_launched_thread&); + }; + + thread_data_base* make_external_thread_data() + { + thread_data_base* const me(detail::heap_new()); + me->self.reset(me); + set_current_thread_data(me); + return me; + } + + + thread_data_base* get_or_make_current_thread_data() + { + thread_data_base* current_thread_data(get_current_thread_data()); + if(!current_thread_data) + { + current_thread_data=make_external_thread_data(); + } + return current_thread_data; + } + + } + + + thread::thread() BOOST_NOEXCEPT + {} + + bool thread::start_thread_noexcept() + { + thread_info->self=thread_info; + int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get()); + if (res != 0) + { + thread_info->self.reset(); + return false; + } + return true; + } + + bool thread::start_thread_noexcept(const attributes& attr) + { + thread_info->self=thread_info; + const attributes::native_handle_type* h = attr.native_handle(); + int res = pthread_create(&thread_info->thread_handle, h, &thread_proxy, thread_info.get()); + if (res != 0) + { + thread_info->self.reset(); + return false; + } + int detached_state; + res = pthread_attr_getdetachstate(h, &detached_state); + if (res != 0) + { + thread_info->self.reset(); + return false; + } + if (PTHREAD_CREATE_DETACHED==detached_state) + { + detail::thread_data_ptr local_thread_info; + thread_info.swap(local_thread_info); + + if(local_thread_info) + { + //lock_guard lock(local_thread_info->data_mutex); + if(!local_thread_info->join_started) + { + //BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle)); + local_thread_info->join_started=true; + local_thread_info->joined=true; + } + } + } + return true; + } + + + + detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const + { + return thread_info; + } + + bool thread::join_noexcept() + { + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); + if(local_thread_info) + { + bool do_join=false; + + { + unique_lock lock(local_thread_info->data_mutex); + while(!local_thread_info->done) + { + local_thread_info->done_condition.wait(lock); + } + do_join=!local_thread_info->join_started; + + if(do_join) + { + local_thread_info->join_started=true; + } + else + { + while(!local_thread_info->joined) + { + local_thread_info->done_condition.wait(lock); + } + } + } + if(do_join) + { + void* result=0; + BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result)); + lock_guard lock(local_thread_info->data_mutex); + local_thread_info->joined=true; + local_thread_info->done_condition.notify_all(); + } + + if(thread_info==local_thread_info) + { + thread_info.reset(); + } + return true; + } + else + { + return false; + } + } + + bool thread::do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res) + { + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); + if(local_thread_info) + { + bool do_join=false; + + { + unique_lock lock(local_thread_info->data_mutex); + while(!local_thread_info->done) + { + if(!local_thread_info->done_condition.do_wait_until(lock,timeout)) break; // timeout occurred + } + if(!local_thread_info->done) + { + res=false; + return true; + } + do_join=!local_thread_info->join_started; + + if(do_join) + { + local_thread_info->join_started=true; + } + else + { + while(!local_thread_info->joined) + { + local_thread_info->done_condition.wait(lock); + } + } + } + if(do_join) + { + void* result=0; + BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result)); + lock_guard lock(local_thread_info->data_mutex); + local_thread_info->joined=true; + local_thread_info->done_condition.notify_all(); + } + + if(thread_info==local_thread_info) + { + thread_info.reset(); + } + res=true; + return true; + } + else + { + return false; + } + } + + bool thread::joinable() const BOOST_NOEXCEPT + { + return (get_thread_info)()?true:false; + } + + + void thread::detach() + { + detail::thread_data_ptr local_thread_info; + thread_info.swap(local_thread_info); + + if(local_thread_info) + { + lock_guard lock(local_thread_info->data_mutex); + if(!local_thread_info->join_started) + { + BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle)); + local_thread_info->join_started=true; + local_thread_info->joined=true; + } + } + } + + namespace this_thread + { + namespace no_interruption_point + { + namespace hidden + { + void BOOST_THREAD_DECL sleep_for_internal(const detail::platform_duration& ts) + { + if (ts > detail::platform_duration::zero()) + { + // Use pthread_delay_np or nanosleep whenever possible here in the no_interruption_point + // namespace because they do not provide an interruption point. + # if defined(BOOST_HAS_PTHREAD_DELAY_NP) + # if defined(__IBMCPP__) || defined(_AIX) + BOOST_VERIFY(!pthread_delay_np(const_cast(&ts.getTs()))); + # else + BOOST_VERIFY(!pthread_delay_np(&ts.getTs())); + # endif + # elif defined(BOOST_HAS_NANOSLEEP) + nanosleep(&ts.getTs(), 0); + # else + // This should never be reached due to BOOST_THREAD_SLEEP_FOR_IS_STEADY + # endif + } + } + } + } + + void yield() BOOST_NOEXCEPT + { +# if defined(BOOST_HAS_SCHED_YIELD) + BOOST_VERIFY(!sched_yield()); +# elif defined(BOOST_HAS_PTHREAD_YIELD) + BOOST_VERIFY(!pthread_yield()); +//# elif defined BOOST_THREAD_USES_DATETIME +// ::boost::xtime xt; +// xtime_get(&xt, TIME_UTC_); +// sleep(xt); +// sleep_for(chrono::milliseconds(0)); +# else + mutex mx; + unique_lock lock(mx); + condition_variable cond; + cond.do_wait_until(lock, detail::internal_platform_clock::now()); +# endif + } + } + unsigned thread::hardware_concurrency() BOOST_NOEXCEPT + { +#if defined(PTW32_VERSION) || defined(__hpux) + return pthread_num_processors_np(); +#elif defined(__APPLE__) || defined(__FreeBSD__) + int count; + size_t size=sizeof(count); + return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count; +#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN) + int const count=sysconf(_SC_NPROCESSORS_ONLN); + return (count>0)?count:0; +#elif defined(__VXWORKS__) + cpuset_t set = ::vxCpuEnabledGet(); + #ifdef __DCC__ + int i; + for( i = 0; set; ++i) + { + set &= set -1; + } + return(i); + #else + return (__builtin_popcount(set) ); + #endif +#elif defined(__GLIBC__) + return get_nprocs(); +#else + return 0; +#endif + } + + unsigned thread::physical_concurrency() BOOST_NOEXCEPT + { +#ifdef __linux__ + try { + using namespace std; + + ifstream proc_cpuinfo ("/proc/cpuinfo"); + + const string physical_id("physical id"), core_id("core id"); + + typedef std::pair core_entry; // [physical ID, core id] + + std::set cores; + + core_entry current_core_entry; + + string line; + while ( getline(proc_cpuinfo, line) ) { + if (line.empty()) + continue; + + vector key_val(2); + boost::split(key_val, line, boost::is_any_of(":")); + + if (key_val.size() != 2) + return hardware_concurrency(); + + string key = key_val[0]; + string value = key_val[1]; + boost::trim(key); + boost::trim(value); + + if (key == physical_id) { + current_core_entry.first = boost::lexical_cast(value); + continue; + } + + if (key == core_id) { + current_core_entry.second = boost::lexical_cast(value); + cores.insert(current_core_entry); + continue; + } + } + // Fall back to hardware_concurrency() in case + // /proc/cpuinfo is formatted differently than we expect. + return cores.size() != 0 ? cores.size() : hardware_concurrency(); + } catch(...) { + return hardware_concurrency(); + } +#elif defined(__APPLE__) + int count; + size_t size=sizeof(count); + return sysctlbyname("hw.physicalcpu",&count,&size,NULL,0)?0:count; +#else + return hardware_concurrency(); +#endif + } + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + void thread::interrupt() + { + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); + if(local_thread_info) + { + lock_guard lk(local_thread_info->data_mutex); + local_thread_info->interrupt_requested=true; + if(local_thread_info->current_cond) + { + boost::pthread::pthread_mutex_scoped_lock internal_lock(local_thread_info->cond_mutex); + BOOST_VERIFY(!posix::pthread_cond_broadcast(local_thread_info->current_cond)); + } + } + } + + bool thread::interruption_requested() const BOOST_NOEXCEPT + { + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); + if(local_thread_info) + { + lock_guard lk(local_thread_info->data_mutex); + return local_thread_info->interrupt_requested; + } + else + { + return false; + } + } +#endif + + thread::native_handle_type thread::native_handle() + { + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); + if(local_thread_info) + { + lock_guard lk(local_thread_info->data_mutex); + return local_thread_info->thread_handle; + } + else + { + return pthread_t(); + } + } + + + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + namespace this_thread + { + void interruption_point() + { +#ifndef BOOST_NO_EXCEPTIONS + boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + if(thread_info && thread_info->interrupt_enabled) + { + lock_guard lg(thread_info->data_mutex); + if(thread_info->interrupt_requested) + { + thread_info->interrupt_requested=false; + throw thread_interrupted(); + } + } +#endif + } + + bool interruption_enabled() BOOST_NOEXCEPT + { + boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + return thread_info && thread_info->interrupt_enabled; + } + + bool interruption_requested() BOOST_NOEXCEPT + { + boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + if(!thread_info) + { + return false; + } + else + { + lock_guard lg(thread_info->data_mutex); + return thread_info->interrupt_requested; + } + } + + disable_interruption::disable_interruption() BOOST_NOEXCEPT: + interruption_was_enabled(interruption_enabled()) + { + if(interruption_was_enabled) + { + detail::get_current_thread_data()->interrupt_enabled=false; + } + } + + disable_interruption::~disable_interruption() BOOST_NOEXCEPT + { + if(detail::get_current_thread_data()) + { + detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled; + } + } + + restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT + { + if(d.interruption_was_enabled) + { + detail::get_current_thread_data()->interrupt_enabled=true; + } + } + + restore_interruption::~restore_interruption() BOOST_NOEXCEPT + { + if(detail::get_current_thread_data()) + { + detail::get_current_thread_data()->interrupt_enabled=false; + } + } + } +#endif + + namespace detail + { + void add_thread_exit_function(thread_exit_function_base* func) + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + thread_exit_callback_node* const new_node= + heap_new(func,current_thread_data->thread_exit_callbacks); + current_thread_data->thread_exit_callbacks=new_node; + } + + tss_data_node* find_tss_data(void const* key) + { + detail::thread_data_base* const current_thread_data(get_current_thread_data()); + if(current_thread_data) + { + std::map::iterator current_node= + current_thread_data->tss_data.find(key); + if(current_node!=current_thread_data->tss_data.end()) + { + return ¤t_node->second; + } + } + return 0; + } + + void* get_tss_data(void const* key) + { + if(tss_data_node* const current_node=find_tss_data(key)) + { + return current_node->value; + } + return 0; + } + + void add_new_tss_node(void const* key, + detail::tss_data_node::cleanup_caller_t caller, + detail::tss_data_node::cleanup_func_t func, + void* tss_data) + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(caller,func,tss_data))); + } + + void erase_tss_node(void const* key) + { + detail::thread_data_base* const current_thread_data(get_current_thread_data()); + if(current_thread_data) + { + current_thread_data->tss_data.erase(key); + } + } + + void set_tss_data(void const* key, + detail::tss_data_node::cleanup_caller_t caller, + detail::tss_data_node::cleanup_func_t func, + void* tss_data,bool cleanup_existing) + { + if(tss_data_node* const current_node=find_tss_data(key)) + { + if(cleanup_existing && current_node->func && (current_node->value!=0)) + { + (*current_node->caller)(current_node->func,current_node->value); + } + if(func || (tss_data!=0)) + { + current_node->caller=caller; + current_node->func=func; + current_node->value=tss_data; + } + else + { + erase_tss_node(key); + } + } + else if(func || (tss_data!=0)) + { + add_new_tss_node(key,caller,func,tss_data); + } + } + } + + BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk) + { + detail::thread_data_base* const current_thread_data(detail::get_current_thread_data()); + if(current_thread_data) + { + current_thread_data->notify_all_at_thread_exit(&cond, lk.release()); + } + } + +//#ifndef BOOST_NO_EXCEPTIONS +namespace detail { + + void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr as) + { + detail::thread_data_base* const current_thread_data(detail::get_current_thread_data()); + if(current_thread_data) + { + current_thread_data->make_ready_at_thread_exit(as); + } + } +} +//#endif + + +} diff --git a/libs/thread/src/tss_null.cpp b/libs/thread/src/tss_null.cpp new file mode 100644 index 0000000..e5e8151 --- /dev/null +++ b/libs/thread/src/tss_null.cpp @@ -0,0 +1,38 @@ +// (C) Copyright Michael Glassford 2004. +// (C) Copyright 2007 Anthony Williams +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +#if defined(BOOST_THREAD_WIN32) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST) || defined(UNDER_CE)) && (!defined(_MSC_VER) || defined(UNDER_CE)) + +namespace boost +{ + /* + This file is a "null" implementation of tss cleanup; it's + purpose is to to eliminate link errors in cases + where it is known that tss cleanup is not needed. + */ + + void tss_cleanup_implemented(void) + { + /* + This function's sole purpose is to cause a link error in cases where + automatic tss cleanup is not implemented by Boost.Threads as a + reminder that user code is responsible for calling the necessary + functions at the appropriate times (and for implementing an a + tss_cleanup_implemented() function to eliminate the linker's + missing symbol error). + + If Boost.Threads later implements automatic tss cleanup in cases + where it currently doesn't (which is the plan), the duplicate + symbol error will warn the user that their custom solution is no + longer needed and can be removed. + */ + } + +} + +#endif //defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_LIB) && !defined(_MSC_VER) diff --git a/libs/thread/src/win32/thread.cpp b/libs/thread/src/win32/thread.cpp new file mode 100644 index 0000000..e1ae050 --- /dev/null +++ b/libs/thread/src/win32/thread.cpp @@ -0,0 +1,980 @@ +// 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) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007 David Deakins +// (C) Copyright 2011-2018 Vicente J. Botet Escriba + +//#define BOOST_THREAD_VERSION 3 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined BOOST_THREAD_USES_DATETIME +#include +#include +#endif +#include +#include +#include +#ifndef UNDER_CE +#include +#endif +#include +#include +#include + +#if BOOST_PLAT_WINDOWS_RUNTIME +#include +#include +#include +#include +#include +#include +#include +#include +#pragma comment(lib, "runtimeobject.lib") +#endif + +namespace boost +{ + namespace detail + { + thread_data_base::~thread_data_base() + { + for (notify_list_t::iterator i = notify.begin(), e = notify.end(); + i != e; ++i) + { + i->second->unlock(); + i->first->notify_all(); + } +//#ifndef BOOST_NO_EXCEPTIONS + for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end(); + i != e; ++i) + { + (*i)->notify_deferred(); + } +//#endif + } + } + + namespace + { +#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 + boost::once_flag current_thread_tls_init_flag; +#else + boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT; +#endif +#if defined(UNDER_CE) + // Windows CE does not define the TLS_OUT_OF_INDEXES constant. +#define TLS_OUT_OF_INDEXES 0xFFFFFFFF +#endif +#if !BOOST_PLAT_WINDOWS_RUNTIME + DWORD current_thread_tls_key=TLS_OUT_OF_INDEXES; +#else + __declspec(thread) boost::detail::thread_data_base* current_thread_data_base; +#endif + + void create_current_thread_tls_key() + { + tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in +#if !BOOST_PLAT_WINDOWS_RUNTIME + current_thread_tls_key=TlsAlloc(); + BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES); +#endif + } + + void cleanup_tls_key() + { +#if !BOOST_PLAT_WINDOWS_RUNTIME + if(current_thread_tls_key!=TLS_OUT_OF_INDEXES) + { + TlsFree(current_thread_tls_key); + current_thread_tls_key=TLS_OUT_OF_INDEXES; + } +#endif + } + + void set_current_thread_data(detail::thread_data_base* new_data) + { + boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); +#if BOOST_PLAT_WINDOWS_RUNTIME + current_thread_data_base = new_data; +#else + if (current_thread_tls_key != TLS_OUT_OF_INDEXES) + { + BOOST_VERIFY(TlsSetValue(current_thread_tls_key, new_data)); + } + else + { + BOOST_VERIFY(false); + //boost::throw_exception(thread_resource_error()); + } +#endif + } + } + + namespace detail + { + thread_data_base* get_current_thread_data() + { +#if BOOST_PLAT_WINDOWS_RUNTIME + return current_thread_data_base; +#else + if (current_thread_tls_key == TLS_OUT_OF_INDEXES) + { + return 0; + } + return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key); +#endif + } + } + + namespace + { +#ifndef BOOST_HAS_THREADEX +// Windows CE doesn't define _beginthreadex + + struct ThreadProxyData + { + typedef unsigned (__stdcall* func)(void*); + func start_address_; + void* arglist_; + ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {} + }; + + DWORD WINAPI ThreadProxy(LPVOID args) + { + boost::csbl::unique_ptr data(reinterpret_cast(args)); + DWORD ret=data->start_address_(data->arglist_); + return ret; + } + + inline uintptr_t _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*), + void* arglist, unsigned initflag, unsigned* thrdaddr) + { + DWORD threadID; + ThreadProxyData* data = new ThreadProxyData(start_address,arglist); + HANDLE hthread=CreateThread(static_cast(security),stack_size,ThreadProxy, + data,initflag,&threadID); + if (hthread==0) { + delete data; + return 0; + } + *thrdaddr=threadID; + return reinterpret_cast(hthread); + } + +#endif + + } + + namespace detail + { + struct thread_exit_callback_node + { + boost::detail::thread_exit_function_base* func; + thread_exit_callback_node* next; + + thread_exit_callback_node(boost::detail::thread_exit_function_base* func_, + thread_exit_callback_node* next_): + func(func_),next(next_) + {} + }; + + } + +#if BOOST_PLAT_WINDOWS_RUNTIME + namespace detail + { + std::atomic_uint threadCount; + + bool win32::scoped_winrt_thread::start(thread_func address, void *parameter, unsigned int *thrdId) + { + Microsoft::WRL::ComPtr threadPoolFactory; + HRESULT hr = ::Windows::Foundation::GetActivationFactory( + Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_System_Threading_ThreadPool).Get(), + &threadPoolFactory); + if (hr != S_OK) + { + return false; + } + + // Create event for tracking work item completion. + *thrdId = ++threadCount; + handle completionHandle = CreateEventExW(NULL, NULL, 0, EVENT_ALL_ACCESS); + if (!completionHandle) + { + return false; + } + m_completionHandle = completionHandle; + + // Create new work item. + Microsoft::WRL::ComPtr workItem = + Microsoft::WRL::Callback, ABI::Windows::System::Threading::IWorkItemHandler, Microsoft::WRL::FtmBase>> + ([address, parameter, completionHandle](ABI::Windows::Foundation::IAsyncAction *) + { + // Add a reference since we need to access the completionHandle after the thread_start_function. + // This is to handle cases where detach() was called and run_thread_exit_callbacks() would end + // up closing the handle. + ::boost::detail::thread_data_base* const thread_info(reinterpret_cast<::boost::detail::thread_data_base*>(parameter)); + intrusive_ptr_add_ref(thread_info); + + __try + { + address(parameter); + } + __finally + { + SetEvent(completionHandle); + intrusive_ptr_release(thread_info); + } + return S_OK; + }); + + // Schedule work item on the threadpool. + Microsoft::WRL::ComPtr asyncAction; + hr = threadPoolFactory->RunWithPriorityAndOptionsAsync( + workItem.Get(), + ABI::Windows::System::Threading::WorkItemPriority_Normal, + ABI::Windows::System::Threading::WorkItemOptions_TimeSliced, + &asyncAction); + return hr == S_OK; + } + } +#endif + + namespace + { + void run_thread_exit_callbacks() + { + detail::thread_data_ptr current_thread_data(detail::get_current_thread_data(),false); + if(current_thread_data) + { + while(! current_thread_data->tss_data.empty() || current_thread_data->thread_exit_callbacks) + { + while(current_thread_data->thread_exit_callbacks) + { + detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks; + current_thread_data->thread_exit_callbacks=current_node->next; + if(current_node->func) + { + (*current_node->func)(); + boost::detail::heap_delete(current_node->func); + } + boost::detail::heap_delete(current_node); + } + while (!current_thread_data->tss_data.empty()) + { + std::map::iterator current + = current_thread_data->tss_data.begin(); + if(current->second.func && (current->second.value!=0)) + { + (*current->second.caller)(current->second.func,current->second.value); + } + current_thread_data->tss_data.erase(current); + } + } + set_current_thread_data(0); + } + } + + unsigned __stdcall thread_start_function(void* param) + { + detail::thread_data_base* const thread_info(reinterpret_cast(param)); + set_current_thread_data(thread_info); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + BOOST_TRY + { +#endif + thread_info->run(); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } + BOOST_CATCH(thread_interrupted const&) + { + } + // Unhandled exceptions still cause the application to terminate + BOOST_CATCH_END +#endif + run_thread_exit_callbacks(); + return 0; + } + } + + thread::thread() BOOST_NOEXCEPT + {} + + bool thread::start_thread_noexcept() + { +#if BOOST_PLAT_WINDOWS_RUNTIME + intrusive_ptr_add_ref(thread_info.get()); + if (!thread_info->thread_handle.start(&thread_start_function, thread_info.get(), &thread_info->id)) + { + intrusive_ptr_release(thread_info.get()); + return false; + } + return true; +#else + uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id); + if(!new_thread) + { + return false; + } + intrusive_ptr_add_ref(thread_info.get()); + thread_info->thread_handle=(detail::win32::handle)(new_thread); + ResumeThread(thread_info->thread_handle); + return true; +#endif + } + + bool thread::start_thread_noexcept(const attributes& attr) + { +#if BOOST_PLAT_WINDOWS_RUNTIME + // Stack size isn't supported with Windows Runtime. + attr; + return start_thread_noexcept(); +#else + uintptr_t const new_thread=_beginthreadex(0,static_cast(attr.get_stack_size()),&thread_start_function,thread_info.get(), + CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, &thread_info->id); + if(!new_thread) + { + return false; + } + intrusive_ptr_add_ref(thread_info.get()); + thread_info->thread_handle=(detail::win32::handle)(new_thread); + ResumeThread(thread_info->thread_handle); + return true; +#endif + } + + thread::thread(detail::thread_data_ptr data): + thread_info(data) + {} + + namespace + { + struct externally_launched_thread: + detail::thread_data_base + { + externally_launched_thread() + { + ++count; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + interruption_enabled=false; +#endif + } + ~externally_launched_thread() { + BOOST_ASSERT(notify.empty()); + notify.clear(); +//#ifndef BOOST_NO_EXCEPTIONS + BOOST_ASSERT(async_states_.empty()); + async_states_.clear(); +//#endif + } + + void run() + {} + void notify_all_at_thread_exit(condition_variable*, mutex*) + {} + + private: + externally_launched_thread(externally_launched_thread&); + void operator=(externally_launched_thread&); + }; + + void make_external_thread_data() + { + externally_launched_thread* me=detail::heap_new(); + BOOST_TRY + { + set_current_thread_data(me); + } + BOOST_CATCH(...) + { + detail::heap_delete(me); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + detail::thread_data_base* get_or_make_current_thread_data() + { + detail::thread_data_base* current_thread_data(detail::get_current_thread_data()); + if(!current_thread_data) + { + make_external_thread_data(); + current_thread_data=detail::get_current_thread_data(); + } + return current_thread_data; + } + } + + thread::id thread::get_id() const BOOST_NOEXCEPT + { +#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID + detail::thread_data_ptr local_thread_info=(get_thread_info)(); + if(!local_thread_info) + { + return 0; + } + return local_thread_info->id; +#else + return thread::id((get_thread_info)()); +#endif + } + + bool thread::joinable() const BOOST_NOEXCEPT + { + detail::thread_data_ptr local_thread_info = (get_thread_info)(); + if(!local_thread_info) + { + return false; + } + return true; + } + bool thread::join_noexcept() + { + detail::thread_data_ptr local_thread_info=(get_thread_info)(); + if(local_thread_info) + { + this_thread::interruptible_wait(this->native_handle(), detail::internal_platform_timepoint::getMax()); + release_handle(); + return true; + } + else + { + return false; + } + } + + bool thread::do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res) + { + detail::thread_data_ptr local_thread_info=(get_thread_info)(); + if(local_thread_info) + { + if(!this_thread::interruptible_wait(this->native_handle(), timeout)) + { + res=false; + return true; + } + release_handle(); + res=true; + return true; + } + else + { + return false; + } + } + + void thread::detach() + { + release_handle(); + } + + void thread::release_handle() + { + thread_info=0; + } + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + void thread::interrupt() + { + detail::thread_data_ptr local_thread_info=(get_thread_info)(); + if(local_thread_info) + { + local_thread_info->interrupt(); + } + } + + bool thread::interruption_requested() const BOOST_NOEXCEPT + { + detail::thread_data_ptr local_thread_info=(get_thread_info)(); + return local_thread_info.get() && (winapi::WaitForSingleObjectEx(local_thread_info->interruption_handle,0,0)==0); + } + +#endif + + unsigned thread::hardware_concurrency() BOOST_NOEXCEPT + { + detail::win32::system_info info; + detail::win32::get_system_info(&info); + return info.dwNumberOfProcessors; + } + + unsigned thread::physical_concurrency() BOOST_NOEXCEPT + { + // a bit too strict: Windows XP with SP3 would be sufficient +#if BOOST_PLAT_WINDOWS_RUNTIME \ + || ( BOOST_USE_WINAPI_VERSION <= BOOST_WINAPI_VERSION_WINXP ) \ + || ( ( defined(__MINGW32__) && !defined(__MINGW64__) ) && _WIN32_WINNT < 0x0600) + return 0; +#else + unsigned cores = 0; + DWORD size = 0; + + GetLogicalProcessorInformation(NULL, &size); + if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) + return 0; + const size_t Elements = size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); + + std::vector buffer(Elements); + if (GetLogicalProcessorInformation(&buffer.front(), &size) == FALSE) + return 0; + + + for (size_t i = 0; i < Elements; ++i) { + if (buffer[i].Relationship == RelationProcessorCore) + ++cores; + } + return cores; +#endif + } + + thread::native_handle_type thread::native_handle() + { + detail::thread_data_ptr local_thread_info=(get_thread_info)(); + if(!local_thread_info) + { + return detail::win32::invalid_handle_value; + } +#if BOOST_PLAT_WINDOWS_RUNTIME + // There is no 'real' Win32 handle so we return a handle that at least can be waited on. + return local_thread_info->thread_handle.waitable_handle(); +#else + return (detail::win32::handle)local_thread_info->thread_handle; +#endif + } + + detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const + { + return thread_info; + } + + namespace this_thread + { +#ifndef UNDER_CE +#if !BOOST_PLAT_WINDOWS_RUNTIME + namespace detail_ + { + typedef struct _REASON_CONTEXT { + ULONG Version; + DWORD Flags; + union { + LPWSTR SimpleReasonString; + struct { + HMODULE LocalizedReasonModule; + ULONG LocalizedReasonId; + ULONG ReasonStringCount; + LPWSTR *ReasonStrings; + } Detailed; + } Reason; + } REASON_CONTEXT, *PREASON_CONTEXT; + typedef BOOL (WINAPI *setwaitabletimerex_t)(HANDLE, const LARGE_INTEGER *, LONG, PTIMERAPCROUTINE, LPVOID, PREASON_CONTEXT, ULONG); + static inline BOOL WINAPI SetWaitableTimerEx_emulation(HANDLE hTimer, const LARGE_INTEGER *lpDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, LPVOID lpArgToCompletionRoutine, PREASON_CONTEXT WakeContext, ULONG TolerableDelay) + { + return SetWaitableTimer(hTimer, lpDueTime, lPeriod, pfnCompletionRoutine, lpArgToCompletionRoutine, FALSE); + } +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 6387) // MSVC sanitiser warns that GetModuleHandleA() might fail +#endif + static inline setwaitabletimerex_t SetWaitableTimerEx() + { + static setwaitabletimerex_t setwaitabletimerex_impl; + if(setwaitabletimerex_impl) + return setwaitabletimerex_impl; + void (*addr)()=(void (*)()) GetProcAddress( +#if !defined(BOOST_NO_ANSI_APIS) + GetModuleHandleA("KERNEL32.DLL"), +#else + GetModuleHandleW(L"KERNEL32.DLL"), +#endif + "SetWaitableTimerEx"); + if(addr) + setwaitabletimerex_impl=(setwaitabletimerex_t) addr; + else + setwaitabletimerex_impl=&SetWaitableTimerEx_emulation; + return setwaitabletimerex_impl; + } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } +#endif +#endif + bool interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout) + { + detail::win32::handle handles[4]={0}; + unsigned handle_count=0; + unsigned wait_handle_index=~0U; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + unsigned interruption_index=~0U; +#endif + unsigned timeout_index=~0U; + if(handle_to_wait_for!=detail::win32::invalid_handle_value) + { + wait_handle_index=handle_count; + handles[handle_count++]=handle_to_wait_for; + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + if(detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled) + { + interruption_index=handle_count; + handles[handle_count++]=detail::get_current_thread_data()->interruption_handle; + } +#endif + detail::win32::handle_manager timer_handle; + +#ifndef UNDER_CE +#if !BOOST_PLAT_WINDOWS_RUNTIME + // Preferentially use coalescing timers for better power consumption and timer accuracy + if(timeout != detail::internal_platform_timepoint::getMax()) + { + boost::intmax_t const time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs(); + timer_handle=CreateWaitableTimer(NULL,false,NULL); + if(timer_handle!=0) + { + ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26 + if(time_left_msec/20>tolerable) // 5% + tolerable=static_cast(time_left_msec/20); + LARGE_INTEGER due_time={{0,0}}; + if(time_left_msec>0) + { + due_time.QuadPart=-(time_left_msec*10000); // negative indicates relative time + } + bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0; + if(set_time_succeeded) + { + timeout_index=handle_count; + handles[handle_count++]=timer_handle; + } + } + } +#endif +#endif + + bool const using_timer=timeout_index!=~0u; + boost::intmax_t time_left_msec(INFINITE); + if(!using_timer && timeout != detail::internal_platform_timepoint::getMax()) + { + time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs(); + if(time_left_msec < 0) + { + time_left_msec = 0; + } + } + + do + { + if(handle_count) + { + unsigned long const notified_index=winapi::WaitForMultipleObjectsEx(handle_count,handles,false,static_cast(time_left_msec), 0); + if(notified_indexinterruption_handle); + throw thread_interrupted(); + } +#endif + else if(notified_index==timeout_index) + { + return false; + } + } + } + else + { + detail::win32::sleep(static_cast(time_left_msec)); + } + + if(!using_timer && timeout != detail::internal_platform_timepoint::getMax()) + { + time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs(); + } + } + while(time_left_msec == INFINITE || time_left_msec > 0); + return false; + } + + namespace no_interruption_point + { + bool non_interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout) + { + detail::win32::handle handles[3]={0}; + unsigned handle_count=0; + unsigned wait_handle_index=~0U; + unsigned timeout_index=~0U; + if(handle_to_wait_for!=detail::win32::invalid_handle_value) + { + wait_handle_index=handle_count; + handles[handle_count++]=handle_to_wait_for; + } + detail::win32::handle_manager timer_handle; + +#ifndef UNDER_CE +#if !BOOST_PLAT_WINDOWS_RUNTIME + // Preferentially use coalescing timers for better power consumption and timer accuracy + if(timeout != detail::internal_platform_timepoint::getMax()) + { + boost::intmax_t const time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs(); + timer_handle=CreateWaitableTimer(NULL,false,NULL); + if(timer_handle!=0) + { + ULONG tolerable=32; // Empirical testing shows Windows ignores this when <= 26 + if(time_left_msec/20>tolerable) // 5% + tolerable=static_cast(time_left_msec/20); + LARGE_INTEGER due_time={{0,0}}; + if(time_left_msec>0) + { + due_time.QuadPart=-(time_left_msec*10000); // negative indicates relative time + } + bool const set_time_succeeded=detail_::SetWaitableTimerEx()(timer_handle,&due_time,0,0,0,NULL,tolerable)!=0; + if(set_time_succeeded) + { + timeout_index=handle_count; + handles[handle_count++]=timer_handle; + } + } + } +#endif +#endif + + bool const using_timer=timeout_index!=~0u; + boost::intmax_t time_left_msec(INFINITE); + if(!using_timer && timeout != detail::internal_platform_timepoint::getMax()) + { + time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs(); + if(time_left_msec < 0) + { + time_left_msec = 0; + } + } + + do + { + if(handle_count) + { + unsigned long const notified_index=winapi::WaitForMultipleObjectsEx(handle_count,handles,false,static_cast(time_left_msec), 0); + if(notified_index(time_left_msec)); + } + + if(!using_timer && timeout != detail::internal_platform_timepoint::getMax()) + { + time_left_msec = (timeout - detail::internal_platform_clock::now()).getMs(); + } + } + while(time_left_msec == INFINITE || time_left_msec > 0); + return false; + } + } + + thread::id get_id() BOOST_NOEXCEPT + { +#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID +#if BOOST_PLAT_WINDOWS_RUNTIME + detail::thread_data_base* current_thread_data(detail::get_current_thread_data()); + if (current_thread_data) + { + return current_thread_data->id; + } +#endif + return winapi::GetCurrentThreadId(); +#else + return thread::id(get_or_make_current_thread_data()); +#endif + } + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + void interruption_point() + { + if(interruption_enabled() && interruption_requested()) + { + winapi::ResetEvent(detail::get_current_thread_data()->interruption_handle); + throw thread_interrupted(); + } + } + + bool interruption_enabled() BOOST_NOEXCEPT + { + return detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled; + } + + bool interruption_requested() BOOST_NOEXCEPT + { + return detail::get_current_thread_data() && (winapi::WaitForSingleObjectEx(detail::get_current_thread_data()->interruption_handle,0,0)==0); + } +#endif + + void yield() BOOST_NOEXCEPT + { + detail::win32::sleep(0); + } + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + disable_interruption::disable_interruption() BOOST_NOEXCEPT: + interruption_was_enabled(interruption_enabled()) + { + if(interruption_was_enabled) + { + detail::get_current_thread_data()->interruption_enabled=false; + } + } + + disable_interruption::~disable_interruption() BOOST_NOEXCEPT + { + if(detail::get_current_thread_data()) + { + detail::get_current_thread_data()->interruption_enabled=interruption_was_enabled; + } + } + + restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT + { + if(d.interruption_was_enabled) + { + detail::get_current_thread_data()->interruption_enabled=true; + } + } + + restore_interruption::~restore_interruption() BOOST_NOEXCEPT + { + if(detail::get_current_thread_data()) + { + detail::get_current_thread_data()->interruption_enabled=false; + } + } +#endif + } + + namespace detail + { + void add_thread_exit_function(thread_exit_function_base* func) + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + thread_exit_callback_node* const new_node= + heap_new( + func,current_thread_data->thread_exit_callbacks); + current_thread_data->thread_exit_callbacks=new_node; + } + + tss_data_node* find_tss_data(void const* key) + { + detail::thread_data_base* const current_thread_data(get_current_thread_data()); + if(current_thread_data) + { + std::map::iterator current_node= + current_thread_data->tss_data.find(key); + if(current_node!=current_thread_data->tss_data.end()) + { + return ¤t_node->second; + } + } + return NULL; + } + + void* get_tss_data(void const* key) + { + if(tss_data_node* const current_node=find_tss_data(key)) + { + return current_node->value; + } + return NULL; + } + + void add_new_tss_node(void const* key, + detail::tss_data_node::cleanup_caller_t caller, + detail::tss_data_node::cleanup_func_t func, + void* tss_data) + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(caller,func,tss_data))); + } + + void erase_tss_node(void const* key) + { + detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data()); + current_thread_data->tss_data.erase(key); + } + + void set_tss_data(void const* key, + detail::tss_data_node::cleanup_caller_t caller, + detail::tss_data_node::cleanup_func_t func, + void* tss_data,bool cleanup_existing) + { + if(tss_data_node* const current_node=find_tss_data(key)) + { + if(cleanup_existing && current_node->func && (current_node->value!=0)) + { + (*current_node->caller)(current_node->func,current_node->value); + } + if(func || (tss_data!=0)) + { + current_node->caller=caller; + current_node->func=func; + current_node->value=tss_data; + } + else + { + erase_tss_node(key); + } + } + else if(func || (tss_data!=0)) + { + add_new_tss_node(key,caller,func,tss_data); + } + } + } + + BOOST_THREAD_DECL void __cdecl on_process_enter() + {} + + BOOST_THREAD_DECL void __cdecl on_thread_enter() + {} + + BOOST_THREAD_DECL void __cdecl on_process_exit() + { + boost::cleanup_tls_key(); + } + + BOOST_THREAD_DECL void __cdecl on_thread_exit() + { + boost::run_thread_exit_callbacks(); + } + + BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk) + { + detail::thread_data_base* const current_thread_data(detail::get_current_thread_data()); + if(current_thread_data) + { + current_thread_data->notify_all_at_thread_exit(&cond, lk.release()); + } + } +} + diff --git a/libs/thread/src/win32/thread_primitives.cpp b/libs/thread/src/win32/thread_primitives.cpp new file mode 100644 index 0000000..5f6e6f0 --- /dev/null +++ b/libs/thread/src/win32/thread_primitives.cpp @@ -0,0 +1,156 @@ +// thread_primitives.cpp +// +// (C) Copyright 2018 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace detail { +namespace win32 { + +#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 + +// Directly use API from Vista and later +BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64 = &::boost::winapi::GetTickCount64; + +#else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 + +namespace { + +enum init_state +{ + uninitialized = 0, + in_progress, + initialized +}; + +struct get_tick_count64_state +{ + boost::atomic< uint64_t > ticks; + boost::atomic< init_state > init; + boost::winapi::HANDLE_ wait_event; + boost::winapi::HANDLE_ wait_handle; +}; + +// Zero-initialized initially +BOOST_ALIGNMENT(64) static get_tick_count64_state g_state; + +//! Artifical implementation of GetTickCount64 +ticks_type WINAPI get_tick_count64() +{ + uint64_t old_state = g_state.ticks.load(boost::memory_order_acquire); + + uint32_t new_ticks = boost::winapi::GetTickCount(); + + uint32_t old_ticks = static_cast< uint32_t >(old_state & UINT64_C(0x00000000ffffffff)); + uint64_t new_state = ((old_state & UINT64_C(0xffffffff00000000)) + (static_cast< uint64_t >(new_ticks < old_ticks) << 32)) | static_cast< uint64_t >(new_ticks); + + g_state.ticks.store(new_state, boost::memory_order_release); + + return new_state; +} + +//! The function is called periodically in the system thread pool to make sure g_state.ticks is timely updated +void NTAPI refresh_get_tick_count64(boost::winapi::PVOID_, boost::winapi::BOOLEAN_) +{ + get_tick_count64(); +} + +//! Cleanup function to stop get_tick_count64 refreshes +void cleanup_get_tick_count64() +{ + if (g_state.wait_handle) + { + boost::winapi::UnregisterWait(g_state.wait_handle); + g_state.wait_handle = NULL; + } + + if (g_state.wait_event) + { + boost::winapi::CloseHandle(g_state.wait_event); + g_state.wait_event = NULL; + } +} + +ticks_type WINAPI get_tick_count_init() +{ + boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll"); + if (hKernel32) + { + // GetProcAddress returns a pointer to some function. It can return + // pointers to different functions, so it has to return something that is + // suitable to store any pointer to function. Microsoft chose FARPROC, + // which is int (WINAPI *)() on 32-bit Windows. The user is supposed to + // know the signature of the function he requests and perform a cast + // (which is a nop on this platform). The result is a pointer to function + // with the required signature, which is bitwise equal to what + // GetProcAddress returned. + // However, gcc >= 8 warns about that. +#if defined(BOOST_GCC) && BOOST_GCC >= 80000 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + boost::detail::win32::detail::gettickcount64_t p = + (boost::detail::win32::detail::gettickcount64_t)boost::winapi::get_proc_address(hKernel32, "GetTickCount64"); +#if defined(BOOST_GCC) && BOOST_GCC >= 80000 +#pragma GCC diagnostic pop +#endif + if (p) + { + // Use native API + boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)p); + return p(); + } + } + + // No native API available. Use emulation with periodic refreshes to make sure the GetTickCount wrap arounds are properly counted. + init_state old_init = uninitialized; + if (g_state.init.compare_exchange_strong(old_init, in_progress, boost::memory_order_acq_rel, boost::memory_order_relaxed)) + { + if (!g_state.wait_event) + g_state.wait_event = boost::winapi::create_anonymous_event(NULL, false, false); + if (g_state.wait_event) + { + boost::winapi::BOOL_ res = boost::winapi::RegisterWaitForSingleObject(&g_state.wait_handle, g_state.wait_event, &refresh_get_tick_count64, NULL, 0x7fffffff, boost::winapi::WT_EXECUTEINWAITTHREAD_); + if (res) + { + std::atexit(&cleanup_get_tick_count64); + + boost::detail::interlocked_write_release((void**)&gettickcount64, (void*)&get_tick_count64); + g_state.init.store(initialized, boost::memory_order_release); + goto finish; + } + } + + g_state.init.store(uninitialized, boost::memory_order_release); + } + +finish: + return get_tick_count64(); +} + +} // namespace + +BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64 = &get_tick_count_init; + +#endif // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 + +} // namespace win32 +} // namespace detail +} // namespace boost diff --git a/libs/thread/src/win32/tss_dll.cpp b/libs/thread/src/win32/tss_dll.cpp new file mode 100644 index 0000000..caddabf --- /dev/null +++ b/libs/thread/src/win32/tss_dll.cpp @@ -0,0 +1,85 @@ +// (C) Copyright Michael Glassford 2004. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + + +#if defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_DLL) + + #include + + #include + + #if defined(__BORLANDC__) + extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/) + #elif defined(_WIN32_WCE) + extern "C" BOOL WINAPI DllMain(HANDLE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/) + #else + extern "C" BOOL WINAPI DllMain(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/) + #endif + { + switch(dwReason) + { + case DLL_PROCESS_ATTACH: + { + boost::on_process_enter(); + boost::on_thread_enter(); + break; + } + + case DLL_THREAD_ATTACH: + { + boost::on_thread_enter(); + break; + } + + case DLL_THREAD_DETACH: + { + boost::on_thread_exit(); + break; + } + + case DLL_PROCESS_DETACH: + { + boost::on_thread_exit(); + boost::on_process_exit(); + break; + } + } + + return TRUE; + } + +namespace boost +{ + void tss_cleanup_implemented() + { + /* + This function's sole purpose is to cause a link error in cases where + automatic tss cleanup is not implemented by Boost.Threads as a + reminder that user code is responsible for calling the necessary + functions at the appropriate times (and for implementing an a + tss_cleanup_implemented() function to eliminate the linker's + missing symbol error). + + If Boost.Threads later implements automatic tss cleanup in cases + where it currently doesn't (which is the plan), the duplicate + symbol error will warn the user that their custom solution is no + longer needed and can be removed. + */ + } +} + +#else //defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_DLL) + +#ifdef _MSC_VER +// Prevent LNK4221 warning with link=static +namespace boost { namespace link_static_warning_inhibit { + extern __declspec(dllexport) void foo() { } +} } +#endif + +#endif //defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_DLL) diff --git a/libs/thread/src/win32/tss_pe.cpp b/libs/thread/src/win32/tss_pe.cpp new file mode 100644 index 0000000..be4d8a7 --- /dev/null +++ b/libs/thread/src/win32/tss_pe.cpp @@ -0,0 +1,337 @@ +// $Id$ +// (C) Copyright Aaron W. LaFramboise, Roland Schwarz, Michael Glassford 2004. +// (C) Copyright 2007 Roland Schwarz +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007 David Deakins +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +#if defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_LIB) + +#if (defined(__MINGW32__) && !defined(_WIN64)) || defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR) + +#include + +#include + +#include + +namespace boost +{ + void tss_cleanup_implemented() {} +} + +namespace { + void NTAPI on_tls_callback(void* , DWORD dwReason, PVOID ) + { + switch (dwReason) + { + case DLL_THREAD_DETACH: + { + boost::on_thread_exit(); + break; + } + } + } +} + +#if defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR) || (__MINGW32__) || (__MINGW32_MAJOR_VERSION >3) || \ + ((__MINGW32_MAJOR_VERSION==3) && (__MINGW32_MINOR_VERSION>=18)) +extern "C" +{ + PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback; +} +#else +extern "C" { + + void (* after_ctors )() __attribute__((section(".ctors"))) = boost::on_process_enter; + void (* before_dtors)() __attribute__((section(".dtors"))) = boost::on_thread_exit; + void (* after_dtors )() __attribute__((section(".dtors.zzz"))) = boost::on_process_exit; + + ULONG __tls_index__ = 0; + char __tls_end__ __attribute__((section(".tls$zzz"))) = 0; + char __tls_start__ __attribute__((section(".tls"))) = 0; + + + PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0; + PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0; +} +extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) = +{ + (DWORD) &__tls_start__, + (DWORD) &__tls_end__, + (DWORD) &__tls_index__, + (DWORD) (&__crt_xl_start__+1), + (DWORD) 0, + (DWORD) 0 +}; +#endif + + +#elif defined(_MSC_VER) && !defined(UNDER_CE) + + #include + + #include + + #include + + +// _pRawDllMainOrig can be defined by including boost/thread/win32/mfc_thread_init.hpp +// into your dll; it ensures that MFC-Dll-initialization will be done properly +// The following code is adapted from the MFC-Dll-init code +/* + * _pRawDllMainOrig MUST be an extern const variable, which will be aliased to + * _pDefaultRawDllMainOrig if no real user definition is present, thanks to the + * alternatename directive. + */ + +// work at least with _MSC_VER 1500 (MSVC++ 9.0, VS 2008) +#if (_MSC_VER >= 1500) + +extern "C" { +extern BOOL (WINAPI * const _pRawDllMainOrig)(HINSTANCE, DWORD, LPVOID); +extern BOOL (WINAPI * const _pDefaultRawDllMainOrig)(HINSTANCE, DWORD, LPVOID) = NULL; +#if defined (_M_IX86) +#pragma comment(linker, "/alternatename:__pRawDllMainOrig=__pDefaultRawDllMainOrig") +#elif defined (_M_X64) || defined (_M_ARM) || defined (_M_ARM64) +#pragma comment(linker, "/alternatename:_pRawDllMainOrig=_pDefaultRawDllMainOrig") +#else /* unknown Windows target (not x86, x64, ARM, ARM64) */ +#error Unsupported platform +#endif /* defined (_M_X64) || defined (_M_ARM) || defined (_M_ARM64) */ +} + +#endif + + + + + //Definitions required by implementation + #if (_MSC_VER < 1300) || ((_MSC_VER > 1900) && (_MSC_VER < 1910)) // 1300 == VC++ 7.0, 1900 == VC++ 14.0, 1910 == VC++ 2017 + typedef void ( __cdecl *_PVFV_ )(); + typedef void ( __cdecl *_PIFV_ )(); + #define INIRETSUCCESS_V + #define INIRETSUCCESS_I + #define PVAPI_V void __cdecl + #define PVAPI_I void __cdecl + #elif (_MSC_VER >= 1910) + typedef void ( __cdecl *_PVFV_ )(); + typedef int ( __cdecl *_PIFV_ )(); + #define INIRETSUCCESS_V + #define INIRETSUCCESS_I 0 + #define PVAPI_V void __cdecl + #define PVAPI_I int __cdecl + #else + typedef int ( __cdecl *_PVFV_ )(); + typedef int ( __cdecl *_PIFV_ )(); + #define INIRETSUCCESS_V 0 + #define INIRETSUCCESS_I 0 + #define PVAPI_V int __cdecl + #define PVAPI_I int __cdecl + #endif + + typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID); + + //Symbols for connection to the runtime environment + + extern "C" + { + extern DWORD _tls_used; //the tls directory (located in .rdata segment) + extern _TLSCB __xl_a[], __xl_z[]; //tls initializers */ + } + + namespace + { + //Forward declarations + + static PVAPI_I on_tls_prepare(); + static PVAPI_V on_process_init(); + static PVAPI_V on_process_term(); + static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID); + + //The .CRT$Xxx information is taken from Codeguru: + //http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/ + +#if (_MSC_VER >= 1400) +#pragma section(".CRT$XIU",long,read) +#pragma section(".CRT$XCU",long,read) +#pragma section(".CRT$XTU",long,read) +#pragma section(".CRT$XLC",long,read) + __declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback; + __declspec(allocate(".CRT$XIU"))_PIFV_ p_tls_prepare = on_tls_prepare; + __declspec(allocate(".CRT$XCU"))_PVFV_ p_process_init = on_process_init; + __declspec(allocate(".CRT$XTU"))_PVFV_ p_process_term = on_process_term; +#else + #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 + # pragma data_seg(push, old_seg) + #endif + //Callback to run tls glue code first. + //I don't think it is necessary to run it + //at .CRT$XIB level, since we are only + //interested in thread detachement. But + //this could be changed easily if required. + + #pragma data_seg(".CRT$XIU") + static _PIFV_ p_tls_prepare = on_tls_prepare; + #pragma data_seg() + + //Callback after all global ctors. + + #pragma data_seg(".CRT$XCU") + static _PVFV_ p_process_init = on_process_init; + #pragma data_seg() + + //Callback for tls notifications. + + #pragma data_seg(".CRT$XLB") + _TLSCB p_thread_callback = on_tls_callback; + #pragma data_seg() + //Callback for termination. + + #pragma data_seg(".CRT$XTU") + static _PVFV_ p_process_term = on_process_term; + #pragma data_seg() + #if (_MSC_VER >= 1300) // 1300 == VC++ 7.0 + # pragma data_seg(pop, old_seg) + #endif +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4189) +#endif + + PVAPI_I on_tls_prepare() + { + //The following line has an important side effect: + //if the TLS directory is not already there, it will + //be created by the linker. In other words, it forces a tls + //directory to be generated by the linker even when static tls + //(i.e. __declspec(thread)) is not used. + //The volatile should prevent the optimizer + //from removing the reference. + + DWORD volatile dw = _tls_used; + + #if (_MSC_VER < 1300) // 1300 == VC++ 7.0 + _TLSCB* pfbegin = __xl_a; + _TLSCB* pfend = __xl_z; + _TLSCB* pfdst = pfbegin; + //pfdst = (_TLSCB*)_tls_used.AddressOfCallBacks; + + //The following loop will merge the address pointers + //into a contiguous area, since the tlssup code seems + //to require this (at least on MSVC 6) + + while (pfbegin < pfend) + { + if (*pfbegin != 0) + { + *pfdst = *pfbegin; + ++pfdst; + } + ++pfbegin; + } + + *pfdst = 0; + #endif + + return INIRETSUCCESS_I; + } +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + + PVAPI_V on_process_init() + { + //Schedule on_thread_exit() to be called for the main + //thread before destructors of global objects have been + //called. + + //It will not be run when 'quick' exiting the + //library; however, this is the standard behaviour + //for destructors of global objects, so that + //shouldn't be a problem. + + atexit(boost::on_thread_exit); + + //Call Boost process entry callback here + + boost::on_process_enter(); + + return INIRETSUCCESS_V; + } + + PVAPI_V on_process_term() + { + boost::on_process_exit(); + return INIRETSUCCESS_V; + } + + void NTAPI on_tls_callback(HINSTANCE /*h*/, DWORD dwReason, PVOID /*pv*/) + { + switch (dwReason) + { + case DLL_THREAD_DETACH: + boost::on_thread_exit(); + break; + } + } + +#if (_MSC_VER >= 1500) + BOOL WINAPI dll_callback(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) +#else + BOOL WINAPI dll_callback(HINSTANCE, DWORD dwReason, LPVOID) +#endif + { + switch (dwReason) + { + case DLL_THREAD_DETACH: + boost::on_thread_exit(); + break; + case DLL_PROCESS_DETACH: + boost::on_process_exit(); + break; + } + +#if (_MSC_VER >= 1500) + if( _pRawDllMainOrig ) + { + return _pRawDllMainOrig(hInstance, dwReason, lpReserved); + } +#endif + return true; + } + } //namespace + +extern "C" +{ + extern BOOL (WINAPI * const _pRawDllMain)(HINSTANCE, DWORD, LPVOID)=&dll_callback; +} +namespace boost +{ + void tss_cleanup_implemented() + { + /* + This function's sole purpose is to cause a link error in cases where + automatic tss cleanup is not implemented by Boost.Threads as a + reminder that user code is responsible for calling the necessary + functions at the appropriate times (and for implementing an a + tss_cleanup_implemented() function to eliminate the linker's + missing symbol error). + + If Boost.Threads later implements automatic tss cleanup in cases + where it currently doesn't (which is the plan), the duplicate + symbol error will warn the user that their custom solution is no + longer needed and can be removed. + */ + } +} + +#endif //defined(_MSC_VER) && !defined(UNDER_CE) + +#endif //defined(BOOST_THREAD_WIN32) && defined(BOOST_THREAD_BUILD_LIB)