diff --git a/boost/INSTALL b/boost/INSTALL new file mode 100644 index 000000000..c242c0457 --- /dev/null +++ b/boost/INSTALL @@ -0,0 +1,8 @@ +See ./index.html for information about this release. The "Getting Started" +section is a useful starting place. + +--------------------------- +Copyright Beman Dawes, 2008 + +Distributed under the Boost Software License, Version 1.0. +See ./LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt \ No newline at end of file diff --git a/boost/Jamroot b/boost/Jamroot new file mode 100644 index 000000000..8fe4275bc --- /dev/null +++ b/boost/Jamroot @@ -0,0 +1,312 @@ +# 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 Win32 +# 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 +# +# 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 ; + +path-constant BOOST_ROOT : . ; +constant BOOST_VERSION : 1.63.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 + : usage-requirements . + : 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) ) + { + ECHO "error: link=shared together with runtime-link=static is not allowed" ; + ECHO "error: such property combination is either impossible " ; + ECHO "error: or too dangerious to be of any use" ; + EXIT ; + } +} + +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 + { + explicit-alias $(l) : libs/$(l)/build//boost_$(l) ; + } +} + +# Log has an additional target +explicit-alias log_setup : libs/log/build//boost_log_setup ; + +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 ] +{ + use-project /boost/tools/inspect : tools/inspect/build ; +} + +if [ path.exists $(BOOST_ROOT)/libs/wave/tool ] +{ + use-project /boost/libs/wave/tool : libs/wave/tool/build ; +} + +# 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 * ) +{ + package.install install + : /boost//install-proper-headers $(install-requirements) + : # No binaries + : $(libraries) + : # No headers, it is handled by the dependency. + ; + + install stage : $(libraries) : $(BOOST_STAGE_LOCATE) ; + + module [ CALLER_MODULE ] + { + explicit stage ; + explicit install ; + } +} + +# 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 * ) +{ + name = boost_$(name) ; + autolink = shared:BOOST_$(name:U)_DYN_LINK=1 ; + lib $(name) + : $(sources) + : $(requirements) $(autolink) + : $(default-build) + : $(usage-requirements) $(autolink) + ; + boost-install $(name) ; +} + + +headers = + # The .SUNWCCh files are present in tr1 include directory and have to be + # installed (see http://lists.boost.org/Archives/boost/2007/05/121430.php). + [ path.glob-tree $(BOOST_ROOT)/boost : *.hpp *.ipp *.h *.inc *.SUNWCCh : CVS .svn ] + [ path.glob-tree $(BOOST_ROOT)/boost/compatibility/cpp_c_headers : c* : CVS .svn ] + [ path.glob boost/tr1/tr1 : * : bcc32 sun CVS .svn ] + ; + +# Declare special top-level targets that build and install the desired variants +# of the libraries. +boostcpp.declare-targets $(all-libraries) : $(headers) ; diff --git a/boost/LICENSE_1_0.txt b/boost/LICENSE_1_0.txt new file mode 100644 index 000000000..1dad8e934 --- /dev/null +++ b/boost/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/boost/README.txt b/boost/README.txt new file mode 100644 index 000000000..cd1a53151 --- /dev/null +++ b/boost/README.txt @@ -0,0 +1,11 @@ +This boost tree is a cut down version of the 1.63.0 source tree built +using the boost bcp utility, invoked thus: + +cd +/bcp iterator range math numeric crc circular_buffer build bootstrap.bat bootstrap.sh boostcpp.jam boost-build.jam + +Note that bcp is built from a separate boost source tree to avoid +polluting the clean tree used to extract components from above. + +Add other boost libraries as necessary. See the Subversion book for +details on how to maintain 3rd-party vendor content used in a project. diff --git a/boost/boost-build.jam b/boost/boost-build.jam new file mode 100644 index 000000000..5194c6628 --- /dev/null +++ b/boost/boost-build.jam @@ -0,0 +1,17 @@ +# Copyright (C) 2002-2003 David Abrahams. +# Copyright (C) 2002-2003 Vladimir Prus. +# Copyright (C) 2003,2007 Rene Rivera. +# 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 is the initial file loaded by Boost Jam when run from any Boost library +# folder. It allows us to choose which Boost Build installation to use for +# building Boost libraries. Unless explicitly selected using a command-line +# option, the version included with the Boost library distribution is used (as +# opposed to any other Boost Build version installed on the user's sytem). + +BOOST_ROOT = $(.boost-build-file:D) ; +BOOST_BUILD = [ MATCH --boost-build=(.*) : $(ARGV) ] ; +BOOST_BUILD ?= tools/build/src ; +boost-build $(BOOST_BUILD) ; diff --git a/boost/boost.css b/boost/boost.css new file mode 100644 index 000000000..5a571c207 --- /dev/null +++ b/boost/boost.css @@ -0,0 +1,66 @@ +/*============================================================================= + Copyright 2002 William E. Kempf + Distributed under the Boost Software License, Version 1.0. (See accompany- + ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ + +H1 +{ + FONT-SIZE: 200%; + COLOR: #00008B; +} +H2 +{ + FONT-SIZE: 150%; +} +H3 +{ + FONT-SIZE: 125%; +} +H4 +{ + FONT-SIZE: 108%; +} +BODY +{ + FONT-SIZE: 100%; + BACKGROUND-COLOR: #ffffff; + COLOR: #000000; +} +PRE +{ + MARGIN-LEFT: 2em; + FONT-FAMILY: Courier, + monospace; +} +CODE +{ + FONT-FAMILY: Courier, + monospace; +} +CODE.as_pre +{ + white-space: pre; +} +.index +{ + TEXT-ALIGN: left; +} +.page-index +{ + TEXT-ALIGN: left; +} +.definition +{ + TEXT-ALIGN: left; +} +.footnote +{ + FONT-SIZE: 66%; + VERTICAL-ALIGN: super; + TEXT-DECORATION: none; +} +.function-semantics +{ + CLEAR: left; +} \ No newline at end of file diff --git a/boost/boost.png b/boost/boost.png new file mode 100644 index 000000000..b4d51fcd5 Binary files /dev/null and b/boost/boost.png differ diff --git a/boost/boost/circular_buffer.hpp b/boost/boost/circular_buffer.hpp new file mode 100644 index 000000000..ba0a73a88 --- /dev/null +++ b/boost/boost/circular_buffer.hpp @@ -0,0 +1,62 @@ +// Circular buffer library header file. + +// Copyright (c) 2003-2008 Jan Gaspar + +// 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) + +// See www.boost.org/libs/circular_buffer for documentation. + +#if !defined(BOOST_CIRCULAR_BUFFER_HPP) +#define BOOST_CIRCULAR_BUFFER_HPP + +#if defined(_MSC_VER) + #pragma once +#endif + +#include +#include +#include + +// BOOST_CB_ENABLE_DEBUG: Debug support control. +#if !defined(BOOST_CB_ENABLE_DEBUG) + #define BOOST_CB_ENABLE_DEBUG 0 +#endif + +// BOOST_CB_ASSERT: Runtime assertion. +#if BOOST_CB_ENABLE_DEBUG + #include + #define BOOST_CB_ASSERT(Expr) BOOST_ASSERT(Expr) +#else + #define BOOST_CB_ASSERT(Expr) ((void)0) +#endif + +// BOOST_CB_IS_CONVERTIBLE: Check if Iterator::value_type is convertible to Type. +#if BOOST_WORKAROUND(__BORLANDC__, <= 0x0550) || BOOST_WORKAROUND(__MWERKS__, <= 0x2407) + #define BOOST_CB_IS_CONVERTIBLE(Iterator, Type) ((void)0) +#else + #include + #include + #define BOOST_CB_IS_CONVERTIBLE(Iterator, Type) \ + BOOST_STATIC_ASSERT((is_convertible::value_type, Type>::value)) +#endif + +// BOOST_CB_ASSERT_TEMPLATED_ITERATOR_CONSTRUCTORS: +// Check if the STL provides templated iterator constructors for its containers. +#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) + #define BOOST_CB_ASSERT_TEMPLATED_ITERATOR_CONSTRUCTORS BOOST_STATIC_ASSERT(false); +#else + #define BOOST_CB_ASSERT_TEMPLATED_ITERATOR_CONSTRUCTORS ((void)0); +#endif + +#include +#include +#include +#include + +#undef BOOST_CB_ASSERT_TEMPLATED_ITERATOR_CONSTRUCTORS +#undef BOOST_CB_IS_CONVERTIBLE +#undef BOOST_CB_ASSERT + +#endif // #if !defined(BOOST_CIRCULAR_BUFFER_HPP) diff --git a/boost/boost/circular_buffer/base.hpp b/boost/boost/circular_buffer/base.hpp new file mode 100644 index 000000000..8f2f16231 --- /dev/null +++ b/boost/boost/circular_buffer/base.hpp @@ -0,0 +1,3123 @@ +// Implementation of the base circular buffer. + +// Copyright (c) 2003-2008 Jan Gaspar +// Copyright (c) 2013 Paul A. Bristow // Doxygen comments changed. +// Copyright (c) 2013 Antony Polukhin // Move semantics implementation. +// Copyright (c) 2014 Glen Fernandes // C++11 allocator model support. + +// 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) + +#if !defined(BOOST_CIRCULAR_BUFFER_BASE_HPP) +#define BOOST_CIRCULAR_BUFFER_BASE_HPP + +#if defined(_MSC_VER) + #pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3205)) + #include +#endif + +namespace boost { + +/*! + \class circular_buffer + \brief Circular buffer - a STL compliant container. + \tparam T The type of the elements stored in the circular_buffer. + \par Type Requirements T + The T has to be + SGIAssignable (SGI STL defined combination of + Assignable and CopyConstructible). + Moreover T has to be + DefaultConstructible if supplied as a default parameter when invoking some of the + circular_buffer's methods e.g. + insert(iterator pos, const value_type& item = %value_type()). And + EqualityComparable and/or + LessThanComparable if the circular_buffer + will be compared with another container. + \tparam Alloc The allocator type used for all internal memory management. + \par Type Requirements Alloc + The Alloc has to meet the allocator requirements imposed by STL. + \par Default Alloc + std::allocator + + For detailed documentation of the circular_buffer visit: + http://www.boost.org/libs/circular_buffer/doc/circular_buffer.html +*/ +template +class circular_buffer +/*! \cond */ +#if BOOST_CB_ENABLE_DEBUG +: public cb_details::debug_iterator_registry +#endif +/*! \endcond */ +{ + + // Requirements + //BOOST_CLASS_REQUIRE(T, boost, SGIAssignableConcept); + + + //BOOST_CONCEPT_ASSERT((Assignable)); + //BOOST_CONCEPT_ASSERT((CopyConstructible)); + //BOOST_CONCEPT_ASSERT((DefaultConstructible)); + + // Required if the circular_buffer will be compared with anther container. + //BOOST_CONCEPT_ASSERT((EqualityComparable)); + //BOOST_CONCEPT_ASSERT((LessThanComparable)); + +public: +// Basic types + + //! The type of this circular_buffer. + typedef circular_buffer this_type; + + //! The type of elements stored in the circular_buffer. + typedef typename boost::container::allocator_traits::value_type value_type; + + //! A pointer to an element. + typedef typename boost::container::allocator_traits::pointer pointer; + + //! A const pointer to the element. + typedef typename boost::container::allocator_traits::const_pointer const_pointer; + + //! A reference to an element. + typedef typename boost::container::allocator_traits::reference reference; + + //! A const reference to an element. + typedef typename boost::container::allocator_traits::const_reference const_reference; + + //! The distance type. + /*! + (A signed integral type used to represent the distance between two iterators.) + */ + typedef typename boost::container::allocator_traits::difference_type difference_type; + + //! The size type. + /*! + (An unsigned integral type that can represent any non-negative value of the container's distance type.) + */ + typedef typename boost::container::allocator_traits::size_type size_type; + + //! The type of an allocator used in the circular_buffer. + typedef Alloc allocator_type; + +// Iterators + + //! A const (random access) iterator used to iterate through the circular_buffer. + typedef cb_details::iterator< circular_buffer, cb_details::const_traits > > const_iterator; + + //! A (random access) iterator used to iterate through the circular_buffer. + typedef cb_details::iterator< circular_buffer, cb_details::nonconst_traits > > iterator; + + //! A const iterator used to iterate backwards through a circular_buffer. + typedef boost::reverse_iterator const_reverse_iterator; + + //! An iterator used to iterate backwards through a circular_buffer. + typedef boost::reverse_iterator reverse_iterator; + +// Container specific types + + //! An array range. + /*! + (A typedef for the std::pair where + its first element is a pointer to a beginning of an array and its second element represents + a size of the array.) + */ + typedef std::pair array_range; + + //! A range of a const array. + /*! + (A typedef for the std::pair where + its first element is a pointer to a beginning of a const array and its second element represents + a size of the const array.) + */ + typedef std::pair const_array_range; + + //! The capacity type. + /*! + (Same as size_type - defined for consistency with the __cbso class. + + */ + // circular_buffer_space_optimized.) + + typedef size_type capacity_type; + +// Helper types + + //! A type representing the "best" way to pass the value_type to a method. + typedef const value_type& param_value_type; + + //! A type representing rvalue from param type. + //! On compilers without rvalue references support this type is the Boost.Moves type used for emulation. + typedef BOOST_RV_REF(value_type) rvalue_type; + +private: +// Member variables + + //! The internal buffer used for storing elements in the circular buffer. + pointer m_buff; + + //! The internal buffer's end (end of the storage space). + pointer m_end; + + //! The virtual beginning of the circular buffer. + pointer m_first; + + //! The virtual end of the circular buffer (one behind the last element). + pointer m_last; + + //! The number of items currently stored in the circular buffer. + size_type m_size; + + //! The allocator. + allocator_type m_alloc; + +// Friends +#if defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) + friend iterator; + friend const_iterator; +#else + template friend struct cb_details::iterator; +#endif + +public: +// Allocator + + //! Get the allocator. + /*! + \return The allocator. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa get_allocator() for obtaining an allocator %reference. + */ + allocator_type get_allocator() const BOOST_NOEXCEPT { return m_alloc; } + + //! Get the allocator reference. + /*! + \return A reference to the allocator. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \note This method was added in order to optimize obtaining of the allocator with a state, + although use of stateful allocators in STL is discouraged. + \sa get_allocator() const + */ + allocator_type& get_allocator() BOOST_NOEXCEPT { return m_alloc; } + +// Element access + + //! Get the iterator pointing to the beginning of the circular_buffer. + /*! + \return A random access iterator pointing to the first element of the circular_buffer. If the + circular_buffer is empty it returns an iterator equal to the one returned by + end(). + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa end(), rbegin(), rend() + */ + iterator begin() BOOST_NOEXCEPT { return iterator(this, empty() ? 0 : m_first); } + + //! Get the iterator pointing to the end of the circular_buffer. + /*! + \return A random access iterator pointing to the element "one behind" the last element of the + circular_buffer. If the circular_buffer is empty it returns an iterator equal to + the one returned by begin(). + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa begin(), rbegin(), rend() + */ + iterator end() BOOST_NOEXCEPT { return iterator(this, 0); } + + //! Get the const iterator pointing to the beginning of the circular_buffer. + /*! + \return A const random access iterator pointing to the first element of the circular_buffer. If + the circular_buffer is empty it returns an iterator equal to the one returned by + end() const. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa end() const, rbegin() const, rend() const + */ + const_iterator begin() const BOOST_NOEXCEPT { return const_iterator(this, empty() ? 0 : m_first); } + + //! Get the const iterator pointing to the end of the circular_buffer. + /*! + \return A const random access iterator pointing to the element "one behind" the last element of the + circular_buffer. If the circular_buffer is empty it returns an iterator equal to + the one returned by begin() const const. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa begin() const, rbegin() const, rend() const + */ + const_iterator end() const BOOST_NOEXCEPT { return const_iterator(this, 0); } + + //! Get the iterator pointing to the beginning of the "reversed" circular_buffer. + /*! + \return A reverse random access iterator pointing to the last element of the circular_buffer. + If the circular_buffer is empty it returns an iterator equal to the one returned by + rend(). + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa rend(), begin(), end() + */ + reverse_iterator rbegin() BOOST_NOEXCEPT { return reverse_iterator(end()); } + + //! Get the iterator pointing to the end of the "reversed" circular_buffer. + /*! + \return A reverse random access iterator pointing to the element "one before" the first element of the + circular_buffer. If the circular_buffer is empty it returns an iterator equal to + the one returned by rbegin(). + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa rbegin(), begin(), end() + */ + reverse_iterator rend() BOOST_NOEXCEPT { return reverse_iterator(begin()); } + + //! Get the const iterator pointing to the beginning of the "reversed" circular_buffer. + /*! + \return A const reverse random access iterator pointing to the last element of the + circular_buffer. If the circular_buffer is empty it returns an iterator equal + to the one returned by rend() const. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa rend() const, begin() const, end() const + */ + const_reverse_iterator rbegin() const BOOST_NOEXCEPT { return const_reverse_iterator(end()); } + + //! Get the const iterator pointing to the end of the "reversed" circular_buffer. + /*! + \return A const reverse random access iterator pointing to the element "one before" the first element of the + circular_buffer. If the circular_buffer is empty it returns an iterator equal + to the one returned by rbegin() const. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa rbegin() const, begin() const, end() const + */ + const_reverse_iterator rend() const BOOST_NOEXCEPT { return const_reverse_iterator(begin()); } + + //! Get the element at the index position. + /*! + \pre 0 \<= index \&\& index \< size() + \param index The position of the element. + \return A reference to the element at the index position. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa at() + */ + reference operator [] (size_type index) { + BOOST_CB_ASSERT(index < size()); // check for invalid index + return *add(m_first, index); + } + + //! Get the element at the index position. + /*! + \pre 0 \<= index \&\& index \< size() + \param index The position of the element. + \return A const reference to the element at the index position. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa \link at(size_type)const at() const \endlink + */ + const_reference operator [] (size_type index) const { + BOOST_CB_ASSERT(index < size()); // check for invalid index + return *add(m_first, index); + } + + //! Get the element at the index position. + /*! + \param index The position of the element. + \return A reference to the element at the index position. + \throws std::out_of_range when the index is invalid (when + index >= size()). + \par Exception Safety + Strong. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa \link operator[](size_type) operator[] \endlink + */ + reference at(size_type index) { + check_position(index); + return (*this)[index]; + } + + //! Get the element at the index position. + /*! + \param index The position of the element. + \return A const reference to the element at the index position. + \throws std::out_of_range when the index is invalid (when + index >= size()). + \par Exception Safety + Strong. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa \link operator[](size_type)const operator[] const \endlink + */ + const_reference at(size_type index) const { + check_position(index); + return (*this)[index]; + } + + //! Get the first element. + /*! + \pre !empty() + \return A reference to the first element of the circular_buffer. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa back() + */ + reference front() { + BOOST_CB_ASSERT(!empty()); // check for empty buffer (front element not available) + return *m_first; + } + + //! Get the last element. + /*! + \pre !empty() + \return A reference to the last element of the circular_buffer. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa front() + */ + reference back() { + BOOST_CB_ASSERT(!empty()); // check for empty buffer (back element not available) + return *((m_last == m_buff ? m_end : m_last) - 1); + } + + //! Get the first element. + /*! + \pre !empty() + \return A const reference to the first element of the circular_buffer. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa back() const + */ + const_reference front() const { + BOOST_CB_ASSERT(!empty()); // check for empty buffer (front element not available) + return *m_first; + } + + //! Get the last element. + /*! + \pre !empty() + \return A const reference to the last element of the circular_buffer. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa front() const + */ + const_reference back() const { + BOOST_CB_ASSERT(!empty()); // check for empty buffer (back element not available) + return *((m_last == m_buff ? m_end : m_last) - 1); + } + + //! Get the first continuous array of the internal buffer. + /*! + This method in combination with array_two() can be useful when passing the stored data into + a legacy C API as an array. Suppose there is a circular_buffer of capacity 10, containing 7 + characters 'a', 'b', ..., 'g' where buff[0] == 'a', buff[1] == 'b', + ... and buff[6] == 'g':

+ circular_buffer buff(10);

+ The internal representation is often not linear and the state of the internal buffer may look like this:
+
+ |e|f|g| | | |a|b|c|d|
+ end ___^
+ begin _______^


+ + where |a|b|c|d| represents the "array one", |e|f|g| represents the "array two" and + | | | | is a free space.
+ Now consider a typical C style function for writing data into a file:

+ int write(int file_desc, char* buff, int num_bytes);

+ There are two ways how to write the content of the circular_buffer into a file. Either relying + on array_one() and array_two() methods and calling the write function twice:

+ array_range ar = buff.array_one();
+ write(file_desc, ar.first, ar.second);
+ ar = buff.array_two();
+ write(file_desc, ar.first, ar.second);


+ Or relying on the linearize() method:

+ write(file_desc, buff.linearize(), buff.size());

+ Since the complexity of array_one() and array_two() methods is constant the first + option is suitable when calling the write method is "cheap". On the other hand the second option is more + suitable when calling the write method is more "expensive" than calling the linearize() method + whose complexity is linear. + \return The array range of the first continuous array of the internal buffer. In the case the + circular_buffer is empty the size of the returned array is 0. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \warning In general invoking any method which modifies the internal state of the circular_buffer may + delinearize the internal buffer and invalidate the array ranges returned by array_one() + and array_two() (and their const versions). + \note In the case the internal buffer is linear e.g. |a|b|c|d|e|f|g| | | | the "array one" is + represented by |a|b|c|d|e|f|g| and the "array two" does not exist (the + array_two() method returns an array with the size 0). + \sa array_two(), linearize() + */ + array_range array_one() { + return array_range(m_first, (m_last <= m_first && !empty() ? m_end : m_last) - m_first); + } + + //! Get the second continuous array of the internal buffer. + /*! + This method in combination with array_one() can be useful when passing the stored data into + a legacy C API as an array. + \return The array range of the second continuous array of the internal buffer. In the case the internal buffer + is linear or the circular_buffer is empty the size of the returned array is + 0. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa array_one() + */ + array_range array_two() { + return array_range(m_buff, m_last <= m_first && !empty() ? m_last - m_buff : 0); + } + + //! Get the first continuous array of the internal buffer. + /*! + This method in combination with array_two() const can be useful when passing the stored data into + a legacy C API as an array. + \return The array range of the first continuous array of the internal buffer. In the case the + circular_buffer is empty the size of the returned array is 0. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa array_two() const; array_one() for more details how to pass data into a legacy C + API. + */ + const_array_range array_one() const { + return const_array_range(m_first, (m_last <= m_first && !empty() ? m_end : m_last) - m_first); + } + + //! Get the second continuous array of the internal buffer. + /*! + This method in combination with array_one() const can be useful when passing the stored data into + a legacy C API as an array. + \return The array range of the second continuous array of the internal buffer. In the case the internal buffer + is linear or the circular_buffer is empty the size of the returned array is + 0. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa array_one() const + */ + const_array_range array_two() const { + return const_array_range(m_buff, m_last <= m_first && !empty() ? m_last - m_buff : 0); + } + + //! Linearize the internal buffer into a continuous array. + /*! + This method can be useful when passing the stored data into a legacy C API as an array. + \post \&(*this)[0] \< \&(*this)[1] \< ... \< \&(*this)[size() - 1] + \return A pointer to the beginning of the array or 0 if empty. + \throws Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operations in the Throws section do not throw anything. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer (except iterators equal to + end()); does not invalidate any iterators if the postcondition (the Effect) is already + met prior calling this method. + \par Complexity + Linear (in the size of the circular_buffer); constant if the postcondition (the + Effect) is already met. + \warning In general invoking any method which modifies the internal state of the circular_buffer + may delinearize the internal buffer and invalidate the returned pointer. + \sa array_one() and array_two() for the other option how to pass data into a legacy + C API; is_linearized(), rotate(const_iterator) + */ + pointer linearize() { + if (empty()) + return 0; + if (m_first < m_last || m_last == m_buff) + return m_first; + pointer src = m_first; + pointer dest = m_buff; + size_type moved = 0; + size_type constructed = 0; + BOOST_TRY { + for (pointer first = m_first; dest < src; src = first) { + for (size_type ii = 0; src < m_end; ++src, ++dest, ++moved, ++ii) { + if (moved == size()) { + first = dest; + break; + } + if (dest == first) { + first += ii; + break; + } + if (is_uninitialized(dest)) { + boost::container::allocator_traits::construct(m_alloc, boost::addressof(*dest), boost::move_if_noexcept(*src)); + ++constructed; + } else { + value_type tmp = boost::move_if_noexcept(*src); + replace(src, boost::move_if_noexcept(*dest)); + replace(dest, boost::move(tmp)); + } + } + } + } BOOST_CATCH(...) { + m_last += constructed; + m_size += constructed; + BOOST_RETHROW + } + BOOST_CATCH_END + for (src = m_end - constructed; src < m_end; ++src) + destroy_item(src); + m_first = m_buff; + m_last = add(m_buff, size()); +#if BOOST_CB_ENABLE_DEBUG + invalidate_iterators_except(end()); +#endif + return m_buff; + } + + //! Is the circular_buffer linearized? + /*! + \return true if the internal buffer is linearized into a continuous array (i.e. the + circular_buffer meets a condition + \&(*this)[0] \< \&(*this)[1] \< ... \< \&(*this)[size() - 1]); + false otherwise. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa linearize(), array_one(), array_two() + */ + bool is_linearized() const BOOST_NOEXCEPT { return m_first < m_last || m_last == m_buff; } + + //! Rotate elements in the circular_buffer. + /*! + A more effective implementation of + std::rotate. + \pre new_begin is a valid iterator pointing to the circular_buffer except its + end. + \post Before calling the method suppose:

+ m == std::distance(new_begin, end())
n == std::distance(begin(), new_begin) +
val_0 == *new_begin, val_1 == *(new_begin + 1), ... val_m == *(new_begin + m)
+ val_r1 == *(new_begin - 1), val_r2 == *(new_begin - 2), ... val_rn == *(new_begin - n)
+
then after call to the method:

+ val_0 == (*this)[0] \&\& val_1 == (*this)[1] \&\& ... \&\& val_m == (*this)[m - 1] \&\& val_r1 == + (*this)[m + n - 1] \&\& val_r2 == (*this)[m + n - 2] \&\& ... \&\& val_rn == (*this)[m] + \param new_begin The new beginning. + \throws See Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the circular_buffer is full or new_begin points to + begin() or if the operations in the Throws section do not throw anything. + \par Iterator Invalidation + If m \< n invalidates iterators pointing to the last m elements + (including new_begin, but not iterators equal to end()) else invalidates + iterators pointing to the first n elements; does not invalidate any iterators if the + circular_buffer is full. + \par Complexity + Linear (in (std::min)(m, n)); constant if the circular_buffer is full. + \sa std::rotate + */ + void rotate(const_iterator new_begin) { + BOOST_CB_ASSERT(new_begin.is_valid(this)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(new_begin.m_it != 0); // check for iterator pointing to end() + if (full()) { + m_first = m_last = const_cast(new_begin.m_it); + } else { + difference_type m = end() - new_begin; + difference_type n = new_begin - begin(); + if (m < n) { + for (; m > 0; --m) { + push_front(boost::move_if_noexcept(back())); + pop_back(); + } + } else { + for (; n > 0; --n) { + push_back(boost::move_if_noexcept(front())); + pop_front(); + } + } + } + } + +// Size and capacity + + //! Get the number of elements currently stored in the circular_buffer. + /*! + \return The number of elements stored in the circular_buffer. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa capacity(), max_size(), reserve(), + \link resize() resize(size_type, const_reference)\endlink + */ + size_type size() const BOOST_NOEXCEPT { return m_size; } + + /*! \brief Get the largest possible size or capacity of the circular_buffer. (It depends on + allocator's %max_size()). + \return The maximum size/capacity the circular_buffer can be set to. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa size(), capacity(), reserve() + */ + size_type max_size() const BOOST_NOEXCEPT { + return (std::min)(boost::container::allocator_traits::max_size(m_alloc), (std::numeric_limits::max)()); + } + + //! Is the circular_buffer empty? + /*! + \return true if there are no elements stored in the circular_buffer; + false otherwise. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa full() + */ + bool empty() const BOOST_NOEXCEPT { return size() == 0; } + + //! Is the circular_buffer full? + /*! + \return true if the number of elements stored in the circular_buffer + equals the capacity of the circular_buffer; false otherwise. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa empty() + */ + bool full() const BOOST_NOEXCEPT { return capacity() == size(); } + + /*! \brief Get the maximum number of elements which can be inserted into the circular_buffer without + overwriting any of already stored elements. + \return capacity() - size() + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa capacity(), size(), max_size() + */ + size_type reserve() const BOOST_NOEXCEPT { return capacity() - size(); } + + //! Get the capacity of the circular_buffer. + /*! + \return The maximum number of elements which can be stored in the circular_buffer. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer). + \sa reserve(), size(), max_size(), + set_capacity(capacity_type) + */ + capacity_type capacity() const BOOST_NOEXCEPT { return m_end - m_buff; } + + //! Change the capacity of the circular_buffer. + /*! + \pre If T is a move only type, then compiler shall support noexcept modifiers + and move constructor of T must be marked with it (must not throw exceptions). + \post capacity() == new_capacity \&\& size() \<= new_capacity

+ If the current number of elements stored in the circular_buffer is greater than the desired + new capacity then number of [size() - new_capacity] last elements will be removed and + the new size will be equal to new_capacity. + \param new_capacity The new capacity. + \throws "An allocation error" if memory is exhausted, (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Strong. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer (except iterators equal to + end()) if the new capacity is different from the original. + \par Complexity + Linear (in min[size(), new_capacity]). + \sa rset_capacity(capacity_type), + \link resize() resize(size_type, const_reference)\endlink + */ + void set_capacity(capacity_type new_capacity) { + if (new_capacity == capacity()) + return; + pointer buff = allocate(new_capacity); + iterator b = begin(); + BOOST_TRY { + reset(buff, + cb_details::uninitialized_move_if_noexcept(b, b + (std::min)(new_capacity, size()), buff, m_alloc), + new_capacity); + } BOOST_CATCH(...) { + deallocate(buff, new_capacity); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + //! Change the size of the circular_buffer. + /*! + \post size() == new_size \&\& capacity() >= new_size

+ If the new size is greater than the current size, copies of item will be inserted at the + back of the of the circular_buffer in order to achieve the desired size. In the case + the resulting size exceeds the current capacity the capacity will be set to new_size.
+ If the current number of elements stored in the circular_buffer is greater than the desired + new size then number of [size() - new_size] last elements will be removed. (The + capacity will remain unchanged.) + \param new_size The new size. + \param item The element the circular_buffer will be filled with in order to gain the requested + size. (See the Effect.) + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer (except iterators equal to + end()) if the new size is greater than the current capacity. Invalidates iterators pointing + to the removed elements if the new size is lower that the original size. Otherwise it does not invalidate + any iterator. + \par Complexity + Linear (in the new size of the circular_buffer). + \sa \link rresize() rresize(size_type, const_reference)\endlink, + set_capacity(capacity_type) + */ + void resize(size_type new_size, param_value_type item = value_type()) { + if (new_size > size()) { + if (new_size > capacity()) + set_capacity(new_size); + insert(end(), new_size - size(), item); + } else { + iterator e = end(); + erase(e - (size() - new_size), e); + } + } + + //! Change the capacity of the circular_buffer. + /*! + \pre If T is a move only type, then compiler shall support noexcept modifiers + and move constructor of T must be marked with it (must not throw exceptions). + \post capacity() == new_capacity \&\& size() \<= new_capacity

+ If the current number of elements stored in the circular_buffer is greater than the desired + new capacity then number of [size() - new_capacity] first elements will be removed + and the new size will be equal to new_capacity. + \param new_capacity The new capacity. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Strong. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer (except iterators equal to + end()) if the new capacity is different from the original. + \par Complexity + Linear (in min[size(), new_capacity]). + \sa set_capacity(capacity_type), + \link rresize() rresize(size_type, const_reference)\endlink + */ + void rset_capacity(capacity_type new_capacity) { + if (new_capacity == capacity()) + return; + pointer buff = allocate(new_capacity); + iterator e = end(); + BOOST_TRY { + reset(buff, cb_details::uninitialized_move_if_noexcept(e - (std::min)(new_capacity, size()), + e, buff, m_alloc), new_capacity); + } BOOST_CATCH(...) { + deallocate(buff, new_capacity); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + //! Change the size of the circular_buffer. + /*! + \post size() == new_size \&\& capacity() >= new_size

+ If the new size is greater than the current size, copies of item will be inserted at the + front of the of the circular_buffer in order to achieve the desired size. In the case + the resulting size exceeds the current capacity the capacity will be set to new_size.
+ If the current number of elements stored in the circular_buffer is greater than the desired + new size then number of [size() - new_size] first elements will be removed. (The + capacity will remain unchanged.) + \param new_size The new size. + \param item The element the circular_buffer will be filled with in order to gain the requested + size. (See the Effect.) + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer (except iterators equal to + end()) if the new size is greater than the current capacity. Invalidates iterators pointing + to the removed elements if the new size is lower that the original size. Otherwise it does not invalidate + any iterator. + \par Complexity + Linear (in the new size of the circular_buffer). + \sa \link resize() resize(size_type, const_reference)\endlink, + rset_capacity(capacity_type) + */ + void rresize(size_type new_size, param_value_type item = value_type()) { + if (new_size > size()) { + if (new_size > capacity()) + set_capacity(new_size); + rinsert(begin(), new_size - size(), item); + } else { + rerase(begin(), end() - new_size); + } + } + +// Construction/Destruction + + //! Create an empty circular_buffer with zero capacity. + /*! + \post capacity() == 0 \&\& size() == 0 + \param alloc The allocator. + \throws Nothing. + \par Complexity + Constant. + \warning Since Boost version 1.36 the behaviour of this constructor has changed. Now the constructor does not + allocate any memory and both capacity and size are set to zero. Also note when inserting an element + into a circular_buffer with zero capacity (e.g. by + \link push_back() push_back(const_reference)\endlink or + \link insert(iterator, param_value_type) insert(iterator, value_type)\endlink) nothing + will be inserted and the size (as well as capacity) remains zero. + \note You can explicitly set the capacity by calling the set_capacity(capacity_type) method or you + can use the other constructor with the capacity specified. + \sa circular_buffer(capacity_type, const allocator_type& alloc), + set_capacity(capacity_type) + */ + explicit circular_buffer(const allocator_type& alloc = allocator_type()) BOOST_NOEXCEPT + : m_buff(0), m_end(0), m_first(0), m_last(0), m_size(0), m_alloc(alloc) {} + + //! Create an empty circular_buffer with the specified capacity. + /*! + \post capacity() == buffer_capacity \&\& size() == 0 + \param buffer_capacity The maximum number of elements which can be stored in the circular_buffer. + \param alloc The allocator. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + \par Complexity + Constant. + */ + explicit circular_buffer(capacity_type buffer_capacity, const allocator_type& alloc = allocator_type()) + : m_size(0), m_alloc(alloc) { + initialize_buffer(buffer_capacity); + m_first = m_last = m_buff; + } + + /*! \brief Create a full circular_buffer with the specified capacity and filled with n + copies of item. + \post capacity() == n \&\& full() \&\& (*this)[0] == item \&\& (*this)[1] == item \&\& ... \&\& + (*this)[n - 1] == item + \param n The number of elements the created circular_buffer will be filled with. + \param item The element the created circular_buffer will be filled with. + \param alloc The allocator. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Complexity + Linear (in the n). + */ + circular_buffer(size_type n, param_value_type item, const allocator_type& alloc = allocator_type()) + : m_size(n), m_alloc(alloc) { + initialize_buffer(n, item); + m_first = m_last = m_buff; + } + + /*! \brief Create a circular_buffer with the specified capacity and filled with n + copies of item. + \pre buffer_capacity >= n + \post capacity() == buffer_capacity \&\& size() == n \&\& (*this)[0] == item \&\& (*this)[1] == item + \&\& ... \&\& (*this)[n - 1] == item + \param buffer_capacity The capacity of the created circular_buffer. + \param n The number of elements the created circular_buffer will be filled with. + \param item The element the created circular_buffer will be filled with. + \param alloc The allocator. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Complexity + Linear (in the n). + */ + circular_buffer(capacity_type buffer_capacity, size_type n, param_value_type item, + const allocator_type& alloc = allocator_type()) + : m_size(n), m_alloc(alloc) { + BOOST_CB_ASSERT(buffer_capacity >= size()); // check for capacity lower than size + initialize_buffer(buffer_capacity, item); + m_first = m_buff; + m_last = buffer_capacity == n ? m_buff : m_buff + n; + } + + //! The copy constructor. + /*! + Creates a copy of the specified circular_buffer. + \post *this == cb + \param cb The circular_buffer to be copied. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Complexity + Linear (in the size of cb). + */ + circular_buffer(const circular_buffer& cb) + : +#if BOOST_CB_ENABLE_DEBUG + debug_iterator_registry(), +#endif + m_size(cb.size()), m_alloc(cb.get_allocator()) { + initialize_buffer(cb.capacity()); + m_first = m_buff; + BOOST_TRY { + m_last = cb_details::uninitialized_copy(cb.begin(), cb.end(), m_buff, m_alloc); + } BOOST_CATCH(...) { + deallocate(m_buff, cb.capacity()); + BOOST_RETHROW + } + BOOST_CATCH_END + if (m_last == m_end) + m_last = m_buff; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + //! The move constructor. + /*! \brief Move constructs a circular_buffer from cb, leaving cb empty. + \pre C++ compiler with rvalue references support. + \post cb.empty() + \param cb circular_buffer to 'steal' value from. + \throws Nothing. + \par Constant. + */ + circular_buffer(circular_buffer&& cb) BOOST_NOEXCEPT + : m_buff(0), m_end(0), m_first(0), m_last(0), m_size(0), m_alloc(cb.get_allocator()) { + cb.swap(*this); + } +#endif // BOOST_NO_CXX11_RVALUE_REFERENCES + + //! Create a full circular_buffer filled with a copy of the range. + /*! + \pre Valid range [first, last).
+ first and last have to meet the requirements of + InputIterator. + \post capacity() == std::distance(first, last) \&\& full() \&\& (*this)[0]== *first \&\& + (*this)[1] == *(first + 1) \&\& ... \&\& (*this)[std::distance(first, last) - 1] == *(last - 1) + \param first The beginning of the range to be copied. + \param last The end of the range to be copied. + \param alloc The allocator. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Complexity + Linear (in the std::distance(first, last)). + */ + template + circular_buffer(InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type()) + : m_alloc(alloc) { + initialize(first, last, is_integral()); + } + + //! Create a circular_buffer with the specified capacity and filled with a copy of the range. + /*! + \pre Valid range [first, last).
+ first and last have to meet the requirements of + InputIterator. + \post capacity() == buffer_capacity \&\& size() \<= std::distance(first, last) \&\& + (*this)[0]== *(last - buffer_capacity) \&\& (*this)[1] == *(last - buffer_capacity + 1) \&\& ... \&\& + (*this)[buffer_capacity - 1] == *(last - 1)

+ If the number of items to be copied from the range [first, last) is greater than the + specified buffer_capacity then only elements from the range + [last - buffer_capacity, last) will be copied. + \param buffer_capacity The capacity of the created circular_buffer. + \param first The beginning of the range to be copied. + \param last The end of the range to be copied. + \param alloc The allocator. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Complexity + Linear (in std::distance(first, last); in + min[capacity, std::distance(first, last)] if the InputIterator is a + RandomAccessIterator). + */ + template + circular_buffer(capacity_type buffer_capacity, InputIterator first, InputIterator last, + const allocator_type& alloc = allocator_type()) + : m_alloc(alloc) { + initialize(buffer_capacity, first, last, is_integral()); + } + + //! The destructor. + /*! + Destroys the circular_buffer. + \throws Nothing. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer (including iterators equal to + end()). + \par Complexity + Constant (in the size of the circular_buffer) for scalar types; linear for other types. + \sa clear() + */ + ~circular_buffer() BOOST_NOEXCEPT { + destroy(); +#if BOOST_CB_ENABLE_DEBUG + invalidate_all_iterators(); +#endif + } + +public: +// Assign methods + + //! The assign operator. + /*! + Makes this circular_buffer to become a copy of the specified circular_buffer. + \post *this == cb + \param cb The circular_buffer to be copied. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Exception Safety + Strong. + \par Iterator Invalidation + Invalidates all iterators pointing to this circular_buffer (except iterators equal to + end()). + \par Complexity + Linear (in the size of cb). + \sa \link assign(size_type, param_value_type) assign(size_type, const_reference)\endlink, + \link assign(capacity_type, size_type, param_value_type) + assign(capacity_type, size_type, const_reference)\endlink, + assign(InputIterator, InputIterator), + assign(capacity_type, InputIterator, InputIterator) + */ + circular_buffer& operator = (const circular_buffer& cb) { + if (this == &cb) + return *this; + pointer buff = allocate(cb.capacity()); + BOOST_TRY { + reset(buff, cb_details::uninitialized_copy(cb.begin(), cb.end(), buff, m_alloc), cb.capacity()); + } BOOST_CATCH(...) { + deallocate(buff, cb.capacity()); + BOOST_RETHROW + } + BOOST_CATCH_END + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + /*! \brief Move assigns content of cb to *this, leaving cb empty. + \pre C++ compiler with rvalue references support. + \post cb.empty() + \param cb circular_buffer to 'steal' value from. + \throws Nothing. + \par Complexity + Constant. + */ + circular_buffer& operator = (circular_buffer&& cb) BOOST_NOEXCEPT { + cb.swap(*this); // now `this` holds `cb` + circular_buffer(get_allocator()) // temprary that holds initial `cb` allocator + .swap(cb); // makes `cb` empty + return *this; + } +#endif // BOOST_NO_CXX11_RVALUE_REFERENCES + + //! Assign n items into the circular_buffer. + /*! + The content of the circular_buffer will be removed and replaced with n copies of the + item. + \post capacity() == n \&\& size() == n \&\& (*this)[0] == item \&\& (*this)[1] == item \&\& ... \&\& + (*this) [n - 1] == item + \param n The number of elements the circular_buffer will be filled with. + \param item The element the circular_buffer will be filled with. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer (except iterators equal to + end()). + \par Complexity + Linear (in the n). + \sa \link operator=(const circular_buffer&) operator=\endlink, + \link assign(capacity_type, size_type, param_value_type) + assign(capacity_type, size_type, const_reference)\endlink, + assign(InputIterator, InputIterator), + assign(capacity_type, InputIterator, InputIterator) + */ + void assign(size_type n, param_value_type item) { + assign_n(n, n, cb_details::assign_n(n, item, m_alloc)); + } + + //! Assign n items into the circular_buffer specifying the capacity. + /*! + The capacity of the circular_buffer will be set to the specified value and the content of the + circular_buffer will be removed and replaced with n copies of the item. + \pre capacity >= n + \post capacity() == buffer_capacity \&\& size() == n \&\& (*this)[0] == item \&\& (*this)[1] == item + \&\& ... \&\& (*this) [n - 1] == item + \param buffer_capacity The new capacity. + \param n The number of elements the circular_buffer will be filled with. + \param item The element the circular_buffer will be filled with. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer (except iterators equal to + end()). + \par Complexity + Linear (in the n). + \sa \link operator=(const circular_buffer&) operator=\endlink, + \link assign(size_type, param_value_type) assign(size_type, const_reference)\endlink, + assign(InputIterator, InputIterator), + assign(capacity_type, InputIterator, InputIterator) + */ + void assign(capacity_type buffer_capacity, size_type n, param_value_type item) { + BOOST_CB_ASSERT(buffer_capacity >= n); // check for new capacity lower than n + assign_n(buffer_capacity, n, cb_details::assign_n(n, item, m_alloc)); + } + + //! Assign a copy of the range into the circular_buffer. + /*! + The content of the circular_buffer will be removed and replaced with copies of elements from the + specified range. + \pre Valid range [first, last).
+ first and last have to meet the requirements of + InputIterator. + \post capacity() == std::distance(first, last) \&\& size() == std::distance(first, last) \&\& + (*this)[0]== *first \&\& (*this)[1] == *(first + 1) \&\& ... \&\& (*this)[std::distance(first, last) - 1] + == *(last - 1) + \param first The beginning of the range to be copied. + \param last The end of the range to be copied. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer (except iterators equal to + end()). + \par Complexity + Linear (in the std::distance(first, last)). + \sa \link operator=(const circular_buffer&) operator=\endlink, + \link assign(size_type, param_value_type) assign(size_type, const_reference)\endlink, + \link assign(capacity_type, size_type, param_value_type) + assign(capacity_type, size_type, const_reference)\endlink, + assign(capacity_type, InputIterator, InputIterator) + */ + template + void assign(InputIterator first, InputIterator last) { + assign(first, last, is_integral()); + } + + //! Assign a copy of the range into the circular_buffer specifying the capacity. + /*! + The capacity of the circular_buffer will be set to the specified value and the content of the + circular_buffer will be removed and replaced with copies of elements from the specified range. + \pre Valid range [first, last).
+ first and last have to meet the requirements of + InputIterator. + \post capacity() == buffer_capacity \&\& size() \<= std::distance(first, last) \&\& + (*this)[0]== *(last - buffer_capacity) \&\& (*this)[1] == *(last - buffer_capacity + 1) \&\& ... \&\& + (*this)[buffer_capacity - 1] == *(last - 1)

+ If the number of items to be copied from the range [first, last) is greater than the + specified buffer_capacity then only elements from the range + [last - buffer_capacity, last) will be copied. + \param buffer_capacity The new capacity. + \param first The beginning of the range to be copied. + \param last The end of the range to be copied. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer (except iterators equal to + end()). + \par Complexity + Linear (in std::distance(first, last); in + min[capacity, std::distance(first, last)] if the InputIterator is a + RandomAccessIterator). + \sa \link operator=(const circular_buffer&) operator=\endlink, + \link assign(size_type, param_value_type) assign(size_type, const_reference)\endlink, + \link assign(capacity_type, size_type, param_value_type) + assign(capacity_type, size_type, const_reference)\endlink, + assign(InputIterator, InputIterator) + */ + template + void assign(capacity_type buffer_capacity, InputIterator first, InputIterator last) { + assign(buffer_capacity, first, last, is_integral()); + } + + //! Swap the contents of two circular_buffers. + /*! + \post this contains elements of cb and vice versa; the capacity of this + equals to the capacity of cb and vice versa. + \param cb The circular_buffer whose content will be swapped. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Invalidates all iterators of both circular_buffers. (On the other hand the iterators still + point to the same elements but within another container. If you want to rely on this feature you have to + turn the Debug Support off otherwise an assertion will report an error if such + invalidated iterator is used.) + \par Complexity + Constant (in the size of the circular_buffer). + \sa swap(circular_buffer&, circular_buffer&) + */ + void swap(circular_buffer& cb) BOOST_NOEXCEPT { + swap_allocator(cb, is_stateless()); + adl_move_swap(m_buff, cb.m_buff); + adl_move_swap(m_end, cb.m_end); + adl_move_swap(m_first, cb.m_first); + adl_move_swap(m_last, cb.m_last); + adl_move_swap(m_size, cb.m_size); +#if BOOST_CB_ENABLE_DEBUG + invalidate_all_iterators(); + cb.invalidate_all_iterators(); +#endif + } + +// push and pop +private: + template + void push_back_impl(ValT item) { + if (full()) { + if (empty()) + return; + replace(m_last, static_cast(item)); + increment(m_last); + m_first = m_last; + } else { + boost::container::allocator_traits::construct(m_alloc, boost::addressof(*m_last), static_cast(item)); + increment(m_last); + ++m_size; + } + } + + template + void push_front_impl(ValT item) { + BOOST_TRY { + if (full()) { + if (empty()) + return; + decrement(m_first); + replace(m_first, static_cast(item)); + m_last = m_first; + } else { + decrement(m_first); + boost::container::allocator_traits::construct(m_alloc, boost::addressof(*m_first), static_cast(item)); + ++m_size; + } + } BOOST_CATCH(...) { + increment(m_first); + BOOST_RETHROW + } + BOOST_CATCH_END + } + +public: + //! Insert a new element at the end of the circular_buffer. + /*! + \post if capacity() > 0 then back() == item
+ If the circular_buffer is full, the first element will be removed. If the capacity is + 0, nothing will be inserted. + \param item The element to be inserted. + \throws Whatever T::T(const T&) throws. + Whatever T::operator = (const T&) throws. + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Does not invalidate any iterators with the exception of iterators pointing to the overwritten element. + \par Complexity + Constant (in the size of the circular_buffer). + \sa \link push_front() push_front(const_reference)\endlink, + pop_back(), pop_front() + */ + void push_back(param_value_type item) { + push_back_impl(item); + } + + //! Insert a new element at the end of the circular_buffer using rvalue references or rvalues references emulation. + /*! + \post if capacity() > 0 then back() == item
+ If the circular_buffer is full, the first element will be removed. If the capacity is + 0, nothing will be inserted. + \param item The element to be inserted. + \throws Whatever T::T(T&&) throws. + Whatever T::operator = (T&&) throws. + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Does not invalidate any iterators with the exception of iterators pointing to the overwritten element. + \par Complexity + Constant (in the size of the circular_buffer). + \sa \link push_front() push_front(const_reference)\endlink, + pop_back(), pop_front() + */ + void push_back(rvalue_type item) { + push_back_impl(boost::move(item)); + } + + //! Insert a new default-constructed element at the end of the circular_buffer. + /*! + \post if capacity() > 0 then back() == item
+ If the circular_buffer is full, the first element will be removed. If the capacity is + 0, nothing will be inserted. + \throws Whatever T::T() throws. + Whatever T::T(T&&) throws. + Whatever T::operator = (T&&) throws. + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Does not invalidate any iterators with the exception of iterators pointing to the overwritten element. + \par Complexity + Constant (in the size of the circular_buffer). + \sa \link push_front() push_front(const_reference)\endlink, + pop_back(), pop_front() + */ + void push_back() { + value_type temp; + push_back(boost::move(temp)); + } + + //! Insert a new element at the beginning of the circular_buffer. + /*! + \post if capacity() > 0 then front() == item
+ If the circular_buffer is full, the last element will be removed. If the capacity is + 0, nothing will be inserted. + \param item The element to be inserted. + \throws Whatever T::T(const T&) throws. + Whatever T::operator = (const T&) throws. + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Does not invalidate any iterators with the exception of iterators pointing to the overwritten element. + \par Complexity + Constant (in the size of the circular_buffer). + \sa \link push_back() push_back(const_reference)\endlink, + pop_back(), pop_front() + */ + void push_front(param_value_type item) { + push_front_impl(item); + } + + //! Insert a new element at the beginning of the circular_buffer using rvalue references or rvalues references emulation. + /*! + \post if capacity() > 0 then front() == item
+ If the circular_buffer is full, the last element will be removed. If the capacity is + 0, nothing will be inserted. + \param item The element to be inserted. + \throws Whatever T::T(T&&) throws. + Whatever T::operator = (T&&) throws. + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Does not invalidate any iterators with the exception of iterators pointing to the overwritten element. + \par Complexity + Constant (in the size of the circular_buffer). + \sa \link push_back() push_back(const_reference)\endlink, + pop_back(), pop_front() + */ + void push_front(rvalue_type item) { + push_front_impl(boost::move(item)); + } + + //! Insert a new default-constructed element at the beginning of the circular_buffer. + /*! + \post if capacity() > 0 then front() == item
+ If the circular_buffer is full, the last element will be removed. If the capacity is + 0, nothing will be inserted. + \throws Whatever T::T() throws. + Whatever T::T(T&&) throws. + Whatever T::operator = (T&&) throws. + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Does not invalidate any iterators with the exception of iterators pointing to the overwritten element. + \par Complexity + Constant (in the size of the circular_buffer). + \sa \link push_back() push_back(const_reference)\endlink, + pop_back(), pop_front() + */ + void push_front() { + value_type temp; + push_front(boost::move(temp)); + } + + //! Remove the last element from the circular_buffer. + /*! + \pre !empty() + \post The last element is removed from the circular_buffer. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Invalidates only iterators pointing to the removed element. + \par Complexity + Constant (in the size of the circular_buffer). + \sa pop_front(), \link push_back() push_back(const_reference)\endlink, + \link push_front() push_front(const_reference)\endlink + */ + void pop_back() { + BOOST_CB_ASSERT(!empty()); // check for empty buffer (back element not available) + decrement(m_last); + destroy_item(m_last); + --m_size; + } + + //! Remove the first element from the circular_buffer. + /*! + \pre !empty() + \post The first element is removed from the circular_buffer. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Invalidates only iterators pointing to the removed element. + \par Complexity + Constant (in the size of the circular_buffer). + \sa pop_back(), \link push_back() push_back(const_reference)\endlink, + \link push_front() push_front(const_reference)\endlink + */ + void pop_front() { + BOOST_CB_ASSERT(!empty()); // check for empty buffer (front element not available) + destroy_item(m_first); + increment(m_first); + --m_size; + } +private: + template + iterator insert_impl(iterator pos, ValT item) { + BOOST_CB_ASSERT(pos.is_valid(this)); // check for uninitialized or invalidated iterator + iterator b = begin(); + if (full() && pos == b) + return b; + return insert_item(pos, static_cast(item)); + } + +public: +// Insert + + //! Insert an element at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer or its end. + \post The item will be inserted at the position pos.
+ If the circular_buffer is full, the first element will be overwritten. If the + circular_buffer is full and the pos points to begin(), then the + item will not be inserted. If the capacity is 0, nothing will be inserted. + \param pos An iterator specifying the position where the item will be inserted. + \param item The element to be inserted. + \return Iterator to the inserted element or begin() if the item is not inserted. (See + the Effect.) + \throws Whatever T::T(const T&) throws. + Whatever T::operator = (const T&) throws. + Exceptions of move_if_noexcept(T&). + + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the elements at the insertion point (including pos) and + iterators behind the insertion point (towards the end; except iterators equal to end()). It + also invalidates iterators pointing to the overwritten element. + \par Complexity + Linear (in std::distance(pos, end())). + \sa \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator), + \link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink, + \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator) + */ + iterator insert(iterator pos, param_value_type item) { + return insert_impl(pos, item); + } + + //! Insert an element at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer or its end. + \post The item will be inserted at the position pos.
+ If the circular_buffer is full, the first element will be overwritten. If the + circular_buffer is full and the pos points to begin(), then the + item will not be inserted. If the capacity is 0, nothing will be inserted. + \param pos An iterator specifying the position where the item will be inserted. + \param item The element to be inserted. + \return Iterator to the inserted element or begin() if the item is not inserted. (See + the Effect.) + \throws Whatever T::T(T&&) throws. + Whatever T::operator = (T&&) throws. + Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the elements at the insertion point (including pos) and + iterators behind the insertion point (towards the end; except iterators equal to end()). It + also invalidates iterators pointing to the overwritten element. + \par Complexity + Linear (in std::distance(pos, end())). + \sa \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator), + \link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink, + \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator) + */ + iterator insert(iterator pos, rvalue_type item) { + return insert_impl(pos, boost::move(item)); + } + + //! Insert a default-constructed element at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer or its end. + \post The item will be inserted at the position pos.
+ If the circular_buffer is full, the first element will be overwritten. If the + circular_buffer is full and the pos points to begin(), then the + item will not be inserted. If the capacity is 0, nothing will be inserted. + \param pos An iterator specifying the position where the item will be inserted. + \return Iterator to the inserted element or begin() if the item is not inserted. (See + the Effect.) + \throws Whatever T::T() throws. + Whatever T::T(T&&) throws. + Whatever T::operator = (T&&) throws. + Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the elements at the insertion point (including pos) and + iterators behind the insertion point (towards the end; except iterators equal to end()). It + also invalidates iterators pointing to the overwritten element. + \par Complexity + Linear (in std::distance(pos, end())). + \sa \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator), + \link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink, + \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator) + */ + iterator insert(iterator pos) { + value_type temp; + return insert(pos, boost::move(temp)); + } + + //! Insert n copies of the item at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer or its end. + \post The number of min[n, (pos - begin()) + reserve()] elements will be inserted at the position + pos.
The number of min[pos - begin(), max[0, n - reserve()]] elements will + be overwritten at the beginning of the circular_buffer.
(See Example for the + explanation.) + \param pos An iterator specifying the position where the items will be inserted. + \param n The number of items the to be inserted. + \param item The element whose copies will be inserted. + \throws Whatever T::T(const T&) throws. + Whatever T::operator = (const T&) throws. + Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operations in the Throws section do not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the elements at the insertion point (including pos) and + iterators behind the insertion point (towards the end; except iterators equal to end()). It + also invalidates iterators pointing to the overwritten elements. + \par Complexity + Linear (in min[capacity(), std::distance(pos, end()) + n]). + \par Example + Consider a circular_buffer with the capacity of 6 and the size of 4. Its internal buffer may + look like the one below.

+ |1|2|3|4| | |
+ p ___^

After inserting 5 elements at the position p:

+ insert(p, (size_t)5, 0);

actually only 4 elements get inserted and elements + 1 and 2 are overwritten. This is due to the fact the insert operation preserves + the capacity. After insertion the internal buffer looks like this:

|0|0|0|0|3|4|
+
For comparison if the capacity would not be preserved the internal buffer would then result in + |1|2|0|0|0|0|0|3|4|. + \sa \link insert(iterator, param_value_type) insert(iterator, value_type)\endlink, + insert(iterator, InputIterator, InputIterator), + \link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink, + \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator) + */ + void insert(iterator pos, size_type n, param_value_type item) { + BOOST_CB_ASSERT(pos.is_valid(this)); // check for uninitialized or invalidated iterator + if (n == 0) + return; + size_type copy = capacity() - (end() - pos); + if (copy == 0) + return; + if (n > copy) + n = copy; + insert_n(pos, n, cb_details::item_wrapper(item)); + } + + //! Insert the range [first, last) at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer or its end.
+ Valid range [first, last) where first and last meet the + requirements of an InputIterator. + \post Elements from the range + [first + max[0, distance(first, last) - (pos - begin()) - reserve()], last) will be + inserted at the position pos.
The number of min[pos - begin(), max[0, + distance(first, last) - reserve()]] elements will be overwritten at the beginning of the + circular_buffer.
(See Example for the explanation.) + \param pos An iterator specifying the position where the range will be inserted. + \param first The beginning of the range to be inserted. + \param last The end of the range to be inserted. + \throws Whatever T::T(const T&) throws if the InputIterator is not a move iterator. + Whatever T::operator = (const T&) throws if the InputIterator is not a move iterator. + Whatever T::T(T&&) throws if the InputIterator is a move iterator. + Whatever T::operator = (T&&) throws if the InputIterator is a move iterator. + \par Exception Safety + Basic; no-throw if the operations in the Throws section do not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the elements at the insertion point (including pos) and + iterators behind the insertion point (towards the end; except iterators equal to end()). It + also invalidates iterators pointing to the overwritten elements. + \par Complexity + Linear (in [std::distance(pos, end()) + std::distance(first, last)]; in + min[capacity(), std::distance(pos, end()) + std::distance(first, last)] if the + InputIterator is a + RandomAccessIterator). + \par Example + Consider a circular_buffer with the capacity of 6 and the size of 4. Its internal buffer may + look like the one below.

+ |1|2|3|4| | |
+ p ___^

After inserting a range of elements at the position p:

+ int array[] = { 5, 6, 7, 8, 9 };
insert(p, array, array + 5);

+ actually only elements 6, 7, 8 and 9 from the + specified range get inserted and elements 1 and 2 are overwritten. This is due + to the fact the insert operation preserves the capacity. After insertion the internal buffer looks like + this:

|6|7|8|9|3|4|

For comparison if the capacity would not be preserved the + internal buffer would then result in |1|2|5|6|7|8|9|3|4|. + \sa \link insert(iterator, param_value_type) insert(iterator, value_type)\endlink, + \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, \link rinsert(iterator, param_value_type) + rinsert(iterator, value_type)\endlink, \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator) + */ + template + void insert(iterator pos, InputIterator first, InputIterator last) { + BOOST_CB_ASSERT(pos.is_valid(this)); // check for uninitialized or invalidated iterator + insert(pos, first, last, is_integral()); + } + +private: + template + iterator rinsert_impl(iterator pos, ValT item) { + BOOST_CB_ASSERT(pos.is_valid(this)); // check for uninitialized or invalidated iterator + if (full() && pos.m_it == 0) + return end(); + if (pos == begin()) { + BOOST_TRY { + decrement(m_first); + construct_or_replace(!full(), m_first, static_cast(item)); + } BOOST_CATCH(...) { + increment(m_first); + BOOST_RETHROW + } + BOOST_CATCH_END + pos.m_it = m_first; + } else { + pointer src = m_first; + pointer dest = m_first; + decrement(dest); + pos.m_it = map_pointer(pos.m_it); + bool construct = !full(); + BOOST_TRY { + while (src != pos.m_it) { + construct_or_replace(construct, dest, boost::move_if_noexcept(*src)); + increment(src); + increment(dest); + construct = false; + } + decrement(pos.m_it); + replace(pos.m_it, static_cast(item)); + } BOOST_CATCH(...) { + if (!construct && !full()) { + decrement(m_first); + ++m_size; + } + BOOST_RETHROW + } + BOOST_CATCH_END + decrement(m_first); + } + if (full()) + m_last = m_first; + else + ++m_size; + return iterator(this, pos.m_it); + } + +public: + + //! Insert an element before the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer or its end. + \post The item will be inserted before the position pos.
+ If the circular_buffer is full, the last element will be overwritten. If the + circular_buffer is full and the pos points to end(), then the + item will not be inserted. If the capacity is 0, nothing will be inserted. + \param pos An iterator specifying the position before which the item will be inserted. + \param item The element to be inserted. + \return Iterator to the inserted element or end() if the item is not inserted. (See + the Effect.) + \throws Whatever T::T(const T&) throws. + Whatever T::operator = (const T&) throws. + Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operations in the Throws section do not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the elements before the insertion point (towards the beginning and + excluding pos). It also invalidates iterators pointing to the overwritten element. + \par Complexity + Linear (in std::distance(begin(), pos)). + \sa \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator), + \link insert(iterator, param_value_type) insert(iterator, value_type)\endlink, + \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator) + */ + iterator rinsert(iterator pos, param_value_type item) { + return rinsert_impl(pos, item); + } + + //! Insert an element before the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer or its end. + \post The item will be inserted before the position pos.
+ If the circular_buffer is full, the last element will be overwritten. If the + circular_buffer is full and the pos points to end(), then the + item will not be inserted. If the capacity is 0, nothing will be inserted. + \param pos An iterator specifying the position before which the item will be inserted. + \param item The element to be inserted. + \return Iterator to the inserted element or end() if the item is not inserted. (See + the Effect.) + \throws Whatever T::T(T&&) throws. + Whatever T::operator = (T&&) throws. + Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operations in the Throws section do not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the elements before the insertion point (towards the beginning and + excluding pos). It also invalidates iterators pointing to the overwritten element. + \par Complexity + Linear (in std::distance(begin(), pos)). + \sa \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator), + \link insert(iterator, param_value_type) insert(iterator, value_type)\endlink, + \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator) + */ + iterator rinsert(iterator pos, rvalue_type item) { + return rinsert_impl(pos, boost::move(item)); + } + + //! Insert an element before the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer or its end. + \post The item will be inserted before the position pos.
+ If the circular_buffer is full, the last element will be overwritten. If the + circular_buffer is full and the pos points to end(), then the + item will not be inserted. If the capacity is 0, nothing will be inserted. + \param pos An iterator specifying the position before which the item will be inserted. + \return Iterator to the inserted element or end() if the item is not inserted. (See + the Effect.) + \throws Whatever T::T() throws. + Whatever T::T(T&&) throws. + Whatever T::operator = (T&&) throws. + Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operations in the Throws section do not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the elements before the insertion point (towards the beginning and + excluding pos). It also invalidates iterators pointing to the overwritten element. + \par Complexity + Linear (in std::distance(begin(), pos)). + \sa \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator), + \link insert(iterator, param_value_type) insert(iterator, value_type)\endlink, + \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator) + */ + iterator rinsert(iterator pos) { + value_type temp; + return rinsert(pos, boost::move(temp)); + } + + //! Insert n copies of the item before the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer or its end. + \post The number of min[n, (end() - pos) + reserve()] elements will be inserted before the + position pos.
The number of min[end() - pos, max[0, n - reserve()]] elements + will be overwritten at the end of the circular_buffer.
(See Example for the + explanation.) + \param pos An iterator specifying the position where the items will be inserted. + \param n The number of items the to be inserted. + \param item The element whose copies will be inserted. + \throws Whatever T::T(const T&) throws. + Whatever T::operator = (const T&) throws. + Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operations in the Throws section do not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the elements before the insertion point (towards the beginning and + excluding pos). It also invalidates iterators pointing to the overwritten elements. + \par Complexity + Linear (in min[capacity(), std::distance(begin(), pos) + n]). + \par Example + Consider a circular_buffer with the capacity of 6 and the size of 4. Its internal buffer may + look like the one below.

+ |1|2|3|4| | |
+ p ___^

After inserting 5 elements before the position p:

+ rinsert(p, (size_t)5, 0);

actually only 4 elements get inserted and elements + 3 and 4 are overwritten. This is due to the fact the rinsert operation preserves + the capacity. After insertion the internal buffer looks like this:

|1|2|0|0|0|0|
+
For comparison if the capacity would not be preserved the internal buffer would then result in + |1|2|0|0|0|0|0|3|4|. + \sa \link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator), + \link insert(iterator, param_value_type) insert(iterator, value_type)\endlink, + \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator) + */ + void rinsert(iterator pos, size_type n, param_value_type item) { + BOOST_CB_ASSERT(pos.is_valid(this)); // check for uninitialized or invalidated iterator + rinsert_n(pos, n, cb_details::item_wrapper(item)); + } + + //! Insert the range [first, last) before the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer or its end.
+ Valid range [first, last) where first and last meet the + requirements of an InputIterator. + \post Elements from the range + [first, last - max[0, distance(first, last) - (end() - pos) - reserve()]) will be inserted + before the position pos.
The number of min[end() - pos, max[0, + distance(first, last) - reserve()]] elements will be overwritten at the end of the + circular_buffer.
(See Example for the explanation.) + \param pos An iterator specifying the position where the range will be inserted. + \param first The beginning of the range to be inserted. + \param last The end of the range to be inserted. + \throws Whatever T::T(const T&) throws if the InputIterator is not a move iterator. + Whatever T::operator = (const T&) throws if the InputIterator is not a move iterator. + Whatever T::T(T&&) throws if the InputIterator is a move iterator. + Whatever T::operator = (T&&) throws if the InputIterator is a move iterator. + \par Exception Safety + Basic; no-throw if the operations in the Throws section do not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the elements before the insertion point (towards the beginning and + excluding pos). It also invalidates iterators pointing to the overwritten elements. + \par Complexity + Linear (in [std::distance(begin(), pos) + std::distance(first, last)]; in + min[capacity(), std::distance(begin(), pos) + std::distance(first, last)] if the + InputIterator is a + RandomAccessIterator). + \par Example + Consider a circular_buffer with the capacity of 6 and the size of 4. Its internal buffer may + look like the one below.

+ |1|2|3|4| | |
+ p ___^

After inserting a range of elements before the position p:

+ int array[] = { 5, 6, 7, 8, 9 };
insert(p, array, array + 5);

+ actually only elements 5, 6, 7 and 8 from the + specified range get inserted and elements 3 and 4 are overwritten. This is due + to the fact the rinsert operation preserves the capacity. After insertion the internal buffer looks like + this:

|1|2|5|6|7|8|

For comparison if the capacity would not be preserved the + internal buffer would then result in |1|2|5|6|7|8|9|3|4|. + \sa \link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink, + \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, \link insert(iterator, param_value_type) + insert(iterator, value_type)\endlink, \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator) + */ + template + void rinsert(iterator pos, InputIterator first, InputIterator last) { + BOOST_CB_ASSERT(pos.is_valid(this)); // check for uninitialized or invalidated iterator + rinsert(pos, first, last, is_integral()); + } + +// Erase + + //! Remove an element at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer (but not an + end()). + \post The element at the position pos is removed. + \param pos An iterator pointing at the element to be removed. + \return Iterator to the first element remaining beyond the removed element or end() if no such + element exists. + \throws Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the erased element and iterators pointing to the elements behind + the erased element (towards the end; except iterators equal to end()). + \par Complexity + Linear (in std::distance(pos, end())). + \sa erase(iterator, iterator), rerase(iterator), + rerase(iterator, iterator), erase_begin(size_type), + erase_end(size_type), clear() + */ + iterator erase(iterator pos) { + BOOST_CB_ASSERT(pos.is_valid(this)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(pos.m_it != 0); // check for iterator pointing to end() + pointer next = pos.m_it; + increment(next); + for (pointer p = pos.m_it; next != m_last; p = next, increment(next)) + replace(p, boost::move_if_noexcept(*next)); + decrement(m_last); + destroy_item(m_last); + --m_size; +#if BOOST_CB_ENABLE_DEBUG + return m_last == pos.m_it ? end() : iterator(this, pos.m_it); +#else + return m_last == pos.m_it ? end() : pos; +#endif + } + + //! Erase the range [first, last). + /*! + \pre Valid range [first, last). + \post The elements from the range [first, last) are removed. (If first == last + nothing is removed.) + \param first The beginning of the range to be removed. + \param last The end of the range to be removed. + \return Iterator to the first element remaining beyond the removed elements or end() if no such + element exists. + \throws Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the erased elements and iterators pointing to the elements behind + the erased range (towards the end; except iterators equal to end()). + \par Complexity + Linear (in std::distance(first, end())). + \sa erase(iterator), rerase(iterator), rerase(iterator, iterator), + erase_begin(size_type), erase_end(size_type), clear() + */ + iterator erase(iterator first, iterator last) { + BOOST_CB_ASSERT(first.is_valid(this)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(last.is_valid(this)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(first <= last); // check for wrong range + if (first == last) + return first; + pointer p = first.m_it; + while (last.m_it != 0) + replace((first++).m_it, boost::move_if_noexcept(*last++)); + do { + decrement(m_last); + destroy_item(m_last); + --m_size; + } while(m_last != first.m_it); + return m_last == p ? end() : iterator(this, p); + } + + //! Remove an element at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer (but not an + end()). + \post The element at the position pos is removed. + \param pos An iterator pointing at the element to be removed. + \return Iterator to the first element remaining in front of the removed element or begin() if no + such element exists. + \throws Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the erased element and iterators pointing to the elements in front of + the erased element (towards the beginning). + \par Complexity + Linear (in std::distance(begin(), pos)). + \note This method is symetric to the erase(iterator) method and is more effective than + erase(iterator) if the iterator pos is close to the beginning of the + circular_buffer. (See the Complexity.) + \sa erase(iterator), erase(iterator, iterator), + rerase(iterator, iterator), erase_begin(size_type), + erase_end(size_type), clear() + */ + iterator rerase(iterator pos) { + BOOST_CB_ASSERT(pos.is_valid(this)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(pos.m_it != 0); // check for iterator pointing to end() + pointer prev = pos.m_it; + pointer p = prev; + for (decrement(prev); p != m_first; p = prev, decrement(prev)) + replace(p, boost::move_if_noexcept(*prev)); + destroy_item(m_first); + increment(m_first); + --m_size; +#if BOOST_CB_ENABLE_DEBUG + return p == pos.m_it ? begin() : iterator(this, pos.m_it); +#else + return p == pos.m_it ? begin() : pos; +#endif + } + + //! Erase the range [first, last). + /*! + \pre Valid range [first, last). + \post The elements from the range [first, last) are removed. (If first == last + nothing is removed.) + \param first The beginning of the range to be removed. + \param last The end of the range to be removed. + \return Iterator to the first element remaining in front of the removed elements or begin() if no + such element exists. + \throws Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. + \par Iterator Invalidation + Invalidates iterators pointing to the erased elements and iterators pointing to the elements in front of + the erased range (towards the beginning). + \par Complexity + Linear (in std::distance(begin(), last)). + \note This method is symetric to the erase(iterator, iterator) method and is more effective than + erase(iterator, iterator) if std::distance(begin(), first) is lower that + std::distance(last, end()). + \sa erase(iterator), erase(iterator, iterator), rerase(iterator), + erase_begin(size_type), erase_end(size_type), clear() + */ + iterator rerase(iterator first, iterator last) { + BOOST_CB_ASSERT(first.is_valid(this)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(last.is_valid(this)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(first <= last); // check for wrong range + if (first == last) + return first; + pointer p = map_pointer(last.m_it); + last.m_it = p; + while (first.m_it != m_first) { + decrement(first.m_it); + decrement(p); + replace(p, boost::move_if_noexcept(*first.m_it)); + } + do { + destroy_item(m_first); + increment(m_first); + --m_size; + } while(m_first != p); + if (m_first == last.m_it) + return begin(); + decrement(last.m_it); + return iterator(this, last.m_it); + } + + //! Remove first n elements (with constant complexity for scalar types). + /*! + \pre n \<= size() + \post The n elements at the beginning of the circular_buffer will be removed. + \param n The number of elements to be removed. + \throws Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. (I.e. no throw in + case of scalars.) + \par Iterator Invalidation + Invalidates iterators pointing to the first n erased elements. + \par Complexity + Constant (in n) for scalar types; linear for other types. + \note This method has been specially designed for types which do not require an explicit destructruction (e.g. + integer, float or a pointer). For these scalar types a call to a destructor is not required which makes + it possible to implement the "erase from beginning" operation with a constant complexity. For non-sacalar + types the complexity is linear (hence the explicit destruction is needed) and the implementation is + actually equivalent to + \link circular_buffer::rerase(iterator, iterator) rerase(begin(), begin() + n)\endlink. + \sa erase(iterator), erase(iterator, iterator), + rerase(iterator), rerase(iterator, iterator), + erase_end(size_type), clear() + */ + void erase_begin(size_type n) { + BOOST_CB_ASSERT(n <= size()); // check for n greater than size +#if BOOST_CB_ENABLE_DEBUG + erase_begin(n, false_type()); +#else + erase_begin(n, is_scalar()); +#endif + } + + //! Remove last n elements (with constant complexity for scalar types). + /*! + \pre n \<= size() + \post The n elements at the end of the circular_buffer will be removed. + \param n The number of elements to be removed. + \throws Exceptions of move_if_noexcept(T&). + \par Exception Safety + Basic; no-throw if the operation in the Throws section does not throw anything. (I.e. no throw in + case of scalars.) + \par Iterator Invalidation + Invalidates iterators pointing to the last n erased elements. + \par Complexity + Constant (in n) for scalar types; linear for other types. + \note This method has been specially designed for types which do not require an explicit destructruction (e.g. + integer, float or a pointer). For these scalar types a call to a destructor is not required which makes + it possible to implement the "erase from end" operation with a constant complexity. For non-sacalar + types the complexity is linear (hence the explicit destruction is needed) and the implementation is + actually equivalent to + \link circular_buffer::erase(iterator, iterator) erase(end() - n, end())\endlink. + \sa erase(iterator), erase(iterator, iterator), + rerase(iterator), rerase(iterator, iterator), + erase_begin(size_type), clear() + */ + void erase_end(size_type n) { + BOOST_CB_ASSERT(n <= size()); // check for n greater than size +#if BOOST_CB_ENABLE_DEBUG + erase_end(n, false_type()); +#else + erase_end(n, is_scalar()); +#endif + } + + //! Remove all stored elements from the circular_buffer. + /*! + \post size() == 0 + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer (except iterators equal to + end()). + \par Complexity + Constant (in the size of the circular_buffer) for scalar types; linear for other types. + \sa ~circular_buffer(), erase(iterator), erase(iterator, iterator), + rerase(iterator), rerase(iterator, iterator), + erase_begin(size_type), erase_end(size_type) + */ + void clear() BOOST_NOEXCEPT { + destroy_content(); + m_size = 0; + } + +private: +// Helper methods + + //! Check if the index is valid. + void check_position(size_type index) const { + if (index >= size()) + throw_exception(std::out_of_range("circular_buffer")); + } + + //! Increment the pointer. + template + void increment(Pointer& p) const { + if (++p == m_end) + p = m_buff; + } + + //! Decrement the pointer. + template + void decrement(Pointer& p) const { + if (p == m_buff) + p = m_end; + --p; + } + + //! Add n to the pointer. + template + Pointer add(Pointer p, difference_type n) const { + return p + (n < (m_end - p) ? n : n - capacity()); + } + + //! Subtract n from the pointer. + template + Pointer sub(Pointer p, difference_type n) const { + return p - (n > (p - m_buff) ? n - capacity() : n); + } + + //! Map the null pointer to virtual end of circular buffer. + pointer map_pointer(pointer p) const { return p == 0 ? m_last : p; } + + //! Allocate memory. + pointer allocate(size_type n) { + if (n > max_size()) + throw_exception(std::length_error("circular_buffer")); +#if BOOST_CB_ENABLE_DEBUG + pointer p = (n == 0) ? 0 : m_alloc.allocate(n); + cb_details::do_fill_uninitialized_memory(p, sizeof(value_type) * n); + return p; +#else + return (n == 0) ? 0 : m_alloc.allocate(n); +#endif + } + + //! Deallocate memory. + void deallocate(pointer p, size_type n) { + if (p != 0) + m_alloc.deallocate(p, n); + } + + //! Does the pointer point to the uninitialized memory? + bool is_uninitialized(const_pointer p) const BOOST_NOEXCEPT { + return p >= m_last && (m_first < m_last || p < m_first); + } + + //! Replace an element. + void replace(pointer pos, param_value_type item) { + *pos = item; +#if BOOST_CB_ENABLE_DEBUG + invalidate_iterators(iterator(this, pos)); +#endif + } + + //! Replace an element. + void replace(pointer pos, rvalue_type item) { + *pos = boost::move(item); +#if BOOST_CB_ENABLE_DEBUG + invalidate_iterators(iterator(this, pos)); +#endif + } + + //! Construct or replace an element. + /*! + construct has to be set to true if and only if + pos points to an uninitialized memory. + */ + void construct_or_replace(bool construct, pointer pos, param_value_type item) { + if (construct) + boost::container::allocator_traits::construct(m_alloc, boost::addressof(*pos), item); + else + replace(pos, item); + } + + //! Construct or replace an element. + /*! + construct has to be set to true if and only if + pos points to an uninitialized memory. + */ + void construct_or_replace(bool construct, pointer pos, rvalue_type item) { + if (construct) + boost::container::allocator_traits::construct(m_alloc, boost::addressof(*pos), boost::move(item)); + else + replace(pos, boost::move(item)); + } + + //! Destroy an item. + void destroy_item(pointer p) { + boost::container::allocator_traits::destroy(m_alloc, boost::addressof(*p)); +#if BOOST_CB_ENABLE_DEBUG + invalidate_iterators(iterator(this, p)); + cb_details::do_fill_uninitialized_memory(p, sizeof(value_type)); +#endif + } + + //! Destroy an item only if it has been constructed. + void destroy_if_constructed(pointer pos) { + if (is_uninitialized(pos)) + destroy_item(pos); + } + + //! Destroy the whole content of the circular buffer. + void destroy_content() { +#if BOOST_CB_ENABLE_DEBUG + destroy_content(false_type()); +#else + destroy_content(is_scalar()); +#endif + } + + //! Specialized destroy_content method. + void destroy_content(const true_type&) { + m_first = add(m_first, size()); + } + + //! Specialized destroy_content method. + void destroy_content(const false_type&) { + for (size_type ii = 0; ii < size(); ++ii, increment(m_first)) + destroy_item(m_first); + } + + //! Destroy content and free allocated memory. + void destroy() BOOST_NOEXCEPT { + destroy_content(); + deallocate(m_buff, capacity()); +#if BOOST_CB_ENABLE_DEBUG + m_buff = 0; + m_first = 0; + m_last = 0; + m_end = 0; +#endif + } + + //! Initialize the internal buffer. + void initialize_buffer(capacity_type buffer_capacity) { + m_buff = allocate(buffer_capacity); + m_end = m_buff + buffer_capacity; + } + + //! Initialize the internal buffer. + void initialize_buffer(capacity_type buffer_capacity, param_value_type item) { + initialize_buffer(buffer_capacity); + BOOST_TRY { + cb_details::uninitialized_fill_n_with_alloc(m_buff, size(), item, m_alloc); + } BOOST_CATCH(...) { + deallocate(m_buff, size()); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + //! Specialized initialize method. + template + void initialize(IntegralType n, IntegralType item, const true_type&) { + m_size = static_cast(n); + initialize_buffer(size(), item); + m_first = m_last = m_buff; + } + + //! Specialized initialize method. + template + void initialize(Iterator first, Iterator last, const false_type&) { + BOOST_CB_IS_CONVERTIBLE(Iterator, value_type); // check for invalid iterator type +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x581)) + initialize(first, last, iterator_category::type()); +#else + initialize(first, last, BOOST_DEDUCED_TYPENAME iterator_category::type()); +#endif + } + + //! Specialized initialize method. + template + void initialize(InputIterator first, InputIterator last, const std::input_iterator_tag&) { + BOOST_CB_ASSERT_TEMPLATED_ITERATOR_CONSTRUCTORS // check if the STL provides templated iterator constructors + // for containers + std::deque tmp(first, last, m_alloc); + size_type distance = tmp.size(); + initialize(distance, boost::make_move_iterator(tmp.begin()), boost::make_move_iterator(tmp.end()), distance); + } + + //! Specialized initialize method. + template + void initialize(ForwardIterator first, ForwardIterator last, const std::forward_iterator_tag&) { + BOOST_CB_ASSERT(std::distance(first, last) >= 0); // check for wrong range + size_type distance = std::distance(first, last); + initialize(distance, first, last, distance); + } + + //! Specialized initialize method. + template + void initialize(capacity_type buffer_capacity, IntegralType n, IntegralType item, const true_type&) { + BOOST_CB_ASSERT(buffer_capacity >= static_cast(n)); // check for capacity lower than n + m_size = static_cast(n); + initialize_buffer(buffer_capacity, item); + m_first = m_buff; + m_last = buffer_capacity == size() ? m_buff : m_buff + size(); + } + + //! Specialized initialize method. + template + void initialize(capacity_type buffer_capacity, Iterator first, Iterator last, const false_type&) { + BOOST_CB_IS_CONVERTIBLE(Iterator, value_type); // check for invalid iterator type +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x581)) + initialize(buffer_capacity, first, last, iterator_category::type()); +#else + initialize(buffer_capacity, first, last, BOOST_DEDUCED_TYPENAME iterator_category::type()); +#endif + } + + //! Specialized initialize method. + template + void initialize(capacity_type buffer_capacity, + InputIterator first, + InputIterator last, + const std::input_iterator_tag&) { + initialize_buffer(buffer_capacity); + m_first = m_last = m_buff; + m_size = 0; + if (buffer_capacity == 0) + return; + while (first != last && !full()) { + boost::container::allocator_traits::construct(m_alloc, boost::addressof(*m_last), *first++); + increment(m_last); + ++m_size; + } + while (first != last) { + replace(m_last, *first++); + increment(m_last); + m_first = m_last; + } + } + + //! Specialized initialize method. + template + void initialize(capacity_type buffer_capacity, + ForwardIterator first, + ForwardIterator last, + const std::forward_iterator_tag&) { + BOOST_CB_ASSERT(std::distance(first, last) >= 0); // check for wrong range + initialize(buffer_capacity, first, last, std::distance(first, last)); + } + + //! Initialize the circular buffer. + template + void initialize(capacity_type buffer_capacity, + ForwardIterator first, + ForwardIterator last, + size_type distance) { + initialize_buffer(buffer_capacity); + m_first = m_buff; + if (distance > buffer_capacity) { + std::advance(first, distance - buffer_capacity); + m_size = buffer_capacity; + } else { + m_size = distance; + } + BOOST_TRY { + m_last = cb_details::uninitialized_copy(first, last, m_buff, m_alloc); + } BOOST_CATCH(...) { + deallocate(m_buff, buffer_capacity); + BOOST_RETHROW + } + BOOST_CATCH_END + if (m_last == m_end) + m_last = m_buff; + } + + //! Reset the circular buffer. + void reset(pointer buff, pointer last, capacity_type new_capacity) { + destroy(); + m_size = last - buff; + m_first = m_buff = buff; + m_end = m_buff + new_capacity; + m_last = last == m_end ? m_buff : last; + } + + //! Specialized method for swapping the allocator. + void swap_allocator(circular_buffer&, const true_type&) { + // Swap is not needed because allocators have no state. + } + + //! Specialized method for swapping the allocator. + void swap_allocator(circular_buffer& cb, const false_type&) { + adl_move_swap(m_alloc, cb.m_alloc); + } + + //! Specialized assign method. + template + void assign(IntegralType n, IntegralType item, const true_type&) { + assign(static_cast(n), static_cast(item)); + } + + //! Specialized assign method. + template + void assign(Iterator first, Iterator last, const false_type&) { + BOOST_CB_IS_CONVERTIBLE(Iterator, value_type); // check for invalid iterator type +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x581)) + assign(first, last, iterator_category::type()); +#else + assign(first, last, BOOST_DEDUCED_TYPENAME iterator_category::type()); +#endif + } + + //! Specialized assign method. + template + void assign(InputIterator first, InputIterator last, const std::input_iterator_tag&) { + BOOST_CB_ASSERT_TEMPLATED_ITERATOR_CONSTRUCTORS // check if the STL provides templated iterator constructors + // for containers + std::deque tmp(first, last, m_alloc); + size_type distance = tmp.size(); + assign_n(distance, distance, + cb_details::make_assign_range + (boost::make_move_iterator(tmp.begin()), boost::make_move_iterator(tmp.end()), m_alloc)); + } + + //! Specialized assign method. + template + void assign(ForwardIterator first, ForwardIterator last, const std::forward_iterator_tag&) { + BOOST_CB_ASSERT(std::distance(first, last) >= 0); // check for wrong range + size_type distance = std::distance(first, last); + assign_n(distance, distance, cb_details::make_assign_range(first, last, m_alloc)); + } + + //! Specialized assign method. + template + void assign(capacity_type new_capacity, IntegralType n, IntegralType item, const true_type&) { + assign(new_capacity, static_cast(n), static_cast(item)); + } + + //! Specialized assign method. + template + void assign(capacity_type new_capacity, Iterator first, Iterator last, const false_type&) { + BOOST_CB_IS_CONVERTIBLE(Iterator, value_type); // check for invalid iterator type +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x581)) + assign(new_capacity, first, last, iterator_category::type()); +#else + assign(new_capacity, first, last, BOOST_DEDUCED_TYPENAME iterator_category::type()); +#endif + } + + //! Specialized assign method. + template + void assign(capacity_type new_capacity, InputIterator first, InputIterator last, const std::input_iterator_tag&) { + if (new_capacity == capacity()) { + clear(); + insert(begin(), first, last); + } else { + circular_buffer tmp(new_capacity, first, last, m_alloc); + tmp.swap(*this); + } + } + + //! Specialized assign method. + template + void assign(capacity_type new_capacity, ForwardIterator first, ForwardIterator last, + const std::forward_iterator_tag&) { + BOOST_CB_ASSERT(std::distance(first, last) >= 0); // check for wrong range + size_type distance = std::distance(first, last); + if (distance > new_capacity) { + std::advance(first, distance - new_capacity); + distance = new_capacity; + } + assign_n(new_capacity, distance, + cb_details::make_assign_range(first, last, m_alloc)); + } + + //! Helper assign method. + template + void assign_n(capacity_type new_capacity, size_type n, const Functor& fnc) { + if (new_capacity == capacity()) { + destroy_content(); + BOOST_TRY { + fnc(m_buff); + } BOOST_CATCH(...) { + m_size = 0; + BOOST_RETHROW + } + BOOST_CATCH_END + } else { + pointer buff = allocate(new_capacity); + BOOST_TRY { + fnc(buff); + } BOOST_CATCH(...) { + deallocate(buff, new_capacity); + BOOST_RETHROW + } + BOOST_CATCH_END + destroy(); + m_buff = buff; + m_end = m_buff + new_capacity; + } + m_size = n; + m_first = m_buff; + m_last = add(m_buff, size()); + } + + //! Helper insert method. + template + iterator insert_item(const iterator& pos, ValT item) { + pointer p = pos.m_it; + if (p == 0) { + construct_or_replace(!full(), m_last, static_cast(item)); + p = m_last; + } else { + pointer src = m_last; + pointer dest = m_last; + bool construct = !full(); + BOOST_TRY { + while (src != p) { + decrement(src); + construct_or_replace(construct, dest, boost::move_if_noexcept(*src)); + decrement(dest); + construct = false; + } + replace(p, static_cast(item)); + } BOOST_CATCH(...) { + if (!construct && !full()) { + increment(m_last); + ++m_size; + } + BOOST_RETHROW + } + BOOST_CATCH_END + } + increment(m_last); + if (full()) + m_first = m_last; + else + ++m_size; + return iterator(this, p); + } + + //! Specialized insert method. + template + void insert(const iterator& pos, IntegralType n, IntegralType item, const true_type&) { + insert(pos, static_cast(n), static_cast(item)); + } + + //! Specialized insert method. + template + void insert(const iterator& pos, Iterator first, Iterator last, const false_type&) { + BOOST_CB_IS_CONVERTIBLE(Iterator, value_type); // check for invalid iterator type +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x581)) + insert(pos, first, last, iterator_category::type()); +#else + insert(pos, first, last, BOOST_DEDUCED_TYPENAME iterator_category::type()); +#endif + } + + //! Specialized insert method. + template + void insert(iterator pos, InputIterator first, InputIterator last, const std::input_iterator_tag&) { + if (!full() || pos != begin()) { + for (;first != last; ++pos) + pos = insert(pos, *first++); + } + } + + //! Specialized insert method. + template + void insert(const iterator& pos, ForwardIterator first, ForwardIterator last, const std::forward_iterator_tag&) { + BOOST_CB_ASSERT(std::distance(first, last) >= 0); // check for wrong range + size_type n = std::distance(first, last); + if (n == 0) + return; + size_type copy = capacity() - (end() - pos); + if (copy == 0) + return; + if (n > copy) { + std::advance(first, n - copy); + n = copy; + } + insert_n(pos, n, cb_details::iterator_wrapper(first)); + } + + //! Helper insert method. + template + void insert_n(const iterator& pos, size_type n, const Wrapper& wrapper) { + size_type construct = reserve(); + if (construct > n) + construct = n; + if (pos.m_it == 0) { + size_type ii = 0; + pointer p = m_last; + BOOST_TRY { + for (; ii < construct; ++ii, increment(p)) + boost::container::allocator_traits::construct(m_alloc, boost::addressof(*p), *wrapper()); + for (;ii < n; ++ii, increment(p)) + replace(p, *wrapper()); + } BOOST_CATCH(...) { + size_type constructed = (std::min)(ii, construct); + m_last = add(m_last, constructed); + m_size += constructed; + BOOST_RETHROW + } + BOOST_CATCH_END + } else { + pointer src = m_last; + pointer dest = add(m_last, n - 1); + pointer p = pos.m_it; + size_type ii = 0; + BOOST_TRY { + while (src != pos.m_it) { + decrement(src); + construct_or_replace(is_uninitialized(dest), dest, *src); + decrement(dest); + } + for (; ii < n; ++ii, increment(p)) + construct_or_replace(is_uninitialized(p), p, *wrapper()); + } BOOST_CATCH(...) { + for (p = add(m_last, n - 1); p != dest; decrement(p)) + destroy_if_constructed(p); + for (n = 0, p = pos.m_it; n < ii; ++n, increment(p)) + destroy_if_constructed(p); + BOOST_RETHROW + } + BOOST_CATCH_END + } + m_last = add(m_last, n); + m_first = add(m_first, n - construct); + m_size += construct; + } + + //! Specialized rinsert method. + template + void rinsert(const iterator& pos, IntegralType n, IntegralType item, const true_type&) { + rinsert(pos, static_cast(n), static_cast(item)); + } + + //! Specialized rinsert method. + template + void rinsert(const iterator& pos, Iterator first, Iterator last, const false_type&) { + BOOST_CB_IS_CONVERTIBLE(Iterator, value_type); // check for invalid iterator type +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x581)) + rinsert(pos, first, last, iterator_category::type()); +#else + rinsert(pos, first, last, BOOST_DEDUCED_TYPENAME iterator_category::type()); +#endif + } + + //! Specialized insert method. + template + void rinsert(iterator pos, InputIterator first, InputIterator last, const std::input_iterator_tag&) { + if (!full() || pos.m_it != 0) { + for (;first != last; ++pos) { + pos = rinsert(pos, *first++); + if (pos.m_it == 0) + break; + } + } + } + + //! Specialized rinsert method. + template + void rinsert(const iterator& pos, ForwardIterator first, ForwardIterator last, const std::forward_iterator_tag&) { + BOOST_CB_ASSERT(std::distance(first, last) >= 0); // check for wrong range + rinsert_n(pos, std::distance(first, last), cb_details::iterator_wrapper(first)); + } + + //! Helper rinsert method. + template + void rinsert_n(const iterator& pos, size_type n, const Wrapper& wrapper) { + if (n == 0) + return; + iterator b = begin(); + size_type copy = capacity() - (pos - b); + if (copy == 0) + return; + if (n > copy) + n = copy; + size_type construct = reserve(); + if (construct > n) + construct = n; + if (pos == b) { + pointer p = sub(m_first, n); + size_type ii = n; + BOOST_TRY { + for (;ii > construct; --ii, increment(p)) + replace(p, *wrapper()); + for (; ii > 0; --ii, increment(p)) + boost::container::allocator_traits::construct(m_alloc, boost::addressof(*p), *wrapper()); + } BOOST_CATCH(...) { + size_type constructed = ii < construct ? construct - ii : 0; + m_last = add(m_last, constructed); + m_size += constructed; + BOOST_RETHROW + } + BOOST_CATCH_END + } else { + pointer src = m_first; + pointer dest = sub(m_first, n); + pointer p = map_pointer(pos.m_it); + BOOST_TRY { + while (src != p) { + construct_or_replace(is_uninitialized(dest), dest, *src); + increment(src); + increment(dest); + } + for (size_type ii = 0; ii < n; ++ii, increment(dest)) + construct_or_replace(is_uninitialized(dest), dest, *wrapper()); + } BOOST_CATCH(...) { + for (src = sub(m_first, n); src != dest; increment(src)) + destroy_if_constructed(src); + BOOST_RETHROW + } + BOOST_CATCH_END + } + m_first = sub(m_first, n); + m_last = sub(m_last, n - construct); + m_size += construct; + } + + //! Specialized erase_begin method. + void erase_begin(size_type n, const true_type&) { + m_first = add(m_first, n); + m_size -= n; + } + + //! Specialized erase_begin method. + void erase_begin(size_type n, const false_type&) { + iterator b = begin(); + rerase(b, b + n); + } + + //! Specialized erase_end method. + void erase_end(size_type n, const true_type&) { + m_last = sub(m_last, n); + m_size -= n; + } + + //! Specialized erase_end method. + void erase_end(size_type n, const false_type&) { + iterator e = end(); + erase(e - n, e); + } +}; + +// Non-member functions + +//! Compare two circular_buffers element-by-element to determine if they are equal. +/*! + \param lhs The circular_buffer to compare. + \param rhs The circular_buffer to compare. + \return lhs.\link circular_buffer::size() size()\endlink == rhs.\link circular_buffer::size() size()\endlink + && std::equal(lhs.\link circular_buffer::begin() + begin()\endlink, lhs.\link circular_buffer::end() end()\endlink, + rhs.\link circular_buffer::begin() begin()\endlink) + \throws Nothing. + \par Complexity + Linear (in the size of the circular_buffers). + \par Iterator Invalidation + Does not invalidate any iterators. +*/ +template +inline bool operator == (const circular_buffer& lhs, const circular_buffer& rhs) { + return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +/*! + \brief Compare two circular_buffers element-by-element to determine if the left one is lesser than the + right one. + \param lhs The circular_buffer to compare. + \param rhs The circular_buffer to compare. + \return + std::lexicographical_compare(lhs.\link circular_buffer::begin() begin()\endlink, + lhs.\link circular_buffer::end() end()\endlink, rhs.\link circular_buffer::begin() begin()\endlink, + rhs.\link circular_buffer::end() end()\endlink) + \throws Nothing. + \par Complexity + Linear (in the size of the circular_buffers). + \par Iterator Invalidation + Does not invalidate any iterators. +*/ +template +inline bool operator < (const circular_buffer& lhs, const circular_buffer& rhs) { + return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) || defined(BOOST_MSVC) + +//! Compare two circular_buffers element-by-element to determine if they are non-equal. +/*! + \param lhs The circular_buffer to compare. + \param rhs The circular_buffer to compare. + \return !(lhs == rhs) + \throws Nothing. + \par Complexity + Linear (in the size of the circular_buffers). + \par Iterator Invalidation + Does not invalidate any iterators. + \sa operator==(const circular_buffer&, const circular_buffer&) +*/ +template +inline bool operator != (const circular_buffer& lhs, const circular_buffer& rhs) { + return !(lhs == rhs); +} + +/*! + \brief Compare two circular_buffers element-by-element to determine if the left one is greater than + the right one. + \param lhs The circular_buffer to compare. + \param rhs The circular_buffer to compare. + \return rhs \< lhs + \throws Nothing. + \par Complexity + Linear (in the size of the circular_buffers). + \par Iterator Invalidation + Does not invalidate any iterators. + \sa operator<(const circular_buffer&, const circular_buffer&) +*/ +template +inline bool operator > (const circular_buffer& lhs, const circular_buffer& rhs) { + return rhs < lhs; +} + +/*! + \brief Compare two circular_buffers element-by-element to determine if the left one is lesser or equal + to the right one. + \param lhs The circular_buffer to compare. + \param rhs The circular_buffer to compare. + \return !(rhs \< lhs) + \throws Nothing. + \par Complexity + Linear (in the size of the circular_buffers). + \par Iterator Invalidation + Does not invalidate any iterators. + \sa operator<(const circular_buffer&, const circular_buffer&) +*/ +template +inline bool operator <= (const circular_buffer& lhs, const circular_buffer& rhs) { + return !(rhs < lhs); +} + +/*! + \brief Compare two circular_buffers element-by-element to determine if the left one is greater or + equal to the right one. + \param lhs The circular_buffer to compare. + \param rhs The circular_buffer to compare. + \return !(lhs < rhs) + \throws Nothing. + \par Complexity + Linear (in the size of the circular_buffers). + \par Iterator Invalidation + Does not invalidate any iterators. + \sa operator<(const circular_buffer&, const circular_buffer&) +*/ +template +inline bool operator >= (const circular_buffer& lhs, const circular_buffer& rhs) { + return !(lhs < rhs); +} + +//! Swap the contents of two circular_buffers. +/*! + \post lhs contains elements of rhs and vice versa. + \param lhs The circular_buffer whose content will be swapped with rhs. + \param rhs The circular_buffer whose content will be swapped with lhs. + \throws Nothing. + \par Complexity + Constant (in the size of the circular_buffers). + \par Iterator Invalidation + Invalidates all iterators of both circular_buffers. (On the other hand the iterators still + point to the same elements but within another container. If you want to rely on this feature you have to + turn the Debug Support off otherwise an assertion will report an error if such + invalidated iterator is used.) + \sa \link circular_buffer::swap(circular_buffer&) swap(circular_buffer&)\endlink +*/ +template +inline void swap(circular_buffer& lhs, circular_buffer& rhs) BOOST_NOEXCEPT { + lhs.swap(rhs); +} + +#endif // #if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) || defined(BOOST_MSVC) + +} // namespace boost + +#endif // #if !defined(BOOST_CIRCULAR_BUFFER_BASE_HPP) diff --git a/boost/boost/circular_buffer/debug.hpp b/boost/boost/circular_buffer/debug.hpp new file mode 100644 index 000000000..5300b6941 --- /dev/null +++ b/boost/boost/circular_buffer/debug.hpp @@ -0,0 +1,248 @@ +// Debug support for the circular buffer library. + +// Copyright (c) 2003-2008 Jan Gaspar + +// 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) + +#if !defined(BOOST_CIRCULAR_BUFFER_DEBUG_HPP) +#define BOOST_CIRCULAR_BUFFER_DEBUG_HPP + +#if defined(_MSC_VER) + #pragma once +#endif + +#if BOOST_CB_ENABLE_DEBUG +#include + +#if defined(BOOST_NO_STDC_NAMESPACE) +namespace std { + using ::memset; +} +#endif + +#endif // BOOST_CB_ENABLE_DEBUG +namespace boost { + +namespace cb_details { + +#if BOOST_CB_ENABLE_DEBUG + +// The value the uninitialized memory is filled with. +const int UNINITIALIZED = 0xcc; + +template +inline void do_fill_uninitialized_memory(T* data, std::size_t size_in_bytes) BOOST_NOEXCEPT { + std::memset(static_cast(data), UNINITIALIZED, size_in_bytes); +} + +template +inline void do_fill_uninitialized_memory(T& /*data*/, std::size_t /*size_in_bytes*/) BOOST_NOEXCEPT { + // Do nothing +} + + +class debug_iterator_registry; + +/*! + \class debug_iterator_base + \brief Registers/unregisters iterators into the registry of valid iterators. + + This class is intended to be a base class of an iterator. +*/ +class debug_iterator_base { + +private: +// Members + + //! Iterator registry. + mutable const debug_iterator_registry* m_registry; + + //! Next iterator in the iterator chain. + mutable const debug_iterator_base* m_next; + +public: +// Construction/destruction + + //! Default constructor. + debug_iterator_base(); + + //! Constructor taking the iterator registry as a parameter. + debug_iterator_base(const debug_iterator_registry* registry); + + //! Copy constructor. + debug_iterator_base(const debug_iterator_base& rhs); + + //! Destructor. + ~debug_iterator_base(); + +// Methods + + //! Assign operator. + debug_iterator_base& operator = (const debug_iterator_base& rhs); + + //! Is the iterator valid? + bool is_valid(const debug_iterator_registry* registry) const; + + //! Invalidate the iterator. + /*! + \note The method is const in order to invalidate const iterators, too. + */ + void invalidate() const; + + //! Return the next iterator in the iterator chain. + const debug_iterator_base* next() const; + + //! Set the next iterator in the iterator chain. + /*! + \note The method is const in order to set a next iterator to a const iterator, too. + */ + void set_next(const debug_iterator_base* it) const; + +private: +// Helpers + + //! Register self as a valid iterator. + void register_self(); + + //! Unregister self from valid iterators. + void unregister_self(); +}; + +/*! + \class debug_iterator_registry + \brief Registry of valid iterators. + + This class is intended to be a base class of a container. +*/ +class debug_iterator_registry { + + //! Pointer to the chain of valid iterators. + mutable const debug_iterator_base* m_iterators; + +public: +// Methods + + //! Default constructor. + debug_iterator_registry() : m_iterators(0) {} + + //! Register an iterator into the list of valid iterators. + /*! + \note The method is const in order to register iterators into const containers, too. + */ + void register_iterator(const debug_iterator_base* it) const { + it->set_next(m_iterators); + m_iterators = it; + } + + //! Unregister an iterator from the list of valid iterators. + /*! + \note The method is const in order to unregister iterators from const containers, too. + */ + void unregister_iterator(const debug_iterator_base* it) const { + const debug_iterator_base* previous = 0; + for (const debug_iterator_base* p = m_iterators; p != it; previous = p, p = p->next()) {} + remove(it, previous); + } + + //! Invalidate every iterator pointing to the same element as the iterator passed as a parameter. + template + void invalidate_iterators(const Iterator& it) { + const debug_iterator_base* previous = 0; + for (const debug_iterator_base* p = m_iterators; p != 0; p = p->next()) { + if (((Iterator*)p)->m_it == it.m_it) { + p->invalidate(); + remove(p, previous); + continue; + } + previous = p; + } + } + + //! Invalidate all iterators except an iterator poining to the same element as the iterator passed as a parameter. + template + void invalidate_iterators_except(const Iterator& it) { + const debug_iterator_base* previous = 0; + for (const debug_iterator_base* p = m_iterators; p != 0; p = p->next()) { + if (((Iterator*)p)->m_it != it.m_it) { + p->invalidate(); + remove(p, previous); + continue; + } + previous = p; + } + } + + //! Invalidate all iterators. + void invalidate_all_iterators() { + for (const debug_iterator_base* p = m_iterators; p != 0; p = p->next()) + p->invalidate(); + m_iterators = 0; + } + +private: +// Helpers + + //! Remove the current iterator from the iterator chain. + void remove(const debug_iterator_base* current, + const debug_iterator_base* previous) const { + if (previous == 0) + m_iterators = m_iterators->next(); + else + previous->set_next(current->next()); + } +}; + +// Implementation of the debug_iterator_base methods. + +inline debug_iterator_base::debug_iterator_base() : m_registry(0), m_next(0) {} + +inline debug_iterator_base::debug_iterator_base(const debug_iterator_registry* registry) +: m_registry(registry), m_next(0) { + register_self(); +} + +inline debug_iterator_base::debug_iterator_base(const debug_iterator_base& rhs) +: m_registry(rhs.m_registry), m_next(0) { + register_self(); +} + +inline debug_iterator_base::~debug_iterator_base() { unregister_self(); } + +inline debug_iterator_base& debug_iterator_base::operator = (const debug_iterator_base& rhs) { + if (m_registry == rhs.m_registry) + return *this; + unregister_self(); + m_registry = rhs.m_registry; + register_self(); + return *this; +} + +inline bool debug_iterator_base::is_valid(const debug_iterator_registry* registry) const { + return m_registry == registry; +} + +inline void debug_iterator_base::invalidate() const { m_registry = 0; } + +inline const debug_iterator_base* debug_iterator_base::next() const { return m_next; } + +inline void debug_iterator_base::set_next(const debug_iterator_base* it) const { m_next = it; } + +inline void debug_iterator_base::register_self() { + if (m_registry != 0) + m_registry->register_iterator(this); +} + +inline void debug_iterator_base::unregister_self() { + if (m_registry != 0) + m_registry->unregister_iterator(this); +} + +#endif // #if BOOST_CB_ENABLE_DEBUG + +} // namespace cb_details + +} // namespace boost + +#endif // #if !defined(BOOST_CIRCULAR_BUFFER_DEBUG_HPP) diff --git a/boost/boost/circular_buffer/details.hpp b/boost/boost/circular_buffer/details.hpp new file mode 100644 index 000000000..9a27099a8 --- /dev/null +++ b/boost/boost/circular_buffer/details.hpp @@ -0,0 +1,498 @@ +// Helper classes and functions for the circular buffer. + +// Copyright (c) 2003-2008 Jan Gaspar +// Copyright (c) 2014 Glen Fernandes // C++11 allocator model support. + +// 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) + +#if !defined(BOOST_CIRCULAR_BUFFER_DETAILS_HPP) +#define BOOST_CIRCULAR_BUFFER_DETAILS_HPP + +#if defined(_MSC_VER) + #pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +// Silence MS /W4 warnings like C4913: +// "user defined binary operator ',' exists but no overload could convert all operands, default built-in binary operator ',' used" +// This might happen when previously including some boost headers that overload the coma operator. +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable:4913) +#endif + +namespace boost { + +namespace cb_details { + +template struct nonconst_traits; + +template +void uninitialized_fill_n_with_alloc( + ForwardIterator first, Diff n, const T& item, Alloc& alloc); + +template +ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a); + +template +ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a); + +/*! + \struct const_traits + \brief Defines the data types for a const iterator. +*/ +template +struct const_traits { + // Basic types + typedef typename Traits::value_type value_type; + typedef typename Traits::const_pointer pointer; + typedef typename Traits::const_reference reference; + typedef typename Traits::size_type size_type; + typedef typename Traits::difference_type difference_type; + + // Non-const traits + typedef nonconst_traits nonconst_self; +}; + +/*! + \struct nonconst_traits + \brief Defines the data types for a non-const iterator. +*/ +template +struct nonconst_traits { + // Basic types + typedef typename Traits::value_type value_type; + typedef typename Traits::pointer pointer; + typedef typename Traits::reference reference; + typedef typename Traits::size_type size_type; + typedef typename Traits::difference_type difference_type; + + // Non-const traits + typedef nonconst_traits nonconst_self; +}; + +/*! + \struct iterator_wrapper + \brief Helper iterator dereference wrapper. +*/ +template +struct iterator_wrapper { + mutable Iterator m_it; + explicit iterator_wrapper(Iterator it) : m_it(it) {} + Iterator operator () () const { return m_it++; } +private: + iterator_wrapper& operator = (const iterator_wrapper&); // do not generate +}; + +/*! + \struct item_wrapper + \brief Helper item dereference wrapper. +*/ +template +struct item_wrapper { + Value m_item; + explicit item_wrapper(Value item) : m_item(item) {} + Pointer operator () () const { return &m_item; } +private: + item_wrapper& operator = (const item_wrapper&); // do not generate +}; + +/*! + \struct assign_n + \brief Helper functor for assigning n items. +*/ +template +struct assign_n { + typedef typename boost::container::allocator_traits::size_type size_type; + size_type m_n; + Value m_item; + Alloc& m_alloc; + assign_n(size_type n, Value item, Alloc& alloc) : m_n(n), m_item(item), m_alloc(alloc) {} + template + void operator () (Pointer p) const { + uninitialized_fill_n_with_alloc(p, m_n, m_item, m_alloc); + } +private: + assign_n& operator = (const assign_n&); // do not generate +}; + +/*! + \struct assign_range + \brief Helper functor for assigning range of items. +*/ +template +struct assign_range { + Iterator m_first; + Iterator m_last; + Alloc& m_alloc; + + assign_range(const Iterator& first, const Iterator& last, Alloc& alloc) + : m_first(first), m_last(last), m_alloc(alloc) {} + + template + void operator () (Pointer p) const { + boost::cb_details::uninitialized_copy(m_first, m_last, p, m_alloc); + } +}; + +template +inline assign_range make_assign_range(const Iterator& first, const Iterator& last, Alloc& a) { + return assign_range(first, last, a); +} + +/*! + \class capacity_control + \brief Capacity controller of the space optimized circular buffer. +*/ +template +class capacity_control { + + //! The capacity of the space-optimized circular buffer. + Size m_capacity; + + //! The lowest guaranteed or minimum capacity of the adapted space-optimized circular buffer. + Size m_min_capacity; + +public: + + //! Constructor. + capacity_control(Size buffer_capacity, Size min_buffer_capacity = 0) + : m_capacity(buffer_capacity), m_min_capacity(min_buffer_capacity) + { // Check for capacity lower than min_capacity. + BOOST_CB_ASSERT(buffer_capacity >= min_buffer_capacity); + } + + // Default copy constructor. + + // Default assign operator. + + //! Get the capacity of the space optimized circular buffer. + Size capacity() const { return m_capacity; } + + //! Get the minimal capacity of the space optimized circular buffer. + Size min_capacity() const { return m_min_capacity; } + + //! Size operator - returns the capacity of the space optimized circular buffer. + operator Size() const { return m_capacity; } +}; + +/*! + \struct iterator + \brief Random access iterator for the circular buffer. + \param Buff The type of the underlying circular buffer. + \param Traits Basic iterator types. + \note This iterator is not circular. It was designed + for iterating from begin() to end() of the circular buffer. +*/ +template +struct iterator : + public std::iterator< + std::random_access_iterator_tag, + typename Traits::value_type, + typename Traits::difference_type, + typename Traits::pointer, + typename Traits::reference> +#if BOOST_CB_ENABLE_DEBUG + , public debug_iterator_base +#endif // #if BOOST_CB_ENABLE_DEBUG +{ +// Helper types + + //! Base iterator. + typedef std::iterator< + std::random_access_iterator_tag, + typename Traits::value_type, + typename Traits::difference_type, + typename Traits::pointer, + typename Traits::reference> base_iterator; + + //! Non-const iterator. + typedef iterator nonconst_self; + +// Basic types + + //! The type of the elements stored in the circular buffer. + typedef typename base_iterator::value_type value_type; + + //! Pointer to the element. + typedef typename base_iterator::pointer pointer; + + //! Reference to the element. + typedef typename base_iterator::reference reference; + + //! Size type. + typedef typename Traits::size_type size_type; + + //! Difference type. + typedef typename base_iterator::difference_type difference_type; + +// Member variables + + //! The circular buffer where the iterator points to. + const Buff* m_buff; + + //! An internal iterator. + pointer m_it; + +// Construction & assignment + + // Default copy constructor. + + //! Default constructor. + iterator() : m_buff(0), m_it(0) {} + +#if BOOST_CB_ENABLE_DEBUG + + //! Copy constructor (used for converting from a non-const to a const iterator). + iterator(const nonconst_self& it) : debug_iterator_base(it), m_buff(it.m_buff), m_it(it.m_it) {} + + //! Internal constructor. + /*! + \note This constructor is not intended to be used directly by the user. + */ + iterator(const Buff* cb, const pointer p) : debug_iterator_base(cb), m_buff(cb), m_it(p) {} + +#else + + iterator(const nonconst_self& it) : m_buff(it.m_buff), m_it(it.m_it) {} + + iterator(const Buff* cb, const pointer p) : m_buff(cb), m_it(p) {} + +#endif // #if BOOST_CB_ENABLE_DEBUG + + //! Assign operator. + iterator& operator = (const iterator& it) { + if (this == &it) + return *this; +#if BOOST_CB_ENABLE_DEBUG + debug_iterator_base::operator =(it); +#endif // #if BOOST_CB_ENABLE_DEBUG + m_buff = it.m_buff; + m_it = it.m_it; + return *this; + } + +// Random access iterator methods + + //! Dereferencing operator. + reference operator * () const { + BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(m_it != 0); // check for iterator pointing to end() + return *m_it; + } + + //! Dereferencing operator. + pointer operator -> () const { return &(operator*()); } + + //! Difference operator. + template + difference_type operator - (const iterator& it) const { + BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(it.is_valid(m_buff)); // check for uninitialized or invalidated iterator + return linearize_pointer(*this) - linearize_pointer(it); + } + + //! Increment operator (prefix). + iterator& operator ++ () { + BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(m_it != 0); // check for iterator pointing to end() + m_buff->increment(m_it); + if (m_it == m_buff->m_last) + m_it = 0; + return *this; + } + + //! Increment operator (postfix). + iterator operator ++ (int) { + iterator tmp = *this; + ++*this; + return tmp; + } + + //! Decrement operator (prefix). + iterator& operator -- () { + BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(m_it != m_buff->m_first); // check for iterator pointing to begin() + if (m_it == 0) + m_it = m_buff->m_last; + m_buff->decrement(m_it); + return *this; + } + + //! Decrement operator (postfix). + iterator operator -- (int) { + iterator tmp = *this; + --*this; + return tmp; + } + + //! Iterator addition. + iterator& operator += (difference_type n) { + BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator + if (n > 0) { + BOOST_CB_ASSERT(m_buff->end() - *this >= n); // check for too large n + m_it = m_buff->add(m_it, n); + if (m_it == m_buff->m_last) + m_it = 0; + } else if (n < 0) { + *this -= -n; + } + return *this; + } + + //! Iterator addition. + iterator operator + (difference_type n) const { return iterator(*this) += n; } + + //! Iterator subtraction. + iterator& operator -= (difference_type n) { + BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator + if (n > 0) { + BOOST_CB_ASSERT(*this - m_buff->begin() >= n); // check for too large n + m_it = m_buff->sub(m_it == 0 ? m_buff->m_last : m_it, n); + } else if (n < 0) { + *this += -n; + } + return *this; + } + + //! Iterator subtraction. + iterator operator - (difference_type n) const { return iterator(*this) -= n; } + + //! Element access operator. + reference operator [] (difference_type n) const { return *(*this + n); } + +// Equality & comparison + + //! Equality. + template + bool operator == (const iterator& it) const { + BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(it.is_valid(m_buff)); // check for uninitialized or invalidated iterator + return m_it == it.m_it; + } + + //! Inequality. + template + bool operator != (const iterator& it) const { + BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(it.is_valid(m_buff)); // check for uninitialized or invalidated iterator + return m_it != it.m_it; + } + + //! Less. + template + bool operator < (const iterator& it) const { + BOOST_CB_ASSERT(is_valid(m_buff)); // check for uninitialized or invalidated iterator + BOOST_CB_ASSERT(it.is_valid(m_buff)); // check for uninitialized or invalidated iterator + return linearize_pointer(*this) < linearize_pointer(it); + } + + //! Greater. + template + bool operator > (const iterator& it) const { return it < *this; } + + //! Less or equal. + template + bool operator <= (const iterator& it) const { return !(it < *this); } + + //! Greater or equal. + template + bool operator >= (const iterator& it) const { return !(*this < it); } + +// Helpers + + //! Get a pointer which would point to the same element as the iterator in case the circular buffer is linearized. + template + typename Traits0::pointer linearize_pointer(const iterator& it) const { + return it.m_it == 0 ? m_buff->m_buff + m_buff->size() : + (it.m_it < m_buff->m_first ? it.m_it + (m_buff->m_end - m_buff->m_first) + : m_buff->m_buff + (it.m_it - m_buff->m_first)); + } +}; + +//! Iterator addition. +template +inline iterator +operator + (typename Traits::difference_type n, const iterator& it) { + return it + n; +} + +/*! + \fn ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest) + \brief Equivalent of std::uninitialized_copy but with explicit specification of value type. +*/ +template +inline ForwardIterator uninitialized_copy(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a) { + ForwardIterator next = dest; + BOOST_TRY { + for (; first != last; ++first, ++dest) + boost::container::allocator_traits::construct(a, boost::addressof(*dest), *first); + } BOOST_CATCH(...) { + for (; next != dest; ++next) + boost::container::allocator_traits::destroy(a, boost::addressof(*next)); + BOOST_RETHROW + } + BOOST_CATCH_END + return dest; +} + +template +ForwardIterator uninitialized_move_if_noexcept_impl(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a, + true_type) { + for (; first != last; ++first, ++dest) + boost::container::allocator_traits::construct(a, boost::addressof(*dest), boost::move(*first)); + return dest; +} + +template +ForwardIterator uninitialized_move_if_noexcept_impl(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a, + false_type) { + return uninitialized_copy(first, last, dest, a); +} + +/*! + \fn ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest) + \brief Equivalent of std::uninitialized_copy but with explicit specification of value type and moves elements if they have noexcept move constructors. +*/ +template +ForwardIterator uninitialized_move_if_noexcept(InputIterator first, InputIterator last, ForwardIterator dest, Alloc& a) { + typedef typename boost::is_nothrow_move_constructible::value_type>::type tag_t; + return uninitialized_move_if_noexcept_impl(first, last, dest, a, tag_t()); +} + +/*! + \fn void uninitialized_fill_n_with_alloc(ForwardIterator first, Diff n, const T& item, Alloc& alloc) + \brief Equivalent of std::uninitialized_fill_n with allocator. +*/ +template +inline void uninitialized_fill_n_with_alloc(ForwardIterator first, Diff n, const T& item, Alloc& alloc) { + ForwardIterator next = first; + BOOST_TRY { + for (; n > 0; ++first, --n) + boost::container::allocator_traits::construct(alloc, boost::addressof(*first), item); + } BOOST_CATCH(...) { + for (; next != first; ++next) + boost::container::allocator_traits::destroy(alloc, boost::addressof(*next)); + BOOST_RETHROW + } + BOOST_CATCH_END +} + +} // namespace cb_details + +} // namespace boost + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // #if !defined(BOOST_CIRCULAR_BUFFER_DETAILS_HPP) diff --git a/boost/boost/circular_buffer/space_optimized.hpp b/boost/boost/circular_buffer/space_optimized.hpp new file mode 100644 index 000000000..a2c7fb872 --- /dev/null +++ b/boost/boost/circular_buffer/space_optimized.hpp @@ -0,0 +1,1719 @@ +// Implementation of the circular buffer adaptor. + +// Copyright (c) 2003-2008 Jan Gaspar +// Copyright (c) 2013 Paul A. Bristow // Doxygen comments changed for new version of documentation. +// Copyright (c) 2013 Antony Polukhin // Move semantics implementation. + +// 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) + +#if !defined(BOOST_CIRCULAR_BUFFER_SPACE_OPTIMIZED_HPP) +#define BOOST_CIRCULAR_BUFFER_SPACE_OPTIMIZED_HPP + +#if defined(_MSC_VER) + #pragma once +#endif + +#include +#include + +namespace boost { + +/*! + \class circular_buffer_space_optimized + \brief Space optimized circular buffer container adaptor. + T must be a copyable class or must have an noexcept move constructor + and move assignment operator. +*/ +template +class circular_buffer_space_optimized : +/*! \cond */ +#if BOOST_CB_ENABLE_DEBUG +public +#endif +/*! \endcond */ +circular_buffer { +public: +// Typedefs + + typedef typename circular_buffer::value_type value_type; + typedef typename circular_buffer::pointer pointer; + typedef typename circular_buffer::const_pointer const_pointer; + typedef typename circular_buffer::reference reference; + typedef typename circular_buffer::const_reference const_reference; + typedef typename circular_buffer::size_type size_type; + typedef typename circular_buffer::difference_type difference_type; + typedef typename circular_buffer::allocator_type allocator_type; + typedef typename circular_buffer::const_iterator const_iterator; + typedef typename circular_buffer::iterator iterator; + typedef typename circular_buffer::const_reverse_iterator const_reverse_iterator; + typedef typename circular_buffer::reverse_iterator reverse_iterator; + typedef typename circular_buffer::array_range array_range; + typedef typename circular_buffer::const_array_range const_array_range; + typedef typename circular_buffer::param_value_type param_value_type; + typedef typename circular_buffer::rvalue_type rvalue_type; + //typedef typename circular_buffer::return_value_type return_value_type; + +/*
 is not passed through to html or pdf. So 
is used in code section below. Ugly :-( +Ideally want a link to capacity_control, but this would require include details +and this would expose all the functions in details. +There must be a better way of doing this. +*/ + + /*! Capacity controller of the space optimized circular buffer. + + \see capacity_control in details.hpp. +

+ +class capacity_control
+{
+ size_type m_capacity; // Available capacity.
+ size_type m_min_capacity; // Minimum capacity.
+public:
+ capacity_control(size_type capacity, size_type min_capacity = 0)
+ : m_capacity(capacity), m_min_capacity(min_capacity)
+ {};
+ size_type %capacity() const { return m_capacity; }
+ size_type min_capacity() const { return m_min_capacity; }
+ operator size_type() const { return m_capacity; }
+};
+
+

+ + +

Always + capacity >= min_capacity. +

+

+ The capacity() represents the capacity + of the circular_buffer_space_optimized and + the min_capacity() determines the minimal allocated size of its internal buffer. +

+

The converting constructor of the capacity_control allows implicit conversion from + size_type-like types which ensures compatibility of creating an instance of the + circular_buffer_space_optimized with other STL containers. + + On the other hand the operator %size_type() + provides implicit conversion to the size_type which allows to treat the + capacity of the circular_buffer_space_optimized the same way as in the + circular_buffer. +

+ */ + typedef cb_details::capacity_control capacity_type; + +// Inherited + + using circular_buffer::get_allocator; + using circular_buffer::begin; + using circular_buffer::end; + using circular_buffer::rbegin; + using circular_buffer::rend; + using circular_buffer::at; + using circular_buffer::front; + using circular_buffer::back; + using circular_buffer::array_one; + using circular_buffer::array_two; + using circular_buffer::linearize; + using circular_buffer::is_linearized; + using circular_buffer::rotate; + using circular_buffer::size; + using circular_buffer::max_size; + using circular_buffer::empty; + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + reference operator [] (size_type n) { return circular_buffer::operator[](n); } + const_reference operator [] (size_type n) const { return circular_buffer::operator[](n); } +#else + using circular_buffer::operator[]; +#endif + +private: +// Member variables + + //! The capacity controller of the space optimized circular buffer. + capacity_type m_capacity_ctrl; + +public: +// Overridden + + //! Is the circular_buffer_space_optimized full? + /*! + \return true if the number of elements stored in the circular_buffer_space_optimized + equals the capacity of the circular_buffer_space_optimized; false otherwise. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer_space_optimized). + \sa empty() + */ + bool full() const BOOST_NOEXCEPT { return m_capacity_ctrl == size(); } + + /*! \brief Get the maximum number of elements which can be inserted into the + circular_buffer_space_optimized without overwriting any of already stored elements. + \return capacity().%capacity() - size() + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer_space_optimized). + \sa capacity(), size(), max_size() + */ + size_type reserve() const BOOST_NOEXCEPT { return m_capacity_ctrl - size(); } + + //! Get the capacity of the circular_buffer_space_optimized. + /*! + \return The capacity controller representing the maximum number of elements which can be stored in the + circular_buffer_space_optimized and the minimal allocated size of the internal buffer. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Does not invalidate any iterators. + \par Complexity + Constant (in the size of the circular_buffer_space_optimized). + \sa reserve(), size(), max_size(), + set_capacity(const capacity_type&) + */ + const capacity_type& capacity() const BOOST_NOEXCEPT { return m_capacity_ctrl; } + +#if defined(BOOST_CB_TEST) + + // Return the current capacity of the adapted circular buffer. + /* + \note This method is not intended to be used directly by the user. + It is defined only for testing purposes. + */ + size_type internal_capacity() const BOOST_NOEXCEPT { return circular_buffer::capacity(); } + +#endif // #if defined(BOOST_CB_TEST) + + /*! \brief Change the capacity (and the minimal guaranteed amount of allocated memory) of the + circular_buffer_space_optimized. + \post capacity() == capacity_ctrl \&\& size() \<= capacity_ctrl.capacity()

+ If the current number of elements stored in the circular_buffer_space_optimized is greater + than the desired new capacity then number of [size() - capacity_ctrl.capacity()] last + elements will be removed and the new size will be equal to capacity_ctrl.capacity().

+ If the current number of elements stored in the circular_buffer_space_optimized is lower + than the new capacity then the amount of allocated memory in the internal buffer may be accommodated as + necessary but it will never drop below capacity_ctrl.min_capacity(). + \param capacity_ctrl The new capacity controller. + \throws "An allocation error" if memory is exhausted, (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Strong. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in min[size(), capacity_ctrl.%capacity()]). + \note To explicitly clear the extra allocated memory use the shrink-to-fit technique:

+ %boost::%circular_buffer_space_optimized\ cb(1000);
+ ...
+ %boost::%circular_buffer_space_optimized\(cb).swap(cb);


+ For more information about the shrink-to-fit technique in STL see + http://www.gotw.ca/gotw/054.htm. + \sa rset_capacity(const capacity_type&), + \link resize() resize(size_type, const_reference)\endlink + */ + void set_capacity(const capacity_type& capacity_ctrl) { + m_capacity_ctrl = capacity_ctrl; + if (capacity_ctrl < size()) { + iterator e = end(); + circular_buffer::erase(e - (size() - capacity_ctrl), e); + } + adjust_min_capacity(); + } + + //! Change the size of the circular_buffer_space_optimized. + /*! + \post size() == new_size \&\& capacity().%capacity() >= new_size

+ If the new size is greater than the current size, copies of item will be inserted at the + back of the of the circular_buffer_space_optimized in order to achieve the desired + size. In the case the resulting size exceeds the current capacity the capacity will be set to + new_size.

+ If the current number of elements stored in the circular_buffer_space_optimized is greater + than the desired new size then number of [size() - new_size] last elements will be + removed. (The capacity will remain unchanged.)

+ The amount of allocated memory in the internal buffer may be accommodated as necessary. + \param new_size The new size. + \param item The element the circular_buffer_space_optimized will be filled with in order to gain + the requested size. (See the Effect.) + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the new size of the circular_buffer_space_optimized). + \sa \link rresize() rresize(size_type, const_reference)\endlink, + set_capacity(const capacity_type&) + */ + void resize(size_type new_size, param_value_type item = value_type()) { + if (new_size > size()) { + if (new_size > m_capacity_ctrl) + m_capacity_ctrl = capacity_type(new_size, m_capacity_ctrl.min_capacity()); + insert(end(), new_size - size(), item); + } else { + iterator e = end(); + erase(e - (size() - new_size), e); + } + } + + /*! \brief Change the capacity (and the minimal guaranteed amount of allocated memory) of the + circular_buffer_space_optimized. + \post capacity() == capacity_ctrl \&\& size() \<= capacity_ctrl

+ If the current number of elements stored in the circular_buffer_space_optimized is greater + than the desired new capacity then number of [size() - capacity_ctrl.capacity()] + first elements will be removed and the new size will be equal to + capacity_ctrl.capacity().

+ If the current number of elements stored in the circular_buffer_space_optimized is lower + than the new capacity then the amount of allocated memory in the internal buffer may be accommodated as + necessary but it will never drop below capacity_ctrl.min_capacity(). + \param capacity_ctrl The new capacity controller. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Strong. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in min[size(), capacity_ctrl.%capacity()]). + \sa set_capacity(const capacity_type&), + \link rresize() rresize(size_type, const_reference)\endlink + */ + void rset_capacity(const capacity_type& capacity_ctrl) { + m_capacity_ctrl = capacity_ctrl; + if (capacity_ctrl < size()) { + iterator b = begin(); + circular_buffer::rerase(b, b + (size() - capacity_ctrl)); + } + adjust_min_capacity(); + } + + //! Change the size of the circular_buffer_space_optimized. + /*! + \post size() == new_size \&\& capacity().%capacity() >= new_size

+ If the new size is greater than the current size, copies of item will be inserted at the + front of the of the circular_buffer_space_optimized in order to achieve the desired + size. In the case the resulting size exceeds the current capacity the capacity will be set to + new_size.

+ If the current number of elements stored in the circular_buffer_space_optimized is greater + than the desired new size then number of [size() - new_size] first elements will be + removed. (The capacity will remain unchanged.)

+ The amount of allocated memory in the internal buffer may be accommodated as necessary. + \param new_size The new size. + \param item The element the circular_buffer_space_optimized will be filled with in order to gain + the requested size. (See the Effect.) + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the new size of the circular_buffer_space_optimized). + \sa \link resize() resize(size_type, const_reference)\endlink, + rset_capacity(const capacity_type&) + */ + void rresize(size_type new_size, param_value_type item = value_type()) { + if (new_size > size()) { + if (new_size > m_capacity_ctrl) + m_capacity_ctrl = capacity_type(new_size, m_capacity_ctrl.min_capacity()); + rinsert(begin(), new_size - size(), item); + } else { + rerase(begin(), end() - new_size); + } + } + + //! Create an empty space optimized circular buffer with zero capacity. + /*! + \post capacity().%capacity() == 0 \&\& capacity().min_capacity() == 0 \&\& size() == 0 + \param alloc The allocator. + \throws Nothing. + \par Complexity + Constant. + \warning Since Boost version 1.36 the behaviour of this constructor has changed. Now it creates a space + optimized circular buffer with zero capacity. + */ + explicit circular_buffer_space_optimized(const allocator_type& alloc = allocator_type()) BOOST_NOEXCEPT + : circular_buffer(0, alloc) + , m_capacity_ctrl(0) {} + + //! Create an empty space optimized circular buffer with the specified capacity. + /*! + \post capacity() == capacity_ctrl \&\& size() == 0

+ The amount of allocated memory in the internal buffer is capacity_ctrl.min_capacity(). + \param capacity_ctrl The capacity controller representing the maximum number of elements which can be stored in + the circular_buffer_space_optimized and the minimal allocated size of the + internal buffer. + \param alloc The allocator. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + \par Complexity + Constant. + */ + explicit circular_buffer_space_optimized(capacity_type capacity_ctrl, + const allocator_type& alloc = allocator_type()) + : circular_buffer(capacity_ctrl.min_capacity(), alloc) + , m_capacity_ctrl(capacity_ctrl) {} + + /*! \brief Create a full space optimized circular buffer with the specified capacity filled with + capacity_ctrl.%capacity() copies of item. + \post capacity() == capacity_ctrl \&\& full() \&\& (*this)[0] == item \&\& (*this)[1] == item \&\& ... + \&\& (*this) [capacity_ctrl.%capacity() - 1] == item

+ The amount of allocated memory in the internal buffer is capacity_ctrl.capacity(). + \param capacity_ctrl The capacity controller representing the maximum number of elements which can be stored in + the circular_buffer_space_optimized and the minimal allocated size of the + internal buffer. + \param item The element the created circular_buffer_space_optimized will be filled with. + \param alloc The allocator. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + \throws Whatever T::T(const T&) throws. + \par Complexity + Linear (in the capacity_ctrl.%capacity()). + */ + circular_buffer_space_optimized(capacity_type capacity_ctrl, param_value_type item, + const allocator_type& alloc = allocator_type()) + : circular_buffer(capacity_ctrl.capacity(), item, alloc) + , m_capacity_ctrl(capacity_ctrl) {} + + /*! \brief Create a space optimized circular buffer with the specified capacity filled with n copies + of item. + \pre capacity_ctrl.%capacity() >= n + \post capacity() == capacity_ctrl \&\& size() == n \&\& (*this)[0] == item \&\& (*this)[1] == item + \&\& ... \&\& (*this)[n - 1] == item

+ The amount of allocated memory in the internal buffer is + max[n, capacity_ctrl.min_capacity()]. + \param capacity_ctrl The capacity controller representing the maximum number of elements which can be stored in + the circular_buffer_space_optimized and the minimal allocated size of the + internal buffer. + \param n The number of elements the created circular_buffer_space_optimized will be filled with. + \param item The element the created circular_buffer_space_optimized will be filled with. + \param alloc The allocator. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Complexity + Linear (in the n). + */ + circular_buffer_space_optimized(capacity_type capacity_ctrl, size_type n, param_value_type item, + const allocator_type& alloc = allocator_type()) + : circular_buffer(init_capacity(capacity_ctrl, n), n, item, alloc) + , m_capacity_ctrl(capacity_ctrl) {} + + //! The copy constructor. + /*! + Creates a copy of the specified circular_buffer_space_optimized. + \post *this == cb

+ The amount of allocated memory in the internal buffer is cb.size(). + \param cb The circular_buffer_space_optimized to be copied. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Complexity + Linear (in the size of cb). + */ + circular_buffer_space_optimized(const circular_buffer_space_optimized& cb) + : circular_buffer(cb.begin(), cb.end(), cb.get_allocator()) + , m_capacity_ctrl(cb.m_capacity_ctrl) {} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + //! The move constructor. + /*! \brief Move constructs a circular_buffer_space_optimized from cb, + leaving cb empty. + \pre C++ compiler with rvalue references support. + \post cb.empty() + \param cb circular_buffer to 'steal' value from. + \throws Nothing. + \par Constant. + */ + circular_buffer_space_optimized(circular_buffer_space_optimized&& cb) BOOST_NOEXCEPT + : circular_buffer() + , m_capacity_ctrl(0) { + cb.swap(*this); + } +#endif // BOOST_NO_CXX11_RVALUE_REFERENCES + + //! Create a full space optimized circular buffer filled with a copy of the range. + /*! + \pre Valid range [first, last).
+ first and last have to meet the requirements of + InputIterator. + \post capacity().%capacity() == std::distance(first, last) \&\& capacity().min_capacity() == 0 \&\& + full() \&\& (*this)[0]== *first \&\& (*this)[1] == *(first + 1) \&\& ... \&\& + (*this)[std::distance(first, last) - 1] == *(last - 1)

+ The amount of allocated memory in the internal buffer is std::distance(first, last). + \param first The beginning of the range to be copied. + \param last The end of the range to be copied. + \param alloc The allocator. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept + and InputIterator is a move iterator. + \par Complexity + Linear (in the std::distance(first, last)). + */ + template + circular_buffer_space_optimized(InputIterator first, InputIterator last, + const allocator_type& alloc = allocator_type()) + : circular_buffer(first, last, alloc) + , m_capacity_ctrl(circular_buffer::capacity()) {} + + /*! \brief Create a space optimized circular buffer with the specified capacity (and the minimal guaranteed amount + of allocated memory) filled with a copy of the range. + \pre Valid range [first, last).
+ first and last have to meet the requirements of + InputIterator. + \post capacity() == capacity_ctrl \&\& size() \<= std::distance(first, last) \&\& (*this)[0]== + *(last - capacity_ctrl.%capacity()) \&\& (*this)[1] == *(last - capacity_ctrl.%capacity() + 1) \&\& ... + \&\& (*this)[capacity_ctrl.%capacity() - 1] == *(last - 1)

+ If the number of items to be copied from the range [first, last) is greater than the + specified capacity_ctrl.%capacity() then only elements from the range + [last - capacity_ctrl.%capacity(), last) will be copied.

+ The amount of allocated memory in the internal buffer is max[capacity_ctrl.min_capacity(), + min[capacity_ctrl.%capacity(), std::distance(first, last)]]. + \param capacity_ctrl The capacity controller representing the maximum number of elements which can be stored in + the circular_buffer_space_optimized and the minimal allocated size of the + internal buffer. + \param first The beginning of the range to be copied. + \param last The end of the range to be copied. + \param alloc The allocator. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Complexity + Linear (in std::distance(first, last); in + min[capacity_ctrl.%capacity(), std::distance(first, last)] if the InputIterator + is a RandomAccessIterator). + */ + template + circular_buffer_space_optimized(capacity_type capacity_ctrl, InputIterator first, InputIterator last, + const allocator_type& alloc = allocator_type()) + : circular_buffer( + init_capacity(capacity_ctrl, first, last, is_integral()), + first, last, alloc) + , m_capacity_ctrl(capacity_ctrl) { + reduce_capacity( + is_same< BOOST_DEDUCED_TYPENAME iterator_category::type, std::input_iterator_tag >()); + } + +#if defined(BOOST_CB_NEVER_DEFINED) +// This section will never be compiled - the default destructor will be generated instead. +// Declared only for documentation purpose. + + //! The destructor. + /*! + Destroys the circular_buffer_space_optimized. + \throws Nothing. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (including + iterators equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa clear() + */ + ~circular_buffer_space_optimized(); + + //! no-comment + void erase_begin(size_type n); + + //! no-comment + void erase_end(size_type n); + +#endif // #if defined(BOOST_CB_NEVER_DEFINED) + + //! The assign operator. + /*! + Makes this circular_buffer_space_optimized to become a copy of the specified + circular_buffer_space_optimized. + \post *this == cb

+ The amount of allocated memory in the internal buffer is cb.size(). + \param cb The circular_buffer_space_optimized to be copied. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + \throws Whatever T::T(const T&) throws. + \par Exception Safety + Strong. + \par Iterator Invalidation + Invalidates all iterators pointing to this circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of cb). + \sa \link assign(size_type, param_value_type) assign(size_type, const_reference)\endlink, + \link assign(capacity_type, size_type, param_value_type) + assign(capacity_type, size_type, const_reference)\endlink, + assign(InputIterator, InputIterator), + assign(capacity_type, InputIterator, InputIterator) + */ + circular_buffer_space_optimized& operator = (const circular_buffer_space_optimized& cb) { + if (this == &cb) + return *this; + circular_buffer::assign(cb.begin(), cb.end()); + m_capacity_ctrl = cb.m_capacity_ctrl; + return *this; + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + /*! \brief Move assigns content of cb to *this, leaving cb empty. + \pre C++ compiler with rvalue references support. + \post cb.empty() + \param cb circular_buffer to 'steal' value from. + \throws Nothing. + \par Complexity + Constant. + */ + circular_buffer_space_optimized& operator = (circular_buffer_space_optimized&& cb) BOOST_NOEXCEPT { + cb.swap(*this); // now `this` holds `cb` + circular_buffer(get_allocator()) // temprary that holds initial `cb` allocator + .swap(cb); // makes `cb` empty + return *this; + } +#endif // BOOST_NO_CXX11_RVALUE_REFERENCES + + + //! Assign n items into the space optimized circular buffer. + /*! + The content of the circular_buffer_space_optimized will be removed and replaced with + n copies of the item. + \post capacity().%capacity() == n \&\& capacity().min_capacity() == 0 \&\& size() == n \&\& (*this)[0] == + item \&\& (*this)[1] == item \&\& ... \&\& (*this) [n - 1] == item

+ The amount of allocated memory in the internal buffer is n. + \param n The number of elements the circular_buffer_space_optimized will be filled with. + \param item The element the circular_buffer_space_optimized will be filled with. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the n). + \sa \link operator=(const circular_buffer_space_optimized&) operator=\endlink, + \link assign(capacity_type, size_type, param_value_type) + assign(capacity_type, size_type, const_reference)\endlink, + assign(InputIterator, InputIterator), + assign(capacity_type, InputIterator, InputIterator) + */ + void assign(size_type n, param_value_type item) { + circular_buffer::assign(n, item); + m_capacity_ctrl = capacity_type(n); + } + + //! Assign n items into the space optimized circular buffer specifying the capacity. + /*! + The capacity of the circular_buffer_space_optimized will be set to the specified value and the + content of the circular_buffer_space_optimized will be removed and replaced with n + copies of the item. + \pre capacity_ctrl.%capacity() >= n + \post capacity() == capacity_ctrl \&\& size() == n \&\& (*this)[0] == item \&\& (*this)[1] == item + \&\& ... \&\& (*this) [n - 1] == item

+ The amount of allocated memory will be max[n, capacity_ctrl.min_capacity()]. + \param capacity_ctrl The new capacity controller. + \param n The number of elements the circular_buffer_space_optimized will be filled with. + \param item The element the circular_buffer_space_optimized will be filled with. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the n). + \sa \link operator=(const circular_buffer_space_optimized&) operator=\endlink, + \link assign(size_type, param_value_type) assign(size_type, const_reference)\endlink, + assign(InputIterator, InputIterator), + assign(capacity_type, InputIterator, InputIterator) + */ + void assign(capacity_type capacity_ctrl, size_type n, param_value_type item) { + BOOST_CB_ASSERT(capacity_ctrl.capacity() >= n); // check for new capacity lower than n + circular_buffer::assign((std::max)(capacity_ctrl.min_capacity(), n), n, item); + m_capacity_ctrl = capacity_ctrl; + } + + //! Assign a copy of the range into the space optimized circular buffer. + /*! + The content of the circular_buffer_space_optimized will be removed and replaced with copies of + elements from the specified range. + \pre Valid range [first, last).
+ first and last have to meet the requirements of + InputIterator. + \post capacity().%capacity() == std::distance(first, last) \&\& capacity().min_capacity() == 0 \&\& + size() == std::distance(first, last) \&\& (*this)[0]== *first \&\& (*this)[1] == *(first + 1) \&\& ... + \&\& (*this)[std::distance(first, last) - 1] == *(last - 1)

+ The amount of allocated memory in the internal buffer is std::distance(first, last). + \param first The beginning of the range to be copied. + \param last The end of the range to be copied. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept and + InputIterator is a move iterator. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the std::distance(first, last)). + \sa \link operator=(const circular_buffer_space_optimized&) operator=\endlink, + \link assign(size_type, param_value_type) assign(size_type, const_reference)\endlink, + \link assign(capacity_type, size_type, param_value_type) + assign(capacity_type, size_type, const_reference)\endlink, + assign(capacity_type, InputIterator, InputIterator) + */ + template + void assign(InputIterator first, InputIterator last) { + circular_buffer::assign(first, last); + m_capacity_ctrl = capacity_type(circular_buffer::capacity()); + } + + //! Assign a copy of the range into the space optimized circular buffer specifying the capacity. + /*! + The capacity of the circular_buffer_space_optimized will be set to the specified value and the + content of the circular_buffer_space_optimized will be removed and replaced with copies of + elements from the specified range. + \pre Valid range [first, last).
+ first and last have to meet the requirements of + InputIterator. + \post capacity() == capacity_ctrl \&\& size() \<= std::distance(first, last) \&\& + (*this)[0]== *(last - capacity) \&\& (*this)[1] == *(last - capacity + 1) \&\& ... \&\& + (*this)[capacity - 1] == *(last - 1)

+ If the number of items to be copied from the range [first, last) is greater than the + specified capacity then only elements from the range [last - capacity, last) + will be copied.

The amount of allocated memory in the internal buffer is + max[std::distance(first, last), capacity_ctrl.min_capacity()]. + \param capacity_ctrl The new capacity controller. + \param first The beginning of the range to be copied. + \param last The end of the range to be copied. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept and + InputIterator is a move iterator. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in std::distance(first, last); in + min[capacity_ctrl.%capacity(), std::distance(first, last)] if the InputIterator + is a RandomAccessIterator). + \sa \link operator=(const circular_buffer_space_optimized&) operator=\endlink, + \link assign(size_type, param_value_type) assign(size_type, const_reference)\endlink, + \link assign(capacity_type, size_type, param_value_type) + assign(capacity_type, size_type, const_reference)\endlink, + assign(InputIterator, InputIterator) + */ + template + void assign(capacity_type capacity_ctrl, InputIterator first, InputIterator last) { + m_capacity_ctrl = capacity_ctrl; + circular_buffer::assign(capacity_ctrl, first, last); + } + + //! Swap the contents of two space-optimized circular-buffers. + /*! + \post this contains elements of cb and vice versa; the capacity and the amount of + allocated memory in the internal buffer of this equal to the capacity and the amount of + allocated memory of cb and vice versa. + \param cb The circular_buffer_space_optimized whose content will be swapped. + \throws Nothing. + \par Exception Safety + No-throw. + \par Iterator Invalidation + Invalidates all iterators of both circular_buffer_space_optimized containers. (On the other + hand the iterators still point to the same elements but within another container. If you want to rely on + this feature you have to turn the __debug_support off, + otherwise an assertion will report an error if such invalidated iterator is used.) + \par Complexity + Constant (in the size of the circular_buffer_space_optimized). + \sa swap(circular_buffer&, circular_buffer&), + swap(circular_buffer_space_optimized&, circular_buffer_space_optimized&) + + + */ + // Note link does not work right. Asked on Doxygen forum for advice 23 May 2103. + + void swap(circular_buffer_space_optimized& cb) BOOST_NOEXCEPT { + std::swap(m_capacity_ctrl, cb.m_capacity_ctrl); + circular_buffer::swap(cb); + } + + //! Insert a new element at the end of the space optimized circular buffer. + /*! + \post if capacity().%capacity() > 0 then back() == item
+ If the circular_buffer_space_optimized is full, the first element will be removed. If the + capacity is 0, nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param item The element to be inserted. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link push_front() push_front(const_reference)\endlink, pop_back(), + pop_front() + */ + void push_back(param_value_type item) { + check_low_capacity(); + circular_buffer::push_back(item); + } + + //! Insert a new element at the end of the space optimized circular buffer. + /*! + \post if capacity().%capacity() > 0 then back() == item
+ If the circular_buffer_space_optimized is full, the first element will be removed. If the + capacity is 0, nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param item The element to be inserted. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link push_front() push_front(const_reference)\endlink, pop_back(), + pop_front() + */ + void push_back(rvalue_type item) { + check_low_capacity(); + circular_buffer::push_back(boost::move(item)); + } + + //! Insert a new element at the end of the space optimized circular buffer. + /*! + \post if capacity().%capacity() > 0 then back() == item
+ If the circular_buffer_space_optimized is full, the first element will be removed. If the + capacity is 0, nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T() throws. + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link push_front() push_front(const_reference)\endlink, pop_back(), + pop_front() + */ + void push_back() { + check_low_capacity(); + circular_buffer::push_back(); + } + + //! Insert a new element at the beginning of the space optimized circular buffer. + /*! + \post if capacity().%capacity() > 0 then front() == item
+ If the circular_buffer_space_optimized is full, the last element will be removed. If the + capacity is 0, nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param item The element to be inserted. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link push_back() push_back(const_reference)\endlink, pop_back(), + pop_front() + */ + void push_front(param_value_type item) { + check_low_capacity(); + circular_buffer::push_front(item); + } + + //! Insert a new element at the beginning of the space optimized circular buffer. + /*! + \post if capacity().%capacity() > 0 then front() == item
+ If the circular_buffer_space_optimized is full, the last element will be removed. If the + capacity is 0, nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param item The element to be inserted. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link push_back() push_back(const_reference)\endlink, pop_back(), + pop_front() + */ + void push_front(rvalue_type item) { + check_low_capacity(); + circular_buffer::push_front(boost::move(item)); + } + + //! Insert a new element at the beginning of the space optimized circular buffer. + /*! + \post if capacity().%capacity() > 0 then front() == item
+ If the circular_buffer_space_optimized is full, the last element will be removed. If the + capacity is 0, nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T() throws. + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link push_back() push_back(const_reference)\endlink, pop_back(), + pop_front() + */ + void push_front() { + check_low_capacity(); + circular_buffer::push_front(); + } + + //! Remove the last element from the space optimized circular buffer. + /*! + \pre !empty() + \post The last element is removed from the circular_buffer_space_optimized.

+ The amount of allocated memory in the internal buffer may be predictively decreased. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa pop_front(), \link push_back() push_back(const_reference)\endlink, + \link push_front() push_front(const_reference)\endlink + */ + void pop_back() { + circular_buffer::pop_back(); + check_high_capacity(); + } + + //! Remove the first element from the space optimized circular buffer. + /*! + \pre !empty() + \post The first element is removed from the circular_buffer_space_optimized.

+ The amount of allocated memory in the internal buffer may be predictively decreased. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa pop_back(), \link push_back() push_back(const_reference)\endlink, + \link push_front() push_front(const_reference)\endlink + */ + void pop_front() { + circular_buffer::pop_front(); + check_high_capacity(); + } + + //! Insert an element at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer_space_optimized or its + end. + \post The item will be inserted at the position pos.
+ If the circular_buffer_space_optimized is full, the first element will be overwritten. If + the circular_buffer_space_optimized is full and the pos points to + begin(), then the item will not be inserted. If the capacity is 0, + nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param pos An iterator specifying the position where the item will be inserted. + \param item The element to be inserted. + \return Iterator to the inserted element or begin() if the item is not inserted. (See + the Effect.) + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + Whatever T::operator = (const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator), + \link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink, + \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator) + */ + iterator insert(iterator pos, param_value_type item) { + size_type index = pos - begin(); + check_low_capacity(); + return circular_buffer::insert(begin() + index, item); + } + + //! Insert an element at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer_space_optimized or its + end. + \post The item will be inserted at the position pos.
+ If the circular_buffer_space_optimized is full, the first element will be overwritten. If + the circular_buffer_space_optimized is full and the pos points to + begin(), then the item will not be inserted. If the capacity is 0, + nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param pos An iterator specifying the position where the item will be inserted. + \param item The element to be inserted. + \return Iterator to the inserted element or begin() if the item is not inserted. (See + the Effect.) + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator), + \link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink, + \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator) + */ + iterator insert(iterator pos, rvalue_type item) { + size_type index = pos - begin(); + check_low_capacity(); + return circular_buffer::insert(begin() + index, boost::move(item)); + } + + //! Insert an element at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer_space_optimized or its + end. + \post The item will be inserted at the position pos.
+ If the circular_buffer_space_optimized is full, the first element will be overwritten. If + the circular_buffer_space_optimized is full and the pos points to + begin(), then the item will not be inserted. If the capacity is 0, + nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param pos An iterator specifying the position where the item will be inserted. + \return Iterator to the inserted element or begin() if the item is not inserted. (See + the Effect.) + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T() throws. + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator), + \link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink, + \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator) + */ + iterator insert(iterator pos) { + size_type index = pos - begin(); + check_low_capacity(); + return circular_buffer::insert(begin() + index); + } + + //! Insert n copies of the item at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer_space_optimized or its + end. + \post The number of min[n, (pos - begin()) + reserve()] elements will be inserted at the position + pos.
The number of min[pos - begin(), max[0, n - reserve()]] elements will + be overwritten at the beginning of the circular_buffer_space_optimized.
(See + Example for the explanation.)

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param pos An iterator specifying the position where the items will be inserted. + \param n The number of items the to be inserted. + \param item The element whose copies will be inserted. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + Whatever T::operator = (const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in min[capacity().%capacity(), size() + n]). + \par Example + Consider a circular_buffer_space_optimized with the capacity of 6 and the size of 4. Its + internal buffer may look like the one below.

+ |1|2|3|4| | |
+ p ___^

After inserting 5 elements at the position p:

+ insert(p, (size_t)5, 0);

actually only 4 elements get inserted and elements + 1 and 2 are overwritten. This is due to the fact the insert operation preserves + the capacity. After insertion the internal buffer looks like this:

|0|0|0|0|3|4|
+
For comparison if the capacity would not be preserved the internal buffer would then result in + |1|2|0|0|0|0|0|3|4|. + \sa \link insert(iterator, param_value_type) insert(iterator, value_type)\endlink, + insert(iterator, InputIterator, InputIterator), + \link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink, + \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator) + */ + void insert(iterator pos, size_type n, param_value_type item) { + size_type index = pos - begin(); + check_low_capacity(n); + circular_buffer::insert(begin() + index, n, item); + } + + //! Insert the range [first, last) at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer_space_optimized or its + end.
Valid range [first, last) where first and last meet the + requirements of an InputIterator. + \post Elements from the range + [first + max[0, distance(first, last) - (pos - begin()) - reserve()], last) will be + inserted at the position pos.
The number of min[pos - begin(), max[0, + distance(first, last) - reserve()]] elements will be overwritten at the beginning of the + circular_buffer_space_optimized.
(See Example for the explanation.)

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param pos An iterator specifying the position where the range will be inserted. + \param first The beginning of the range to be inserted. + \param last The end of the range to be inserted. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in [size() + std::distance(first, last)]; in + min[capacity().%capacity(), size() + std::distance(first, last)] if the + InputIterator is a + RandomAccessIterator). + \par Example + Consider a circular_buffer_space_optimized with the capacity of 6 and the size of 4. Its + internal buffer may look like the one below.

+ |1|2|3|4| | |
+ p ___^

After inserting a range of elements at the position p:

+ int array[] = { 5, 6, 7, 8, 9 };
insert(p, array, array + 5);

+ actually only elements 6, 7, 8 and 9 from the + specified range get inserted and elements 1 and 2 are overwritten. This is due + to the fact the insert operation preserves the capacity. After insertion the internal buffer looks like + this:

|6|7|8|9|3|4|

For comparison if the capacity would not be preserved the + internal buffer would then result in |1|2|5|6|7|8|9|3|4|. + \sa \link insert(iterator, param_value_type) insert(iterator, value_type)\endlink, + \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, \link rinsert(iterator, param_value_type) + rinsert(iterator, value_type)\endlink, \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator) + */ + template + void insert(iterator pos, InputIterator first, InputIterator last) { + insert(pos, first, last, is_integral()); + } + + //! Insert an element before the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer_space_optimized or its + end. + \post The item will be inserted before the position pos.
+ If the circular_buffer_space_optimized is full, the last element will be overwritten. If the + circular_buffer_space_optimized is full and the pos points to + end(), then the item will not be inserted. If the capacity is 0, + nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param pos An iterator specifying the position before which the item will be inserted. + \param item The element to be inserted. + \return Iterator to the inserted element or end() if the item is not inserted. (See + the Effect.) + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + Whatever T::operator = (const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator), + \link insert(iterator, param_value_type) insert(iterator, value_type)\endlink, + \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator) + */ + iterator rinsert(iterator pos, param_value_type item) { + size_type index = pos - begin(); + check_low_capacity(); + return circular_buffer::rinsert(begin() + index, item); + } + + //! Insert an element before the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer_space_optimized or its + end. + \post The item will be inserted before the position pos.
+ If the circular_buffer_space_optimized is full, the last element will be overwritten. If the + circular_buffer_space_optimized is full and the pos points to + end(), then the item will not be inserted. If the capacity is 0, + nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param pos An iterator specifying the position before which the item will be inserted. + \param item The element to be inserted. + \return Iterator to the inserted element or end() if the item is not inserted. (See + the Effect.) + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator), + \link insert(iterator, param_value_type) insert(iterator, value_type)\endlink, + \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator) + */ + iterator rinsert(iterator pos, rvalue_type item) { + size_type index = pos - begin(); + check_low_capacity(); + return circular_buffer::rinsert(begin() + index, boost::move(item)); + } + + //! Insert an element before the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer_space_optimized or its + end. + \post The item will be inserted before the position pos.
+ If the circular_buffer_space_optimized is full, the last element will be overwritten. If the + circular_buffer_space_optimized is full and the pos points to + end(), then the item will not be inserted. If the capacity is 0, + nothing will be inserted.

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param pos An iterator specifying the position before which the item will be inserted. + \return Iterator to the inserted element or end() if the item is not inserted. (See + the Effect.) + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T() throws. + Whatever T::T(const T&) throws or nothing if T::T(T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator), + \link insert(iterator, param_value_type) insert(iterator, value_type)\endlink, + \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator) + */ + iterator rinsert(iterator pos) { + size_type index = pos - begin(); + check_low_capacity(); + return circular_buffer::rinsert(begin() + index); + } + + //! Insert n copies of the item before the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer_space_optimized or its + end. + \post The number of min[n, (end() - pos) + reserve()] elements will be inserted before the + position pos.
The number of min[end() - pos, max[0, n - reserve()]] elements + will be overwritten at the end of the circular_buffer_space_optimized.
(See + Example for the explanation.)

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param pos An iterator specifying the position where the items will be inserted. + \param n The number of items the to be inserted. + \param item The element whose copies will be inserted. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + Whatever T::operator = (const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in min[capacity().%capacity(), size() + n]). + \par Example + Consider a circular_buffer_space_optimized with the capacity of 6 and the size of 4. Its + internal buffer may look like the one below.

+ |1|2|3|4| | |
+ p ___^

After inserting 5 elements before the position p:

+ rinsert(p, (size_t)5, 0);

actually only 4 elements get inserted and elements + 3 and 4 are overwritten. This is due to the fact the rinsert operation preserves + the capacity. After insertion the internal buffer looks like this:

|1|2|0|0|0|0|
+
For comparison if the capacity would not be preserved the internal buffer would then result in + |1|2|0|0|0|0|0|3|4|. + \sa \link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink, + rinsert(iterator, InputIterator, InputIterator), + \link insert(iterator, param_value_type) insert(iterator, value_type)\endlink, + \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator) + */ + void rinsert(iterator pos, size_type n, param_value_type item) { + size_type index = pos - begin(); + check_low_capacity(n); + circular_buffer::rinsert(begin() + index, n, item); + } + + //! Insert the range [first, last) before the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer_space_optimized or its + end.
+ Valid range [first, last) where first and last meet the + requirements of an InputIterator. + \post Elements from the range + [first, last - max[0, distance(first, last) - (end() - pos) - reserve()]) will be inserted + before the position pos.
The number of min[end() - pos, max[0, + distance(first, last) - reserve()]] elements will be overwritten at the end of the + circular_buffer.
(See Example for the explanation.)

+ The amount of allocated memory in the internal buffer may be predictively increased. + \param pos An iterator specifying the position where the range will be inserted. + \param first The beginning of the range to be inserted. + \param last The end of the range to be inserted. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::T(const T&) throws. + Whatever T::operator = (const T&) throws. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in [size() + std::distance(first, last)]; in + min[capacity().%capacity(), size() + std::distance(first, last)] if the + InputIterator is a + RandomAccessIterator). + \par Example + Consider a circular_buffer_space_optimized with the capacity of 6 and the size of 4. Its + internal buffer may look like the one below.

+ |1|2|3|4| | |
+ p ___^

After inserting a range of elements before the position p:

+ int array[] = { 5, 6, 7, 8, 9 };
insert(p, array, array + 5);

+ actually only elements 5, 6, 7 and 8 from the + specified range get inserted and elements 3 and 4 are overwritten. This is due + to the fact the rinsert operation preserves the capacity. After insertion the internal buffer looks like + this:

|1|2|5|6|7|8|

For comparison if the capacity would not be preserved the + internal buffer would then result in |1|2|5|6|7|8|9|3|4|. + \sa \link rinsert(iterator, param_value_type) rinsert(iterator, value_type)\endlink, + \link rinsert(iterator, size_type, param_value_type) + rinsert(iterator, size_type, value_type)\endlink, \link insert(iterator, param_value_type) + insert(iterator, value_type)\endlink, \link insert(iterator, size_type, param_value_type) + insert(iterator, size_type, value_type)\endlink, + insert(iterator, InputIterator, InputIterator) + */ + template + void rinsert(iterator pos, InputIterator first, InputIterator last) { + rinsert(pos, first, last, is_integral()); + } + + //! Remove an element at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer_space_optimized (but not + an end()). + \post The element at the position pos is removed.

+ The amount of allocated memory in the internal buffer may be predictively decreased. + \param pos An iterator pointing at the element to be removed. + \return Iterator to the first element remaining beyond the removed element or end() if no such + element exists. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::operator = (const T&) throws or + nothing if T::operator = (T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa erase(iterator, iterator), rerase(iterator), + rerase(iterator, iterator), clear() + */ + iterator erase(iterator pos) { + iterator it = circular_buffer::erase(pos); + size_type index = it - begin(); + check_high_capacity(); + return begin() + index; + } + + //! Erase the range [first, last). + /*! + \pre Valid range [first, last). + \post The elements from the range [first, last) are removed. (If first == last + nothing is removed.)

+ The amount of allocated memory in the internal buffer may be predictively decreased. + \param first The beginning of the range to be removed. + \param last The end of the range to be removed. + \return Iterator to the first element remaining beyond the removed elements or end() if no such + element exists. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::operator = (const T&) throws or + nothing if T::operator = (T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa erase(iterator), rerase(iterator), rerase(iterator, iterator), + clear() + */ + iterator erase(iterator first, iterator last) { + iterator it = circular_buffer::erase(first, last); + size_type index = it - begin(); + check_high_capacity(); + return begin() + index; + } + + //! Remove an element at the specified position. + /*! + \pre pos is a valid iterator pointing to the circular_buffer_space_optimized (but not + an end()).

+ The amount of allocated memory in the internal buffer may be predictively decreased. + \post The element at the position pos is removed. + \param pos An iterator pointing at the element to be removed. + \return Iterator to the first element remaining in front of the removed element or begin() if no + such element exists. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::operator = (const T&) throws or + nothing if T::operator = (T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \note Basically there is no difference between erase(iterator) and this method. It is implemented + only for consistency with the base circular_buffer. + \sa erase(iterator), erase(iterator, iterator), + rerase(iterator, iterator), clear() + */ + iterator rerase(iterator pos) { + iterator it = circular_buffer::rerase(pos); + size_type index = it - begin(); + check_high_capacity(); + return begin() + index; + } + + //! Erase the range [first, last). + /*! + \pre Valid range [first, last). + \post The elements from the range [first, last) are removed. (If first == last + nothing is removed.)

+ The amount of allocated memory in the internal buffer may be predictively decreased. + \param first The beginning of the range to be removed. + \param last The end of the range to be removed. + \return Iterator to the first element remaining in front of the removed elements or begin() if no + such element exists. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + Whatever T::operator = (const T&) throws or + nothing if T::operator = (T&&) is noexcept. + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \note Basically there is no difference between erase(iterator, iterator) and this method. It is + implemented only for consistency with the base + . + \sa erase(iterator), erase(iterator, iterator), rerase(iterator), + clear() + */ + iterator rerase(iterator first, iterator last) { + iterator it = circular_buffer::rerase(first, last); + size_type index = it - begin(); + check_high_capacity(); + return begin() + index; + } + + //! Remove all stored elements from the space optimized circular buffer. + /*! + \post size() == 0

+ The amount of allocated memory in the internal buffer may be predictively decreased. + \throws "An allocation error" if memory is exhausted (std::bad_alloc if the standard allocator is + used). + \par Exception Safety + Basic. + \par Iterator Invalidation + Invalidates all iterators pointing to the circular_buffer_space_optimized (except iterators + equal to end()). + \par Complexity + Linear (in the size of the circular_buffer_space_optimized). + \sa ~circular_buffer_space_optimized(), erase(iterator), + erase(iterator, iterator), rerase(iterator), + rerase(iterator, iterator) + */ + void clear() { erase(begin(), end()); } + +private: +// Helper methods + + //! Adjust the amount of allocated memory. + void adjust_min_capacity() { + if (m_capacity_ctrl.min_capacity() > circular_buffer::capacity()) + circular_buffer::set_capacity(m_capacity_ctrl.min_capacity()); + else + check_high_capacity(); + } + + //! Ensure the reserve for possible growth up. + size_type ensure_reserve(size_type new_capacity, size_type buffer_size) const { + if (buffer_size + new_capacity / 5 >= new_capacity) + new_capacity *= 2; // ensure at least 20% reserve + if (new_capacity > m_capacity_ctrl) + return m_capacity_ctrl; + return new_capacity; + } + + //! Check for low capacity. + /* + \post If the capacity is low it will be increased. + */ + void check_low_capacity(size_type n = 1) { + size_type new_size = size() + n; + size_type new_capacity = circular_buffer::capacity(); + if (new_size > new_capacity) { + if (new_capacity == 0) + new_capacity = 1; + for (; new_size > new_capacity; new_capacity *= 2) {} + circular_buffer::set_capacity( + ensure_reserve(new_capacity, new_size)); + } +#if BOOST_CB_ENABLE_DEBUG + this->invalidate_iterators_except(end()); +#endif + } + + //! Check for high capacity. + /* + \post If the capacity is high it will be decreased. + */ + void check_high_capacity() { + size_type new_capacity = circular_buffer::capacity(); + while (new_capacity / 3 >= size()) { // (new_capacity / 3) -> avoid oscillations + new_capacity /= 2; + if (new_capacity <= m_capacity_ctrl.min_capacity()) { + new_capacity = m_capacity_ctrl.min_capacity(); + break; + } + } + circular_buffer::set_capacity( + ensure_reserve(new_capacity, size())); +#if BOOST_CB_ENABLE_DEBUG + this->invalidate_iterators_except(end()); +#endif + } + + //! Specialized method for reducing the capacity. + void reduce_capacity(const true_type&) { + circular_buffer::set_capacity((std::max)(m_capacity_ctrl.min_capacity(), size())); + } + + //! Specialized method for reducing the capacity. + void reduce_capacity(const false_type&) {} + + //! Determine the initial capacity. + static size_type init_capacity(const capacity_type& capacity_ctrl, size_type n) { + BOOST_CB_ASSERT(capacity_ctrl.capacity() >= n); // check for capacity lower than n + return (std::max)(capacity_ctrl.min_capacity(), n); + } + + //! Specialized method for determining the initial capacity. + template + static size_type init_capacity(const capacity_type& capacity_ctrl, IntegralType n, IntegralType, + const true_type&) { + return init_capacity(capacity_ctrl, static_cast(n)); + } + + //! Specialized method for determining the initial capacity. + template + static size_type init_capacity(const capacity_type& capacity_ctrl, Iterator first, Iterator last, + const false_type&) { + BOOST_CB_IS_CONVERTIBLE(Iterator, value_type); // check for invalid iterator type +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x581)) + return init_capacity(capacity_ctrl, first, last, iterator_category::type()); +#else + return init_capacity( + capacity_ctrl, first, last, BOOST_DEDUCED_TYPENAME iterator_category::type()); +#endif + } + + //! Specialized method for determining the initial capacity. + template + static size_type init_capacity(const capacity_type& capacity_ctrl, InputIterator, InputIterator, + const std::input_iterator_tag&) { + return capacity_ctrl.capacity(); + } + + //! Specialized method for determining the initial capacity. + template + static size_type init_capacity(const capacity_type& capacity_ctrl, ForwardIterator first, ForwardIterator last, + const std::forward_iterator_tag&) { + BOOST_CB_ASSERT(std::distance(first, last) >= 0); // check for wrong range + return (std::max)(capacity_ctrl.min_capacity(), + (std::min)(capacity_ctrl.capacity(), static_cast(std::distance(first, last)))); + } + + //! Specialized insert method. + template + void insert(const iterator& pos, IntegralType n, IntegralType item, const true_type&) { + insert(pos, static_cast(n), static_cast(item)); + } + + //! Specialized insert method. + template + void insert(const iterator& pos, Iterator first, Iterator last, const false_type&) { + size_type index = pos - begin(); + check_low_capacity(std::distance(first, last)); + circular_buffer::insert(begin() + index, first, last); + } + + //! Specialized rinsert method. + template + void rinsert(const iterator& pos, IntegralType n, IntegralType item, const true_type&) { + rinsert(pos, static_cast(n), static_cast(item)); + } + + //! Specialized rinsert method. + template + void rinsert(const iterator& pos, Iterator first, Iterator last, const false_type&) { + size_type index = pos - begin(); + check_low_capacity(std::distance(first, last)); + circular_buffer::rinsert(begin() + index, first, last); + } +}; + +// Non-member functions + +//! Test two space optimized circular buffers for equality. +template +inline bool operator == (const circular_buffer_space_optimized& lhs, + const circular_buffer_space_optimized& rhs) { + return lhs.size() == rhs.size() && + std::equal(lhs.begin(), lhs.end(), rhs.begin()); +} + +//! Lexicographical comparison. +template +inline bool operator < (const circular_buffer_space_optimized& lhs, + const circular_buffer_space_optimized& rhs) { + return std::lexicographical_compare( + lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); +} + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1310)) + +//! Test two space optimized circular buffers for non-equality. +template +inline bool operator != (const circular_buffer_space_optimized& lhs, + const circular_buffer_space_optimized& rhs) { + return !(lhs == rhs); +} + +//! Lexicographical comparison. +template +inline bool operator > (const circular_buffer_space_optimized& lhs, + const circular_buffer_space_optimized& rhs) { + return rhs < lhs; +} + +//! Lexicographical comparison. +template +inline bool operator <= (const circular_buffer_space_optimized& lhs, + const circular_buffer_space_optimized& rhs) { + return !(rhs < lhs); +} + +//! Lexicographical comparison. +template +inline bool operator >= (const circular_buffer_space_optimized& lhs, + const circular_buffer_space_optimized& rhs) { + return !(lhs < rhs); +} + +//! Swap the contents of two space optimized circular buffers. +template +inline void swap(circular_buffer_space_optimized& lhs, + circular_buffer_space_optimized& rhs) BOOST_NOEXCEPT { + lhs.swap(rhs); +} + +#endif // #if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) || BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1310)) + +} // namespace boost + +#endif // #if !defined(BOOST_CIRCULAR_BUFFER_SPACE_OPTIMIZED_HPP) diff --git a/boost/boost/circular_buffer_fwd.hpp b/boost/boost/circular_buffer_fwd.hpp new file mode 100644 index 000000000..3801ad472 --- /dev/null +++ b/boost/boost/circular_buffer_fwd.hpp @@ -0,0 +1,43 @@ +// Forward declaration of the circular buffer and its adaptor. + +// Copyright (c) 2003-2008 Jan Gaspar + +// 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) + +// See www.boost.org/libs/circular_buffer for documentation. + +#if !defined(BOOST_CIRCULAR_BUFFER_FWD_HPP) +#define BOOST_CIRCULAR_BUFFER_FWD_HPP + +#if defined(_MSC_VER) + #pragma once +#endif + +#include +#if !defined(BOOST_NO_STD_ALLOCATOR) + #include +#else + #include +#endif + +namespace boost { + +#if !defined(BOOST_NO_STD_ALLOCATOR) + #define BOOST_CB_DEFAULT_ALLOCATOR(T) std::allocator +#else + #define BOOST_CB_DEFAULT_ALLOCATOR(T) BOOST_DEDUCED_TYPENAME std::vector::allocator_type +#endif + +template +class circular_buffer; + +template +class circular_buffer_space_optimized; + +#undef BOOST_CB_DEFAULT_ALLOCATOR + +} // namespace boost + +#endif // #if !defined(BOOST_CIRCULAR_BUFFER_FWD_HPP) diff --git a/boost/boost/detail/lightweight_main.hpp b/boost/boost/detail/lightweight_main.hpp new file mode 100644 index 000000000..e6514b9f9 --- /dev/null +++ b/boost/boost/detail/lightweight_main.hpp @@ -0,0 +1,36 @@ +// boost/detail/lightweight_main.hpp -------------------------------------------------// + +// Copyright Beman Dawes 2010 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#include +#include + +//--------------------------------------------------------------------------------------// +// // +// exception reporting main() that calls cpp_main() // +// // +//--------------------------------------------------------------------------------------// + +int cpp_main(int argc, char* argv[]); + +int main(int argc, char* argv[]) +{ + try + { + return cpp_main(argc, argv); + } + + catch (const std::exception& ex) + { + std::cout + << "\nERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR\n" + << "\n****************************** std::exception *****************************\n" + << ex.what() + << "\n***************************************************************************\n" + << std::endl; + } + return 1; +} diff --git a/boost/boost/progress.hpp b/boost/boost/progress.hpp new file mode 100644 index 000000000..dfc26f6df --- /dev/null +++ b/boost/boost/progress.hpp @@ -0,0 +1,142 @@ +// boost progress.hpp header file ------------------------------------------// + +// Copyright Beman Dawes 1994-99. Distributed under the 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/timer for documentation. + +// Revision History +// 1 Dec 01 Add leading progress display strings (suggested by Toon Knapen) +// 20 May 01 Introduce several static_casts<> to eliminate warning messages +// (Fixed by Beman, reported by Herve Bronnimann) +// 12 Jan 01 Change to inline implementation to allow use without library +// builds. See docs for more rationale. (Beman Dawes) +// 22 Jul 99 Name changed to .hpp +// 16 Jul 99 Second beta +// 6 Jul 99 Initial boost version + +#ifndef BOOST_PROGRESS_HPP +#define BOOST_PROGRESS_HPP + +#include +#include +#include // for uintmax_t +#include // for ostream, cout, etc +#include // for string + +namespace boost { + +// progress_timer ----------------------------------------------------------// + +// A progress_timer behaves like a timer except that the destructor displays +// an elapsed time message at an appropriate place in an appropriate form. + +class progress_timer : public timer, private noncopyable +{ + + public: + explicit progress_timer( std::ostream & os = std::cout ) + // os is hint; implementation may ignore, particularly in embedded systems + : timer(), noncopyable(), m_os(os) {} + ~progress_timer() + { + // A) Throwing an exception from a destructor is a Bad Thing. + // B) The progress_timer destructor does output which may throw. + // C) A progress_timer is usually not critical to the application. + // Therefore, wrap the I/O in a try block, catch and ignore all exceptions. + try + { + // use istream instead of ios_base to workaround GNU problem (Greg Chicares) + std::istream::fmtflags old_flags = m_os.setf( std::istream::fixed, + std::istream::floatfield ); + std::streamsize old_prec = m_os.precision( 2 ); + m_os << elapsed() << " s\n" // "s" is System International d'Unites std + << std::endl; + m_os.flags( old_flags ); + m_os.precision( old_prec ); + } + + catch (...) {} // eat any exceptions + } // ~progress_timer + + private: + std::ostream & m_os; +}; + + +// progress_display --------------------------------------------------------// + +// progress_display displays an appropriate indication of +// progress at an appropriate place in an appropriate form. + +// NOTE: (Jan 12, 2001) Tried to change unsigned long to boost::uintmax_t, but +// found some compilers couldn't handle the required conversion to double. +// Reverted to unsigned long until the compilers catch up. + +class progress_display : private noncopyable +{ + public: + explicit progress_display( unsigned long expected_count_, + std::ostream & os = std::cout, + const std::string & s1 = "\n", //leading strings + const std::string & s2 = "", + const std::string & s3 = "" ) + // os is hint; implementation may ignore, particularly in embedded systems + : noncopyable(), m_os(os), m_s1(s1), m_s2(s2), m_s3(s3) { restart(expected_count_); } + + void restart( unsigned long expected_count_ ) + // Effects: display appropriate scale + // Postconditions: count()==0, expected_count()==expected_count_ + { + _count = _next_tic_count = _tic = 0; + _expected_count = expected_count_; + + m_os << m_s1 << "0% 10 20 30 40 50 60 70 80 90 100%\n" + << m_s2 << "|----|----|----|----|----|----|----|----|----|----|" + << std::endl // endl implies flush, which ensures display + << m_s3; + if ( !_expected_count ) _expected_count = 1; // prevent divide by zero + } // restart + + unsigned long operator+=( unsigned long increment ) + // Effects: Display appropriate progress tic if needed. + // Postconditions: count()== original count() + increment + // Returns: count(). + { + if ( (_count += increment) >= _next_tic_count ) { display_tic(); } + return _count; + } + + unsigned long operator++() { return operator+=( 1 ); } + unsigned long count() const { return _count; } + unsigned long expected_count() const { return _expected_count; } + + private: + std::ostream & m_os; // may not be present in all imps + const std::string m_s1; // string is more general, safer than + const std::string m_s2; // const char *, and efficiency or size are + const std::string m_s3; // not issues + + unsigned long _count, _expected_count, _next_tic_count; + unsigned int _tic; + void display_tic() + { + // use of floating point ensures that both large and small counts + // work correctly. static_cast<>() is also used several places + // to suppress spurious compiler warnings. + unsigned int tics_needed = static_cast((static_cast(_count) + / static_cast(_expected_count)) * 50.0); + do { m_os << '*' << std::flush; } while ( ++_tic < tics_needed ); + _next_tic_count = + static_cast((_tic/50.0) * static_cast(_expected_count)); + if ( _count == _expected_count ) { + if ( _tic < 51 ) m_os << '*'; + m_os << std::endl; + } + } // display_tic +}; + +} // namespace boost + +#endif // BOOST_PROGRESS_HPP diff --git a/boost/boost/thread/condition.hpp b/boost/boost/thread/condition.hpp new file mode 100644 index 000000000..eead47cf1 --- /dev/null +++ b/boost/boost/thread/condition.hpp @@ -0,0 +1,21 @@ +#ifndef BOOST_THREAD_CONDITION_HPP +#define BOOST_THREAD_CONDITION_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_PROVIDES_CONDITION + +#include + +namespace boost +{ + typedef condition_variable_any condition; +} + +#endif +#endif diff --git a/boost/boost/thread/detail/thread_group.hpp b/boost/boost/thread/detail/thread_group.hpp new file mode 100644 index 000000000..db15c3bfb --- /dev/null +++ b/boost/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/boost/thread/pthread/shared_mutex.hpp b/boost/boost/thread/pthread/shared_mutex.hpp new file mode 100644 index 000000000..9d4c707d1 --- /dev/null +++ b/boost/boost/thread/pthread/shared_mutex.hpp @@ -0,0 +1,716 @@ +#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 +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS +#include +#endif +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif +#include +#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 exclusive_blocked (bool blocked) + { + exclusive_waiting_blocked = blocked; + } + + void lock () + { + exclusive = true; + } + + void unlock () + { + exclusive = false; + exclusive_waiting_blocked = false; + } + + bool can_lock_shared () const + { + return ! (exclusive || exclusive_waiting_blocked); + } + + bool more_shared () const + { + return shared_count > 0 ; + } + unsigned get_shared_count () const + { + return shared_count ; + } + unsigned lock_shared () + { + return ++shared_count; + } + + + void unlock_shared () + { + --shared_count; + } + + bool unlock_shared_downgrades() + { + if (upgrade) { + upgrade=false; + exclusive=true; + return true; + } else { + exclusive_waiting_blocked=false; + return false; + } + } + + 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); + while(!state.can_lock_shared()) + { + shared_cond.wait(lk); + } + 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); + + while(!state.can_lock_shared()) + { + if(!shared_cond.timed_wait(lk,timeout)) + { + return false; + } + } + state.lock_shared(); + return true; + } + + template + bool timed_lock_shared(TimeDuration const & relative_time) + { + return timed_lock_shared(get_system_time()+relative_time); + } +#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); + + while(!state.can_lock_shared()) + //while(state.exclusive || state.exclusive_waiting_blocked) + { + if(cv_status::timeout==shared_cond.wait_until(lk,abs_time)) + { + 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.more_shared()) + { + if (state.upgrade) + { + // As there is a thread doing a unlock_upgrade_and_lock that is waiting for ! state.more_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); + + while (state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=true; + exclusive_cond.wait(lk); + } + 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); + + while(state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=true; + if(!exclusive_cond.timed_wait(lk,timeout)) + { + if(state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=false; + release_waiters(); + return false; + } + break; + } + } + state.exclusive=true; + return true; + } + + template + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } +#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); + + while(state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=true; + if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time)) + { + if(state.shared_count || state.exclusive) + { + state.exclusive_waiting_blocked=false; + release_waiters(); + return false; + } + break; + } + } + state.exclusive=true; + return true; + } +#endif + + bool try_lock() + { + boost::unique_lock lk(state_change); + + if(state.shared_count || state.exclusive) + { + return false; + } + else + { + 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); + while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + shared_cond.wait(lk); + } + 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); + while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + if(!shared_cond.timed_wait(lk,timeout)) + { + if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + return false; + } + break; + } + } + state.lock_shared(); + state.upgrade=true; + return true; + } + + template + bool timed_lock_upgrade(TimeDuration const & relative_time) + { + return timed_lock_upgrade(get_system_time()+relative_time); + } +#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); + while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + if(cv_status::timeout == shared_cond.wait_until(lk,abs_time)) + { + if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + return false; + } + break; + } + } + state.lock_shared(); + state.upgrade=true; + return true; + } +#endif + bool try_lock_upgrade() + { + boost::unique_lock lk(state_change); + if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) + { + return false; + } + else + { + 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.more_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(); + while (state.more_shared()) + { + upgrade_cond.wait(lk); + } + 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 (state.shared_count != 1) + { + for (;;) + { + cv_status status = shared_cond.wait_until(lk,abs_time); + if (state.shared_count == 1) + break; + if(status == cv_status::timeout) + 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 (state.shared_count != 1) + { + for (;;) + { + cv_status status = shared_cond.wait_until(lk,abs_time); + if (state.shared_count == 1) + break; + if(status == cv_status::timeout) + 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.exclusive + && !state.exclusive_waiting_blocked + && !state.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( state.exclusive + || state.exclusive_waiting_blocked + || state.upgrade + ) + { + for (;;) + { + cv_status status = exclusive_cond.wait_until(lk,abs_time); + if( ! state.exclusive + && ! state.exclusive_waiting_blocked + && ! state.upgrade + ) + break; + if(status == cv_status::timeout) + return false; + } + } + state.upgrade=true; + return true; + } +#endif +#endif + }; + + typedef shared_mutex upgrade_mutex; +} + +#include + +#endif diff --git a/boost/boost/thread/shared_mutex.hpp b/boost/boost/thread/shared_mutex.hpp new file mode 100644 index 000000000..08a58bd6a --- /dev/null +++ b/boost/boost/thread/shared_mutex.hpp @@ -0,0 +1,50 @@ +#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) +#include +#else +#include +#endif +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) +//#include +#include +#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/boost/thread/thread.hpp b/boost/boost/thread/thread.hpp new file mode 100644 index 000000000..ead27961b --- /dev/null +++ b/boost/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/boost/thread/win32/shared_mutex.hpp b/boost/boost/thread/win32/shared_mutex.hpp new file mode 100644 index 000000000..b3f0160ef --- /dev/null +++ b/boost/boost/thread/win32/shared_mutex.hpp @@ -0,0 +1,903 @@ +#ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP +#define BOOST_THREAD_WIN32_SHARED_MUTEX_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 +#include +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif +#include + +#include + +namespace boost +{ + class shared_mutex + { + private: + struct state_data + { + unsigned 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 *reinterpret_cast(&lhs)==*reinterpret_cast(&rhs); + } + }; + + + template + T interlocked_compare_exchange(T* target,T new_value,T comparand) + { + BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long)); + long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast(target), + *reinterpret_cast(&new_value), + *reinterpret_cast(&comparand)); + return *reinterpret_cast(&res); + } + + 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(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0); + } + + if(old_state.shared_waiting || old_state.exclusive_waiting) + { + BOOST_VERIFY(detail::win32::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(detail::win32::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() + { + detail::win32::CloseHandle(upgrade_sem); + detail::win32::CloseHandle(semaphores[unlock_sem]); + detail::win32::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() + { + +#if defined BOOST_THREAD_USES_DATETIME + BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel())); +#else + BOOST_VERIFY(try_lock_shared_until(chrono::steady_clock::now())); +#endif + } + +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_lock_shared(TimeDuration const & relative_time) + { + return timed_lock_shared(get_system_time()+relative_time); + } + bool timed_lock_shared(boost::system_time const& wait_until) + { + 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; + } + + unsigned long const res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until), 0); + 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); + } + } +#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& t) + { + using namespace chrono; + system_clock::time_point s_now = system_clock::now(); + typename Clock::time_point c_now = Clock::now(); + return try_lock_shared_until(s_now + ceil(t - c_now)); + } + template + bool try_lock_shared_until(const chrono::time_point& t) + { + using namespace chrono; + typedef time_point sys_tmpt; + return try_lock_shared_until(sys_tmpt(chrono::ceil(t.time_since_epoch()))); + } + bool try_lock_shared_until(const chrono::time_point& tp) + { + 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; + } + + chrono::system_clock::time_point n = chrono::system_clock::now(); + unsigned long res; + if (tp>n) { + chrono::milliseconds rel_time= chrono::ceil(tp-n); + res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem], + static_cast(rel_time.count()), 0); + } else { + res=detail::win32::timeout; + } + 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); + } + } +#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(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0); + } + else + { + release_waiters(old_state); + } + } + break; + } + old_state=current_state; + } + } + + void lock() + { + +#if defined BOOST_THREAD_USES_DATETIME + BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel())); +#else + BOOST_VERIFY(try_lock_until(chrono::steady_clock::now())); +#endif + } + +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_lock(TimeDuration const & relative_time) + { + return timed_lock(get_system_time()+relative_time); + } +#endif + + 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; + } + + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(boost::system_time const& wait_until) + { + 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; + } + #ifndef UNDER_CE + const bool wait_all = true; + #else + const bool wait_all = false; + #endif + unsigned long const wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until), 0); + 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(detail::win32::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); + } + } +#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) + { + using namespace chrono; + system_clock::time_point s_now = system_clock::now(); + typename Clock::time_point c_now = Clock::now(); + return try_lock_until(s_now + ceil(t - c_now)); + } + template + bool try_lock_until(const chrono::time_point& t) + { + using namespace chrono; + typedef time_point sys_tmpt; + return try_lock_until(sys_tmpt(chrono::ceil(t.time_since_epoch()))); + } + bool try_lock_until(const chrono::time_point& tp) + { + 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; + } + #ifndef UNDER_CE + const bool wait_all = true; + #else + const bool wait_all = false; + #endif + + chrono::system_clock::time_point n = chrono::system_clock::now(); + unsigned long wait_res; + if (tp>n) { + chrono::milliseconds rel_time= chrono::ceil(tp-chrono::system_clock::now()); + wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all, + static_cast(rel_time.count()), 0); + } else { + wait_res=detail::win32::timeout; + } + 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(detail::win32::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); + } + } +#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(!detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],detail::win32::infinite, 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(!detail::win32::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite, 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); + } +// bool try_unlock_upgrade_and_lock() +// { +// 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) +// { +// return false; +// } +//#endif + + 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/boost/tr1/detail/config.hpp b/boost/boost/tr1/detail/config.hpp new file mode 100644 index 000000000..c5af2bf03 --- /dev/null +++ b/boost/boost/tr1/detail/config.hpp @@ -0,0 +1,173 @@ +// (C) Copyright John Maddock 2005-7. +// 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_TR1_DETAIL_CONFIG_HPP_INCLUDED +# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED + +#include + +#if (defined(__GNUC__) && !(defined(linux) || defined(__linux) || defined(__linux__))) \ + || (!defined(__FreeBSD__) && defined(__GNUC__)) \ + || (!defined(_AIX) && defined(__IBMCPP__) && (__IBMCPP__ >= 800)) + // Disable use of #include_next on Linux as typically we are installed in a + // directory that is searched *after* the std lib include path. +#if !defined(BOOST_HAS_INCLUDE_NEXT) +# define BOOST_HAS_INCLUDE_NEXT +#endif +// Need to find out if we're using GLIBC: +#ifdef BOOST_TR1_UTILITY_INCLUDED +// Oops we're in a recursive include path!! +// Need to include utility, or some std lib header, +// but *not* via or +# ifndef BOOST_TR1_NO_RECURSION +# define BOOST_TR1_NO_RECURSION +# define BOOST_TR1_NO_CONFIG_RECURSION +# endif +# if defined(BOOST_HAS_INCLUDE_NEXT) && !defined(BOOST_TR1_DISABLE_INCLUDE_NEXT) +# include_next +# else +# include BOOST_TR1_STD_HEADER(utility) +# endif +# ifdef BOOST_TR1_NO_CONFIG_RECURSION +# undef BOOST_TR1_NO_CONFIG_RECURSION +# undef BOOST_TR1_NO_RECURSION +# endif +#else +#include +#endif +#endif + +#if defined(__GLIBCXX__) && !defined(BOOST_TR1_PATH) +# define BOOST_TR1_PATH(name) tr1/name +#endif +#if !defined(BOOST_TR1_PATH) +# define BOOST_TR1_PATH(name) name +#endif + +#define BOOST_TR1_HEADER(name) + +// Can't use BOOST_WORKAROUND here, it leads to recursive includes: +#if (defined(__BORLANDC__) && (__BORLANDC__ <= 0x600)) +# define BOOST_TR1_USE_OLD_TUPLE +#endif + +#ifdef __IBMCPP_TR1__ + // turn on support for everything: +# define BOOST_HAS_TR1 +#endif + +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +# define BOOST_HAS_TR1_COMPLEX_OVERLOADS +# define BOOST_HAS_TR1_COMPLEX_INVERSE_TRIG +#endif + +#ifdef BOOST_HAS_TR1 + // turn on support for everything: +# define BOOST_HAS_TR1_ARRAY +# define BOOST_HAS_TR1_COMPLEX_OVERLOADS +# define BOOST_HAS_TR1_COMPLEX_INVERSE_TRIG +# define BOOST_HAS_TR1_REFERENCE_WRAPPER +# define BOOST_HAS_TR1_RESULT_OF +# define BOOST_HAS_TR1_MEM_FN +# define BOOST_HAS_TR1_BIND +# define BOOST_HAS_TR1_FUNCTION +# define BOOST_HAS_TR1_HASH +# define BOOST_HAS_TR1_SHARED_PTR +# define BOOST_HAS_TR1_RANDOM +# define BOOST_HAS_TR1_REGEX +# define BOOST_HAS_TR1_TUPLE +# define BOOST_HAS_TR1_TYPE_TRAITS +# define BOOST_HAS_TR1_UTILITY +# define BOOST_HAS_TR1_UNORDERED_MAP +# define BOOST_HAS_TR1_UNORDERED_SET +# define BOOST_HAS_TR1_CMATH + +#endif + +#if defined(__MWERKS__) && (__MWERKS__ >= 0x3205) +// +// Very preliminary MWCW support, may not be right: +// +# define BOOST_HAS_TR1_SHARED_PTR +# define BOOST_HAS_TR1_REFERENCE_WRAPPER +# define BOOST_HAS_TR1_FUNCTION +# define BOOST_HAS_TR1_TUPLE +# define BOOST_HAS_TR1_RESULT_OF +#endif + +#ifdef BOOST_HAS_GCC_TR1 + // turn on support for everything in gcc 4.0.x: +# define BOOST_HAS_TR1_ARRAY +#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 403 +//# define BOOST_HAS_TR1_COMPLEX_OVERLOADS +# define BOOST_HAS_TR1_COMPLEX_INVERSE_TRIG +#endif +# define BOOST_HAS_TR1_REFERENCE_WRAPPER +# define BOOST_HAS_TR1_RESULT_OF +# define BOOST_HAS_TR1_MEM_FN +# define BOOST_HAS_TR1_BIND +# define BOOST_HAS_TR1_FUNCTION +# define BOOST_HAS_TR1_HASH +# define BOOST_HAS_TR1_SHARED_PTR +#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 403 +# define BOOST_HAS_TR1_RANDOM +//# define BOOST_HAS_TR1_REGEX +#ifdef _GLIBCXX_USE_C99_MATH_TR1 +# define BOOST_HAS_TR1_CMATH +#endif +#endif +# define BOOST_HAS_TR1_TUPLE +# define BOOST_HAS_TR1_TYPE_TRAITS +# define BOOST_HAS_TR1_UTILITY +# define BOOST_HAS_TR1_UNORDERED_MAP +# define BOOST_HAS_TR1_UNORDERED_SET + +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1500) \ + && defined(_MSC_FULL_VER) && \ + !defined(__SGI_STL_PORT) && \ + !defined(_STLPORT_VERSION) && \ + !defined(_RWSTD_VER_STR) && \ + !defined(_RWSTD_VER) +// +// MSVC-9.0 defines a not-quite TR1 conforming hash +// function object in , so we must define +// this here, in addition the feature pack for VC9 +// provides a more or less full TR1 implementation: +// +# if (defined(_HAS_TR1) && (_HAS_TR1 + 0)) || (_CPPLIB_VER >= 540) +# define BOOST_HAS_TR1_ARRAY +# define BOOST_HAS_TR1_REFERENCE_WRAPPER +# define BOOST_HAS_TR1_RESULT_OF +# define BOOST_HAS_TR1_MEM_FN +# define BOOST_HAS_TR1_BIND +# define BOOST_HAS_TR1_FUNCTION +# define BOOST_HAS_TR1_HASH +# define BOOST_HAS_TR1_SHARED_PTR +# define BOOST_HAS_TR1_RANDOM +# define BOOST_HAS_TR1_REGEX +# define BOOST_HAS_TR1_TUPLE +# define BOOST_HAS_TR1_TYPE_TRAITS +# define BOOST_HAS_TR1_UTILITY +# define BOOST_HAS_TR1_UNORDERED_MAP +# define BOOST_HAS_TR1_UNORDERED_SET +# else +# define BOOST_HAS_TR1_HASH +# endif +# if _MSC_VER >= 1600 +# define BOOST_HAS_CPP_0X +# endif +# if _MSC_VER >= 1700 +# define BOOST_HAS_TR1_COMPLEX_OVERLOADS +# endif +#endif + +#include + +#endif + + + diff --git a/boost/boostcpp.jam b/boost/boostcpp.jam new file mode 100644 index 000000000..623b75357 --- /dev/null +++ b/boost/boostcpp.jam @@ -0,0 +1,705 @@ +# Boost.Build support specific for the Boost C++ Libraries. +# Copyright Vladimir Prus 2002-2010. +# 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) + +import "class" : new ; +import common ; +import configure ; +import build-system ; +import generate ; +import modules ; +import option ; +import os ; +import package ; +import path ; +import project ; +import regex ; +import set ; +import targets ; +import feature ; +import property ; + +############################################################################## +# +# 0. General setup. Parse options, check them. +# +############################################################################## + +BOOST_ROOT = [ modules.binding $(__name__) ] ; +BOOST_ROOT = $(BOOST_ROOT:D) ; + +rule set-version ( version ) +{ + BOOST_VERSION = $(version) ; + + local version-tag = [ MATCH ^([^.]+)[.]([^.]+)[.]([^.]+) : $(BOOST_VERSION) + ] ; + if $(version-tag[3]) = 0 + { + version-tag = $(version-tag[1-2]) ; + } + BOOST_VERSION_TAG = $(version-tag:J=_) ; +} + +# Option to choose how many variants to build. The default is "minimal". +build-type = [ option.get build-type ] ; +build-type ?= minimal ; +if ! ( $(build-type) in complete minimal ) +{ + EXIT The value of the --build-type option should be either 'complete' or + 'minimal' ; +} + +# What kind of layout are we doing? +layout = [ option.get layout : "" ] ; +# On Windows, we used versioned layout by default in order to be compatible with +# autolink. On other systems, we use system layout which is what every other +# program uses. Note that the Windows check is static, and will not be affected +# by specific build properties used. +if ! $(layout) +{ + if [ os.name ] = NT + { + layout = versioned ; + } + else + { + layout = system ; + } +} +layout-$(layout) = true ; + +if $(layout) = system && $(build-type) = complete +{ + ECHO error: Cannot use --layout=system with --build-type complete. ; + ECHO error: Please use either --layout=versioned or --layout=tagged ; + ECHO error: if you wish to build multiple variants. ; + if [ os.name ] != NT + { + ECHO error: Note that --layout=system is used by default on Unix + starting with Boost 1.40. ; + } + EXIT ; +} + +# Possible stage only location. +stage-locate = [ option.get stagedir ] ; +stage-locate ?= stage ; +BOOST_STAGE_LOCATE = $(stage-locate) ; + +# Custom build ID. +build-id = [ option.get buildid ] ; +if $(build-id) +{ + BUILD_ID = [ regex.replace $(build-id) "[*\\/:.\"\' ]" _ ] ; +} + +# Python build id (for Python libraries only). +python-id = [ option.get "python-buildid" ] ; +if $(python-id) +{ + PYTHON_ID = [ regex.replace $(python-id) [*\\/:.\"\'] _ ] ; +} + + +################################################################################ +# +# 1. 'tag' function adding decorations suitable to the properties if versioned +# or tagged layout is requested. Called from Jamroot. +# +################################################################################ + +rule tag ( name : type ? : property-set ) +{ + if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB + { + local result ; + if $(layout) = versioned + { + result = [ common.format-name + -$(BOOST_VERSION_TAG) + -$(BUILD_ID) + : $(name) : $(type) : $(property-set) ] ; + } + else if $(layout) = tagged + { + result = [ common.format-name + + -$(BUILD_ID) + : $(name) : $(type) : $(property-set) ] ; + } + else if $(layout) = system + { + result = [ common.format-name + + -$(BUILD_ID) + : $(name) : $(type) : $(property-set) ] ; + } + else + { + EXIT error: invalid layout '$(layout:E=)' ; + } + + # Optionally add version suffix. On NT, library with version suffix will + # not be recognized by linkers. On CYGWIN, we get strage duplicate + # symbol errors when library is generated with version suffix. On OSX, + # version suffix is not needed -- the linker expects the + # libFoo.1.2.3.dylib format. AIX linkers do not accept version suffixes + # either. Pgi compilers can not accept a library with version suffix. + if $(type) = SHARED_LIB && + ! [ $(property-set).get ] in windows cygwin darwin aix && + ! [ $(property-set).get ] in pgi + { + result = $(result).$(BOOST_VERSION) ; + } + + return $(result) ; + } +} + +# Specialized tag function to use for libraries linking to Python. +# Appends value of --python-buildid if provided. +rule python-tag ( name : type ? : property-set ) +{ + local result = $(name) ; + if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB && $(PYTHON_ID) + { + result = $(result)-$(PYTHON_ID) ; + } + + # forward to the boost tagging rule + return [ tag $(result) : $(type) : $(property-set) ] ; +} + +################################################################################ +# +# 2. Declare targets that build and install all libraries. Specifically: +# +# - 'stage-proper' that puts all libraries in stage/lib +# - 'install-proper' that install libraries and headers to system location +# - 'stage-unversioned' that creates links to libraries without boost version +# in name +# - 'install-unversioned' which creates unversioned linked to installed +# libraries. +# +################################################################################ + +# Worker function suitable to the 'generate' metatarget. Creates a link to +# 'source', striping any version number information from the name. +rule make-unversioned-links ( project name ? : property-set : sources * ) +{ + local filter ; + if [ modules.peek : NT ] + { + filter = (.*[.]lib) ; + } + else + { + filter = + (.*[.]so)[.0-9]* + (.*[.]dylib) + (.*[.]a) ; + } + + local result ; + for local s in $(sources) + { + local m = [ MATCH ^(.*)-[0-9_]+$(filter)$ : [ $(s).name ] ] ; + if $(m) + { + local ea = [ $(s).action ] ; + local ep = [ $(ea).properties ] ; + local a = [ new non-scanning-action $(s) : symlink.ln : $(ep) ] ; + result += [ new file-target $(m:J=) exact : [ $(s).type ] : + $(project) : $(a) ] ; + } + } + return $(result) ; +} + +rule filtered-target ( name : message + : sources + : requirements * ) +{ + message $(name)-message : warning: $(message) ; + alias $(name) : $(sources) : $(requirements) ; + alias $(name) : $(name)-message ; + + local p = [ project.current ] ; + $(p).mark-target-as-explicit $(name) ; + $(p).mark-target-as-explicit $(name)-message ; +} + +rule declare_install_and_stage_proper_targets ( libraries * : headers * ) +{ + local p = [ project.current ] ; + for local l in $(libraries) + { + if $(l) = locale + { + filtered-target $(l)-for-install : + Skipping Boost.Locale library with threading=single. : + libs/$(l)/build : multi ; + } + else if $(l) = wave + { + filtered-target $(l)-for-install : + Skipping Boost.Wave library with threading=single. : + libs/$(l)/build : multi ; + } + else if $(l) = thread + { + filtered-target $(l)-for-install : + Skipping Boost.Thread library with threading=single. : + libs/$(l)/build : multi ; + } + else + { + alias $(l)-for-install : libs/$(l)/build ; + $(p).mark-target-as-explicit $(l)-for-install ; + } + } + local library-targets = $(libraries)-for-install ; + + install-requirements = $(BOOST_ROOT)/boost ; + + if $(layout-versioned) + { + install-requirements += + boost-$(BOOST_VERSION_TAG)/boost ; + } + else + { + install-requirements += boost ; + } + + if [ os.name ] = NT + { + install-requirements += C:/Boost ; + } + else + { + install-requirements += /usr/local ; + } + + p = [ project.current ] ; + + # Complete install. + package.install install-proper + : $(install-requirements) on + : + : $(libraries)-for-install + : $(headers) + ; + $(p).mark-target-as-explicit install-proper ; + + # Install just library. + install stage-proper + : $(libraries)-for-install + : $(stage-locate)/lib + on LIB + on + ; + $(p).mark-target-as-explicit stage-proper ; + + # Commented out as it does not seem to work. Whoever wrote this originally, + # left some typos in the code, but when that got corrected and the code got + # enabled - it started reporting ambiguous/duplicate target Boost Build + # errors. Anyone requiring unversioned staged libraries needs to correct + # those errors before reenabling this code. For more detailed information + # see the related Boost library development mailing list thread at + # 'http://lists.boost.org/Archives/boost/2012/06/194312.php'. + # (06.07.2012.) (Jurko) + #~ if $(layout-versioned) && ( [ modules.peek : NT ] || [ modules.peek : UNIX ] ) + #~ { + #~ generate stage-unversioned : stage-proper : + #~ @boostcpp.make-unversioned-links ; + #~ $(p).mark-target-as-explicit stage-unversioned ; + #~ + #~ generate install-unversioned : install-proper : + #~ @boostcpp.make-unversioned-links ; + #~ $(p).mark-target-as-explicit install-unversioned ; + #~ } + #~ else + { + # Create do-nothing aliases. + alias stage-unversioned ; + $(p).mark-target-as-explicit stage-unversioned ; + alias install-unversioned ; + $(p).mark-target-as-explicit install-unversioned ; + } +} + + +################################################################################ +# +# 3. Declare top-level targets 'stage' and 'install'. These examine the +# --build-type option and, in case it is 'complete', build the 'install-proper' +# and 'stage-proper' targets with a number of property sets. +# +################################################################################ + +class top-level-target : alias-target-class +{ + import modules ; + + rule __init__ ( name : project : sources * : requirements * + : default-build * : usage-requirements * ) + { + alias-target-class.__init__ $(name) : $(project) : $(sources) : + $(requirements) : $(default-build) : $(usage-requirements) ; + + self.build-type = [ modules.peek boostcpp : build-type ] ; + # On Linux, we build the release variant by default, since few users + # will ever want to debug C++ Boost libraries, and there is no ABI + # incompatibility between debug and release variants. We build shared + # and static libraries since that is what most packages seem to provide + # (.so in libfoo and .a in libfoo-dev). + self.minimal-properties = [ property-set.create release + multi shared static shared ] ; + # On Windows, new IDE projects use: + # + # runtime-link=dynamic, threading=multi, variant=(debug|release) + # + # and in addition, C++ Boost's autolink defaults to static linking. + self.minimal-properties-win = [ property-set.create debug + release multi static shared + ] ; + + self.complete-properties = [ property-set.create + debug release + single multi + shared static + shared static ] ; + } + + rule generate ( property-set ) + { + modules.poke : top-level-targets : [ modules.peek : top-level-targets ] + $(self.name) ; + if $(self.build-type) = minimal + { + local expanded ; + + local os = [ $(property-set).get ] ; + # Because we completely override the parent's 'generate' we need to + # check for default feature values ourselves. + if ! $(os) + { + os = [ feature.defaults ] ; + os = $(os:G=) ; + } + + if $(os) = windows + { + expanded = [ targets.apply-default-build $(property-set) + : $(self.minimal-properties-win) ] ; + } + else + { + expanded = [ targets.apply-default-build $(property-set) + : $(self.minimal-properties) ] ; + } + return [ build-multiple $(expanded) ] ; + } + else if $(self.build-type) = complete + { + local expanded = [ targets.apply-default-build $(property-set) + : $(self.complete-properties) ] ; + + # Filter inappopriate combinations. + local filtered ; + for local p in $(expanded) + { + # See comment in handle-static-runtime regarding this logic. + if [ $(p).get ] = shared + && [ $(p).get ] = static + && [ $(p).get ] != cw + { + # Skip this. + } + else + { + filtered += $(p) ; + } + } + return [ build-multiple $(filtered) ] ; + } + else + { + import errors ; + errors.error "Unknown build type" ; + } + } + + rule build-multiple ( property-sets * ) + { + local usage-requirements = [ property-set.empty ] ; + local result ; + for local p in $(property-sets) + { + local r = [ alias-target-class.generate $(p) ] ; + if $(r) + { + usage-requirements = [ $(usage-requirements).add $(r[1]) ] ; + result += $(r[2-]) ; + } + } + return $(usage-requirements) [ sequence.unique $(result) ] ; + } +} + +rule declare_top_level_targets ( libraries * : headers * ) +{ + declare_install_and_stage_proper_targets $(libraries) : $(headers) ; + + targets.create-metatarget top-level-target : [ project.current ] + : install + : install-proper install-unversioned + ; + targets.create-metatarget top-level-target : [ project.current ] + : stage + : stage-proper stage-unversioned + ; + + p = [ project.current ] ; + $(p).mark-target-as-explicit install stage ; + + # This target is built by default, and will forward to 'stage' after + # producing some explanations. + targets.create-metatarget top-level-target : [ project.current ] + : forward + : explain stage + ; +} + + +stage-abs = [ path.native [ path.root $(stage-locate)/lib [ path.pwd ] ] ] ; + + +################################################################################ +# +# 4. Add hook to report configuration before the build, and confirmation with +# setup instructions after the build. +# +################################################################################ + +message explain : "\nBuilding the Boost C++ Libraries.\n\n" ; +local p = [ project.current ] ; +$(p).mark-target-as-explicit explain ; + +rule pre-build ( ) +{ + local tl = [ modules.peek : top-level-targets ] ; + if stage in $(tl) || install in $(tl) + { + # FIXME: Remove 'if' when Boost regression tests start using trunk bjam. + if PAD in [ RULENAMES ] + { + configure.print-component-configuration ; + } + } +} +IMPORT $(__name__) : pre-build : : $(__name__).pre-build ; +build-system.set-pre-build-hook $(__name__).pre-build ; + +# FIXME: Revise stage_abs. +rule post-build ( ok ? ) +{ + if forward in [ modules.peek : top-level-targets ] + { + if $(ok) + { + local include-path = [ path.native $(BOOST_ROOT) ] ; + ECHO " + +The Boost C++ Libraries were successfully built! + +The following directory should be added to compiler include paths: + + $(include-path) + +The following directory should be added to linker library paths: + + $(stage-abs) +" ; + } + } +} +IMPORT $(__name__) : post-build : : $(__name__).post-build ; +build-system.set-post-build-hook $(__name__).post-build ; + + +################################################################################ +# +# 5. Top-level setup. +# +################################################################################ + +# Decides which libraries are to be installed by looking at --with- +# --without- arguments. Returns the list of directories under "libs" +# which must be built and installed. +# +rule libraries-to-install ( existing-libs * ) +{ + local argv = [ modules.peek : ARGV ] ; + local with-parameter = [ MATCH ^--with-(.*) : $(argv) ] ; + local without-parameter = [ MATCH ^--without-(.*) : $(argv) ] ; + + if ! $(with-parameter) && ! $(without-parameter) + { + # Nothing is specified on command line. See if maybe project-config.jam + # has some choices. + local libs = [ modules.peek project-config : libraries ] ; + with-parameter = [ MATCH ^--with-(.*) : $(libs) ] ; + without-parameter = [ MATCH ^--without-(.*) : $(libs) ] ; + } + + # Do some checks. + if $(with-parameter) && $(without-parameter) + { + EXIT error: both --with- and --without- specified ; + } + + local wrong = [ set.difference $(with-parameter) : $(existing-libs) ] ; + if $(wrong) + { + EXIT error: wrong library name '$(wrong[1])' in the --with- + option. ; + } + local wrong = [ set.difference $(without-parameter) : $(existing-libs) ] ; + if $(wrong) + { + EXIT error: wrong library name '$(wrong[1])' in the --without- + option. ; + } + + if $(with-parameter) + { + return [ set.intersection $(existing-libs) : $(with-parameter) ] ; + } + else + { + return [ set.difference $(existing-libs) : $(without-parameter) ] ; + } +} + +rule declare-targets ( all-libraries * : headers * ) +{ + configure.register-components $(all-libraries) ; + + # Select the libraries to install. + libraries = [ libraries-to-install $(all-libraries) ] ; + configure.components-building $(libraries) ; + + if [ option.get "show-libraries" : : true ] + { + ECHO The following libraries require building: ; + for local l in $(libraries) + { + ECHO " - $(l)" ; + } + EXIT ; + } + + declare_top_level_targets $(libraries) : $(headers) ; +} + +# Returns the properties identifying the toolset. We'll use them +# below to configure checks. These are essentially same as in +# configure.builds, except we don't use address-model and +# architecture - as we're trying to detect them here. +# +rule toolset-properties ( properties * ) +{ + local toolset = [ property.select : $(properties) ] ; + local toolset-version-property = "" ; + return [ property.select $(toolset-version-property) : $(properties) ] ; +} + +feature.feature deduced-address-model : 32 64 : propagated optional composite hidden ; +feature.compose 32 : 32 ; +feature.compose 64 : 64 ; + +rule deduce-address-model ( properties * ) +{ + local result ; + local filtered = [ toolset-properties $(properties) ] ; + + if [ configure.builds /boost/architecture//32 : $(filtered) : 32-bit ] + { + result = 32 ; + } + else if [ configure.builds /boost/architecture//64 : $(filtered) : 64-bit ] + { + result = 64 ; + } + + if $(result) + { + # Normally, returning composite feature here is equivalent to forcing + # consituent properties as well. But we only want to indicate toolset + # deduced default, so also pick whatever address-model is explicitly + # specified, if any. + result = $(result) [ property.select : $(properties) ] ; + } + return $(result) ; +} + +rule address-model ( ) +{ + return @boostcpp.deduce-address-model ; +} + +local deducable-architectures = arm mips1 power sparc x86 combined ; +feature.feature deduced-architecture : $(deducable-architectures) : propagated optional composite hidden ; +for a in $(deducable-architectures) +{ + feature.compose $(a) : $(a) ; +} + +rule deduce-architecture ( properties * ) +{ + local result ; + local filtered = [ toolset-properties $(properties) ] ; + if [ configure.builds /boost/architecture//arm : $(filtered) : arm ] + { + result = arm ; + } + else if [ configure.builds /boost/architecture//mips1 : $(filtered) : mips1 ] + { + result = mips1 ; + } + else if [ configure.builds /boost/architecture//power : $(filtered) : power ] + { + result = power ; + } + else if [ configure.builds /boost/architecture//sparc : $(filtered) : sparc ] + { + result = sparc ; + } + else if [ configure.builds /boost/architecture//x86 : $(filtered) : x86 ] + { + result = x86 ; + } + else if [ configure.builds /boost/architecture//combined : $(filtered) : combined ] + { + result = combined ; + } + + if $(result) + { + # See comment in deduce-address-model. + result = $(result) [ property.select : $(properties) ] ; + } + return $(result) ; +} + +rule architecture ( ) +{ + return @boostcpp.deduce-architecture ; +} diff --git a/boost/bootstrap.bat b/boost/bootstrap.bat new file mode 100644 index 000000000..3678b1bcc --- /dev/null +++ b/boost/bootstrap.bat @@ -0,0 +1,81 @@ +@ECHO OFF + +REM Copyright (C) 2009 Vladimir Prus +REM +REM Distributed under the Boost Software License, Version 1.0. +REM (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +ECHO Building Boost.Build engine +if exist ".\tools\build\src\engine\bin.ntx86\b2.exe" del tools\build\src\engine\bin.ntx86\b2.exe +if exist ".\tools\build\src\engine\bin.ntx86\bjam.exe" del tools\build\src\engine\bin.ntx86\bjam.exe +if exist ".\tools\build\src\engine\bin.ntx86_64\b2.exe" del tools\build\src\engine\bin.ntx86_64\b2.exe +if exist ".\tools\build\src\engine\bin.ntx86_64\bjam.exe" del tools\build\src\engine\bin.ntx86_64\bjam.exe +pushd tools\build\src\engine + +call .\build.bat %* > ..\..\..\..\bootstrap.log +@ECHO OFF + +popd + +if exist ".\tools\build\src\engine\bin.ntx86\bjam.exe" ( + copy .\tools\build\src\engine\bin.ntx86\b2.exe . > nul + copy .\tools\build\src\engine\bin.ntx86\bjam.exe . > nul + goto :bjam_built) + +if exist ".\tools\build\src\engine\bin.ntx86_64\bjam.exe" ( + copy .\tools\build\src\engine\bin.ntx86_64\b2.exe . > nul + copy .\tools\build\src\engine\bin.ntx86_64\bjam.exe . > nul + goto :bjam_built) + +goto :bjam_failure + +:bjam_built + +REM Ideally, we should obtain the toolset that build.bat has +REM guessed. However, it uses setlocal at the start and does not +REM export BOOST_JAM_TOOLSET, and I don't know how to do that +REM properly. Default to msvc for now. +set toolset=msvc + +ECHO import option ; > project-config.jam +ECHO. >> project-config.jam +ECHO using %toolset% ; >> project-config.jam +ECHO. >> project-config.jam +ECHO option.set keep-going : false ; >> project-config.jam +ECHO. >> project-config.jam + +ECHO. +ECHO Bootstrapping is done. To build, run: +ECHO. +ECHO .\b2 +ECHO. +ECHO To adjust configuration, edit 'project-config.jam'. +ECHO Further information: +ECHO. +ECHO - Command line help: +ECHO .\b2 --help +ECHO. +ECHO - Getting started guide: +ECHO http://boost.org/more/getting_started/windows.html +ECHO. +ECHO - Boost.Build documentation: +ECHO http://www.boost.org/build/doc/html/index.html + +goto :end + +:bjam_failure + +ECHO. +ECHO Failed to build Boost.Build engine. +ECHO Please consult bootstrap.log for further diagnostics. +ECHO. +ECHO You can try to obtain a prebuilt binary from +ECHO. +ECHO http://sf.net/project/showfiles.php?group_id=7586^&package_id=72941 +ECHO. +ECHO Also, you can file an issue at http://svn.boost.org +ECHO Please attach bootstrap.log in that case. + +goto :end + +:end diff --git a/boost/bootstrap.sh b/boost/bootstrap.sh new file mode 100644 index 000000000..9e61569e2 --- /dev/null +++ b/boost/bootstrap.sh @@ -0,0 +1,409 @@ +#!/bin/sh +# Copyright (C) 2005, 2006 Douglas Gregor. +# Copyright (C) 2006 The Trustees of Indiana University +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +# boostinspect:notab - Tabs are required for the Makefile. + +BJAM="" +TOOLSET="" +BJAM_CONFIG="" +BUILD="" +PREFIX=/usr/local +EPREFIX= +LIBDIR= +INCLUDEDIR= +LIBS="" +PYTHON=python +PYTHON_VERSION= +PYTHON_ROOT= +ICU_ROOT= + +# Handle case where builtin shell version of echo command doesn't +# support -n. Use the installed echo executable if there is one +# rather than builtin version to ensure -n is supported. +ECHO=`which echo` +if test "x$ECHO" = x; then + ECHO=echo +fi + +# Internal flags +flag_no_python= +flag_icu= +flag_show_libraries= + +for option +do + case $option in + + -help | --help | -h) + want_help=yes ;; + + -prefix=* | --prefix=*) + PREFIX=`expr "x$option" : "x-*prefix=\(.*\)"` + ;; + + -exec-prefix=* | --exec-prefix=*) + EPREFIX=`expr "x$option" : "x-*exec-prefix=\(.*\)"` + ;; + + -libdir=* | --libdir=*) + LIBDIR=`expr "x$option" : "x-*libdir=\(.*\)"` + ;; + + -includedir=* | --includedir=*) + INCLUDEDIR=`expr "x$option" : "x-*includedir=\(.*\)"` + ;; + + -show-libraries | --show-libraries ) + flag_show_libraries=yes + ;; + + -with-bjam=* | --with-bjam=* ) + BJAM=`expr "x$option" : "x-*with-bjam=\(.*\)"` + ;; + + -with-icu | --with-icu ) + flag_icu=yes + ;; + + -with-icu=* | --with-icu=* ) + flag_icu=yes + ICU_ROOT=`expr "x$option" : "x-*with-icu=\(.*\)"` + ;; + + -without-icu | --without-icu ) + flag_icu=no + ;; + + -with-libraries=* | --with-libraries=* ) + library_list=`expr "x$option" : "x-*with-libraries=\(.*\)"` + if test "$library_list" != "all"; then + old_IFS=$IFS + IFS=, + for library in $library_list + do + LIBS="$LIBS --with-$library" + + if test $library = python; then + requested_python=yes + fi + done + IFS=$old_IFS + + if test "x$requested_python" != xyes; then + flag_no_python=yes + fi + fi + ;; + + -without-libraries=* | --without-libraries=* ) + library_list=`expr "x$option" : "x-*without-libraries=\(.*\)"` + old_IFS=$IFS + IFS=, + for library in $library_list + do + LIBS="$LIBS --without-$library" + + if test $library = python; then + flag_no_python=yes + fi + done + IFS=$old_IFS + ;; + + -with-python=* | --with-python=* ) + PYTHON=`expr "x$option" : "x-*with-python=\(.*\)"` + ;; + + -with-python-root=* | --with-python-root=* ) + PYTHON_ROOT=`expr "x$option" : "x-*with-python-root=\(.*\)"` + ;; + + -with-python-version=* | --with-python-version=* ) + PYTHON_VERSION=`expr "x$option" : "x-*with-python-version=\(.*\)"` + ;; + + -with-toolset=* | --with-toolset=* ) + TOOLSET=`expr "x$option" : "x-*with-toolset=\(.*\)"` + ;; + + -*) + { echo "error: unrecognized option: $option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + esac +done + +if test "x$want_help" = xyes; then + cat < bootstrap.log 2>&1 + if [ $? -ne 0 ]; then + echo + echo "Failed to build Boost.Build build engine" + echo "Consult 'bootstrap.log' for more details" + exit 1 + fi + cd "$pwd" + arch=`cd $my_dir/tools/build/src/engine && ./bootstrap/jam0 -d0 -f build.jam --toolset=$TOOLSET --toolset-root= --show-locate-target && cd ..` + BJAM="$my_dir/tools/build/src/engine/$arch/b2" + echo "tools/build/src/engine/$arch/b2" + cp "$BJAM" . + cp "$my_dir/tools/build/src/engine/$arch/bjam" . + +fi + +# TBD: Turn BJAM into an absolute path + +# If there is a list of libraries +if test "x$flag_show_libraries" = xyes; then + cat < /dev/null 2>&1` + if [ "$?" -ne "0" ]; then + flag_no_python=yes + fi +fi + +if test "x$flag_no_python" = x; then + if test "x$PYTHON_VERSION" = x; then + $ECHO -n "Detecting Python version... " + PYTHON_VERSION=`$PYTHON -c "import sys; print (\"%d.%d\" % (sys.version_info[0], sys.version_info[1]))"` + echo $PYTHON_VERSION + fi + + if test "x$PYTHON_ROOT" = x; then + $ECHO -n "Detecting Python root... " + PYTHON_ROOT=`$PYTHON -c "import sys; print(sys.prefix)"` + echo $PYTHON_ROOT + fi +fi + +# Configure ICU +$ECHO -n "Unicode/ICU support for Boost.Regex?... " +if test "x$flag_icu" != xno; then + if test "x$ICU_ROOT" = x; then + COMMON_ICU_PATHS="/usr /usr/local /sw" + for p in $COMMON_ICU_PATHS; do + if test -r $p/include/unicode/utypes.h; then + ICU_ROOT=$p + fi + done + + if test "x$ICU_ROOT" = x; then + echo "not found." + else + BJAM_CONFIG="$BJAM_CONFIG -sICU_PATH=$ICU_ROOT" + echo "$ICU_ROOT" + fi + else + BJAM_CONFIG="$BJAM_CONFIG -sICU_PATH=$ICU_ROOT" + echo "$ICU_ROOT" + fi +else + echo "disabled." +fi + +# Backup the user's existing project-config.jam +JAM_CONFIG_OUT="project-config.jam" +if test -r "project-config.jam"; then + counter=1 + + while test -r "project-config.jam.$counter"; do + counter=`expr $counter + 1` + done + + echo "Backing up existing Boost.Build configuration in project-config.jam.$counter" + mv "project-config.jam" "project-config.jam.$counter" +fi + +# Generate user-config.jam +echo "Generating Boost.Build configuration in project-config.jam..." +cat > project-config.jam < ] +{ + using $TOOLSET ; +} + +project : default-build $TOOLSET ; +EOF + +# - Python configuration +if test "x$flag_no_python" = x; then + cat >> project-config.jam <> project-config.jam << EOF + +path-constant ICU_PATH : $ICU_ROOT ; + +EOF +fi + +cat >> project-config.jam << EOF + +# List of --with- and --without- +# options. If left empty, all libraries will be built. +# Options specified on the command line completely +# override this variable. +libraries = $LIBS ; + +# These settings are equivivalent to corresponding command-line +# options. +option.set prefix : $PREFIX ; +option.set exec-prefix : $EPREFIX ; +option.set libdir : $LIBDIR ; +option.set includedir : $INCLUDEDIR ; + +# Stop on first error +option.set keep-going : false ; +EOF + +cat << EOF + +Bootstrapping is done. To build, run: + + ./b2 + +To adjust configuration, edit 'project-config.jam'. +Further information: + + - Command line help: + ./b2 --help + + - Getting started guide: + http://www.boost.org/more/getting_started/unix-variants.html + + - Boost.Build documentation: + http://www.boost.org/build/doc/html/index.html + +EOF diff --git a/boost/rst.css b/boost/rst.css new file mode 100644 index 000000000..0517aad57 --- /dev/null +++ b/boost/rst.css @@ -0,0 +1,149 @@ +@import url("doc/src/boostbook.css"); +@import url("doc/src/docutils.css"); +/* Copyright David Abrahams 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) + */ + +dl.docutils dt { + font-weight: bold } + +img.boost-logo { + border: none; + vertical-align: middle +} + +pre.literal-block span.concept { + font-style: italic; +} + +.nav { +display: inline; +list-style-type: none; +} + +.prevpage { +padding-top: -5px; +text-align: left; +float: left; +} + +.nextpage { +padding-top: -20px; +text-align: right; +float: right; +} + +div.small { + font-size: smaller } + +h2 a { + font-size: 90%; +} +h3 a { + font-size: 80%; +} +h4 a { + font-size: 70%; +} +h5 a { + font-size: 60%; +} + +dl,table +{ + text-align: left; + font-size: 10pt; + line-height: 1.15; +} + + +/*============================================================================= + Tables +=============================================================================*/ + +/* The only clue docutils gives us that tables are logically tables, + and not, e.g., footnotes, is that they have border="1". Therefore + we're keying off of that. We used to manually patch docutils to + add a "table" class to all logical tables, but that proved much too + fragile. +*/ + + table[border="1"] + { + width: 92%; + margin-left: 4%; + margin-right: 4%; + } + + table[border="1"] + { + padding: 4px; + } + + /* Table Cells */ + table[border="1"] tr td + { + padding: 0.5em; + text-align: left; + font-size: 9pt; + } + + table[border="1"] tr th + { + padding: 0.5em 0.5em 0.5em 0.5em; + border: 1pt solid white; + font-size: 80%; + } + + @media screen + { + + /* Tables */ + table[border="1"] tr td + { + border: 1px solid #DCDCDC; + } + + table[border="1"] tr th + { + background-color: #F0F0F0; + border: 1px solid #DCDCDC; + } + + pre, + .screen + { + border: 1px solid #DCDCDC; + } + + td pre + td .screen + { + border: 0px + } + + .sidebar pre + { + border: 0px + } + + } + + pre, + .screen + { + font-size: 9pt; + display: block; + margin: 1pc 4% 0pc 4%; + padding: 0.5pc 0.5pc 0.5pc 0.5pc; + } + + /* Program listings in tables don't get borders */ + td pre, + td .screen + { + margin: 0pc 0pc 0pc 0pc; + padding: 0pc 0pc 0pc 0pc; + } +